UtilitiesPython2/pep8.py

changeset 2864
d973dab8b715
parent 2861
cdcbca0cea82
child 2866
c77e08c38a5c
equal deleted inserted replaced
2863:62171fa4a6a4 2864:d973dab8b715
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 2
3 # 3 #
4 # pep8.py - Check Python source code formatting, according to PEP 8 4 # pep8.py - Check Python source code formatting, according to PEP 8
5 # Copyright (C) 2006 Johann C. Rocholl <johann@rocholl.net> 5 # Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
6 # Copyright (C) 2009-2013 Florent Xicluna <florent.xicluna@gmail.com>
6 # 7 #
7 # Permission is hereby granted, free of charge, to any person 8 # Permission is hereby granted, free of charge, to any person
8 # obtaining a copy of this software and associated documentation files 9 # obtaining a copy of this software and associated documentation files
9 # (the "Software"), to deal in the Software without restriction, 10 # (the "Software"), to deal in the Software without restriction,
10 # including without limitation the rights to use, copy, modify, merge, 11 # including without limitation the rights to use, copy, modify, merge,
42 300 blank lines 43 300 blank lines
43 400 imports 44 400 imports
44 500 line length 45 500 line length
45 600 deprecation 46 600 deprecation
46 700 statements 47 700 statements
47 900 processing errors 48 900 syntax error
48
49 You can add checks to this program by writing plugins. Each plugin is
50 a simple function that is called for each line of source code, either
51 physical or logical.
52
53 Physical line:
54 - Raw line of text from the input file.
55
56 Logical line:
57 - Multi-line statements converted to a single line.
58 - Stripped left and right.
59 - Contents of strings replaced with 'xxx' of same length.
60 - Comments removed.
61
62 The check function requests physical or logical lines by the name of
63 the first argument:
64
65 def maximum_line_length(physical_line)
66 def extraneous_whitespace(logical_line)
67 def blank_lines(logical_line, blank_lines, indent_level, line_number)
68
69 The last example above demonstrates how check plugins can request
70 additional information with extra arguments. All attributes of the
71 Checker object are available. Some examples:
72
73 lines: a list of the raw lines from the input file
74 tokens: the tokens that contribute to this logical line
75 line_number: line number in the input file
76 blank_lines: blank lines before this one
77 indent_char: first indentation character in this file (' ' or '\t')
78 indent_level: indentation (with tabs expanded to multiples of 8)
79 previous_indent_level: indentation on previous line
80 previous_logical: previous logical line
81
82 The docstring of each check function shall be the relevant part of
83 text from PEP 8. It is printed if the user enables --show-pep8.
84 Several docstrings contain examples directly from the PEP 8 document.
85
86 Okay: spam(ham[1], {eggs: 2})
87 E201: spam( ham[1], {eggs: 2})
88
89 These examples are verified automatically when pep8.py is run with the
90 --doctest option. You can add examples for your own check functions.
91 The format is simple: "Okay" or error/warning code followed by colon
92 and space, the rest of the line is example source code. If you put 'r'
93 before the docstring, you can use \n for newline, \t for tab and \s
94 for space.
95
96 """ 49 """
97 50
98 # 51 #
99 # This is a modified version to make the original pep8.py better suitable 52 # This is a modified version to make the original pep8.py better suitable
100 # for being called from within the eric5 IDE. The modifications are as 53 # for being called from within the eric5 IDE. The modifications are as
101 # follows: 54 # follows:
102 # 55 #
103 # - made messages translatable via Qt 56 # - made messages translatable via Qt
57 # - added code for eric5 integration
104 # 58 #
105 # Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de> 59 # Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
106 # 60 #
107 61
108 __version__ = '0.6.1' 62 __version__ = '1.4.6'
109 63
110 import os 64 import os
111 import sys 65 import sys
112 import re 66 import re
113 import time 67 import time
115 import keyword 69 import keyword
116 import tokenize 70 import tokenize
117 from optparse import OptionParser 71 from optparse import OptionParser
118 from fnmatch import fnmatch 72 from fnmatch import fnmatch
119 try: 73 try:
120 frozenset 74 from configparser import RawConfigParser
121 except NameError: 75 from io import TextIOWrapper
122 from sets import ImmutableSet as frozenset 76 except ImportError:
123 77 from ConfigParser import RawConfigParser # __IGNORE_WARNING__
124 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git' 78
125 DEFAULT_IGNORE = 'E24' 79 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'
80 DEFAULT_IGNORE = 'E123,E226,E24'
81 if sys.platform == 'win32':
82 DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
83 else:
84 DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or
85 os.path.expanduser('~/.config'), 'pep8')
86 PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')
87 TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
126 MAX_LINE_LENGTH = 79 88 MAX_LINE_LENGTH = 79
89 REPORT_FORMAT = {
90 'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
91 'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
92 }
93
94 PyCF_ONLY_AST = 1024
95 SINGLETONS = frozenset(['False', 'None', 'True'])
96 KEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS
97 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
98 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])
99 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
100 WS_NEEDED_OPERATORS = frozenset([
101 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
102 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='])
103 WHITESPACE = frozenset(' \t')
104 SKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE,
105 tokenize.INDENT, tokenize.DEDENT])
106 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
127 107
128 INDENT_REGEX = re.compile(r'([ \t]*)') 108 INDENT_REGEX = re.compile(r'([ \t]*)')
129 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*(,)') 109 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
130 SELFTEST_REGEX = re.compile(r'(Okay|[EW]\d{3}):\s(.*)') 110 RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,\s*\w+\s*,\s*\w+')
131 ERRORCODE_REGEX = re.compile(r'[EW]\d{3}') 111 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
132 DOCSTRING_REGEX = re.compile(r'u?r?["\']') 112 DOCSTRING_REGEX = re.compile(r'u?r?["\']')
133 WHITESPACE_AROUND_OPERATOR_REGEX = \
134 re.compile('([^\w\s]*)\s*(\t| )\s*([^\w\s]*)')
135 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]') 113 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
136 WHITESPACE_AROUND_NAMED_PARAMETER_REGEX = \ 114 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
137 re.compile(r'[()]|\s=[^=]|[^=!<>]=\s') 115 COMPARE_SINGLETON_REGEX = re.compile(r'([=!]=)\s*(None|False|True)')
138 116 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
139 117 r'|\s*\(\s*([^)]*[^ )])\s*\))')
140 WHITESPACE = ' \t' 118 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
141 119 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
142 BINARY_OPERATORS = frozenset(['**=', '*=', '+=', '-=', '!=', '<>', 120 LAMBDA_REGEX = re.compile(r'\blambda\b')
143 '%=', '^=', '&=', '|=', '==', '/=', '//=', '<=', '>=', '<<=', '>>=', 121 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
144 '%', '^', '&', '|', '=', '/', '//', '<', '>', '<<']) 122
145 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-']) 123 # Work around Python < 2.6 behaviour, which does not generate NL after
146 OPERATORS = BINARY_OPERATORS | UNARY_OPERATORS 124 # a comment which is on a line by itself.
147 SKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.INDENT, 125 COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
148 tokenize.DEDENT, tokenize.NEWLINE])
149 E225NOT_KEYWORDS = (frozenset(keyword.kwlist + ['print']) -
150 frozenset(['False', 'None', 'True']))
151 BENCHMARK_KEYS = ('directories', 'files', 'logical lines', 'physical lines')
152
153 options = None
154 args = None
155 126
156 127
157 ############################################################################## 128 ##############################################################################
158 # Plugins (check functions) for physical lines 129 # Plugins (check functions) for physical lines
159 ############################################################################## 130 ##############################################################################
186 157
187 Okay: if True:\n return 158 Okay: if True:\n return
188 W191: if True:\n\treturn 159 W191: if True:\n\treturn
189 """ 160 """
190 indent = INDENT_REGEX.match(physical_line).group(1) 161 indent = INDENT_REGEX.match(physical_line).group(1)
191 if indent.count('\t'): 162 if '\t' in indent:
192 return indent.index('\t'), "W191" 163 return indent.index('\t'), "W191"
193 164
194 165
195 def trailing_whitespace(physical_line): 166 def trailing_whitespace(physical_line):
196 r""" 167 r"""
205 [1] http://docs.python.org/reference/lexical_analysis.html#blank-lines 176 [1] http://docs.python.org/reference/lexical_analysis.html#blank-lines
206 177
207 The warning returned varies on whether the line itself is blank, for easier 178 The warning returned varies on whether the line itself is blank, for easier
208 filtering for those who want to indent their blank lines. 179 filtering for those who want to indent their blank lines.
209 180
210 Okay: spam(1) 181 Okay: spam(1)\n#
211 W291: spam(1)\s 182 W291: spam(1) \n#
212 W293: class Foo(object):\n \n bang = 12 183 W293: class Foo(object):\n \n bang = 12
213 """ 184 """
214 physical_line = physical_line.rstrip('\n') # chr(10), newline 185 physical_line = physical_line.rstrip('\n') # chr(10), newline
215 physical_line = physical_line.rstrip('\r') # chr(13), carriage return 186 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
216 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L 187 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
217 stripped = physical_line.rstrip() 188 stripped = physical_line.rstrip(' \t\v')
218 if physical_line != stripped: 189 if physical_line != stripped:
219 if stripped: 190 if stripped:
220 return len(stripped), "W291" 191 return len(stripped), "W291"
221 else: 192 else:
222 return 0, "W293" 193 return 0, "W293"
227 JCR: Trailing blank lines are superfluous. 198 JCR: Trailing blank lines are superfluous.
228 199
229 Okay: spam(1) 200 Okay: spam(1)
230 W391: spam(1)\n 201 W391: spam(1)\n
231 """ 202 """
232 if physical_line.strip() == '' and line_number == len(lines): 203 if not physical_line.rstrip() and line_number == len(lines):
233 return 0, "W391" 204 return 0, "W391"
234 205
235 206
236 def missing_newline(physical_line): 207 def missing_newline(physical_line):
237 """ 208 """
238 JCR: The last line should have a newline. 209 JCR: The last line should have a newline.
210
211 Reports warning W292.
239 """ 212 """
240 if physical_line.rstrip() == physical_line: 213 if physical_line.rstrip() == physical_line:
241 return len(physical_line), "W292" 214 return len(physical_line), "W292"
242 215
243 216
244 def maximum_line_length(physical_line): 217 def maximum_line_length(physical_line, max_line_length):
245 """ 218 """
246 Limit all lines to a maximum of 79 characters. 219 Limit all lines to a maximum of 79 characters.
247 220
248 There are still many devices around that are limited to 80 character 221 There are still many devices around that are limited to 80 character
249 lines; plus, limiting windows to 80 characters makes it possible to have 222 lines; plus, limiting windows to 80 characters makes it possible to have
250 several windows side-by-side. The default wrapping on such devices looks 223 several windows side-by-side. The default wrapping on such devices looks
251 ugly. Therefore, please limit all lines to a maximum of 79 characters. 224 ugly. Therefore, please limit all lines to a maximum of 79 characters.
252 For flowing long blocks of text (docstrings or comments), limiting the 225 For flowing long blocks of text (docstrings or comments), limiting the
253 length to 72 characters is recommended. 226 length to 72 characters is recommended.
227
228 Reports error E501.
254 """ 229 """
255 line = physical_line.rstrip() 230 line = physical_line.rstrip()
256 length = len(line) 231 length = len(line)
257 if length > MAX_LINE_LENGTH: 232 if length > max_line_length and not noqa(line):
258 try: 233 if hasattr(line, 'decode'): # Python 2
259 # The line could contain multi-byte characters 234 # The line could contain multi-byte characters
260 if hasattr(line, 'decode'): # Python 2 only 235 try:
261 length = len(line.decode('utf-8')) 236 length = len(line.decode('utf-8'))
262 except UnicodeDecodeError: 237 except UnicodeError:
263 pass 238 pass
264 if length > MAX_LINE_LENGTH: 239 if length > max_line_length:
265 return MAX_LINE_LENGTH, "E501", length 240 return max_line_length, "E501", length, max_line_length
266 241
267 242
268 ############################################################################## 243 ##############################################################################
269 # Plugins (check functions) for logical lines 244 # Plugins (check functions) for logical lines
270 ############################################################################## 245 ##############################################################################
271 246
272 247
273 def blank_lines(logical_line, blank_lines, indent_level, line_number, 248 def blank_lines(logical_line, blank_lines, indent_level, line_number,
274 previous_logical, previous_indent_level, 249 previous_logical, previous_indent_level):
275 blank_lines_before_comment):
276 r""" 250 r"""
277 Separate top-level function and class definitions with two blank lines. 251 Separate top-level function and class definitions with two blank lines.
278 252
279 Method definitions inside a class are separated by a single blank line. 253 Method definitions inside a class are separated by a single blank line.
280 254
291 E302: def a():\n pass\n\ndef b(n):\n pass 265 E302: def a():\n pass\n\ndef b(n):\n pass
292 E303: def a():\n pass\n\n\n\ndef b(n):\n pass 266 E303: def a():\n pass\n\n\n\ndef b(n):\n pass
293 E303: def a():\n\n\n\n pass 267 E303: def a():\n\n\n\n pass
294 E304: @decorator\n\ndef a():\n pass 268 E304: @decorator\n\ndef a():\n pass
295 """ 269 """
296 if line_number == 1: 270 if line_number < 3 and not previous_logical:
297 return # Don't expect blank lines before the first line 271 return # Don't expect blank lines before the first line
298 max_blank_lines = max(blank_lines, blank_lines_before_comment)
299 if previous_logical.startswith('@'): 272 if previous_logical.startswith('@'):
300 if max_blank_lines: 273 if blank_lines:
301 return 0, "E304" 274 yield 0, "E304"
302 elif max_blank_lines > 2 or (indent_level and max_blank_lines == 2): 275 elif blank_lines > 2 or (indent_level and blank_lines == 2):
303 return 0, "E303", max_blank_lines 276 yield 0, "E303", blank_lines
304 elif (logical_line.startswith('def ') or 277 elif logical_line.startswith(('def ', 'class ', '@')):
305 logical_line.startswith('class ') or
306 logical_line.startswith('@')):
307 if indent_level: 278 if indent_level:
308 if not (max_blank_lines or previous_indent_level < indent_level or 279 if not (blank_lines or previous_indent_level < indent_level or
309 DOCSTRING_REGEX.match(previous_logical)): 280 DOCSTRING_REGEX.match(previous_logical)):
310 return 0, "E301" 281 yield 0, "E301"
311 elif max_blank_lines != 2: 282 elif blank_lines != 2:
312 return 0, "E302", max_blank_lines 283 yield 0, "E302", blank_lines
313 284
314 285
315 def extraneous_whitespace(logical_line): 286 def extraneous_whitespace(logical_line):
316 """ 287 """
317 Avoid extraneous whitespace in the following situations: 288 Avoid extraneous whitespace in the following situations:
335 line = logical_line 306 line = logical_line
336 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line): 307 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
337 text = match.group() 308 text = match.group()
338 char = text.strip() 309 char = text.strip()
339 found = match.start() 310 found = match.start()
340 if text == char + ' ' and char in '([{': 311 if text == char + ' ':
341 return found + 1, "E201", char 312 # assert char in '([{'
342 if text == ' ' + char and line[found - 1] != ',': 313 yield found + 1, "E201", char
343 if char in '}])': 314 elif line[found - 1] != ',':
344 return found, "E202", char 315 code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
345 if char in ',;:': 316 yield found, code, char
346 return found, "E203", char 317
318
319 def whitespace_around_keywords(logical_line):
320 r"""
321 Avoid extraneous whitespace around keywords.
322
323 Okay: True and False
324 E271: True and False
325 E272: True and False
326 E273: True and\tFalse
327 E274: True\tand False
328 """
329 for match in KEYWORD_REGEX.finditer(logical_line):
330 before, after = match.groups()
331
332 if '\t' in before:
333 yield match.start(1), "E274"
334 elif len(before) > 1:
335 yield match.start(1), "E272"
336
337 if '\t' in after:
338 yield match.start(2), "E273"
339 elif len(after) > 1:
340 yield match.start(2), "E271"
347 341
348 342
349 def missing_whitespace(logical_line): 343 def missing_whitespace(logical_line):
350 """ 344 """
351 JCR: Each comma, semicolon or colon should be followed by whitespace. 345 JCR: Each comma, semicolon or colon should be followed by whitespace.
356 Okay: a[:4] 350 Okay: a[:4]
357 Okay: a[1:] 351 Okay: a[1:]
358 Okay: a[1:4:2] 352 Okay: a[1:4:2]
359 E231: ['a','b'] 353 E231: ['a','b']
360 E231: foo(bar,baz) 354 E231: foo(bar,baz)
355 E231: [{'a':'b'}]
361 """ 356 """
362 line = logical_line 357 line = logical_line
363 for index in range(len(line) - 1): 358 for index in range(len(line) - 1):
364 char = line[index] 359 char = line[index]
365 if char in ',;:' and line[index + 1] not in WHITESPACE: 360 if char in ',;:' and line[index + 1] not in WHITESPACE:
366 before = line[:index] 361 before = line[:index]
367 if char == ':' and before.count('[') > before.count(']'): 362 if char == ':' and before.count('[') > before.count(']') and \
363 before.rfind('{') < before.rfind('['):
368 continue # Slice syntax, no space required 364 continue # Slice syntax, no space required
369 if char == ',' and line[index + 1] == ')': 365 if char == ',' and line[index + 1] == ')':
370 continue # Allow tuple with only one element: (3,) 366 continue # Allow tuple with only one element: (3,)
371 return index, "E231", char 367 yield index, "E231", char
372 368
373 369
374 def indentation(logical_line, previous_logical, indent_char, 370 def indentation(logical_line, previous_logical, indent_char,
375 indent_level, previous_indent_level): 371 indent_level, previous_indent_level):
376 r""" 372 r"""
388 384
389 Okay: a = 1\nb = 2 385 Okay: a = 1\nb = 2
390 E113: a = 1\n b = 2 386 E113: a = 1\n b = 2
391 """ 387 """
392 if indent_char == ' ' and indent_level % 4: 388 if indent_char == ' ' and indent_level % 4:
393 return 0, "E111" 389 yield 0, "E111"
394 indent_expect = previous_logical.endswith(':') 390 indent_expect = previous_logical.endswith(':')
395 if indent_expect and indent_level <= previous_indent_level: 391 if indent_expect and indent_level <= previous_indent_level:
396 return 0, "E112" 392 yield 0, "E112"
397 if indent_level > previous_indent_level and not indent_expect: 393 if indent_level > previous_indent_level and not indent_expect:
398 return 0, "E113" 394 yield 0, "E113"
395
396
397 def continued_indentation(logical_line, tokens, indent_level, hang_closing,
398 noqa, verbose):
399 r"""
400 Continuation lines should align wrapped elements either vertically using
401 Python's implicit line joining inside parentheses, brackets and braces, or
402 using a hanging indent.
403
404 When using a hanging indent the following considerations should be applied:
405
406 - there should be no arguments on the first line, and
407
408 - further indentation should be used to clearly distinguish itself as a
409 continuation line.
410
411 Okay: a = (\n)
412 E123: a = (\n )
413
414 Okay: a = (\n 42)
415 E121: a = (\n 42)
416 E122: a = (\n42)
417 E123: a = (\n 42\n )
418 E124: a = (24,\n 42\n)
419 E125: if (a or\n b):\n pass
420 E126: a = (\n 42)
421 E127: a = (24,\n 42)
422 E128: a = (24,\n 42)
423 """
424 first_row = tokens[0][2][0]
425 nrows = 1 + tokens[-1][2][0] - first_row
426 if noqa or nrows == 1:
427 return
428
429 # indent_next tells us whether the next block is indented; assuming
430 # that it is indented by 4 spaces, then we should not allow 4-space
431 # indents on the final continuation line; in turn, some other
432 # indents are allowed to have an extra 4 spaces.
433 indent_next = logical_line.endswith(':')
434
435 row = depth = 0
436 # remember how many brackets were opened on each line
437 parens = [0] * nrows
438 # relative indents of physical lines
439 rel_indent = [0] * nrows
440 # visual indents
441 indent_chances = {}
442 last_indent = tokens[0][2]
443 indent = [last_indent[1]]
444 if verbose >= 3:
445 print(">>> " + tokens[0][4].rstrip())
446
447 for token_type, text, start, end, line in tokens:
448
449 last_token_multiline = (start[0] != end[0])
450 newline = row < start[0] - first_row
451 if newline:
452 row = start[0] - first_row
453 newline = (not last_token_multiline and
454 token_type not in (tokenize.NL, tokenize.NEWLINE))
455
456 if newline:
457 # this is the beginning of a continuation line.
458 last_indent = start
459 if verbose >= 3:
460 print("... " + line.rstrip())
461
462 # record the initial indent.
463 rel_indent[row] = expand_indent(line) - indent_level
464
465 if depth:
466 # a bracket expression in a continuation line.
467 # find the line that it was opened on
468 for open_row in range(row - 1, -1, -1):
469 if parens[open_row]:
470 break
471 else:
472 # an unbracketed continuation line (ie, backslash)
473 open_row = 0
474 hang = rel_indent[row] - rel_indent[open_row]
475 close_bracket = (token_type == tokenize.OP and text in ']})')
476 visual_indent = (not close_bracket and hang > 0 and
477 indent_chances.get(start[1]))
478
479 if close_bracket and indent[depth]:
480 # closing bracket for visual indent
481 if start[1] != indent[depth]:
482 yield start, "E124"
483 elif close_bracket and not hang:
484 # closing bracket matches indentation of opening bracket's line
485 if hang_closing:
486 yield start, "E133"
487 elif visual_indent is True:
488 # visual indent is verified
489 if not indent[depth]:
490 indent[depth] = start[1]
491 elif visual_indent in (text, str):
492 # ignore token lined up with matching one from a previous line
493 pass
494 elif indent[depth] and start[1] < indent[depth]:
495 # visual indent is broken
496 yield start, "E128"
497 elif hang == 4 or (indent_next and rel_indent[row] == 8):
498 # hanging indent is verified
499 if close_bracket and not hang_closing:
500 yield (start, "E123")
501 else:
502 # indent is broken
503 if hang <= 0:
504 error = "E122"
505 elif indent[depth]:
506 error = "E127"
507 elif hang % 4:
508 error = "E121"
509 else:
510 error = "E126"
511 yield start, error
512
513 # look for visual indenting
514 if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)
515 and not indent[depth]):
516 indent[depth] = start[1]
517 indent_chances[start[1]] = True
518 if verbose >= 4:
519 print("bracket depth %s indent to %s" % (depth, start[1]))
520 # deal with implicit string concatenation
521 elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
522 text in ('u', 'ur', 'b', 'br')):
523 indent_chances[start[1]] = str
524 # special case for the "if" statement because len("if (") == 4
525 elif not indent_chances and not row and not depth and text == 'if':
526 indent_chances[end[1] + 1] = True
527
528 # keep track of bracket depth
529 if token_type == tokenize.OP:
530 if text in '([{':
531 depth += 1
532 indent.append(0)
533 parens[row] += 1
534 if verbose >= 4:
535 print("bracket depth %s seen, col %s, visual min = %s" %
536 (depth, start[1], indent[depth]))
537 elif text in ')]}' and depth > 0:
538 # parent indents should not be more than this one
539 prev_indent = indent.pop() or last_indent[1]
540 for d in range(depth):
541 if indent[d] > prev_indent:
542 indent[d] = 0
543 for ind in list(indent_chances):
544 if ind >= prev_indent:
545 del indent_chances[ind]
546 depth -= 1
547 if depth:
548 indent_chances[indent[depth]] = True
549 for idx in range(row, -1, -1):
550 if parens[idx]:
551 parens[idx] -= 1
552 rel_indent[row] = rel_indent[idx]
553 break
554 assert len(indent) == depth + 1
555 if start[1] not in indent_chances:
556 # allow to line up tokens
557 indent_chances[start[1]] = text
558
559 if indent_next and expand_indent(line) == indent_level + 4:
560 yield last_indent, "E125"
399 561
400 562
401 def whitespace_before_parameters(logical_line, tokens): 563 def whitespace_before_parameters(logical_line, tokens):
402 """ 564 """
403 Avoid extraneous whitespace in the following situations: 565 Avoid extraneous whitespace in the following situations:
413 575
414 Okay: dict['key'] = list[index] 576 Okay: dict['key'] = list[index]
415 E211: dict ['key'] = list[index] 577 E211: dict ['key'] = list[index]
416 E211: dict['key'] = list [index] 578 E211: dict['key'] = list [index]
417 """ 579 """
418 prev_type = tokens[0][0] 580 prev_type, prev_text, __, prev_end, __ = tokens[0]
419 prev_text = tokens[0][1]
420 prev_end = tokens[0][3]
421 for index in range(1, len(tokens)): 581 for index in range(1, len(tokens)):
422 token_type, text, start, end, line = tokens[index] 582 token_type, text, start, end, __ = tokens[index]
423 if (token_type == tokenize.OP and 583 if (token_type == tokenize.OP and
424 text in '([' and 584 text in '([' and
425 start != prev_end and 585 start != prev_end and
426 (prev_type == tokenize.NAME or prev_text in '}])') and 586 (prev_type == tokenize.NAME or prev_text in '}])') and
427 # Syntax "class A (B):" is allowed, but avoid it 587 # Syntax "class A (B):" is allowed, but avoid it
428 (index < 2 or tokens[index - 2][1] != 'class') and 588 (index < 2 or tokens[index - 2][1] != 'class') and
429 # Allow "return (a.foo for a in range(5))" 589 # Allow "return (a.foo for a in range(5))"
430 (not keyword.iskeyword(prev_text))): 590 not keyword.iskeyword(prev_text)):
431 return prev_end, "E211", text 591 yield prev_end, "E211", text
432 prev_type = token_type 592 prev_type = token_type
433 prev_text = text 593 prev_text = text
434 prev_end = end 594 prev_end = end
435 595
436 596
445 E221: a = 4 + 5 605 E221: a = 4 + 5
446 E222: a = 4 + 5 606 E222: a = 4 + 5
447 E223: a = 4\t+ 5 607 E223: a = 4\t+ 5
448 E224: a = 4 +\t5 608 E224: a = 4 +\t5
449 """ 609 """
450 for match in WHITESPACE_AROUND_OPERATOR_REGEX.finditer(logical_line): 610 for match in OPERATOR_REGEX.finditer(logical_line):
451 before, whitespace, after = match.groups() 611 before, after = match.groups()
452 tab = whitespace == '\t' 612
453 offset = match.start(2) 613 if '\t' in before:
454 if before in OPERATORS: 614 yield match.start(1), "E223"
455 return offset, (tab and "E224" or "E222") 615 elif len(before) > 1:
456 elif after in OPERATORS: 616 yield match.start(1), "E221"
457 return offset, (tab and "E223" or "E221") 617
458 618 if '\t' in after:
619 yield match.start(2), "E224"
620 elif len(after) > 1:
621 yield match.start(2), "E222"
459 622
460 def missing_whitespace_around_operator(logical_line, tokens): 623 def missing_whitespace_around_operator(logical_line, tokens):
461 r""" 624 r"""
462 - Always surround these binary operators with a single space on 625 - Always surround these binary operators with a single space on
463 either side: assignment (=), augmented assignment (+=, -= etc.), 626 either side: assignment (=), augmented assignment (+=, -= etc.),
470 Okay: submitted += 1 633 Okay: submitted += 1
471 Okay: x = x * 2 - 1 634 Okay: x = x * 2 - 1
472 Okay: hypot2 = x * x + y * y 635 Okay: hypot2 = x * x + y * y
473 Okay: c = (a + b) * (a - b) 636 Okay: c = (a + b) * (a - b)
474 Okay: foo(bar, key='word', *args, **kwargs) 637 Okay: foo(bar, key='word', *args, **kwargs)
475 Okay: baz(**kwargs)
476 Okay: negative = -1
477 Okay: spam(-1)
478 Okay: alpha[:-i] 638 Okay: alpha[:-i]
479 Okay: if not -5 < x < +5:\n pass
480 Okay: lambda *args, **kw: (args, kw)
481 639
482 E225: i=i+1 640 E225: i=i+1
483 E225: submitted +=1 641 E225: submitted +=1
484 E225: x = x*2 - 1 642 E225: x = x /2 - 1
485 E225: hypot2 = x*x + y*y
486 E225: c = (a+b) * (a-b)
487 E225: c = alpha -4
488 E225: z = x **y 643 E225: z = x **y
644 E226: c = (a+b) * (a-b)
645 E226: hypot2 = x*x + y*y
646 E227: c = a|b
647 E228: msg = fmt%(errno, errmsg)
489 """ 648 """
490 parens = 0 649 parens = 0
491 need_space = False 650 need_space = False
492 prev_type = tokenize.OP 651 prev_type = tokenize.OP
493 prev_text = prev_end = None 652 prev_text = prev_end = None
494 for token_type, text, start, end, line in tokens: 653 for token_type, text, start, end, line in tokens:
495 if token_type in (tokenize.NL, tokenize.NEWLINE, tokenize.ERRORTOKEN): 654 if token_type in (tokenize.NL, tokenize.NEWLINE, tokenize.ERRORTOKEN):
496 # ERRORTOKEN is triggered by backticks in Python 3000 655 # ERRORTOKEN is triggered by backticks in Python 3
497 continue 656 continue
498 if text in ('(', 'lambda'): 657 if text in ('(', 'lambda'):
499 parens += 1 658 parens += 1
500 elif text == ')': 659 elif text == ')':
501 parens -= 1 660 parens -= 1
502 if need_space: 661 if need_space:
503 if start != prev_end: 662 if start != prev_end:
663 # Found a (probably) needed space
664 if need_space is not True and not need_space[1]:
665 yield need_space[0], "E225"
504 need_space = False 666 need_space = False
505 elif text == '>' and prev_text == '<': 667 elif text == '>' and prev_text in ('<', '-'):
506 # Tolerate the "<>" operator, even if running Python 3 668 # Tolerate the "<>" operator, even if running Python 3
669 # Deal with Python 3's annotated return value "->"
507 pass 670 pass
508 else: 671 else:
509 return prev_end, "E225" 672 if need_space is True or need_space[1]:
673 # A needed trailing space was not found
674 yield prev_end, "E225"
675 else:
676 code = 'E226'
677 if prev_text == '%':
678 code = 'E228'
679 elif prev_text not in ARITHMETIC_OP:
680 code = 'E227'
681 yield need_space[0], code
682 need_space = False
510 elif token_type == tokenize.OP and prev_end is not None: 683 elif token_type == tokenize.OP and prev_end is not None:
511 if text == '=' and parens: 684 if text == '=' and parens:
512 # Allow keyword args or defaults: foo(bar=None). 685 # Allow keyword args or defaults: foo(bar=None).
513 pass 686 pass
514 elif text in BINARY_OPERATORS: 687 elif text in WS_NEEDED_OPERATORS:
515 need_space = True 688 need_space = True
516 elif text in UNARY_OPERATORS: 689 elif text in UNARY_OPERATORS:
690 # Check if the operator is being used as a binary operator
517 # Allow unary operators: -123, -x, +1. 691 # Allow unary operators: -123, -x, +1.
518 # Allow argument unpacking: foo(*args, **kwargs). 692 # Allow argument unpacking: foo(*args, **kwargs).
519 if prev_type == tokenize.OP: 693 if prev_type == tokenize.OP:
520 if prev_text in '}])': 694 binary_usage = (prev_text in '}])')
521 need_space = True
522 elif prev_type == tokenize.NAME: 695 elif prev_type == tokenize.NAME:
523 if prev_text not in E225NOT_KEYWORDS: 696 binary_usage = (prev_text not in KEYWORDS)
524 need_space = True
525 else: 697 else:
526 need_space = True 698 binary_usage = (prev_type not in SKIP_TOKENS)
527 if need_space and start == prev_end: 699
528 return prev_end, "E225" 700 if binary_usage:
701 need_space = None
702 elif text in WS_OPTIONAL_OPERATORS:
703 need_space = None
704
705 if need_space is None:
706 # Surrounding space is optional, but ensure that
707 # trailing space matches opening space
708 need_space = (prev_end, start != prev_end)
709 elif need_space and start == prev_end:
710 # A needed opening space was not found
711 yield prev_end, "E225"
712 need_space = False
529 prev_type = token_type 713 prev_type = token_type
530 prev_text = text 714 prev_text = text
531 prev_end = end 715 prev_end = end
532 716
533 717
544 Okay: a = (1, 2) 728 Okay: a = (1, 2)
545 E241: a = (1, 2) 729 E241: a = (1, 2)
546 E242: a = (1,\t2) 730 E242: a = (1,\t2)
547 """ 731 """
548 line = logical_line 732 line = logical_line
549 for separator in ',;:': 733 for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
550 found = line.find(separator + ' ') 734 found = m.start() + 1
551 if found > -1: 735 if '\t' in m.group():
552 return found + 1, "E241", separator 736 yield found, "E242", m.group()[0]
553 found = line.find(separator + '\t') 737 else:
554 if found > -1: 738 yield found, "E241", m.group()[0]
555 return found + 1, "E242", separator 739
556 740
557 741 def whitespace_around_named_parameter_equals(logical_line, tokens):
558 def whitespace_around_named_parameter_equals(logical_line):
559 """ 742 """
560 Don't use spaces around the '=' sign when used to indicate a 743 Don't use spaces around the '=' sign when used to indicate a
561 keyword argument or a default parameter value. 744 keyword argument or a default parameter value.
562 745
563 Okay: def complex(real, imag=0.0): 746 Okay: def complex(real, imag=0.0):
569 752
570 E251: def complex(real, imag = 0.0): 753 E251: def complex(real, imag = 0.0):
571 E251: return magic(r = real, i = imag) 754 E251: return magic(r = real, i = imag)
572 """ 755 """
573 parens = 0 756 parens = 0
574 for match in WHITESPACE_AROUND_NAMED_PARAMETER_REGEX.finditer( 757 no_space = False
575 logical_line): 758 prev_end = None
576 text = match.group() 759 message = "E251"
577 if parens and len(text) == 3: 760 for token_type, text, start, end, line in tokens:
578 issue = "E251" 761 if no_space:
579 return match.start(), issue 762 no_space = False
580 if text == '(': 763 if start != prev_end:
581 parens += 1 764 yield prev_end, message
582 elif text == ')': 765 elif token_type == tokenize.OP:
583 parens -= 1 766 if text == '(':
767 parens += 1
768 elif text == ')':
769 parens -= 1
770 elif parens and text == '=':
771 no_space = True
772 if start != prev_end:
773 yield prev_end, message
774 prev_end = end
584 775
585 776
586 def whitespace_before_inline_comment(logical_line, tokens): 777 def whitespace_before_inline_comment(logical_line, tokens):
587 """ 778 """
588 Separate inline comments by at least two spaces. 779 Separate inline comments by at least two spaces.
597 E262: x = x + 1 #Increment x 788 E262: x = x + 1 #Increment x
598 E262: x = x + 1 # Increment x 789 E262: x = x + 1 # Increment x
599 """ 790 """
600 prev_end = (0, 0) 791 prev_end = (0, 0)
601 for token_type, text, start, end, line in tokens: 792 for token_type, text, start, end, line in tokens:
602 if token_type == tokenize.NL:
603 continue
604 if token_type == tokenize.COMMENT: 793 if token_type == tokenize.COMMENT:
605 if not line[:start[1]].strip(): 794 if not line[:start[1]].strip():
606 continue 795 continue
607 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2: 796 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
608 return (prev_end, "E261") 797 yield prev_end, "E261"
609 if (len(text) > 1 and text.startswith('# ') 798 symbol, sp, comment = text.partition(' ')
610 or not text.startswith('# ')): 799 if symbol not in ('#', '#:') or comment[:1].isspace():
611 return start, "E262" 800 yield start, "E262"
612 else: 801 elif token_type != tokenize.NL:
613 prev_end = end 802 prev_end = end
614 803
615 804
616 def imports_on_separate_lines(logical_line): 805 def imports_on_separate_lines(logical_line):
617 r""" 806 r"""
627 Okay: import foo.bar.yourclass 816 Okay: import foo.bar.yourclass
628 """ 817 """
629 line = logical_line 818 line = logical_line
630 if line.startswith('import '): 819 if line.startswith('import '):
631 found = line.find(',') 820 found = line.find(',')
632 if found > -1: 821 if -1 < found and ';' not in line[:found]:
633 return found, "E401" 822 yield found, "E401"
634 823
635 824
636 def compound_statements(logical_line): 825 def compound_statements(logical_line):
637 r""" 826 r"""
638 Compound statements (multiple statements on the same line) are 827 Compound statements (multiple statements on the same line) are
655 E701: try: something() 844 E701: try: something()
656 E701: finally: cleanup() 845 E701: finally: cleanup()
657 E701: if foo == 'blah': one(); two(); three() 846 E701: if foo == 'blah': one(); two(); three()
658 847
659 E702: do_one(); do_two(); do_three() 848 E702: do_one(); do_two(); do_three()
849 E703: do_four(); # useless semicolon
660 """ 850 """
661 line = logical_line 851 line = logical_line
852 last_char = len(line) - 1
662 found = line.find(':') 853 found = line.find(':')
663 if -1 < found < len(line) - 1: 854 while -1 < found < last_char:
664 before = line[:found] 855 before = line[:found]
665 if (before.count('{') <= before.count('}') and # {'a': 1} (dict) 856 if (before.count('{') <= before.count('}') and # {'a': 1} (dict)
666 before.count('[') <= before.count(']') and # [1:2] (slice) 857 before.count('[') <= before.count(']') and # [1:2] (slice)
667 not re.search(r'\blambda\b', before)): # lambda x: x 858 before.count('(') <= before.count(')') and # (Python 3 annotation)
668 return found, "E701" 859 not LAMBDA_REGEX.search(before)): # lambda x: x
860 yield found, "E701"
861 found = line.find(':', found + 1)
669 found = line.find(';') 862 found = line.find(';')
670 if -1 < found: 863 while -1 < found:
671 return found, "E702" 864 if found < last_char:
672 865 yield found, "E702"
673 866 else:
674 def python_3000_has_key(logical_line): 867 yield found, "E703"
675 """ 868 found = line.find(';', found + 1)
676 The {}.has_key() method will be removed in the future version of 869
677 Python. Use the 'in' operation instead, like: 870
678 d = {"a": 1, "b": 2} 871 def explicit_line_join(logical_line, tokens):
679 if "b" in d: 872 r"""
680 print d["b"] 873 Avoid explicit line join between brackets.
874
875 The preferred way of wrapping long lines is by using Python's implied line
876 continuation inside parentheses, brackets and braces. Long lines can be
877 broken over multiple lines by wrapping expressions in parentheses. These
878 should be used in preference to using a backslash for line continuation.
879
880 E502: aaa = [123, \\n 123]
881 E502: aaa = ("bbb " \\n "ccc")
882
883 Okay: aaa = [123,\n 123]
884 Okay: aaa = ("bbb "\n "ccc")
885 Okay: aaa = "bbb " \\n "ccc"
886 """
887 prev_start = prev_end = parens = 0
888 backslash = None
889 for token_type, text, start, end, line in tokens:
890 if start[0] != prev_start and parens and backslash:
891 yield backslash, "E502"
892 if end[0] != prev_end:
893 if line.rstrip('\r\n').endswith('\\'):
894 backslash = (end[0], len(line.splitlines()[-1]) - 1)
895 else:
896 backslash = None
897 prev_start = prev_end = end[0]
898 else:
899 prev_start = start[0]
900 if token_type == tokenize.OP:
901 if text in '([{':
902 parens += 1
903 elif text in ')]}':
904 parens -= 1
905
906
907 def comparison_to_singleton(logical_line, noqa):
908 """
909 Comparisons to singletons like None should always be done
910 with "is" or "is not", never the equality operators.
911
912 Okay: if arg is not None:
913 E711: if arg != None:
914 E712: if arg == True:
915
916 Also, beware of writing if x when you really mean if x is not None --
917 e.g. when testing whether a variable or argument that defaults to None was
918 set to some other value. The other value might have a type (such as a
919 container) that could be false in a boolean context!
920 """
921 match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
922 if match:
923 same = (match.group(1) == '==')
924 singleton = match.group(2)
925 msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
926 if singleton in ('None',):
927 code = 'E711'
928 else:
929 code = 'E712'
930 nonzero = ((singleton == 'True' and same) or
931 (singleton == 'False' and not same))
932 msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
933 yield match.start(1), code, singleton, msg
934
935
936 def comparison_type(logical_line):
937 """
938 Object type comparisons should always use isinstance() instead of
939 comparing types directly.
940
941 Okay: if isinstance(obj, int):
942 E721: if type(obj) is type(1):
943
944 When checking if an object is a string, keep in mind that it might be a
945 unicode string too! In Python 2.3, str and unicode have a common base
946 class, basestring, so you can do:
947
948 Okay: if isinstance(obj, basestring):
949 Okay: if type(a1) is type(b1):
950 """
951 match = COMPARE_TYPE_REGEX.search(logical_line)
952 if match:
953 inst = match.group(1)
954 if inst and isidentifier(inst) and inst not in SINGLETONS:
955 return # Allow comparison for types which are not obvious
956 yield match.start(), "E721"
957
958
959 r"""
960 The {}.has_key() method is removed in the Python 3.
961 Use the 'in' operation instead.
962
963 Okay: if "alph" in d:\n print d["alph"]
964 W601: assert d.has_key('alph')
681 """ 965 """
682 pos = logical_line.find('.has_key(') 966 pos = logical_line.find('.has_key(')
683 if pos > -1: 967 if pos > -1:
684 return pos, "W601" 968 yield pos, "W601"
685 969
686 970
687 def python_3000_raise_comma(logical_line): 971 def python_3000_raise_comma(logical_line):
688 """ 972 """
689 When raising an exception, use "raise ValueError('message')" 973 When raising an exception, use "raise ValueError('message')"
690 instead of the older form "raise ValueError, 'message'". 974 instead of the older form "raise ValueError, 'message'".
691 975
692 The paren-using form is preferred because when the exception arguments 976 The paren-using form is preferred because when the exception arguments
693 are long or include string formatting, you don't need to use line 977 are long or include string formatting, you don't need to use line
694 continuation characters thanks to the containing parentheses. The older 978 continuation characters thanks to the containing parentheses. The older
695 form will be removed in Python 3000. 979 form is removed in Python 3.
980
981 Okay: raise DummyError("Message")
982 W602: raise DummyError, "Message"
696 """ 983 """
697 match = RAISE_COMMA_REGEX.match(logical_line) 984 match = RAISE_COMMA_REGEX.match(logical_line)
698 if match: 985 if match and not RERAISE_COMMA_REGEX.match(logical_line):
699 return match.start(1), "W602" 986 yield match.end() - 1, "W602"
700 987
701 988
702 def python_3000_not_equal(logical_line): 989 def python_3000_not_equal(logical_line):
703 """ 990 """
704 != can also be written <>, but this is an obsolete usage kept for 991 != can also be written <>, but this is an obsolete usage kept for
705 backwards compatibility only. New code should always use !=. 992 backwards compatibility only. New code should always use !=.
706 The older syntax is removed in Python 3000. 993 The older syntax is removed in Python 3.
994
995 Okay: if a != 'no':
996 W603: if a <> 'no':
707 """ 997 """
708 pos = logical_line.find('<>') 998 pos = logical_line.find('<>')
709 if pos > -1: 999 if pos > -1:
710 return pos, "W603" 1000 yield pos, "W603"
711 1001
712 1002
713 def python_3000_backticks(logical_line): 1003 def python_3000_backticks(logical_line):
714 """ 1004 """
715 Backticks are removed in Python 3000. 1005 Backticks are removed in Python 3.
716 Use repr() instead. 1006 Use repr() instead.
1007
1008 Okay: val = repr(1 + 2)
1009 W604: val = `1 + 2`
717 """ 1010 """
718 pos = logical_line.find('`') 1011 pos = logical_line.find('`')
719 if pos > -1: 1012 if pos > -1:
720 return pos, "W604" 1013 yield pos, "W604"
721 1014
722 1015
723 ############################################################################## 1016 ##############################################################################
724 # Helper functions 1017 # Helper functions
725 ############################################################################## 1018 ##############################################################################
726 1019
727 1020
728 if '' == ''.encode(): 1021 if '' == ''.encode():
729 # Python 2: implicit encoding. 1022 # Python 2: implicit encoding.
730 def readlines(filename): 1023 def readlines(filename):
731 return open(filename).readlines() 1024 f = open(filename)
1025 try:
1026 return f.readlines()
1027 finally:
1028 f.close()
1029 isidentifier = re.compile(r'[a-zA-Z_]\w*').match
1030 stdin_get_value = sys.stdin.read
732 else: 1031 else:
733 # Python 3: decode to latin-1. 1032 # Python 3
734 # This function is lazy, it does not read the encoding declaration. 1033 def readlines(filename): # __IGNORE_WARNING__
735 # XXX: use tokenize.detect_encoding() 1034 f = open(filename, 'rb')
736 def readlines(filename): # __IGNORE_WARNING__ 1035 try:
737 return open(filename, encoding='latin-1').readlines() 1036 coding, lines = tokenize.detect_encoding(f.readline)
1037 f = TextIOWrapper(f, coding, line_buffering=True)
1038 return [l.decode(coding) for l in lines] + f.readlines()
1039 except (LookupError, SyntaxError, UnicodeError):
1040 f.close()
1041 # Fall back if files are improperly declared
1042 f = open(filename, encoding='latin-1')
1043 return f.readlines()
1044 finally:
1045 f.close()
1046 isidentifier = str.isidentifier
1047
1048 def stdin_get_value():
1049 return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1050 readlines.__doc__ = " Read the source code."
1051 noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
738 1052
739 1053
740 def expand_indent(line): 1054 def expand_indent(line):
741 """ 1055 r"""
742 Return the amount of indentation. 1056 Return the amount of indentation.
743 Tabs are expanded to the next multiple of 8. 1057 Tabs are expanded to the next multiple of 8.
744 1058
745 >>> expand_indent(' ') 1059 >>> expand_indent(' ')
746 4 1060 4
747 >>> expand_indent('\\t') 1061 >>> expand_indent('\t')
748 8 1062 8
749 >>> expand_indent(' \\t') 1063 >>> expand_indent(' \t')
750 8 1064 8
751 >>> expand_indent(' \\t') 1065 >>> expand_indent(' \t')
752 8 1066 8
753 >>> expand_indent(' \\t') 1067 >>> expand_indent(' \t')
754 16 1068 16
755 """ 1069 """
1070 if '\t' not in line:
1071 return len(line) - len(line.lstrip())
756 result = 0 1072 result = 0
757 for char in line: 1073 for char in line:
758 if char == '\t': 1074 if char == '\t':
759 result = result // 8 * 8 + 8 1075 result = result // 8 * 8 + 8
760 elif char == ' ': 1076 elif char == ' ':
773 >>> mute_string("'''abc'''") 1089 >>> mute_string("'''abc'''")
774 "'''xxx'''" 1090 "'''xxx'''"
775 >>> mute_string("r'abc'") 1091 >>> mute_string("r'abc'")
776 "r'xxx'" 1092 "r'xxx'"
777 """ 1093 """
778 start = 1 1094 # String modifiers (e.g. u or r)
1095 start = text.index(text[-1]) + 1
779 end = len(text) - 1 1096 end = len(text) - 1
780 # String modifiers (e.g. u or r)
781 if text.endswith('"'):
782 start += text.index('"')
783 elif text.endswith("'"):
784 start += text.index("'")
785 # Triple quotes 1097 # Triple quotes
786 if text.endswith('"""') or text.endswith("'''"): 1098 if text[-3:] in ('"""', "'''"):
787 start += 2 1099 start += 2
788 end -= 2 1100 end -= 2
789 return text[:start] + 'x' * (end - start) + text[end:] 1101 return text[:start] + 'x' * (end - start) + text[end:]
790 1102
791 1103
792 def message(text): 1104 def parse_udiff(diff, patterns=None, parent='.'):
793 """Print a message.""" 1105 """Return a dictionary of matching lines."""
794 # print >> sys.stderr, options.prog + ': ' + text 1106 # For each file of the diff, the entry key is the filename,
795 # print >> sys.stderr, text 1107 # and the value is a set of row numbers to consider.
796 print(text) 1108 rv = {}
1109 path = nrows = None
1110 for line in diff.splitlines():
1111 if nrows:
1112 if line[:1] != '-':
1113 nrows -= 1
1114 continue
1115 if line[:3] == '@@ ':
1116 hunk_match = HUNK_REGEX.match(line)
1117 row, nrows = [int(g or '1') for g in hunk_match.groups()]
1118 rv[path].update(range(row, row + nrows))
1119 elif line[:3] == '+++':
1120 path = line[4:].split('\t', 1)[0]
1121 if path[:2] == 'b/':
1122 path = path[2:]
1123 rv[path] = set()
1124 return dict([(os.path.join(parent, path), rows)
1125 for (path, rows) in rv.items()
1126 if rows and filename_match(path, patterns)])
1127
1128
1129 def filename_match(filename, patterns, default=True):
1130 """
1131 Check if patterns contains a pattern that matches filename.
1132 If patterns is unspecified, this always returns True.
1133 """
1134 if not patterns:
1135 return default
1136 return any(fnmatch(filename, pattern) for pattern in patterns)
797 1137
798 1138
799 ############################################################################## 1139 ##############################################################################
800 # Framework to run all checks 1140 # Framework to run all checks
801 ############################################################################## 1141 ##############################################################################
802 1142
803 1143
804 def find_checks(argument_name): 1144 _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
805 """ 1145
806 Find all globally visible functions where the first argument name 1146
807 starts with argument_name. 1147 def register_check(check, codes=None):
808 """ 1148 """
809 checks = [] 1149 Register a new check object.
810 for name, function in globals().items(): 1150 """
811 if not inspect.isfunction(function): 1151 def _add_check(check, kind, codes, args):
812 continue 1152 if check in _checks[kind]:
813 args = inspect.getargspec(function)[0] 1153 _checks[kind][check][0].extend(codes or [])
814 if args and args[0].startswith(argument_name): 1154 else:
815 codes = ERRORCODE_REGEX.findall(inspect.getdoc(function) or '') 1155 _checks[kind][check] = (codes or [''], args)
816 for code in codes or ['']: 1156 if inspect.isfunction(check):
817 if not code or not ignore_code(code): 1157 args = inspect.getargspec(check)[0]
818 checks.append((name, function, args)) 1158 if args and args[0] in ('physical_line', 'logical_line'):
819 break 1159 if codes is None:
820 checks.sort() 1160 codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
821 return checks 1161 _add_check(check, args[0], codes, args)
1162 elif inspect.isclass(check):
1163 if inspect.getargspec(check.__init__)[0][:2] == ['self', 'tree']:
1164 _add_check(check, 'tree', codes, None)
1165
1166
1167 def init_checks_registry():
1168 """
1169 Register all globally visible functions where the first argument name
1170 is 'physical_line' or 'logical_line'.
1171 """
1172 mod = inspect.getmodule(register_check)
1173 for (name, function) in inspect.getmembers(mod, inspect.isfunction):
1174 register_check(function)
1175 init_checks_registry()
822 1176
823 1177
824 class Checker(object): 1178 class Checker(object):
825 """ 1179 """
826 Load a Python source file, tokenize it, check coding style. 1180 Load a Python source file, tokenize it, check coding style.
827 """ 1181 """
828 1182
829 def __init__(self, filename, lines=None): 1183 def __init__(self, filename=None, lines=None,
1184 options=None, report=None, **kwargs):
1185 if options is None:
1186 options = StyleGuide(kwargs).options
1187 else:
1188 assert not kwargs
1189 self._io_error = None
1190 self._physical_checks = options.physical_checks
1191 self._logical_checks = options.logical_checks
1192 self._ast_checks = options.ast_checks
1193 self.max_line_length = options.max_line_length
1194 self.hang_closing = options.hang_closing
1195 self.verbose = options.verbose
830 self.filename = filename 1196 self.filename = filename
831 if filename is None: 1197 if filename is None:
832 self.filename = 'stdin' 1198 self.filename = 'stdin'
833 self.lines = lines or [] 1199 self.lines = lines or []
1200 elif filename == '-':
1201 self.filename = 'stdin'
1202 self.lines = stdin_get_value().splitlines(True)
834 elif lines is None: 1203 elif lines is None:
835 self.lines = readlines(filename) 1204 try:
1205 self.lines = readlines(filename)
1206 except IOError:
1207 exc_type, exc = sys.exc_info()[:2]
1208 self._io_error = '%s: %s' % (exc_type.__name__, exc)
1209 self.lines = []
836 else: 1210 else:
837 self.lines = lines 1211 self.lines = lines
838 options.counters['physical lines'] += len(self.lines) 1212 if self.lines:
1213 ord0 = ord(self.lines[0][0])
1214 if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
1215 if ord0 == 0xfeff:
1216 self.lines[0] = self.lines[0][1:]
1217 elif self.lines[0][:3] == '\xef\xbb\xbf':
1218 self.lines[0] = self.lines[0][3:]
1219 self.report = report or options.report
1220 self.report_error = self.report.error
1221 self.report_error_args = self.report.error_args
1222
1223 def report_invalid_syntax(self):
1224 exc_type, exc = sys.exc_info()[:2]
1225 if len(exc.args) > 1:
1226 offset = exc.args[1]
1227 if len(offset) > 2:
1228 offset = offset[1:3]
1229 else:
1230 offset = (1, 0)
1231 self.report_error_args(offset[0], offset[1] or 0,
1232 'E901', exc_type.__name__, exc.args[0],
1233 self.report_invalid_syntax)
1234 report_invalid_syntax.__doc__ = " Check if the syntax is valid."
839 1235
840 def readline(self): 1236 def readline(self):
841 """ 1237 """
842 Get the next line from the input buffer. 1238 Get the next line from the input buffer.
843 """ 1239 """
868 def check_physical(self, line): 1264 def check_physical(self, line):
869 """ 1265 """
870 Run all physical checks on a raw input line. 1266 Run all physical checks on a raw input line.
871 """ 1267 """
872 self.physical_line = line 1268 self.physical_line = line
873 if self.indent_char is None and len(line) and line[0] in ' \t': 1269 if self.indent_char is None and line[:1] in WHITESPACE:
874 self.indent_char = line[0] 1270 self.indent_char = line[0]
875 for name, check, argument_names in options.physical_checks: 1271 for name, check, argument_names in self._physical_checks:
876 result = self.run_check(check, argument_names) 1272 result = self.run_check(check, argument_names)
877 if result is not None: 1273 if result is not None:
878 offset, code = result[:2] 1274 offset, code = result[:2]
879 args = result[2:] 1275 args = result[2:]
880 self.report_error_args(self.line_number, offset, code, check, 1276 self.report_error_args(self.line_number, offset, code, check,
884 """ 1280 """
885 Build a logical line from tokens. 1281 Build a logical line from tokens.
886 """ 1282 """
887 self.mapping = [] 1283 self.mapping = []
888 logical = [] 1284 logical = []
1285 comments = []
889 length = 0 1286 length = 0
890 previous = None 1287 previous = None
891 for token in self.tokens: 1288 for token in self.tokens:
892 token_type, text = token[0:2] 1289 token_type, text = token[0:2]
1290 if token_type == tokenize.COMMENT:
1291 comments.append(text)
1292 continue
893 if token_type in SKIP_TOKENS: 1293 if token_type in SKIP_TOKENS:
894 continue 1294 continue
895 if token_type == tokenize.STRING: 1295 if token_type == tokenize.STRING:
896 text = mute_string(text) 1296 text = mute_string(text)
897 if previous: 1297 if previous:
898 end_line, end = previous[3] 1298 end_row, end = previous[3]
899 start_line, start = token[2] 1299 start_row, start = token[2]
900 if end_line != start_line: # different row 1300 if end_row != start_row: # different row
901 prev_text = self.lines[end_line - 1][end - 1] 1301 prev_text = self.lines[end_row - 1][end - 1]
902 if prev_text == ',' or (prev_text not in '{[(' 1302 if prev_text == ',' or (prev_text not in '{[('
903 and text not in '}])'): 1303 and text not in '}])'):
904 logical.append(' ') 1304 logical.append(' ')
905 length += 1 1305 length += 1
906 elif end != start: # different column 1306 elif end != start: # different column
907 fill = self.lines[end_line - 1][end:start] 1307 fill = self.lines[end_row - 1][end:start]
908 logical.append(fill) 1308 logical.append(fill)
909 length += len(fill) 1309 length += len(fill)
910 self.mapping.append((length, token)) 1310 self.mapping.append((length, token))
911 logical.append(text) 1311 logical.append(text)
912 length += len(text) 1312 length += len(text)
913 previous = token 1313 previous = token
914 self.logical_line = ''.join(logical) 1314 self.logical_line = ''.join(logical)
915 assert self.logical_line.lstrip() == self.logical_line 1315 self.noqa = comments and noqa(''.join(comments))
916 assert self.logical_line.rstrip() == self.logical_line 1316 # With Python 2, if the line ends with '\r\r\n' the assertion fails
1317 # assert self.logical_line.strip() == self.logical_line
917 1318
918 def check_logical(self): 1319 def check_logical(self):
919 """ 1320 """
920 Build a line from tokens and run all logical checks on it. 1321 Build a line from tokens and run all logical checks on it.
921 """ 1322 """
922 options.counters['logical lines'] += 1
923 self.build_tokens_line() 1323 self.build_tokens_line()
1324 self.report.increment_logical_line()
924 first_line = self.lines[self.mapping[0][1][2][0] - 1] 1325 first_line = self.lines[self.mapping[0][1][2][0] - 1]
925 indent = first_line[:self.mapping[0][1][2][1]] 1326 indent = first_line[:self.mapping[0][1][2][1]]
926 self.previous_indent_level = self.indent_level 1327 self.previous_indent_level = self.indent_level
927 self.indent_level = expand_indent(indent) 1328 self.indent_level = expand_indent(indent)
928 if options.verbose >= 2: 1329 if self.verbose >= 2:
929 print(self.logical_line[:80].rstrip()) 1330 print(self.logical_line[:80].rstrip())
930 for name, check, argument_names in options.logical_checks: 1331 for name, check, argument_names in self._logical_checks:
931 if options.verbose >= 4: 1332 if self.verbose >= 4:
932 print(' ' + name) 1333 print(' ' + name)
933 result = self.run_check(check, argument_names) 1334 for result in self.run_check(check, argument_names):
934 if result is not None:
935 offset, code = result[:2] 1335 offset, code = result[:2]
936 args = result[2:] 1336 args = result[2:]
937 if isinstance(offset, tuple): 1337 if isinstance(offset, tuple):
938 original_number, original_offset = offset 1338 orig_number, orig_offset = offset
939 else: 1339 else:
940 for token_offset, token in self.mapping: 1340 for token_offset, token in self.mapping:
941 if offset >= token_offset: 1341 if offset >= token_offset:
942 original_number = token[2][0] 1342 orig_number = token[2][0]
943 original_offset = (token[2][1] 1343 orig_offset = (token[2][1] + offset - token_offset)
944 + offset - token_offset) 1344 self.report_error_args(orig_number, orig_offset, code, check,
945 self.report_error_args(original_number, original_offset, 1345 *args)
946 code, check, *args)
947 self.previous_logical = self.logical_line 1346 self.previous_logical = self.logical_line
948 1347
1348 def check_ast(self):
1349 try:
1350 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
1351 except (SyntaxError, TypeError):
1352 return self.report_invalid_syntax()
1353 for name, cls, _ in self._ast_checks:
1354 checker = cls(tree, self.filename)
1355 for result in checker.run():
1356 lineno, offset, code, check = result[:4]
1357 args = result[4:]
1358 if not noqa(self.lines[lineno - 1]):
1359 self.report_error_args(lineno, offset, code, check, *args)
1360
1361 def generate_tokens(self):
1362 if self._io_error:
1363 self.report_error(1, 0, 'E902 %s' % self._io_error, readlines)
1364 tokengen = tokenize.generate_tokens(self.readline_check_physical)
1365 try:
1366 for token in tokengen:
1367 yield token
1368 except (SyntaxError, tokenize.TokenError):
1369 self.report_invalid_syntax()
1370
949 def check_all(self, expected=None, line_offset=0): 1371 def check_all(self, expected=None, line_offset=0):
950 """ 1372 """
951 Run all checks on the input file. 1373 Run all checks on the input file.
952 """ 1374 """
953 self.expected = expected or () 1375 self.report.init_file(self.filename, self.lines, expected, line_offset)
954 self.line_offset = line_offset 1376 if self._ast_checks:
1377 self.check_ast()
955 self.line_number = 0 1378 self.line_number = 0
956 self.file_errors = 0
957 self.indent_char = None 1379 self.indent_char = None
958 self.indent_level = 0 1380 self.indent_level = 0
959 self.previous_logical = '' 1381 self.previous_logical = ''
960 self.blank_lines = 0
961 self.blank_lines_before_comment = 0
962 self.tokens = [] 1382 self.tokens = []
1383 self.blank_lines = blank_lines_before_comment = 0
963 parens = 0 1384 parens = 0
964 try: 1385 for token in self.generate_tokens():
965 for token in tokenize.generate_tokens(self.readline_check_physical): 1386 self.tokens.append(token)
966 if options.verbose >= 3: 1387 token_type, text = token[0:2]
967 if token[2][0] == token[3][0]: 1388 if self.verbose >= 3:
968 pos = '[%s:%s]' % (token[2][1] or '', token[3][1]) 1389 if token[2][0] == token[3][0]:
969 else: 1390 pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
970 pos = 'l.%s' % token[3][0] 1391 else:
971 print('l.%s\t%s\t%s\t%r' % 1392 pos = 'l.%s' % token[3][0]
972 (token[2][0], pos, tokenize.tok_name[token[0]], token[1])) 1393 print('l.%s\t%s\t%s\t%r' %
973 self.tokens.append(token) 1394 (token[2][0], pos, tokenize.tok_name[token[0]], text))
974 token_type, text = token[0:2] 1395 if token_type == tokenize.OP:
975 if token_type == tokenize.OP and text in '([{': 1396 if text in '([{':
976 parens += 1 1397 parens += 1
977 if token_type == tokenize.OP and text in '}])': 1398 elif text in '}])':
978 parens -= 1 1399 parens -= 1
979 if token_type == tokenize.NEWLINE and not parens: 1400 elif not parens:
1401 if token_type == tokenize.NEWLINE:
1402 if self.blank_lines < blank_lines_before_comment:
1403 self.blank_lines = blank_lines_before_comment
980 self.check_logical() 1404 self.check_logical()
981 self.blank_lines = 0
982 self.blank_lines_before_comment = 0
983 self.tokens = [] 1405 self.tokens = []
984 if token_type == tokenize.NL and not parens: 1406 self.blank_lines = blank_lines_before_comment = 0
985 if len(self.tokens) <= 1: 1407 elif token_type == tokenize.NL:
1408 if len(self.tokens) == 1:
986 # The physical line contains only this token. 1409 # The physical line contains only this token.
987 self.blank_lines += 1 1410 self.blank_lines += 1
988 self.tokens = [] 1411 self.tokens = []
989 if token_type == tokenize.COMMENT: 1412 elif token_type == tokenize.COMMENT and len(self.tokens) == 1:
990 source_line = token[4] 1413 if blank_lines_before_comment < self.blank_lines:
991 token_start = token[2][1] 1414 blank_lines_before_comment = self.blank_lines
992 if source_line[:token_start].strip() == '': 1415 self.blank_lines = 0
993 self.blank_lines_before_comment = max(self.blank_lines, 1416 if COMMENT_WITH_NL:
994 self.blank_lines_before_comment) 1417 # The comment also ends a physical line
995 self.blank_lines = 0
996 if text.endswith('\n') and not parens:
997 # The comment also ends a physical line. This works around
998 # Python < 2.6 behaviour, which does not generate NL after
999 # a comment which is on a line by itself.
1000 self.tokens = [] 1418 self.tokens = []
1001 except tokenize.TokenError, err: 1419 return self.report.get_file_results()
1002 msg, (lnum, pos) = err.args 1420
1003 self.report_error_args(lnum, pos, "E901", "TokenError", msg) 1421
1422 class BaseReport(object):
1423 """Collect the results of the checks."""
1424 print_filename = False
1425
1426 def __init__(self, options):
1427 self._benchmark_keys = options.benchmark_keys
1428 self._ignore_code = options.ignore_code
1429 # Results
1430 self.elapsed = 0
1431 self.total_errors = 0
1432 self.counters = dict.fromkeys(self._benchmark_keys, 0)
1433 self.messages = {}
1434
1435 def start(self):
1436 """Start the timer."""
1437 self._start_time = time.time()
1438
1439 def stop(self):
1440 """Stop the timer."""
1441 self.elapsed = time.time() - self._start_time
1442
1443 def init_file(self, filename, lines, expected, line_offset):
1444 """Signal a new file."""
1445 self.filename = filename
1446 self.lines = lines
1447 self.expected = expected or ()
1448 self.line_offset = line_offset
1449 self.file_errors = 0
1450 self.counters['files'] += 1
1451 self.counters['physical lines'] += len(lines)
1452
1453 def increment_logical_line(self):
1454 """Signal a new logical line."""
1455 self.counters['logical lines'] += 1
1456
1457 def error(self, line_number, offset, text, check):
1458 """Report an error, according to options."""
1459 code = text[:4]
1460 if self._ignore_code(code):
1461 return
1462 if code in self.counters:
1463 self.counters[code] += 1
1464 else:
1465 self.counters[code] = 1
1466 self.messages[code] = text[5:]
1467 # Don't care about expected errors or warnings
1468 if code in self.expected:
1469 return
1470 if self.print_filename and not self.file_errors:
1471 print(self.filename)
1472 self.file_errors += 1
1473 self.total_errors += 1
1474 return code
1475
1476 def error_args(self, line_number, offset, code, check, *args):
1477 """Report an error, according to options."""
1478 if self._ignore_code(code):
1479 return
1480 if code in self.counters:
1481 self.counters[code] += 1
1482 else:
1483 self.counters[code] = 1
1484 # Don't care about expected errors or warnings
1485 if code in self.expected:
1486 return
1487 if self.print_filename and not self.file_errors:
1488 print(self.filename)
1489 self.file_errors += 1
1490 self.total_errors += 1
1491 return code
1492
1493 def get_file_results(self):
1494 """Return the count of errors and warnings for this file."""
1004 return self.file_errors 1495 return self.file_errors
1005 1496
1006 def report_error(self, line_number, offset, text, check): 1497 def get_count(self, prefix=''):
1007 """ 1498 """Return the total count of errors and warnings."""
1008 Report an error, according to options. 1499 return sum([self.counters[key]
1009 """ 1500 for key in self.messages if key.startswith(prefix)])
1010 code = text[:4] 1501
1011 if ignore_code(code): 1502 def get_statistics(self, prefix=''):
1503 """
1504 Get statistics for message codes that start with the prefix.
1505
1506 prefix='' matches all errors and warnings
1507 prefix='E' matches all errors
1508 prefix='W' matches all warnings
1509 prefix='E4' matches all errors that have to do with imports
1510 """
1511 return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
1512 for key in sorted(self.messages) if key.startswith(prefix)]
1513
1514 def print_statistics(self, prefix=''):
1515 """Print overall statistics (number of errors and warnings)."""
1516 for line in self.get_statistics(prefix):
1517 print(line)
1518
1519 def print_benchmark(self):
1520 """Print benchmark numbers."""
1521 print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
1522 if self.elapsed:
1523 for key in self._benchmark_keys:
1524 print('%-7d %s per second (%d total)' %
1525 (self.counters[key] / self.elapsed, key,
1526 self.counters[key]))
1527
1528
1529 class FileReport(BaseReport):
1530 """Collect the results of the checks and print only the filenames."""
1531 print_filename = True
1532
1533
1534 class StandardReport(BaseReport):
1535 """Collect and print the results of the checks."""
1536
1537 def __init__(self, options):
1538 super(StandardReport, self).__init__(options)
1539 self._fmt = REPORT_FORMAT.get(options.format.lower(),
1540 options.format)
1541 self._repeat = options.repeat
1542 self._show_source = options.show_source
1543 self._show_pep8 = options.show_pep8
1544
1545 def init_file(self, filename, lines, expected, line_offset):
1546 """Signal a new file."""
1547 self._deferred_print = []
1548 return super(StandardReport, self).init_file(
1549 filename, lines, expected, line_offset)
1550
1551 def error(self, line_number, offset, text, check):
1552 """Report an error, according to options."""
1553 code = super(StandardReport, self).error(line_number, offset,
1554 text, check)
1555 if code and (self.counters[code] == 1 or self._repeat):
1556 self._deferred_print.append(
1557 (line_number, offset, code, text[5:], check.__doc__))
1558 return code
1559
1560 def error_args(self, line_number, offset, code, check, *args):
1561 """Report an error, according to options."""
1562 code = super(StandardReport, self).error_args(line_number, offset,
1563 code, check, *args)
1564 if code and (self.counters[code] == 1 or self._repeat):
1565 self._deferred_print.append(
1566 (line_number, offset, code, "", check.__doc__))
1567 return code
1568
1569 def get_file_results(self):
1570 """Print the result and return the overall count for this file."""
1571 self._deferred_print.sort()
1572 for line_number, offset, code, text, doc in self._deferred_print:
1573 print(self._fmt % {
1574 'path': self.filename,
1575 'row': self.line_offset + line_number, 'col': offset + 1,
1576 'code': code, 'text': text,
1577 })
1578 if self._show_source:
1579 if line_number > len(self.lines):
1580 line = ''
1581 else:
1582 line = self.lines[line_number - 1]
1583 print(line.rstrip())
1584 print(' ' * offset + '^')
1585 if self._show_pep8 and doc:
1586 print(doc.lstrip('\n').rstrip())
1587 return self.file_errors
1588
1589
1590 class DiffReport(StandardReport):
1591 """Collect and print the results for the changed lines only."""
1592
1593 def __init__(self, options):
1594 super(DiffReport, self).__init__(options)
1595 self._selected = options.selected_lines
1596
1597 def error(self, line_number, offset, text, check):
1598 if line_number not in self._selected[self.filename]:
1012 return 1599 return
1013 if options.quiet == 1 and not self.file_errors: 1600 return super(DiffReport, self).error(line_number, offset, text, check)
1014 message(self.filename) 1601
1015 if code in options.counters: 1602
1016 options.counters[code] += 1 1603 class StyleGuide(object):
1604 """Initialize a PEP-8 instance with few options."""
1605
1606 def __init__(self, *args, **kwargs):
1607 # build options from the command line
1608 self.checker_class = kwargs.pop('checker_class', Checker)
1609 parse_argv = kwargs.pop('parse_argv', False)
1610 config_file = kwargs.pop('config_file', None)
1611 parser = kwargs.pop('parser', None)
1612 options, self.paths = process_options(
1613 parse_argv=parse_argv, config_file=config_file, parser=parser)
1614 if args or kwargs:
1615 # build options from dict
1616 options_dict = dict(*args, **kwargs)
1617 options.__dict__.update(options_dict)
1618 if 'paths' in options_dict:
1619 self.paths = options_dict['paths']
1620
1621 self.runner = self.input_file
1622 self.options = options
1623
1624 if not options.reporter:
1625 options.reporter = BaseReport if options.quiet else StandardReport
1626
1627 for index, value in enumerate(options.exclude):
1628 options.exclude[index] = value.rstrip('/')
1629 options.select = tuple(options.select or ())
1630 if not (options.select or options.ignore or
1631 options.testsuite or options.doctest) and DEFAULT_IGNORE:
1632 # The default choice: ignore controversial checks
1633 options.ignore = tuple(DEFAULT_IGNORE.split(','))
1017 else: 1634 else:
1018 options.counters[code] = 1 1635 # Ignore all checks which are not explicitly selected
1019 options.messages[code] = text[5:] 1636 options.ignore = ('',) if options.select else tuple(options.ignore)
1020 if options.quiet or code in self.expected: 1637 options.benchmark_keys = BENCHMARK_KEYS[:]
1021 # Don't care about expected errors or warnings 1638 options.ignore_code = self.ignore_code
1022 return 1639 options.physical_checks = self.get_checks('physical_line')
1023 self.file_errors += 1 1640 options.logical_checks = self.get_checks('logical_line')
1024 if options.counters[code] == 1 or options.repeat: 1641 options.ast_checks = self.get_checks('tree')
1025 message("%s:%s:%d: %s" % 1642 self.init_report()
1026 (self.filename, self.line_offset + line_number, 1643
1027 offset + 1, text)) 1644 def init_report(self, reporter=None):
1028 if options.show_source: 1645 """Initialize the report instance."""
1029 line = self.lines[line_number - 1] 1646 self.options.report = (reporter or self.options.reporter)(self.options)
1030 message(line.rstrip()) 1647 return self.options.report
1031 message(' ' * offset + '^') 1648
1032 if options.show_pep8: 1649 def check_files(self, paths=None):
1033 message(check.__doc__.lstrip('\n').rstrip()) 1650 """Run all checks on the paths."""
1034 1651 if paths is None:
1035 1652 paths = self.paths
1036 def input_file(filename): 1653 report = self.options.report
1037 """ 1654 runner = self.runner
1038 Run all checks on a Python source file. 1655 report.start()
1039 """ 1656 try:
1040 if options.verbose: 1657 for path in paths:
1041 message('checking ' + filename) 1658 if os.path.isdir(path):
1042 Checker(filename).check_all() 1659 self.input_dir(path)
1043 1660 elif not self.excluded(path):
1044 1661 runner(path)
1045 def input_dir(dirname, runner=None): 1662 except KeyboardInterrupt:
1046 """ 1663 print('... stopped')
1047 Check all Python source files in this directory and all subdirectories. 1664 report.stop()
1048 """ 1665 return report
1049 dirname = dirname.rstrip('/') 1666
1050 if excluded(dirname): 1667 def input_file(self, filename, lines=None, expected=None, line_offset=0):
1051 return 1668 """Run all checks on a Python source file."""
1052 if runner is None: 1669 if self.options.verbose:
1053 runner = input_file 1670 print('checking %s' % filename)
1054 for root, dirs, files in os.walk(dirname): 1671 fchecker = self.checker_class(
1055 if options.verbose: 1672 filename, lines=lines, options=self.options)
1056 message('directory ' + root) 1673 return fchecker.check_all(expected=expected, line_offset=line_offset)
1057 options.counters['directories'] += 1 1674
1058 dirs.sort() 1675 def input_dir(self, dirname):
1059 for subdir in dirs: 1676 """Check all files in this directory and all subdirectories."""
1060 if excluded(subdir): 1677 dirname = dirname.rstrip('/')
1061 dirs.remove(subdir) 1678 if self.excluded(dirname):
1062 files.sort() 1679 return 0
1063 for filename in files: 1680 counters = self.options.report.counters
1064 if filename_match(filename) and not excluded(filename): 1681 verbose = self.options.verbose
1065 options.counters['files'] += 1 1682 filepatterns = self.options.filename
1066 runner(os.path.join(root, filename)) 1683 runner = self.runner
1067 1684 for root, dirs, files in os.walk(dirname):
1068 1685 if verbose:
1069 def excluded(filename): 1686 print('directory ' + root)
1070 """ 1687 counters['directories'] += 1
1071 Check if options.exclude contains a pattern that matches filename. 1688 for subdir in sorted(dirs):
1072 """ 1689 if self.excluded(subdir, root):
1073 basename = os.path.basename(filename) 1690 dirs.remove(subdir)
1074 for pattern in options.exclude: 1691 for filename in sorted(files):
1075 if fnmatch(basename, pattern): 1692 # contain a pattern that matches?
1076 # print basename, 'excluded because it matches', pattern 1693 if ((filename_match(filename, filepatterns) and
1694 not self.excluded(filename, root))):
1695 runner(os.path.join(root, filename))
1696
1697 def excluded(self, filename, parent=None):
1698 """
1699 Check if options.exclude contains a pattern that matches filename.
1700 """
1701 if not self.options.exclude:
1702 return False
1703 basename = os.path.basename(filename)
1704 if filename_match(basename, self.options.exclude):
1077 return True 1705 return True
1078 1706 if parent:
1079 1707 filename = os.path.join(parent, filename)
1080 def filename_match(filename): 1708 return filename_match(filename, self.options.exclude)
1081 """ 1709
1082 Check if options.filename contains a pattern that matches filename. 1710 def ignore_code(self, code):
1083 If options.filename is unspecified, this always returns True. 1711 """
1084 """ 1712 Check if the error code should be ignored.
1085 if not options.filename: 1713
1086 return True 1714 If 'options.select' contains a prefix of the error code,
1087 for pattern in options.filename: 1715 return False. Else, if 'options.ignore' contains a prefix of
1088 if fnmatch(filename, pattern): 1716 the error code, return True.
1089 return True 1717 """
1090 1718 return (code.startswith(self.options.ignore) and
1091 1719 not code.startswith(self.options.select))
1092 def ignore_code(code): 1720
1093 """ 1721 def get_checks(self, argument_name):
1094 Check if options.ignore contains a prefix of the error code. 1722 """
1095 If options.select contains a prefix of the error code, do not ignore it. 1723 Find all globally visible functions where the first argument name
1096 """ 1724 starts with argument_name and which contain selected tests.
1097 for select in options.select: 1725 """
1098 if code.startswith(select): 1726 checks = []
1099 return False 1727 for check, attrs in _checks[argument_name].items():
1100 for ignore in options.ignore: 1728 (codes, args) = attrs
1101 if code.startswith(ignore): 1729 if any(not (code and self.ignore_code(code)) for code in codes):
1102 return True 1730 checks.append((check.__name__, check, args))
1103 1731 return sorted(checks)
1104 1732
1105 def reset_counters(): 1733
1106 for key in list(options.counters.keys()): 1734 def get_parser(prog='pep8', version=__version__):
1107 if key not in BENCHMARK_KEYS: 1735 parser = OptionParser(prog=prog, version=version,
1108 del options.counters[key]
1109 options.messages = {}
1110
1111
1112 def get_error_statistics():
1113 """Get error statistics."""
1114 return get_statistics("E")
1115
1116
1117 def get_warning_statistics():
1118 """Get warning statistics."""
1119 return get_statistics("W")
1120
1121
1122 def get_statistics(prefix=''):
1123 """
1124 Get statistics for message codes that start with the prefix.
1125
1126 prefix='' matches all errors and warnings
1127 prefix='E' matches all errors
1128 prefix='W' matches all warnings
1129 prefix='E4' matches all errors that have to do with imports
1130 """
1131 stats = []
1132 keys = list(options.messages.keys())
1133 keys.sort()
1134 for key in keys:
1135 if key.startswith(prefix):
1136 stats.append('%-7s %s %s' %
1137 (options.counters[key], key, options.messages[key]))
1138 return stats
1139
1140
1141 def get_count(prefix=''):
1142 """Return the total count of errors and warnings."""
1143 keys = list(options.messages.keys())
1144 count = 0
1145 for key in keys:
1146 if key.startswith(prefix):
1147 count += options.counters[key]
1148 return count
1149
1150
1151 def print_statistics(prefix=''):
1152 """Print overall statistics (number of errors and warnings)."""
1153 for line in get_statistics(prefix):
1154 print(line)
1155
1156
1157 def print_benchmark(elapsed):
1158 """
1159 Print benchmark numbers.
1160 """
1161 print('%-7.2f %s' % (elapsed, 'seconds elapsed'))
1162 for key in BENCHMARK_KEYS:
1163 print('%-7d %s per second (%d total)' % (
1164 options.counters[key] / elapsed, key,
1165 options.counters[key]))
1166
1167
1168 def run_tests(filename):
1169 """
1170 Run all the tests from a file.
1171
1172 A test file can provide many tests. Each test starts with a declaration.
1173 This declaration is a single line starting with '#:'.
1174 It declares codes of expected failures, separated by spaces or 'Okay'
1175 if no failure is expected.
1176 If the file does not contain such declaration, it should pass all tests.
1177 If the declaration is empty, following lines are not checked, until next
1178 declaration.
1179
1180 Examples:
1181
1182 * Only E224 and W701 are expected: #: E224 W701
1183 * Following example is conform: #: Okay
1184 * Don't check these lines: #:
1185 """
1186 lines = readlines(filename) + ['#:\n']
1187 line_offset = 0
1188 codes = ['Okay']
1189 testcase = []
1190 for index, line in enumerate(lines):
1191 if not line.startswith('#:'):
1192 if codes:
1193 # Collect the lines of the test case
1194 testcase.append(line)
1195 continue
1196 if codes and index > 0:
1197 label = '%s:%s:1' % (filename, line_offset + 1)
1198 codes = [c for c in codes if c != 'Okay']
1199 # Run the checker
1200 errors = Checker(filename, testcase).check_all(codes, line_offset)
1201 # Check if the expected errors were found
1202 for code in codes:
1203 if not options.counters.get(code):
1204 errors += 1
1205 message('%s: error %s not found' % (label, code))
1206 if options.verbose and not errors:
1207 message('%s: passed (%s)' % (label, ' '.join(codes)))
1208 # Keep showing errors for multiple tests
1209 reset_counters()
1210 # output the real line numbers
1211 line_offset = index
1212 # configure the expected errors
1213 codes = line.split()[1:]
1214 # empty the test case buffer
1215 del testcase[:]
1216
1217
1218 def selftest():
1219 """
1220 Test all check functions with test cases in docstrings.
1221 """
1222 count_passed = 0
1223 count_failed = 0
1224 checks = options.physical_checks + options.logical_checks
1225 for name, check, argument_names in checks:
1226 for line in check.__doc__.splitlines():
1227 line = line.lstrip()
1228 match = SELFTEST_REGEX.match(line)
1229 if match is None:
1230 continue
1231 code, source = match.groups()
1232 checker = Checker(None)
1233 for part in source.split(r'\n'):
1234 part = part.replace(r'\t', '\t')
1235 part = part.replace(r'\s', ' ')
1236 checker.lines.append(part + '\n')
1237 options.quiet = 2
1238 checker.check_all()
1239 error = None
1240 if code == 'Okay':
1241 if len(options.counters) > len(BENCHMARK_KEYS):
1242 codes = [key for key in options.counters.keys()
1243 if key not in BENCHMARK_KEYS]
1244 error = "incorrectly found %s" % ', '.join(codes)
1245 elif not options.counters.get(code):
1246 error = "failed to find %s" % code
1247 # Reset the counters
1248 reset_counters()
1249 if not error:
1250 count_passed += 1
1251 else:
1252 count_failed += 1
1253 if len(checker.lines) == 1:
1254 print("pep8.py: %s: %s" %
1255 (error, checker.lines[0].rstrip()))
1256 else:
1257 print("pep8.py: %s:" % error)
1258 for line in checker.lines:
1259 print(line.rstrip())
1260 if options.verbose:
1261 print("%d passed and %d failed." % (count_passed, count_failed))
1262 if count_failed:
1263 print("Test failed.")
1264 else:
1265 print("Test passed.")
1266
1267
1268 def process_options(arglist=None):
1269 """
1270 Process options passed either via arglist or via command line args.
1271 """
1272 global options, args
1273 parser = OptionParser(version=__version__,
1274 usage="%prog [options] input ...") 1736 usage="%prog [options] input ...")
1737 parser.config_options = [
1738 'exclude', 'filename', 'select', 'ignore', 'max-line-length',
1739 'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
1740 'show-source', 'statistics', 'verbose']
1275 parser.add_option('-v', '--verbose', default=0, action='count', 1741 parser.add_option('-v', '--verbose', default=0, action='count',
1276 help="print status messages, or debug with -vv") 1742 help="print status messages, or debug with -vv")
1277 parser.add_option('-q', '--quiet', default=0, action='count', 1743 parser.add_option('-q', '--quiet', default=0, action='count',
1278 help="report only file names, or nothing with -qq") 1744 help="report only file names, or nothing with -qq")
1279 parser.add_option('-r', '--repeat', action='store_true', 1745 parser.add_option('-r', '--repeat', default=True, action='store_true',
1280 help="show all occurrences of the same error") 1746 help="(obsolete) show all occurrences of the same error")
1747 parser.add_option('--first', action='store_false', dest='repeat',
1748 help="show first occurrence of each error")
1281 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE, 1749 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
1282 help="exclude files or directories which match these " 1750 help="exclude files or directories which match these "
1283 "comma separated patterns (default: %s)" % 1751 "comma separated patterns (default: %default)")
1284 DEFAULT_EXCLUDE)
1285 parser.add_option('--filename', metavar='patterns', default='*.py', 1752 parser.add_option('--filename', metavar='patterns', default='*.py',
1286 help="when parsing directories, only check filenames " 1753 help="when parsing directories, only check filenames "
1287 "matching these comma separated patterns (default: " 1754 "matching these comma separated patterns "
1288 "*.py)") 1755 "(default: %default)")
1289 parser.add_option('--select', metavar='errors', default='', 1756 parser.add_option('--select', metavar='errors', default='',
1290 help="select errors and warnings (e.g. E,W6)") 1757 help="select errors and warnings (e.g. E,W6)")
1291 parser.add_option('--ignore', metavar='errors', default='', 1758 parser.add_option('--ignore', metavar='errors', default='',
1292 help="skip errors and warnings (e.g. E4,W)") 1759 help="skip errors and warnings (e.g. E4,W)")
1293 parser.add_option('--show-source', action='store_true', 1760 parser.add_option('--show-source', action='store_true',
1294 help="show source code for each error") 1761 help="show source code for each error")
1295 parser.add_option('--show-pep8', action='store_true', 1762 parser.add_option('--show-pep8', action='store_true',
1296 help="show text of PEP 8 for each error") 1763 help="show text of PEP 8 for each error "
1764 "(implies --first)")
1297 parser.add_option('--statistics', action='store_true', 1765 parser.add_option('--statistics', action='store_true',
1298 help="count errors and warnings") 1766 help="count errors and warnings")
1299 parser.add_option('--count', action='store_true', 1767 parser.add_option('--count', action='store_true',
1300 help="print total number of errors and warnings " 1768 help="print total number of errors and warnings "
1301 "to standard error and set exit code to 1 if " 1769 "to standard error and set exit code to 1 if "
1302 "total is not null") 1770 "total is not null")
1303 parser.add_option('--benchmark', action='store_true', 1771 parser.add_option('--max-line-length', type='int', metavar='n',
1304 help="measure processing speed") 1772 default=MAX_LINE_LENGTH,
1305 parser.add_option('--testsuite', metavar='dir', 1773 help="set maximum allowed line length "
1306 help="run regression tests from dir") 1774 "(default: %default)")
1307 parser.add_option('--doctest', action='store_true', 1775 parser.add_option('--hang-closing', action='store_true',
1308 help="run doctest on myself") 1776 help="hang closing bracket instead of matching "
1777 "indentation of opening bracket's line")
1778 parser.add_option('--format', metavar='format', default='default',
1779 help="set the error format [default|pylint|<custom>]")
1780 parser.add_option('--diff', action='store_true',
1781 help="report only lines changed according to the "
1782 "unified diff received on STDIN")
1783 group = parser.add_option_group("Testing Options")
1784 if os.path.exists(TESTSUITE_PATH):
1785 group.add_option('--testsuite', metavar='dir',
1786 help="run regression tests from dir")
1787 group.add_option('--doctest', action='store_true',
1788 help="run doctest on myself")
1789 group.add_option('--benchmark', action='store_true',
1790 help="measure processing speed")
1791 return parser
1792
1793
1794 def read_config(options, args, arglist, parser):
1795 """Read both user configuration and local configuration."""
1796 config = RawConfigParser()
1797
1798 user_conf = options.config
1799 if user_conf and os.path.isfile(user_conf):
1800 if options.verbose:
1801 print('user configuration: %s' % user_conf)
1802 config.read(user_conf)
1803
1804 parent = tail = args and os.path.abspath(os.path.commonprefix(args))
1805 while tail:
1806 if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):
1807 if options.verbose:
1808 print('local configuration: in %s' % parent)
1809 break
1810 parent, tail = os.path.split(parent)
1811
1812 pep8_section = parser.prog
1813 if config.has_section(pep8_section):
1814 option_list = dict([(o.dest, o.type or o.action)
1815 for o in parser.option_list])
1816
1817 # First, read the default values
1818 new_options, _ = parser.parse_args([])
1819
1820 # Second, parse the configuration
1821 for opt in config.options(pep8_section):
1822 if options.verbose > 1:
1823 print(" %s = %s" % (opt, config.get(pep8_section, opt)))
1824 if opt.replace('_', '-') not in parser.config_options:
1825 print("Unknown option: '%s'\n not in [%s]" %
1826 (opt, ' '.join(parser.config_options)))
1827 sys.exit(1)
1828 normalized_opt = opt.replace('-', '_')
1829 opt_type = option_list[normalized_opt]
1830 if opt_type in ('int', 'count'):
1831 value = config.getint(pep8_section, opt)
1832 elif opt_type == 'string':
1833 value = config.get(pep8_section, opt)
1834 else:
1835 assert opt_type in ('store_true', 'store_false')
1836 value = config.getboolean(pep8_section, opt)
1837 setattr(new_options, normalized_opt, value)
1838
1839 # Third, overwrite with the command-line options
1840 options, _ = parser.parse_args(arglist, values=new_options)
1841 options.doctest = options.testsuite = False
1842 return options
1843
1844
1845 def process_options(arglist=None, parse_argv=False, config_file=None,
1846 parser=None):
1847 """Process options passed either via arglist or via command line args."""
1848 if not arglist and not parse_argv:
1849 # Don't read the command line if the module is used as a library.
1850 arglist = []
1851 if not parser:
1852 parser = get_parser()
1853 if not parser.has_option('--config'):
1854 if config_file is True:
1855 config_file = DEFAULT_CONFIG
1856 group = parser.add_option_group("Configuration", description=(
1857 "The project options are read from the [%s] section of the "
1858 "tox.ini file or the setup.cfg file located in any parent folder "
1859 "of the path(s) being processed. Allowed options are: %s." %
1860 (parser.prog, ', '.join(parser.config_options))))
1861 group.add_option('--config', metavar='path', default=config_file,
1862 help="user config file location (default: %default)")
1309 options, args = parser.parse_args(arglist) 1863 options, args = parser.parse_args(arglist)
1310 if options.testsuite: 1864 options.reporter = None
1865
1866 if options.ensure_value('testsuite', False):
1311 args.append(options.testsuite) 1867 args.append(options.testsuite)
1312 if not args and not options.doctest: 1868 elif not options.ensure_value('doctest', False):
1313 parser.error('input not specified') 1869 if parse_argv and not args:
1314 options.prog = os.path.basename(sys.argv[0]) 1870 if options.diff or any(os.path.exists(name)
1871 for name in PROJECT_CONFIG):
1872 args = ['.']
1873 else:
1874 parser.error('input not specified')
1875 options = read_config(options, args, arglist, parser)
1876 options.reporter = parse_argv and options.quiet == 1 and FileReport
1877
1878 options.filename = options.filename and options.filename.split(',')
1315 options.exclude = options.exclude.split(',') 1879 options.exclude = options.exclude.split(',')
1316 for index in range(len(options.exclude)): 1880 options.select = options.select and options.select.split(',')
1317 options.exclude[index] = options.exclude[index].rstrip('/') 1881 options.ignore = options.ignore and options.ignore.split(',')
1318 if options.filename: 1882
1319 options.filename = options.filename.split(',') 1883 if options.diff:
1320 if options.select: 1884 options.reporter = DiffReport
1321 options.select = options.select.split(',') 1885 stdin = stdin_get_value()
1886 options.selected_lines = parse_udiff(stdin, options.filename, args[0])
1887 args = sorted(options.selected_lines)
1888
1889 return options, args
1890
1891
1892 def _main():
1893 """Parse options and run checks on Python source."""
1894 pep8style = StyleGuide(parse_argv=True, config_file=True)
1895 options = pep8style.options
1896 if options.doctest or options.testsuite:
1897 from testsuite.support import run_tests
1898 report = run_tests(pep8style)
1322 else: 1899 else:
1323 options.select = [] 1900 report = pep8style.check_files()
1324 if options.ignore:
1325 options.ignore = options.ignore.split(',')
1326 elif options.select:
1327 # Ignore all checks which are not explicitly selected
1328 options.ignore = ['']
1329 elif options.testsuite or options.doctest:
1330 # For doctest and testsuite, all checks are required
1331 options.ignore = []
1332 else:
1333 # The default choice: ignore controversial checks
1334 options.ignore = DEFAULT_IGNORE.split(',')
1335 options.physical_checks = find_checks('physical_line')
1336 options.logical_checks = find_checks('logical_line')
1337 options.counters = dict.fromkeys(BENCHMARK_KEYS, 0)
1338 options.messages = {}
1339 return options, args
1340
1341
1342 def _main():
1343 """
1344 Parse options and run checks on Python source.
1345 """
1346 options, args = process_options()
1347 if options.doctest:
1348 import doctest
1349 doctest.testmod(verbose=options.verbose)
1350 selftest()
1351 if options.testsuite:
1352 runner = run_tests
1353 else:
1354 runner = input_file
1355 start_time = time.time()
1356 for path in args:
1357 if os.path.isdir(path):
1358 input_dir(path, runner=runner)
1359 elif not excluded(path):
1360 options.counters['files'] += 1
1361 runner(path)
1362 elapsed = time.time() - start_time
1363 if options.statistics: 1901 if options.statistics:
1364 print_statistics() 1902 report.print_statistics()
1365 if options.benchmark: 1903 if options.benchmark:
1366 print_benchmark(elapsed) 1904 report.print_benchmark()
1367 count = get_count() 1905 if options.testsuite and not options.quiet:
1368 if count: 1906 report.print_results()
1907 if report.total_errors:
1369 if options.count: 1908 if options.count:
1370 sys.stderr.write(str(count) + '\n') 1909 sys.stderr.write(str(report.total_errors) + '\n')
1371 sys.exit(1) 1910 sys.exit(1)
1372
1373 1911
1374 if __name__ == '__main__': 1912 if __name__ == '__main__':
1375 _main() 1913 _main()
1376 1914
1377 # 1915 #

eric ide

mercurial