forked from egao1980/PyAV
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathautolint
More file actions
executable file
·196 lines (140 loc) · 5.39 KB
/
Copy pathautolint
File metadata and controls
executable file
·196 lines (140 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/usr/bin/env python
from __future__ import print_function
import argparse
import fnmatch
import os
import re
import sys
import autopep8
import editorconfig
import lib2to3.refactor
SOURCE_ROOTS = ['av', 'docs', 'examples', 'include', 'scratchpad', 'scripts', 'tests']
SOURCE_EXTS = set('.py .pyx .pxd .rst'.split())
def iter_source_paths():
for root in SOURCE_ROOTS:
for dir_path, _, file_names in os.walk(root):
for file_name in file_names:
base, ext = os.path.splitext(file_name)
if base.startswith('.'):
continue
if ext not in SOURCE_EXTS:
continue
yield os.path.abspath(os.path.join(dir_path, file_name))
def apply_editorconfig(source, path):
config = editorconfig.get_properties(path)
soft_indent = config.get('indent_style', 'space') == 'space'
indent_size = int(config.get('indent_size', 4))
do_trim = config['trim_trailing_whitespace'] == 'true'
do_final_newline = config['insert_final_newline'] == 'true'
spaced_indent = ' ' * indent_size
output = []
for line in source.splitlines():
# Apply trim_trailing_whitespace.
if do_trim:
line = line.rstrip()
# Adapt tabs to/from spaces.
m = re.match(r'(\s+)(.*)', line)
if m:
indent, content = m.groups()
if soft_indent:
indent.replace('\t', spaced_indent)
else:
indent.replace(indent, '\t')
line = indent + content
output.append(line)
while output and not output[-1]:
output.pop()
if do_final_newline:
output.append('')
return '\n'.join(output)
pep8_fixes_by_ext = {
pattern: tuple(filter(None, (x.split('#')[0].split('-')[0].strip() for x in value.splitlines())))
for pattern, value in {
'*': '''
E121 - Fix indentation to be a multiple of four.
E122 - Add absent indentation for hanging indentation.
''',
'.py': '''
E226 - Fix missing whitespace around arithmetic operator.
E227 - Fix missing whitespace around bitwise/shift operator.
E228 - Fix missing whitespace around modulo operator.
E231 - Add missing whitespace.
E242 - Remove extraneous whitespace around operator.
W603 - Use "!=" instead of "<>"
W604 - Use "repr()" instead of backticks.
E22 - Fix extraneous whitespace around keywords. # Messes with Cython.
E241 - Fix extraneous whitespace around keywords. # Messes with Cython.
''',
'.py*': '''
E224 - Remove extraneous whitespace around operator.
# E301 - Add missing blank line.
# E302 - Add missing 2 blank lines.
# E303 - Remove extra blank lines.
E251 - Remove whitespace around parameter '=' sign.
E304 - Remove blank line following function decorator.
E401 - Put imports on separate lines.
E20 - Remove extraneous whitespace.
E211 - Remove extraneous whitespace.
''',
}.iteritems()
}
def apply_autopep8(source, path):
fixes = set()
ext = os.path.splitext(path)[1]
for pattern in pep8_fixes_by_ext:
if fnmatch.fnmatch(ext, pattern):
fixes.update(pep8_fixes_by_ext[pattern])
source = autopep8.fix_code(source, options=dict(
select=filter(None, fixes),
))
return source
def apply_future(source, path):
if os.path.splitext(path)[1] not in ('.py', ):
return source
m = re.search(r'^from __future__ import ([\w, \t]+)', source, flags=re.MULTILINE)
if m:
features = set(x.strip() for x in m.group(1).split(','))
else:
features = set()
fixes = []
if 'print_function' not in features and re.search(r'^\s*print\s+', source, flags=re.MULTILINE):
fixes.append('lib2to3.fixes.fix_print')
if not fixes:
# Nothing to do.
return source
# The parser chokes if the last line is not empty.
if not source.endswith('\n'):
source += '\n'
tool = lib2to3.refactor.RefactoringTool(fixes)
tree = tool.refactor_string(source, path)
source = str(tree)
if 'print' in source:
features.add('print_function')
source = 'from __future__ import {}\n{}'.format(', '.join(sorted(features)), source)
return source
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-a', '--all', action='store_true')
parser.add_argument('-e', '--editorconfig', action='store_true')
parser.add_argument('-p', '--pep8', action='store_true')
parser.add_argument('-f', '--future', action='store_true')
args = parser.parse_args()
if not (args.all or args.editorconfig or args.pep8 or args.future):
print("Nothing to do.", file=sys.stderr)
parser.print_usage()
exit(1)
for path in iter_source_paths():
before = after = open(path).read()
if args.all or args.pep8:
after = apply_autopep8(after, path)
if args.all or args.future:
after = apply_future(after, path)
if args.all or args.editorconfig:
after = apply_editorconfig(after, path)
if before == after:
continue
print(path)
with open(path, 'wb') as fh:
fh.write(after)
if __name__ == '__main__':
main()