Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py

changeset 5147
d39dd5cee0c8
parent 5146
f96c32abd120
child 5288
ff831e3e383e
equal deleted inserted replaced
5146:f96c32abd120 5147:d39dd5cee0c8
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # pycodestyle.py - Check Python source code formatting, according to PEP 8
5 # Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
6 # Copyright (C) 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
7 # Copyright (C) 2014-2016 Ian Lee <ianlee1521@gmail.com>
8 #
9 # Permission is hereby granted, free of charge, to any person
10 # obtaining a copy of this software and associated documentation files
11 # (the "Software"), to deal in the Software without restriction,
12 # including without limitation the rights to use, copy, modify, merge,
13 # publish, distribute, sublicense, and/or sell copies of the Software,
14 # and to permit persons to whom the Software is furnished to do so,
15 # subject to the following conditions:
16 #
17 # The above copyright notice and this permission notice shall be
18 # included in all copies or substantial portions of the Software.
19 #
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 # SOFTWARE.
28
29 r"""
30 Check Python source code formatting, according to PEP 8.
31
32 For usage and a list of options, try this:
33 $ python pycodestyle.py -h
34
35 This program and its regression test suite live here:
36 https://github.com/pycqa/pycodestyle
37
38 Groups of errors and warnings:
39 E errors
40 W warnings
41 100 indentation
42 200 whitespace
43 300 blank lines
44 400 imports
45 500 line length
46 600 deprecation
47 700 statements
48 900 syntax error
49 """
50 from __future__ import with_statement
51
52 #
53 # This is a modified version to make the original pycodestyle.py better suitable
54 # for being called from within the eric6 IDE. The modifications are as
55 # follows:
56 #
57 # - made messages translatable via Qt
58 # - added code for eric6 integration
59 #
60 # Copyright (c) 2011 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
61 #
62
63 import inspect
64 import keyword
65 import os
66 import re
67 import sys
68 import time
69 import tokenize
70 ##import ast
71 from fnmatch import fnmatch
72 from optparse import OptionParser
73 try:
74 from configparser import RawConfigParser
75 from io import TextIOWrapper
76 except ImportError:
77 from ConfigParser import RawConfigParser # __IGNORE_WARNING__
78
79 __version__ = '2.1.0.dev0'
80
81 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
82 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503'
83 try:
84 if sys.platform == 'win32':
85 USER_CONFIG = os.path.expanduser(r'~\.pycodestyle')
86 else:
87 USER_CONFIG = os.path.join(
88 os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
89 'pycodestyle'
90 )
91 except ImportError:
92 USER_CONFIG = None
93
94 PROJECT_CONFIG = ('setup.cfg', 'tox.ini')
95 TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
96 MAX_LINE_LENGTH = 79
97 REPORT_FORMAT = {
98 'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
99 'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
100 }
101
102 PyCF_ONLY_AST = 1024
103 SINGLETONS = frozenset(['False', 'None', 'True'])
104 KEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS
105 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
106 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])
107 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
108 WS_NEEDED_OPERATORS = frozenset([
109 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
110 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='])
111 WHITESPACE = frozenset(' \t')
112 NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
113 SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT])
114 # ERRORTOKEN is triggered by backticks in Python 3
115 SKIP_COMMENTS = SKIP_TOKENS.union([tokenize.COMMENT, tokenize.ERRORTOKEN])
116 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
117
118 INDENT_REGEX = re.compile(r'([ \t]*)')
119 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
120 RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$')
121 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
122 DOCSTRING_REGEX = re.compile(r'u?r?["\']')
123 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
124 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
125 COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
126 r'\s*(?(1)|(None|False|True))\b')
127 COMPARE_NEGATIVE_REGEX = re.compile(r'\b(not)\s+[^][)(}{ ]+\s+(in|is)\s')
128 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
129 r'|\s*\(\s*([^)]*[^ )])\s*\))')
130 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
131 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
132 LAMBDA_REGEX = re.compile(r'\blambda\b')
133 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
134
135 # Work around Python < 2.6 behaviour, which does not generate NL after
136 # a comment which is on a line by itself.
137 COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
138
139
140 ##############################################################################
141 # Plugins (check functions) for physical lines
142 ##############################################################################
143
144
145 def tabs_or_spaces(physical_line, indent_char):
146 r"""Never mix tabs and spaces.
147
148 The most popular way of indenting Python is with spaces only. The
149 second-most popular way is with tabs only. Code indented with a mixture
150 of tabs and spaces should be converted to using spaces exclusively. When
151 invoking the Python command line interpreter with the -t option, it issues
152 warnings about code that illegally mixes tabs and spaces. When using -tt
153 these warnings become errors. These options are highly recommended!
154
155 Okay: if a == 0:\n a = 1\n b = 1
156 E101: if a == 0:\n a = 1\n\tb = 1
157 """
158 indent = INDENT_REGEX.match(physical_line).group(1)
159 for offset, char in enumerate(indent):
160 if char != indent_char:
161 return offset, "E101 indentation contains mixed spaces and tabs"
162
163
164 def tabs_obsolete(physical_line):
165 r"""For new projects, spaces-only are strongly recommended over tabs.
166
167 Okay: if True:\n return
168 W191: if True:\n\treturn
169 """
170 indent = INDENT_REGEX.match(physical_line).group(1)
171 if '\t' in indent:
172 return indent.index('\t'), "W191 indentation contains tabs"
173
174
175 def trailing_whitespace(physical_line):
176 r"""Trailing whitespace is superfluous.
177
178 The warning returned varies on whether the line itself is blank, for easier
179 filtering for those who want to indent their blank lines.
180
181 Okay: spam(1)\n#
182 W291: spam(1) \n#
183 W293: class Foo(object):\n \n bang = 12
184 """
185 physical_line = physical_line.rstrip('\n') # chr(10), newline
186 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
187 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
188 stripped = physical_line.rstrip(' \t\v')
189 if physical_line != stripped:
190 if stripped:
191 return len(stripped), "W291 trailing whitespace"
192 else:
193 return 0, "W293 blank line contains whitespace"
194
195
196 def trailing_blank_lines(physical_line, lines, line_number, total_lines):
197 r"""Trailing blank lines are superfluous.
198
199 Okay: spam(1)
200 W391: spam(1)\n
201
202 However the last line should end with a new line (warning W292).
203 """
204 if line_number == total_lines:
205 stripped_last_line = physical_line.rstrip()
206 if not stripped_last_line:
207 return 0, "W391 blank line at end of file"
208 if stripped_last_line == physical_line:
209 return len(physical_line), "W292 no newline at end of file"
210
211
212 def maximum_line_length(physical_line, max_line_length, multiline, noqa):
213 r"""Limit all lines to a maximum of 79 characters.
214
215 There are still many devices around that are limited to 80 character
216 lines; plus, limiting windows to 80 characters makes it possible to have
217 several windows side-by-side. The default wrapping on such devices looks
218 ugly. Therefore, please limit all lines to a maximum of 79 characters.
219 For flowing long blocks of text (docstrings or comments), limiting the
220 length to 72 characters is recommended.
221
222 Reports error E501.
223 """
224 line = physical_line.rstrip()
225 length = len(line)
226 if length > max_line_length and not noqa:
227 # Special case for long URLs in multi-line docstrings or comments,
228 # but still report the error when the 72 first chars are whitespaces.
229 chunks = line.split()
230 if ((len(chunks) == 1 and multiline) or
231 (len(chunks) == 2 and chunks[0] == '#')) and \
232 len(line) - len(chunks[-1]) < max_line_length - 7:
233 return
234 if hasattr(line, 'decode'): # Python 2
235 # The line could contain multi-byte characters
236 try:
237 length = len(line.decode('utf-8'))
238 except UnicodeError:
239 pass
240 if length > max_line_length:
241 return (max_line_length, "E501 line too long "
242 "(%d > %d characters)" % (length, max_line_length),
243 length, max_line_length)
244
245
246 ##############################################################################
247 # Plugins (check functions) for logical lines
248 ##############################################################################
249
250
251 def blank_lines(logical_line, blank_lines, indent_level, line_number,
252 blank_before, previous_logical,
253 previous_unindented_logical_line, previous_indent_level,
254 lines):
255 r"""Separate top-level function and class definitions with two blank lines.
256
257 Method definitions inside a class are separated by a single blank line.
258
259 Extra blank lines may be used (sparingly) to separate groups of related
260 functions. Blank lines may be omitted between a bunch of related
261 one-liners (e.g. a set of dummy implementations).
262
263 Use blank lines in functions, sparingly, to indicate logical sections.
264
265 Okay: def a():\n pass\n\n\ndef b():\n pass
266 Okay: def a():\n pass\n\n\nasync def b():\n pass
267 Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
268
269 E301: class Foo:\n b = 0\n def bar():\n pass
270 E302: def a():\n pass\n\ndef b(n):\n pass
271 E302: def a():\n pass\n\nasync def b(n):\n pass
272 E303: def a():\n pass\n\n\n\ndef b(n):\n pass
273 E303: def a():\n\n\n\n pass
274 E304: @decorator\n\ndef a():\n pass
275 E305: def a():\n pass\na()
276 """
277 if line_number < 3 and not previous_logical:
278 return # Don't expect blank lines before the first line
279 if previous_logical.startswith('@'):
280 if blank_lines:
281 yield 0, "E304 blank lines found after function decorator"
282 elif blank_lines > 2 or (indent_level and blank_lines == 2):
283 yield 0, "E303 too many blank lines (%d)", blank_lines
284 elif logical_line.startswith(('def ', 'async def ', 'class ', '@')):
285 if indent_level:
286 if not (blank_before or previous_indent_level < indent_level or
287 DOCSTRING_REGEX.match(previous_logical)):
288 ancestor_level = indent_level
289 nested = False
290 # Search backwards for a def ancestor or tree root (top level).
291 for line in lines[line_number - 2::-1]:
292 if line.strip() and expand_indent(line) < ancestor_level:
293 ancestor_level = expand_indent(line)
294 nested = line.lstrip().startswith('def ')
295 if nested or ancestor_level == 0:
296 break
297 if nested:
298 yield 0, "E306 expected 1 blank line before a " \
299 "nested definition, found 0"
300 else:
301 yield 0, "E301 expected 1 blank line, found 0"
302 elif blank_before != 2:
303 yield 0, "E302 expected 2 blank lines, found %d", blank_before
304 elif (logical_line and not indent_level and blank_before != 2 and
305 previous_unindented_logical_line.startswith(('def', 'class'))):
306 yield 0, "E305 expected 2 blank lines after " \
307 "class or function definition, found %d", blank_before
308
309
310 def extraneous_whitespace(logical_line):
311 r"""Avoid extraneous whitespace.
312
313 Avoid extraneous whitespace in these situations:
314 - Immediately inside parentheses, brackets or braces.
315 - Immediately before a comma, semicolon, or colon.
316
317 Okay: spam(ham[1], {eggs: 2})
318 E201: spam( ham[1], {eggs: 2})
319 E201: spam(ham[ 1], {eggs: 2})
320 E201: spam(ham[1], { eggs: 2})
321 E202: spam(ham[1], {eggs: 2} )
322 E202: spam(ham[1 ], {eggs: 2})
323 E202: spam(ham[1], {eggs: 2 })
324
325 E203: if x == 4: print x, y; x, y = y , x
326 E203: if x == 4: print x, y ; x, y = y, x
327 E203: if x == 4 : print x, y; x, y = y, x
328 """
329 line = logical_line
330 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
331 text = match.group()
332 char = text.strip()
333 found = match.start()
334 if text == char + ' ':
335 # assert char in '([{'
336 yield found + 1, "E201 whitespace after '%s'", char
337 elif line[found - 1] != ',':
338 code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
339 yield found, "%s whitespace before '%s'" % (code, char), char
340
341
342 def whitespace_around_keywords(logical_line):
343 r"""Avoid extraneous whitespace around keywords.
344
345 Okay: True and False
346 E271: True and False
347 E272: True and False
348 E273: True and\tFalse
349 E274: True\tand False
350 """
351 for match in KEYWORD_REGEX.finditer(logical_line):
352 before, after = match.groups()
353
354 if '\t' in before:
355 yield match.start(1), "E274 tab before keyword"
356 elif len(before) > 1:
357 yield match.start(1), "E272 multiple spaces before keyword"
358
359 if '\t' in after:
360 yield match.start(2), "E273 tab after keyword"
361 elif len(after) > 1:
362 yield match.start(2), "E271 multiple spaces after keyword"
363
364
365 def missing_whitespace_after_import_keyword(logical_line):
366 r"""Multiple imports in form from x import (a, b, c) should have space
367 between import statement and parenthesised name list.
368
369 Okay: from foo import (bar, baz)
370 E275: from foo import(bar, baz)
371 E275: from importable.module import(bar, baz)
372 """
373 line = logical_line
374 indicator = ' import('
375 if line.startswith('from '):
376 found = line.find(indicator)
377 if -1 < found:
378 pos = found + len(indicator) - 1
379 yield pos, "E275 missing whitespace after keyword"
380
381
382 def missing_whitespace(logical_line):
383 r"""Each comma, semicolon or colon should be followed by whitespace.
384
385 Okay: [a, b]
386 Okay: (3,)
387 Okay: a[1:4]
388 Okay: a[:4]
389 Okay: a[1:]
390 Okay: a[1:4:2]
391 E231: ['a','b']
392 E231: foo(bar,baz)
393 E231: [{'a':'b'}]
394 """
395 line = logical_line
396 for index in range(len(line) - 1):
397 char = line[index]
398 if char in ',;:' and line[index + 1] not in WHITESPACE:
399 before = line[:index]
400 if char == ':' and before.count('[') > before.count(']') and \
401 before.rfind('{') < before.rfind('['):
402 continue # Slice syntax, no space required
403 if char == ',' and line[index + 1] == ')':
404 continue # Allow tuple with only one element: (3,)
405 yield index, "E231 missing whitespace after '%s'", char
406
407
408 def indentation(logical_line, previous_logical, indent_char,
409 indent_level, previous_indent_level):
410 r"""Use 4 spaces per indentation level.
411
412 For really old code that you don't want to mess up, you can continue to
413 use 8-space tabs.
414
415 Okay: a = 1
416 Okay: if a == 0:\n a = 1
417 E111: a = 1
418 E114: # a = 1
419
420 Okay: for item in items:\n pass
421 E112: for item in items:\npass
422 E115: for item in items:\n# Hi\n pass
423
424 Okay: a = 1\nb = 2
425 E113: a = 1\n b = 2
426 E116: a = 1\n # b = 2
427 """
428 c = 0 if logical_line else 3
429 tmpl = "E11%d %s" if logical_line else "E11%d %s (comment)"
430 if indent_level % 4:
431 yield 0, tmpl % (1 + c, "indentation is not a multiple of four")
432 indent_expect = previous_logical.endswith(':')
433 if indent_expect and indent_level <= previous_indent_level:
434 yield 0, tmpl % (2 + c, "expected an indented block")
435 elif not indent_expect and indent_level > previous_indent_level:
436 yield 0, tmpl % (3 + c, "unexpected indentation")
437
438
439 def continued_indentation(logical_line, tokens, indent_level, hang_closing,
440 indent_char, noqa, verbose):
441 r"""Continuation lines indentation.
442
443 Continuation lines should align wrapped elements either vertically
444 using Python's implicit line joining inside parentheses, brackets
445 and braces, or using a hanging indent.
446
447 When using a hanging indent these considerations should be applied:
448 - there should be no arguments on the first line, and
449 - further indentation should be used to clearly distinguish itself as a
450 continuation line.
451
452 Okay: a = (\n)
453 E123: a = (\n )
454
455 Okay: a = (\n 42)
456 E121: a = (\n 42)
457 E122: a = (\n42)
458 E123: a = (\n 42\n )
459 E124: a = (24,\n 42\n)
460 E125: if (\n b):\n pass
461 E126: a = (\n 42)
462 E127: a = (24,\n 42)
463 E128: a = (24,\n 42)
464 E129: if (a or\n b):\n pass
465 E131: a = (\n 42\n 24)
466 """
467 first_row = tokens[0][2][0]
468 nrows = 1 + tokens[-1][2][0] - first_row
469 if noqa or nrows == 1:
470 return
471
472 # indent_next tells us whether the next block is indented; assuming
473 # that it is indented by 4 spaces, then we should not allow 4-space
474 # indents on the final continuation line; in turn, some other
475 # indents are allowed to have an extra 4 spaces.
476 indent_next = logical_line.endswith(':')
477
478 row = depth = 0
479 valid_hangs = (4,) if indent_char != '\t' else (4, 8)
480 # remember how many brackets were opened on each line
481 parens = [0] * nrows
482 # relative indents of physical lines
483 rel_indent = [0] * nrows
484 # for each depth, collect a list of opening rows
485 open_rows = [[0]]
486 # for each depth, memorize the hanging indentation
487 hangs = [None]
488 # visual indents
489 indent_chances = {}
490 last_indent = tokens[0][2]
491 visual_indent = None
492 last_token_multiline = False
493 # for each depth, memorize the visual indent column
494 indent = [last_indent[1]]
495 if verbose >= 3:
496 print(">>> " + tokens[0][4].rstrip())
497
498 for token_type, text, start, end, line in tokens:
499
500 newline = row < start[0] - first_row
501 if newline:
502 row = start[0] - first_row
503 newline = not last_token_multiline and token_type not in NEWLINE
504
505 if newline:
506 # this is the beginning of a continuation line.
507 last_indent = start
508 if verbose >= 3:
509 print("... " + line.rstrip())
510
511 # record the initial indent.
512 rel_indent[row] = expand_indent(line) - indent_level
513
514 # identify closing bracket
515 close_bracket = (token_type == tokenize.OP and text in ']})')
516
517 # is the indent relative to an opening bracket line?
518 for open_row in reversed(open_rows[depth]):
519 hang = rel_indent[row] - rel_indent[open_row]
520 hanging_indent = hang in valid_hangs
521 if hanging_indent:
522 break
523 if hangs[depth]:
524 hanging_indent = (hang == hangs[depth])
525 # is there any chance of visual indent?
526 visual_indent = (not close_bracket and hang > 0 and
527 indent_chances.get(start[1]))
528
529 if close_bracket and indent[depth]:
530 # closing bracket for visual indent
531 if start[1] != indent[depth]:
532 yield (start, "E124 closing bracket does not match "
533 "visual indentation")
534 elif close_bracket and not hang:
535 # closing bracket matches indentation of opening bracket's line
536 if hang_closing:
537 yield start, "E133 closing bracket is missing indentation"
538 elif indent[depth] and start[1] < indent[depth]:
539 if visual_indent is not True:
540 # visual indent is broken
541 yield (start, "E128 continuation line "
542 "under-indented for visual indent")
543 elif hanging_indent or (indent_next and rel_indent[row] == 8):
544 # hanging indent is verified
545 if close_bracket and not hang_closing:
546 yield (start, "E123 closing bracket does not match "
547 "indentation of opening bracket's line")
548 hangs[depth] = hang
549 elif visual_indent is True:
550 # visual indent is verified
551 indent[depth] = start[1]
552 elif visual_indent in (text, str):
553 # ignore token lined up with matching one from a previous line
554 pass
555 else:
556 # indent is broken
557 if hang <= 0:
558 error = "E122", "missing indentation or outdented"
559 elif indent[depth]:
560 error = "E127", "over-indented for visual indent"
561 elif not close_bracket and hangs[depth]:
562 error = "E131", "unaligned for hanging indent"
563 else:
564 hangs[depth] = hang
565 if hang > 4:
566 error = "E126", "over-indented for hanging indent"
567 else:
568 error = "E121", "under-indented for hanging indent"
569 yield start, "%s continuation line %s" % error
570
571 # look for visual indenting
572 if (parens[row] and
573 token_type not in (tokenize.NL, tokenize.COMMENT) and
574 not indent[depth]):
575 indent[depth] = start[1]
576 indent_chances[start[1]] = True
577 if verbose >= 4:
578 print("bracket depth %s indent to %s" % (depth, start[1]))
579 # deal with implicit string concatenation
580 elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
581 text in ('u', 'ur', 'b', 'br')):
582 indent_chances[start[1]] = str
583 # special case for the "if" statement because len("if (") == 4
584 elif not indent_chances and not row and not depth and text == 'if':
585 indent_chances[end[1] + 1] = True
586 elif text == ':' and line[end[1]:].isspace():
587 open_rows[depth].append(row)
588
589 # keep track of bracket depth
590 if token_type == tokenize.OP:
591 if text in '([{':
592 depth += 1
593 indent.append(0)
594 hangs.append(None)
595 if len(open_rows) == depth:
596 open_rows.append([])
597 open_rows[depth].append(row)
598 parens[row] += 1
599 if verbose >= 4:
600 print("bracket depth %s seen, col %s, visual min = %s" %
601 (depth, start[1], indent[depth]))
602 elif text in ')]}' and depth > 0:
603 # parent indents should not be more than this one
604 prev_indent = indent.pop() or last_indent[1]
605 hangs.pop()
606 for d in range(depth):
607 if indent[d] > prev_indent:
608 indent[d] = 0
609 for ind in list(indent_chances):
610 if ind >= prev_indent:
611 del indent_chances[ind]
612 del open_rows[depth + 1:]
613 depth -= 1
614 if depth:
615 indent_chances[indent[depth]] = True
616 for idx in range(row, -1, -1):
617 if parens[idx]:
618 parens[idx] -= 1
619 break
620 assert len(indent) == depth + 1
621 if start[1] not in indent_chances:
622 # allow lining up tokens
623 indent_chances[start[1]] = text
624
625 last_token_multiline = (start[0] != end[0])
626 if last_token_multiline:
627 rel_indent[end[0] - first_row] = rel_indent[row]
628
629 if indent_next and expand_indent(line) == indent_level + 4:
630 pos = (start[0], indent[0] + 4)
631 if visual_indent:
632 code = "E129 visually indented line"
633 else:
634 code = "E125 continuation line"
635 yield pos, "%s with same indent as next logical line" % code
636
637
638 def whitespace_before_parameters(logical_line, tokens):
639 r"""Avoid extraneous whitespace.
640
641 Avoid extraneous whitespace in the following situations:
642 - before the open parenthesis that starts the argument list of a
643 function call.
644 - before the open parenthesis that starts an indexing or slicing.
645
646 Okay: spam(1)
647 E211: spam (1)
648
649 Okay: dict['key'] = list[index]
650 E211: dict ['key'] = list[index]
651 E211: dict['key'] = list [index]
652 """
653 prev_type, prev_text, __, prev_end, __ = tokens[0]
654 for index in range(1, len(tokens)):
655 token_type, text, start, end, __ = tokens[index]
656 if (token_type == tokenize.OP and
657 text in '([' and
658 start != prev_end and
659 (prev_type == tokenize.NAME or prev_text in '}])') and
660 # Syntax "class A (B):" is allowed, but avoid it
661 (index < 2 or tokens[index - 2][1] != 'class') and
662 # Allow "return (a.foo for a in range(5))"
663 not keyword.iskeyword(prev_text)):
664 yield prev_end, "E211 whitespace before '%s'", text
665 prev_type = token_type
666 prev_text = text
667 prev_end = end
668
669
670 def whitespace_around_operator(logical_line):
671 r"""Avoid extraneous whitespace around an operator.
672
673 Okay: a = 12 + 3
674 E221: a = 4 + 5
675 E222: a = 4 + 5
676 E223: a = 4\t+ 5
677 E224: a = 4 +\t5
678 """
679 for match in OPERATOR_REGEX.finditer(logical_line):
680 before, after = match.groups()
681
682 if '\t' in before:
683 yield match.start(1), "E223 tab before operator"
684 elif len(before) > 1:
685 yield match.start(1), "E221 multiple spaces before operator"
686
687 if '\t' in after:
688 yield match.start(2), "E224 tab after operator"
689 elif len(after) > 1:
690 yield match.start(2), "E222 multiple spaces after operator"
691
692
693 def missing_whitespace_around_operator(logical_line, tokens):
694 r"""Surround operators with a single space on either side.
695
696 - Always surround these binary operators with a single space on
697 either side: assignment (=), augmented assignment (+=, -= etc.),
698 comparisons (==, <, >, !=, <=, >=, in, not in, is, is not),
699 Booleans (and, or, not).
700
701 - If operators with different priorities are used, consider adding
702 whitespace around the operators with the lowest priorities.
703
704 Okay: i = i + 1
705 Okay: submitted += 1
706 Okay: x = x * 2 - 1
707 Okay: hypot2 = x * x + y * y
708 Okay: c = (a + b) * (a - b)
709 Okay: foo(bar, key='word', *args, **kwargs)
710 Okay: alpha[:-i]
711
712 E225: i=i+1
713 E225: submitted +=1
714 E225: x = x /2 - 1
715 E225: z = x **y
716 E226: c = (a+b) * (a-b)
717 E226: hypot2 = x*x + y*y
718 E227: c = a|b
719 E228: msg = fmt%(errno, errmsg)
720 """
721 parens = 0
722 need_space = False
723 prev_type = tokenize.OP
724 prev_text = prev_end = None
725 for token_type, text, start, end, line in tokens:
726 if token_type in SKIP_COMMENTS:
727 continue
728 if text in ('(', 'lambda'):
729 parens += 1
730 elif text == ')':
731 parens -= 1
732 if need_space:
733 if start != prev_end:
734 # Found a (probably) needed space
735 if need_space is not True and not need_space[1]:
736 yield (need_space[0],
737 "E225 missing whitespace around operator")
738 need_space = False
739 elif text == '>' and prev_text in ('<', '-'):
740 # Tolerate the "<>" operator, even if running Python 3
741 # Deal with Python 3's annotated return value "->"
742 pass
743 else:
744 if need_space is True or need_space[1]:
745 # A needed trailing space was not found
746 yield prev_end, "E225 missing whitespace around operator"
747 elif prev_text != '**':
748 code, optype = 'E226', 'arithmetic'
749 if prev_text == '%':
750 code, optype = 'E228', 'modulo'
751 elif prev_text not in ARITHMETIC_OP:
752 code, optype = 'E227', 'bitwise or shift'
753 yield (need_space[0], "%s missing whitespace "
754 "around %s operator" % (code, optype))
755 need_space = False
756 elif token_type == tokenize.OP and prev_end is not None:
757 if text == '=' and parens:
758 # Allow keyword args or defaults: foo(bar=None).
759 pass
760 elif text in WS_NEEDED_OPERATORS:
761 need_space = True
762 elif text in UNARY_OPERATORS:
763 # Check if the operator is being used as a binary operator
764 # Allow unary operators: -123, -x, +1.
765 # Allow argument unpacking: foo(*args, **kwargs).
766 if (prev_text in '}])' if prev_type == tokenize.OP
767 else prev_text not in KEYWORDS):
768 need_space = None
769 elif text in WS_OPTIONAL_OPERATORS:
770 need_space = None
771
772 if need_space is None:
773 # Surrounding space is optional, but ensure that
774 # trailing space matches opening space
775 need_space = (prev_end, start != prev_end)
776 elif need_space and start == prev_end:
777 # A needed opening space was not found
778 yield prev_end, "E225 missing whitespace around operator"
779 need_space = False
780 prev_type = token_type
781 prev_text = text
782 prev_end = end
783
784
785 def whitespace_around_comma(logical_line):
786 r"""Avoid extraneous whitespace after a comma or a colon.
787
788 Note: these checks are disabled by default
789
790 Okay: a = (1, 2)
791 E241: a = (1, 2)
792 E242: a = (1,\t2)
793 """
794 line = logical_line
795 for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
796 found = m.start() + 1
797 if '\t' in m.group():
798 yield found, "E242 tab after '%s'", m.group()[0]
799 else:
800 yield found, "E241 multiple spaces after '%s'", m.group()[0]
801
802
803 def whitespace_around_named_parameter_equals(logical_line, tokens):
804 r"""Don't use spaces around the '=' sign in function arguments.
805
806 Don't use spaces around the '=' sign when used to indicate a
807 keyword argument or a default parameter value.
808
809 Okay: def complex(real, imag=0.0):
810 Okay: return magic(r=real, i=imag)
811 Okay: boolean(a == b)
812 Okay: boolean(a != b)
813 Okay: boolean(a <= b)
814 Okay: boolean(a >= b)
815 Okay: def foo(arg: int = 42):
816 Okay: async def foo(arg: int = 42):
817
818 E251: def complex(real, imag = 0.0):
819 E251: return magic(r = real, i = imag)
820 """
821 parens = 0
822 no_space = False
823 prev_end = None
824 annotated_func_arg = False
825 in_def = logical_line.startswith(('def', 'async def'))
826 message = "E251 unexpected spaces around keyword / parameter equals"
827 for token_type, text, start, end, line in tokens:
828 if token_type == tokenize.NL:
829 continue
830 if no_space:
831 no_space = False
832 if start != prev_end:
833 yield (prev_end, message)
834 if token_type == tokenize.OP:
835 if text in '([':
836 parens += 1
837 elif text in ')]':
838 parens -= 1
839 elif in_def and text == ':' and parens == 1:
840 annotated_func_arg = True
841 elif parens and text == ',' and parens == 1:
842 annotated_func_arg = False
843 elif parens and text == '=' and not annotated_func_arg:
844 no_space = True
845 if start != prev_end:
846 yield (prev_end, message)
847 if not parens:
848 annotated_func_arg = False
849
850 prev_end = end
851
852
853 def whitespace_before_comment(logical_line, tokens):
854 r"""Separate inline comments by at least two spaces.
855
856 An inline comment is a comment on the same line as a statement. Inline
857 comments should be separated by at least two spaces from the statement.
858 They should start with a # and a single space.
859
860 Each line of a block comment starts with a # and a single space
861 (unless it is indented text inside the comment).
862
863 Okay: x = x + 1 # Increment x
864 Okay: x = x + 1 # Increment x
865 Okay: # Block comment
866 E261: x = x + 1 # Increment x
867 E262: x = x + 1 #Increment x
868 E262: x = x + 1 # Increment x
869 E265: #Block comment
870 E266: ### Block comment
871 """
872 prev_end = (0, 0)
873 for token_type, text, start, end, line in tokens:
874 if token_type == tokenize.COMMENT:
875 inline_comment = line[:start[1]].strip()
876 if inline_comment:
877 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
878 yield (prev_end,
879 "E261 at least two spaces before inline comment")
880 symbol, sp, comment = text.partition(' ')
881 bad_prefix = symbol not in '#:' and (symbol.lstrip('#')[:1] or '#')
882 if inline_comment:
883 if bad_prefix or comment[:1] in WHITESPACE:
884 yield start, "E262 inline comment should start with '# '"
885 elif bad_prefix and (bad_prefix != '!' or start[0] > 1):
886 if bad_prefix != '#':
887 yield start, "E265 block comment should start with '# '"
888 elif comment:
889 yield start, "E266 too many leading '#' for block comment"
890 elif token_type != tokenize.NL:
891 prev_end = end
892
893
894 def imports_on_separate_lines(logical_line):
895 r"""Place imports on separate lines.
896
897 Okay: import os\nimport sys
898 E401: import sys, os
899
900 Okay: from subprocess import Popen, PIPE
901 Okay: from myclas import MyClass
902 Okay: from foo.bar.yourclass import YourClass
903 Okay: import myclass
904 Okay: import foo.bar.yourclass
905 """
906 line = logical_line
907 if line.startswith('import '):
908 found = line.find(',')
909 if -1 < found and ';' not in line[:found]:
910 yield found, "E401 multiple imports on one line"
911
912
913 def module_imports_on_top_of_file(
914 logical_line, indent_level, checker_state, noqa):
915 r"""Place imports at the top of the file.
916
917 Always put imports at the top of the file, just after any module comments
918 and docstrings, and before module globals and constants.
919
920 Okay: import os
921 Okay: # this is a comment\nimport os
922 Okay: '''this is a module docstring'''\nimport os
923 Okay: r'''this is a module docstring'''\nimport os
924 Okay: try:\n import x\nexcept:\n pass\nelse:\n pass\nimport y
925 Okay: try:\n import x\nexcept:\n pass\nfinally:\n pass\nimport y
926 E402: a=1\nimport os
927 E402: 'One string'\n"Two string"\nimport os
928 E402: a=1\nfrom sys import x
929
930 Okay: if x:\n import os
931 """
932 def is_string_literal(line):
933 if line[0] in 'uUbB':
934 line = line[1:]
935 if line and line[0] in 'rR':
936 line = line[1:]
937 return line and (line[0] == '"' or line[0] == "'")
938
939 allowed_try_keywords = ('try', 'except', 'else', 'finally')
940
941 if indent_level: # Allow imports in conditional statements or functions
942 return
943 if not logical_line: # Allow empty lines or comments
944 return
945 if noqa:
946 return
947 line = logical_line
948 if line.startswith('import ') or line.startswith('from '):
949 if checker_state.get('seen_non_imports', False):
950 yield 0, "E402 module level import not at top of file"
951 elif any(line.startswith(kw) for kw in allowed_try_keywords):
952 # Allow try, except, else, finally keywords intermixed with imports in
953 # order to support conditional importing
954 return
955 elif is_string_literal(line):
956 # The first literal is a docstring, allow it. Otherwise, report error.
957 if checker_state.get('seen_docstring', False):
958 checker_state['seen_non_imports'] = True
959 else:
960 checker_state['seen_docstring'] = True
961 else:
962 checker_state['seen_non_imports'] = True
963
964
965 def compound_statements(logical_line):
966 r"""Compound statements (on the same line) are generally discouraged.
967
968 While sometimes it's okay to put an if/for/while with a small body
969 on the same line, never do this for multi-clause statements.
970 Also avoid folding such long lines!
971
972 Always use a def statement instead of an assignment statement that
973 binds a lambda expression directly to a name.
974
975 Okay: if foo == 'blah':\n do_blah_thing()
976 Okay: do_one()
977 Okay: do_two()
978 Okay: do_three()
979
980 E701: if foo == 'blah': do_blah_thing()
981 E701: for x in lst: total += x
982 E701: while t < 10: t = delay()
983 E701: if foo == 'blah': do_blah_thing()
984 E701: else: do_non_blah_thing()
985 E701: try: something()
986 E701: finally: cleanup()
987 E701: if foo == 'blah': one(); two(); three()
988 E702: do_one(); do_two(); do_three()
989 E703: do_four(); # useless semicolon
990 E704: def f(x): return 2*x
991 E705: async def f(x): return 2*x
992 E731: f = lambda x: 2*x
993 """
994 line = logical_line
995 last_char = len(line) - 1
996 found = line.find(':')
997 prev_found = 0
998 counts = dict((char, 0) for char in '{}[]()')
999 while -1 < found < last_char:
1000 update_counts(line[prev_found:found], counts)
1001 if ((counts['{'] <= counts['}'] and # {'a': 1} (dict)
1002 counts['['] <= counts[']'] and # [1:2] (slice)
1003 counts['('] <= counts[')'])): # (annotation)
1004 lambda_kw = LAMBDA_REGEX.search(line, 0, found)
1005 if lambda_kw:
1006 before = line[:lambda_kw.start()].rstrip()
1007 if before[-1:] == '=' and isidentifier(before[:-1].strip()):
1008 yield 0, ("E731 do not assign a lambda expression, use a "
1009 "def")
1010 break
1011 if line.startswith('def '):
1012 yield 0, "E704 multiple statements on one line (def)"
1013 elif line.startswith('async def '):
1014 yield 0, "E705 multiple statements on one line (async def)"
1015 else:
1016 yield found, "E701 multiple statements on one line (colon)"
1017 prev_found = found
1018 found = line.find(':', found + 1)
1019 found = line.find(';')
1020 while -1 < found:
1021 if found < last_char:
1022 yield found, "E702 multiple statements on one line (semicolon)"
1023 else:
1024 yield found, "E703 statement ends with a semicolon"
1025 found = line.find(';', found + 1)
1026
1027
1028 def explicit_line_join(logical_line, tokens):
1029 r"""Avoid explicit line join between brackets.
1030
1031 The preferred way of wrapping long lines is by using Python's implied line
1032 continuation inside parentheses, brackets and braces. Long lines can be
1033 broken over multiple lines by wrapping expressions in parentheses. These
1034 should be used in preference to using a backslash for line continuation.
1035
1036 E502: aaa = [123, \\n 123]
1037 E502: aaa = ("bbb " \\n "ccc")
1038
1039 Okay: aaa = [123,\n 123]
1040 Okay: aaa = ("bbb "\n "ccc")
1041 Okay: aaa = "bbb " \\n "ccc"
1042 Okay: aaa = 123 # \\
1043 """
1044 prev_start = prev_end = parens = 0
1045 comment = False
1046 backslash = None
1047 for token_type, text, start, end, line in tokens:
1048 if token_type == tokenize.COMMENT:
1049 comment = True
1050 if start[0] != prev_start and parens and backslash and not comment:
1051 yield backslash, "E502 the backslash is redundant between brackets"
1052 if end[0] != prev_end:
1053 if line.rstrip('\r\n').endswith('\\'):
1054 backslash = (end[0], len(line.splitlines()[-1]) - 1)
1055 else:
1056 backslash = None
1057 prev_start = prev_end = end[0]
1058 else:
1059 prev_start = start[0]
1060 if token_type == tokenize.OP:
1061 if text in '([{':
1062 parens += 1
1063 elif text in ')]}':
1064 parens -= 1
1065
1066
1067 def break_around_binary_operator(logical_line, tokens):
1068 r"""
1069 Avoid breaks before binary operators.
1070
1071 The preferred place to break around a binary operator is after the
1072 operator, not before it.
1073
1074 W503: (width == 0\n + height == 0)
1075 W503: (width == 0\n and height == 0)
1076
1077 Okay: (width == 0 +\n height == 0)
1078 Okay: foo(\n -x)
1079 Okay: foo(x\n [])
1080 Okay: x = '''\n''' + ''
1081 Okay: foo(x,\n -y)
1082 Okay: foo(x, # comment\n -y)
1083 Okay: var = (1 &\n ~2)
1084 Okay: var = (1 /\n -2)
1085 Okay: var = (1 +\n -1 +\n -2)
1086 """
1087 def is_binary_operator(token_type, text):
1088 # The % character is strictly speaking a binary operator, but the
1089 # common usage seems to be to put it next to the format parameters,
1090 # after a line break.
1091 return ((token_type == tokenize.OP or text in ['and', 'or']) and
1092 text not in "()[]{},:.;@=%~")
1093
1094 line_break = False
1095 unary_context = True
1096 # Previous non-newline token types and text
1097 previous_token_type = None
1098 previous_text = None
1099 for token_type, text, start, end, line in tokens:
1100 if token_type == tokenize.COMMENT:
1101 continue
1102 if ('\n' in text or '\r' in text) and token_type != tokenize.STRING:
1103 line_break = True
1104 else:
1105 if (is_binary_operator(token_type, text) and line_break and
1106 not unary_context and
1107 not is_binary_operator(previous_token_type,
1108 previous_text)):
1109 yield start, "W503 line break before binary operator"
1110 unary_context = text in '([{,;'
1111 line_break = False
1112 previous_token_type = token_type
1113 previous_text = text
1114
1115
1116 def comparison_to_singleton(logical_line, noqa):
1117 r"""Comparison to singletons should use "is" or "is not".
1118
1119 Comparisons to singletons like None should always be done
1120 with "is" or "is not", never the equality operators.
1121
1122 Okay: if arg is not None:
1123 E711: if arg != None:
1124 E711: if None == arg:
1125 E712: if arg == True:
1126 E712: if False == arg:
1127
1128 Also, beware of writing if x when you really mean if x is not None --
1129 e.g. when testing whether a variable or argument that defaults to None was
1130 set to some other value. The other value might have a type (such as a
1131 container) that could be false in a boolean context!
1132 """
1133 match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
1134 if match:
1135 singleton = match.group(1) or match.group(3)
1136 same = (match.group(2) == '==')
1137
1138 msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
1139 if singleton in ('None',):
1140 code = 'E711'
1141 else:
1142 code = 'E712'
1143 nonzero = ((singleton == 'True' and same) or
1144 (singleton == 'False' and not same))
1145 msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
1146 yield (match.start(2), ("%s comparison to %s should be %s" %
1147 (code, singleton, msg)), singleton, msg)
1148
1149
1150 def comparison_negative(logical_line):
1151 r"""Negative comparison should be done using "not in" and "is not".
1152
1153 Okay: if x not in y:\n pass
1154 Okay: assert (X in Y or X is Z)
1155 Okay: if not (X in Y):\n pass
1156 Okay: zz = x is not y
1157 E713: Z = not X in Y
1158 E713: if not X.B in Y:\n pass
1159 E714: if not X is Y:\n pass
1160 E714: Z = not X.B is Y
1161 """
1162 match = COMPARE_NEGATIVE_REGEX.search(logical_line)
1163 if match:
1164 pos = match.start(1)
1165 if match.group(2) == 'in':
1166 yield pos, "E713 test for membership should be 'not in'"
1167 else:
1168 yield pos, "E714 test for object identity should be 'is not'"
1169
1170
1171 def comparison_type(logical_line, noqa):
1172 r"""Object type comparisons should always use isinstance().
1173
1174 Do not compare types directly.
1175
1176 Okay: if isinstance(obj, int):
1177 E721: if type(obj) is type(1):
1178
1179 When checking if an object is a string, keep in mind that it might be a
1180 unicode string too! In Python 2.3, str and unicode have a common base
1181 class, basestring, so you can do:
1182
1183 Okay: if isinstance(obj, basestring):
1184 Okay: if type(a1) is type(b1):
1185 """
1186 match = COMPARE_TYPE_REGEX.search(logical_line)
1187 if match and not noqa:
1188 inst = match.group(1)
1189 if inst and isidentifier(inst) and inst not in SINGLETONS:
1190 return # Allow comparison for types which are not obvious
1191 yield match.start(), "E721 do not compare types, use 'isinstance()'"
1192
1193
1194 def ambiguous_identifier(logical_line, tokens):
1195 r"""Never use the characters 'l', 'O', or 'I' as variable names.
1196
1197 In some fonts, these characters are indistinguishable from the numerals
1198 one and zero. When tempted to use 'l', use 'L' instead.
1199
1200 Okay: L = 0
1201 Okay: o = 123
1202 Okay: i = 42
1203 E741: l = 0
1204 E741: O = 123
1205 E741: I = 42
1206
1207 Variables can be bound in several other contexts, including class and
1208 function definitions, 'global' and 'nonlocal' statements, exception
1209 handlers, and 'with' statements.
1210
1211 Okay: except AttributeError as o:
1212 Okay: with lock as L:
1213 E741: except AttributeError as O:
1214 E741: with lock as l:
1215 E741: global I
1216 E741: nonlocal l
1217 E742: class I(object):
1218 E743: def l(x):
1219 """
1220 idents_to_avoid = ('l', 'O', 'I')
1221 prev_type, prev_text, prev_start, prev_end, __ = tokens[0]
1222 for token_type, text, start, end, line in tokens[1:]:
1223 ident = pos = None
1224 # identifiers on the lhs of an assignment operator
1225 if token_type == tokenize.OP and '=' in text:
1226 if prev_text in idents_to_avoid:
1227 ident = prev_text
1228 pos = prev_start
1229 # identifiers bound to a value with 'as', 'global', or 'nonlocal'
1230 if prev_text in ('as', 'global', 'nonlocal'):
1231 if text in idents_to_avoid:
1232 ident = text
1233 pos = start
1234 if prev_text == 'class':
1235 if text in idents_to_avoid:
1236 yield start, "E742 ambiguous class definition '%s'", text
1237 if prev_text == 'def':
1238 if text in idents_to_avoid:
1239 yield start, "E743 ambiguous function definition '%s'", text
1240 if ident:
1241 yield pos, "E741 ambiguous variable name '%s'", ident
1242 prev_text = text
1243 prev_start = start
1244
1245
1246 def python_3000_has_key(logical_line, noqa):
1247 r"""The {}.has_key() method is removed in Python 3: use the 'in' operator.
1248
1249 Okay: if "alph" in d:\n print d["alph"]
1250 W601: assert d.has_key('alph')
1251 """
1252 pos = logical_line.find('.has_key(')
1253 if pos > -1 and not noqa:
1254 yield pos, "W601 .has_key() is deprecated, use 'in'"
1255
1256
1257 def python_3000_raise_comma(logical_line):
1258 r"""When raising an exception, use "raise ValueError('message')".
1259
1260 The older form is removed in Python 3.
1261
1262 Okay: raise DummyError("Message")
1263 W602: raise DummyError, "Message"
1264 """
1265 match = RAISE_COMMA_REGEX.match(logical_line)
1266 if match and not RERAISE_COMMA_REGEX.match(logical_line):
1267 yield match.end() - 1, "W602 deprecated form of raising exception"
1268
1269
1270 def python_3000_not_equal(logical_line):
1271 r"""New code should always use != instead of <>.
1272
1273 The older syntax is removed in Python 3.
1274
1275 Okay: if a != 'no':
1276 W603: if a <> 'no':
1277 """
1278 pos = logical_line.find('<>')
1279 if pos > -1:
1280 yield pos, "W603 '<>' is deprecated, use '!='"
1281
1282
1283 def python_3000_backticks(logical_line):
1284 r"""Use repr() instead of backticks in Python 3.
1285
1286 Okay: val = repr(1 + 2)
1287 W604: val = `1 + 2`
1288 """
1289 pos = logical_line.find('`')
1290 if pos > -1:
1291 yield pos, "W604 backticks are deprecated, use 'repr()'"
1292
1293
1294 ##############################################################################
1295 # Helper functions
1296 ##############################################################################
1297
1298
1299 if sys.version_info < (3,):
1300 # Python 2: implicit encoding.
1301 def readlines(filename):
1302 """Read the source code."""
1303 with open(filename, 'rU') as f:
1304 return f.readlines()
1305 isidentifier = re.compile(r'[a-zA-Z_]\w*$').match
1306 stdin_get_value = sys.stdin.read
1307 else:
1308 # Python 3
1309 def readlines(filename):
1310 """Read the source code."""
1311 try:
1312 with open(filename, 'rb') as f:
1313 (coding, lines) = tokenize.detect_encoding(f.readline)
1314 f = TextIOWrapper(f, coding, line_buffering=True)
1315 return [line.decode(coding) for line in lines] + f.readlines()
1316 except (LookupError, SyntaxError, UnicodeError):
1317 # Fall back if file encoding is improperly declared
1318 with open(filename, encoding='latin-1') as f:
1319 return f.readlines()
1320 isidentifier = str.isidentifier
1321
1322 def stdin_get_value():
1323 """Read the value from stdin."""
1324 return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1325
1326 noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
1327
1328
1329 def expand_indent(line):
1330 r"""Return the amount of indentation.
1331
1332 Tabs are expanded to the next multiple of 8.
1333
1334 >>> expand_indent(' ')
1335 4
1336 >>> expand_indent('\t')
1337 8
1338 >>> expand_indent(' \t')
1339 8
1340 >>> expand_indent(' \t')
1341 16
1342 """
1343 if '\t' not in line:
1344 return len(line) - len(line.lstrip())
1345 result = 0
1346 for char in line:
1347 if char == '\t':
1348 result = result // 8 * 8 + 8
1349 elif char == ' ':
1350 result += 1
1351 else:
1352 break
1353 return result
1354
1355
1356 def mute_string(text):
1357 """Replace contents with 'xxx' to prevent syntax matching.
1358
1359 >>> mute_string('"abc"')
1360 '"xxx"'
1361 >>> mute_string("'''abc'''")
1362 "'''xxx'''"
1363 >>> mute_string("r'abc'")
1364 "r'xxx'"
1365 """
1366 # String modifiers (e.g. u or r)
1367 start = text.index(text[-1]) + 1
1368 end = len(text) - 1
1369 # Triple quotes
1370 if text[-3:] in ('"""', "'''"):
1371 start += 2
1372 end -= 2
1373 return text[:start] + 'x' * (end - start) + text[end:]
1374
1375
1376 def parse_udiff(diff, patterns=None, parent='.'):
1377 """Return a dictionary of matching lines."""
1378 # For each file of the diff, the entry key is the filename,
1379 # and the value is a set of row numbers to consider.
1380 rv = {}
1381 path = nrows = None
1382 for line in diff.splitlines():
1383 if nrows:
1384 if line[:1] != '-':
1385 nrows -= 1
1386 continue
1387 if line[:3] == '@@ ':
1388 hunk_match = HUNK_REGEX.match(line)
1389 (row, nrows) = [int(g or '1') for g in hunk_match.groups()]
1390 rv[path].update(range(row, row + nrows))
1391 elif line[:3] == '+++':
1392 path = line[4:].split('\t', 1)[0]
1393 if path[:2] == 'b/':
1394 path = path[2:]
1395 rv[path] = set()
1396 return dict([(os.path.join(parent, path), rows)
1397 for (path, rows) in rv.items()
1398 if rows and filename_match(path, patterns)])
1399
1400
1401 def normalize_paths(value, parent=os.curdir):
1402 """Parse a comma-separated list of paths.
1403
1404 Return a list of absolute paths.
1405 """
1406 if not value:
1407 return []
1408 if isinstance(value, list):
1409 return value
1410 paths = []
1411 for path in value.split(','):
1412 path = path.strip()
1413 if '/' in path:
1414 path = os.path.abspath(os.path.join(parent, path))
1415 paths.append(path.rstrip('/'))
1416 return paths
1417
1418
1419 def filename_match(filename, patterns, default=True):
1420 """Check if patterns contains a pattern that matches filename.
1421
1422 If patterns is unspecified, this always returns True.
1423 """
1424 if not patterns:
1425 return default
1426 return any(fnmatch(filename, pattern) for pattern in patterns)
1427
1428
1429 def update_counts(s, counts):
1430 r"""Adds one to the counts of each appearance of characters in s,
1431 for characters in counts"""
1432 for char in s:
1433 if char in counts:
1434 counts[char] += 1
1435
1436
1437 def _is_eol_token(token):
1438 return token[0] in NEWLINE or token[4][token[3][1]:].lstrip() == '\\\n'
1439
1440
1441 if COMMENT_WITH_NL:
1442 def _is_eol_token(token, _eol_token=_is_eol_token):
1443 return _eol_token(token) or (token[0] == tokenize.COMMENT and
1444 token[1] == token[4])
1445
1446 ##############################################################################
1447 # Framework to run all checks
1448 ##############################################################################
1449
1450
1451 _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
1452
1453
1454 def _get_parameters(function):
1455 if sys.version_info >= (3, 3):
1456 return [parameter.name
1457 for parameter
1458 in inspect.signature(function).parameters.values()
1459 if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
1460 else:
1461 return inspect.getargspec(function)[0]
1462
1463
1464 def register_check(check, codes=None):
1465 """Register a new check object."""
1466 def _add_check(check, kind, codes, args):
1467 if check in _checks[kind]:
1468 _checks[kind][check][0].extend(codes or [])
1469 else:
1470 _checks[kind][check] = (codes or [''], args)
1471 if inspect.isfunction(check):
1472 args = _get_parameters(check)
1473 if args and args[0] in ('physical_line', 'logical_line'):
1474 if codes is None:
1475 codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
1476 _add_check(check, args[0], codes, args)
1477 elif inspect.isclass(check):
1478 if _get_parameters(check.__init__)[:2] == ['self', 'tree']:
1479 _add_check(check, 'tree', codes, None)
1480
1481
1482 def init_checks_registry():
1483 """Register all globally visible functions.
1484
1485 The first argument name is either 'physical_line' or 'logical_line'.
1486 """
1487 mod = inspect.getmodule(register_check)
1488 for (name, function) in inspect.getmembers(mod, inspect.isfunction):
1489 register_check(function)
1490
1491
1492 init_checks_registry()
1493
1494
1495 class Checker(object):
1496 """Load a Python source file, tokenize it, check coding style."""
1497
1498 def __init__(self, filename=None, lines=None,
1499 options=None, report=None, **kwargs):
1500 if options is None:
1501 options = StyleGuide(kwargs).options
1502 else:
1503 assert not kwargs
1504 self._io_error = None
1505 self._physical_checks = options.physical_checks
1506 self._logical_checks = options.logical_checks
1507 self._ast_checks = options.ast_checks
1508 self.max_line_length = options.max_line_length
1509 self.multiline = False # in a multiline string?
1510 self.hang_closing = options.hang_closing
1511 self.verbose = options.verbose
1512 self.filename = filename
1513 # Dictionary where a checker can store its custom state.
1514 self._checker_states = {}
1515 if filename is None:
1516 self.filename = 'stdin'
1517 self.lines = lines or []
1518 elif filename == '-':
1519 self.filename = 'stdin'
1520 self.lines = stdin_get_value().splitlines(True)
1521 elif lines is None:
1522 try:
1523 self.lines = readlines(filename)
1524 except IOError:
1525 (exc_type, exc) = sys.exc_info()[:2]
1526 self._io_error = '%s: %s' % (exc_type.__name__, exc)
1527 self.lines = []
1528 else:
1529 self.lines = lines
1530 if self.lines:
1531 ord0 = ord(self.lines[0][0])
1532 if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
1533 if ord0 == 0xfeff:
1534 self.lines[0] = self.lines[0][1:]
1535 elif self.lines[0][:3] == '\xef\xbb\xbf':
1536 self.lines[0] = self.lines[0][3:]
1537 self.report = report or options.report
1538 self.report_error = self.report.error
1539 self.report_error_args = self.report.error_args
1540 self.noqa = False
1541
1542 # added for eric6 integration
1543 self.options = options
1544
1545 def report_invalid_syntax(self):
1546 """Check if the syntax is valid."""
1547 (exc_type, exc) = sys.exc_info()[:2]
1548 if len(exc.args) > 1:
1549 offset = exc.args[1]
1550 if len(offset) > 2:
1551 offset = offset[1:3]
1552 else:
1553 offset = (1, 0)
1554 self.report_error_args(offset[0], offset[1] or 0,
1555 'E901', self.report_invalid_syntax,
1556 exc_type.__name__, exc.args[0])
1557
1558 def readline(self):
1559 """Get the next line from the input buffer."""
1560 if self.line_number >= self.total_lines:
1561 return ''
1562 line = self.lines[self.line_number]
1563 self.line_number += 1
1564 if self.indent_char is None and line[:1] in WHITESPACE:
1565 self.indent_char = line[0]
1566 return line
1567
1568 def run_check(self, check, argument_names):
1569 """Run a check plugin."""
1570 arguments = []
1571 for name in argument_names:
1572 arguments.append(getattr(self, name))
1573 return check(*arguments)
1574
1575 def init_checker_state(self, name, argument_names):
1576 """ Prepare custom state for the specific checker plugin."""
1577 if 'checker_state' in argument_names:
1578 self.checker_state = self._checker_states.setdefault(name, {})
1579
1580 def check_physical(self, line):
1581 """Run all physical checks on a raw input line."""
1582 self.physical_line = line
1583 for name, check, argument_names in self._physical_checks:
1584 self.init_checker_state(name, argument_names)
1585 result = self.run_check(check, argument_names)
1586 if result is not None:
1587 (offset, text) = result[:2]
1588 args = result[2:]
1589 self.report_error_args(
1590 self.line_number, offset, text, check, *args)
1591 if text[:4] == 'E101':
1592 self.indent_char = line[0]
1593
1594 def build_tokens_line(self):
1595 """Build a logical line from tokens."""
1596 logical = []
1597 comments = []
1598 length = 0
1599 prev_row = prev_col = mapping = None
1600 for token_type, text, start, end, line in self.tokens:
1601 if token_type in SKIP_TOKENS:
1602 continue
1603 if not mapping:
1604 mapping = [(0, start)]
1605 if token_type == tokenize.COMMENT:
1606 comments.append(text)
1607 continue
1608 if token_type == tokenize.STRING:
1609 text = mute_string(text)
1610 if prev_row:
1611 (start_row, start_col) = start
1612 if prev_row != start_row: # different row
1613 prev_text = self.lines[prev_row - 1][prev_col - 1]
1614 if prev_text == ',' or (prev_text not in '{[(' and
1615 text not in '}])'):
1616 text = ' ' + text
1617 elif prev_col != start_col: # different column
1618 text = line[prev_col:start_col] + text
1619 logical.append(text)
1620 length += len(text)
1621 mapping.append((length, end))
1622 (prev_row, prev_col) = end
1623 self.logical_line = ''.join(logical)
1624 self.noqa = comments and noqa(''.join(comments))
1625 return mapping
1626
1627 def check_logical(self):
1628 """Build a line from tokens and run all logical checks on it."""
1629 self.report.increment_logical_line()
1630 mapping = self.build_tokens_line()
1631
1632 if not mapping:
1633 return
1634
1635 (start_row, start_col) = mapping[0][1]
1636 start_line = self.lines[start_row - 1]
1637 self.indent_level = expand_indent(start_line[:start_col])
1638 if self.blank_before < self.blank_lines:
1639 self.blank_before = self.blank_lines
1640 if self.verbose >= 2:
1641 print(self.logical_line[:80].rstrip())
1642 for name, check, argument_names in self._logical_checks:
1643 if self.verbose >= 4:
1644 print(' ' + name)
1645 self.init_checker_state(name, argument_names)
1646 for result in self.run_check(check, argument_names) or ():
1647 offset, text = result[:2]
1648 args = result[2:]
1649 if not isinstance(offset, tuple):
1650 for token_offset, pos in mapping:
1651 if offset <= token_offset:
1652 break
1653 offset = (pos[0], pos[1] + offset - token_offset)
1654 self.report_error_args(
1655 offset[0], offset[1], text, check, *args)
1656 if self.logical_line:
1657 self.previous_indent_level = self.indent_level
1658 self.previous_logical = self.logical_line
1659 if not self.indent_level:
1660 self.previous_unindented_logical_line = self.logical_line
1661 self.blank_lines = 0
1662 self.tokens = []
1663
1664 def check_ast(self):
1665 """Build the file's AST and run all AST checks."""
1666 try:
1667 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
1668 except (ValueError, SyntaxError, TypeError):
1669 return self.report_invalid_syntax()
1670 for name, cls, __ in self._ast_checks:
1671 # extended API for eric6 integration
1672 checker = cls(tree, self.filename, self.options)
1673 for args in checker.run():
1674 lineno = args[0]
1675 if not self.lines or not noqa(self.lines[lineno - 1]):
1676 self.report_error_args(lineno, *args[1:])
1677
1678 def generate_tokens(self):
1679 """Tokenize the file, run physical line checks and yield tokens."""
1680 if self._io_error:
1681 self.report_error_args(1, 0, 'E902', self._io_error, readlines)
1682 tokengen = tokenize.generate_tokens(self.readline)
1683 try:
1684 for token in tokengen:
1685 if token[2][0] > self.total_lines:
1686 return
1687 self.noqa = token[4] and noqa(token[4])
1688 self.maybe_check_physical(token)
1689 yield token
1690 except (SyntaxError, tokenize.TokenError):
1691 self.report_invalid_syntax()
1692
1693 def maybe_check_physical(self, token):
1694 """If appropriate (based on token), check current physical line(s)."""
1695 # Called after every token, but act only on end of line.
1696 if _is_eol_token(token):
1697 # Obviously, a newline token ends a single physical line.
1698 self.check_physical(token[4])
1699 elif token[0] == tokenize.STRING and '\n' in token[1]:
1700 # Less obviously, a string that contains newlines is a
1701 # multiline string, either triple-quoted or with internal
1702 # newlines backslash-escaped. Check every physical line in the
1703 # string *except* for the last one: its newline is outside of
1704 # the multiline string, so we consider it a regular physical
1705 # line, and will check it like any other physical line.
1706 #
1707 # Subtleties:
1708 # - we don't *completely* ignore the last line; if it contains
1709 # the magical "# noqa" comment, we disable all physical
1710 # checks for the entire multiline string
1711 # - have to wind self.line_number back because initially it
1712 # points to the last line of the string, and we want
1713 # check_physical() to give accurate feedback
1714 if noqa(token[4]):
1715 return
1716 self.multiline = True
1717 self.line_number = token[2][0]
1718 for line in token[1].split('\n')[:-1]:
1719 self.check_physical(line + '\n')
1720 self.line_number += 1
1721 self.multiline = False
1722
1723 def check_all(self, expected=None, line_offset=0):
1724 """Run all checks on the input file."""
1725 self.report.init_file(self.filename, self.lines, expected, line_offset)
1726 self.total_lines = len(self.lines)
1727 if self._ast_checks:
1728 self.check_ast()
1729 self.line_number = 0
1730 self.indent_char = None
1731 self.indent_level = self.previous_indent_level = 0
1732 self.previous_logical = ''
1733 self.previous_unindented_logical_line = ''
1734 self.tokens = []
1735 self.blank_lines = self.blank_before = 0
1736 parens = 0
1737 for token in self.generate_tokens():
1738 self.tokens.append(token)
1739 token_type, text = token[0:2]
1740 if self.verbose >= 3:
1741 if token[2][0] == token[3][0]:
1742 pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
1743 else:
1744 pos = 'l.%s' % token[3][0]
1745 print('l.%s\t%s\t%s\t%r' %
1746 (token[2][0], pos, tokenize.tok_name[token[0]], text))
1747 if token_type == tokenize.OP:
1748 if text in '([{':
1749 parens += 1
1750 elif text in '}])':
1751 parens -= 1
1752 elif not parens:
1753 if token_type in NEWLINE:
1754 if token_type == tokenize.NEWLINE:
1755 self.check_logical()
1756 self.blank_before = 0
1757 elif len(self.tokens) == 1:
1758 # The physical line contains only this token.
1759 self.blank_lines += 1
1760 del self.tokens[0]
1761 else:
1762 self.check_logical()
1763 elif COMMENT_WITH_NL and token_type == tokenize.COMMENT:
1764 if len(self.tokens) == 1:
1765 # The comment also ends a physical line
1766 token = list(token)
1767 token[1] = text.rstrip('\r\n')
1768 token[3] = (token[2][0], token[2][1] + len(token[1]))
1769 self.tokens = [tuple(token)]
1770 self.check_logical()
1771 if self.tokens:
1772 self.check_physical(self.lines[-1])
1773 self.check_logical()
1774 return self.report.get_file_results()
1775
1776
1777 class BaseReport(object):
1778 """Collect the results of the checks."""
1779
1780 print_filename = False
1781
1782 def __init__(self, options):
1783 self._benchmark_keys = options.benchmark_keys
1784 self._ignore_code = options.ignore_code
1785 # Results
1786 self.elapsed = 0
1787 self.total_errors = 0
1788 self.counters = dict.fromkeys(self._benchmark_keys, 0)
1789 self.messages = {}
1790
1791 def start(self):
1792 """Start the timer."""
1793 self._start_time = time.time()
1794
1795 def stop(self):
1796 """Stop the timer."""
1797 self.elapsed = time.time() - self._start_time
1798
1799 def init_file(self, filename, lines, expected, line_offset):
1800 """Signal a new file."""
1801 self.filename = filename
1802 self.lines = lines
1803 self.expected = expected or ()
1804 self.line_offset = line_offset
1805 self.file_errors = 0
1806 self.counters['files'] += 1
1807 self.counters['physical lines'] += len(lines)
1808
1809 def increment_logical_line(self):
1810 """Signal a new logical line."""
1811 self.counters['logical lines'] += 1
1812
1813 def error(self, line_number, offset, text, check):
1814 """Report an error, according to options."""
1815 code = text[:4]
1816 if self._ignore_code(code):
1817 return
1818 if code in self.counters:
1819 self.counters[code] += 1
1820 else:
1821 self.counters[code] = 1
1822 self.messages[code] = []
1823 # Don't care about expected errors or warnings
1824 if code in self.expected:
1825 return
1826 if self.print_filename and not self.file_errors:
1827 print(self.filename)
1828 self.file_errors += 1
1829 self.total_errors += 1
1830 return code
1831
1832 def error_args(self, line_number, offset, text, check, *args):
1833 """Report an error, according to options."""
1834 code = text[:4]
1835 if self._ignore_code(code):
1836 return
1837 if code in self.counters:
1838 self.counters[code] += 1
1839 else:
1840 self.counters[code] = 1
1841 self.messages[code] = args
1842 # Don't care about expected errors or warnings
1843 if code in self.expected:
1844 return
1845 if self.print_filename and not self.file_errors:
1846 print(self.filename)
1847 self.file_errors += 1
1848 self.total_errors += 1
1849 return code
1850
1851 def get_file_results(self):
1852 """Return the count of errors and warnings for this file."""
1853 return self.file_errors
1854
1855 def get_count(self, prefix=''):
1856 """Return the total count of errors and warnings."""
1857 return sum([self.counters[key]
1858 for key in self.messages if key.startswith(prefix)])
1859
1860 def get_statistics(self, prefix=''):
1861 """Get statistics for message codes that start with the prefix.
1862
1863 prefix='' matches all errors and warnings
1864 prefix='E' matches all errors
1865 prefix='W' matches all warnings
1866 prefix='E4' matches all errors that have to do with imports
1867 """
1868 return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
1869 for key in sorted(self.messages) if key.startswith(prefix)]
1870
1871 def print_statistics(self, prefix=''):
1872 """Print overall statistics (number of errors and warnings)."""
1873 for line in self.get_statistics(prefix):
1874 print(line)
1875
1876 def print_benchmark(self):
1877 """Print benchmark numbers."""
1878 print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
1879 if self.elapsed:
1880 for key in self._benchmark_keys:
1881 print('%-7d %s per second (%d total)' %
1882 (self.counters[key] / self.elapsed, key,
1883 self.counters[key]))
1884
1885
1886 class FileReport(BaseReport):
1887 """Collect the results of the checks and print only the filenames."""
1888 print_filename = True
1889
1890
1891 class StandardReport(BaseReport):
1892 """Collect and print the results of the checks."""
1893
1894 def __init__(self, options):
1895 super(StandardReport, self).__init__(options)
1896 self._fmt = REPORT_FORMAT.get(options.format.lower(),
1897 options.format)
1898 self._repeat = options.repeat
1899 self._show_source = options.show_source
1900 self._show_pep8 = options.show_pep8
1901
1902 def init_file(self, filename, lines, expected, line_offset):
1903 """Signal a new file."""
1904 self._deferred_print = []
1905 return super(StandardReport, self).init_file(
1906 filename, lines, expected, line_offset)
1907
1908 def error(self, line_number, offset, text, check):
1909 """Report an error, according to options."""
1910 code = super(StandardReport, self).error(line_number, offset,
1911 text, check)
1912 if code and (self.counters[code] == 1 or self._repeat):
1913 self._deferred_print.append(
1914 (line_number, offset, code, text[5:], check.__doc__))
1915 return code
1916
1917 def error_args(self, line_number, offset, code, check, *args):
1918 """Report an error, according to options."""
1919 code = super(StandardReport, self).error_args(line_number, offset,
1920 code, check, *args)
1921 if code and (self.counters[code] == 1 or self._repeat):
1922 self._deferred_print.append(
1923 (line_number, offset, code, args, check.__doc__))
1924 return code
1925
1926 def get_file_results(self):
1927 """Print the result and return the overall count for this file."""
1928 self._deferred_print.sort()
1929 for line_number, offset, code, text, doc in self._deferred_print:
1930 print(self._fmt % {
1931 'path': self.filename,
1932 'row': self.line_offset + line_number, 'col': offset + 1,
1933 'code': code, 'text': text,
1934 })
1935 if self._show_source:
1936 if line_number > len(self.lines):
1937 line = ''
1938 else:
1939 line = self.lines[line_number - 1]
1940 print(line.rstrip())
1941 print(re.sub(r'\S', ' ', line[:offset]) + '^')
1942 if self._show_pep8 and doc:
1943 print(' ' + doc.strip())
1944
1945 # stdout is block buffered when not stdout.isatty().
1946 # line can be broken where buffer boundary since other processes
1947 # write to same file.
1948 # flush() after print() to avoid buffer boundary.
1949 # Typical buffer size is 8192. line written safely when
1950 # len(line) < 8192.
1951 sys.stdout.flush()
1952 return self.file_errors
1953
1954
1955 class DiffReport(StandardReport):
1956 """Collect and print the results for the changed lines only."""
1957
1958 def __init__(self, options):
1959 super(DiffReport, self).__init__(options)
1960 self._selected = options.selected_lines
1961
1962 def error(self, line_number, offset, text, check):
1963 if line_number not in self._selected[self.filename]:
1964 return
1965 return super(DiffReport, self).error(line_number, offset, text, check)
1966
1967
1968 class StyleGuide(object):
1969 """Initialize a PEP-8 instance with few options."""
1970
1971 def __init__(self, *args, **kwargs):
1972 # build options from the command line
1973 self.checker_class = kwargs.pop('checker_class', Checker)
1974 parse_argv = kwargs.pop('parse_argv', False)
1975 config_file = kwargs.pop('config_file', False)
1976 parser = kwargs.pop('parser', None)
1977 # build options from dict
1978 options_dict = dict(*args, **kwargs)
1979 arglist = None if parse_argv else options_dict.get('paths', None)
1980 options, self.paths = process_options(
1981 arglist, parse_argv, config_file, parser)
1982 if options_dict:
1983 options.__dict__.update(options_dict)
1984 if 'paths' in options_dict:
1985 self.paths = options_dict['paths']
1986
1987 self.runner = self.input_file
1988 self.options = options
1989
1990 if not options.reporter:
1991 options.reporter = BaseReport if options.quiet else StandardReport
1992
1993 options.select = tuple(options.select or ())
1994 # if not (options.select or options.ignore or
1995 # options.testsuite or options.doctest) and DEFAULT_IGNORE:
1996 # # The default choice: ignore controversial checks
1997 # options.ignore = tuple(DEFAULT_IGNORE.split(','))
1998 # else:
1999 # # Ignore all checks which are not explicitly selected or all if no
2000 # options.ignore = ('',) if options.select else tuple(options.ignore)
2001
2002 # check is ignored or explicitly selected
2003 options.ignore = ('',) if options.select else tuple(options.ignore)
2004 options.benchmark_keys = BENCHMARK_KEYS[:]
2005 options.ignore_code = self.ignore_code
2006 options.physical_checks = self.get_checks('physical_line')
2007 options.logical_checks = self.get_checks('logical_line')
2008 options.ast_checks = self.get_checks('tree')
2009 self.init_report()
2010
2011 def init_report(self, reporter=None):
2012 """Initialize the report instance."""
2013 self.options.report = (reporter or self.options.reporter)(self.options)
2014 return self.options.report
2015
2016 def check_files(self, paths=None):
2017 """Run all checks on the paths."""
2018 if paths is None:
2019 paths = self.paths
2020 report = self.options.report
2021 runner = self.runner
2022 report.start()
2023 try:
2024 for path in paths:
2025 if os.path.isdir(path):
2026 self.input_dir(path)
2027 elif not self.excluded(path):
2028 runner(path)
2029 except KeyboardInterrupt:
2030 print('... stopped')
2031 report.stop()
2032 return report
2033
2034 def input_file(self, filename, lines=None, expected=None, line_offset=0):
2035 """Run all checks on a Python source file."""
2036 if self.options.verbose:
2037 print('checking %s' % filename)
2038 fchecker = self.checker_class(
2039 filename, lines=lines, options=self.options)
2040 return fchecker.check_all(expected=expected, line_offset=line_offset)
2041
2042 def input_dir(self, dirname):
2043 """Check all files in this directory and all subdirectories."""
2044 dirname = dirname.rstrip('/')
2045 if self.excluded(dirname):
2046 return 0
2047 counters = self.options.report.counters
2048 verbose = self.options.verbose
2049 filepatterns = self.options.filename
2050 runner = self.runner
2051 for root, dirs, files in os.walk(dirname):
2052 if verbose:
2053 print('directory ' + root)
2054 counters['directories'] += 1
2055 for subdir in sorted(dirs):
2056 if self.excluded(subdir, root):
2057 dirs.remove(subdir)
2058 for filename in sorted(files):
2059 # contain a pattern that matches?
2060 if ((filename_match(filename, filepatterns) and
2061 not self.excluded(filename, root))):
2062 runner(os.path.join(root, filename))
2063
2064 def excluded(self, filename, parent=None):
2065 """Check if the file should be excluded.
2066
2067 Check if 'options.exclude' contains a pattern that matches filename.
2068 """
2069 if not self.options.exclude:
2070 return False
2071 basename = os.path.basename(filename)
2072 if filename_match(basename, self.options.exclude):
2073 return True
2074 if parent:
2075 filename = os.path.join(parent, filename)
2076 filename = os.path.abspath(filename)
2077 return filename_match(filename, self.options.exclude)
2078
2079 def ignore_code(self, code):
2080 """Check if the error code should be ignored.
2081
2082 If 'options.select' contains a prefix of the error code,
2083 return False. Else, if 'options.ignore' contains a prefix of
2084 the error code, return True.
2085 """
2086 if len(code) < 4 and any(s.startswith(code)
2087 for s in self.options.select):
2088 return False
2089 return (code.startswith(self.options.ignore) and
2090 not code.startswith(self.options.select))
2091
2092 def get_checks(self, argument_name):
2093 """Get all the checks for this category.
2094
2095 Find all globally visible functions where the first argument name
2096 starts with argument_name and which contain selected tests.
2097 """
2098 checks = []
2099 for check, attrs in _checks[argument_name].items():
2100 (codes, args) = attrs
2101 if any(not (code and self.ignore_code(code)) for code in codes):
2102 checks.append((check.__name__, check, args))
2103 return sorted(checks)
2104
2105
2106 def get_parser(prog='pycodestyle', version=__version__):
2107 """Create the parser for the program."""
2108 parser = OptionParser(prog=prog, version=version,
2109 usage="%prog [options] input ...")
2110 parser.config_options = [
2111 'exclude', 'filename', 'select', 'ignore', 'max-line-length',
2112 'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
2113 'show-source', 'statistics', 'verbose']
2114 parser.add_option('-v', '--verbose', default=0, action='count',
2115 help="print status messages, or debug with -vv")
2116 parser.add_option('-q', '--quiet', default=0, action='count',
2117 help="report only file names, or nothing with -qq")
2118 parser.add_option('-r', '--repeat', default=True, action='store_true',
2119 help="(obsolete) show all occurrences of the same error")
2120 parser.add_option('--first', action='store_false', dest='repeat',
2121 help="show first occurrence of each error")
2122 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
2123 help="exclude files or directories which match these "
2124 "comma separated patterns (default: %default)")
2125 parser.add_option('--filename', metavar='patterns', default='*.py',
2126 help="when parsing directories, only check filenames "
2127 "matching these comma separated patterns "
2128 "(default: %default)")
2129 parser.add_option('--select', metavar='errors', default='',
2130 help="select errors and warnings (e.g. E,W6)")
2131 parser.add_option('--ignore', metavar='errors', default='',
2132 help="skip errors and warnings (e.g. E4,W) "
2133 "(default: %s)" % DEFAULT_IGNORE)
2134 parser.add_option('--show-source', action='store_true',
2135 help="show source code for each error")
2136 parser.add_option('--show-pep8', action='store_true',
2137 help="show text of PEP 8 for each error "
2138 "(implies --first)")
2139 parser.add_option('--statistics', action='store_true',
2140 help="count errors and warnings")
2141 parser.add_option('--count', action='store_true',
2142 help="print total number of errors and warnings "
2143 "to standard error and set exit code to 1 if "
2144 "total is not null")
2145 parser.add_option('--max-line-length', type='int', metavar='n',
2146 default=MAX_LINE_LENGTH,
2147 help="set maximum allowed line length "
2148 "(default: %default)")
2149 parser.add_option('--hang-closing', action='store_true',
2150 help="hang closing bracket instead of matching "
2151 "indentation of opening bracket's line")
2152 parser.add_option('--format', metavar='format', default='default',
2153 help="set the error format [default|pylint|<custom>]")
2154 parser.add_option('--diff', action='store_true',
2155 help="report changes only within line number ranges in "
2156 "the unified diff received on STDIN")
2157 group = parser.add_option_group("Testing Options")
2158 if os.path.exists(TESTSUITE_PATH):
2159 group.add_option('--testsuite', metavar='dir',
2160 help="run regression tests from dir")
2161 group.add_option('--doctest', action='store_true',
2162 help="run doctest on myself")
2163 group.add_option('--benchmark', action='store_true',
2164 help="measure processing speed")
2165 return parser
2166
2167
2168 def read_config(options, args, arglist, parser):
2169 """Read and parse configurations
2170
2171 If a config file is specified on the command line with the "--config"
2172 option, then only it is used for configuration.
2173
2174 Otherwise, the user configuration (~/.config/pycodestyle) and any local
2175 configurations in the current directory or above will be merged together
2176 (in that order) using the read method of ConfigParser.
2177 """
2178 config = RawConfigParser()
2179
2180 cli_conf = options.config
2181
2182 local_dir = os.curdir
2183
2184 if USER_CONFIG and os.path.isfile(USER_CONFIG):
2185 if options.verbose:
2186 print('user configuration: %s' % USER_CONFIG)
2187 config.read(USER_CONFIG)
2188
2189 parent = tail = args and os.path.abspath(os.path.commonprefix(args))
2190 while tail:
2191 if config.read(os.path.join(parent, fn) for fn in PROJECT_CONFIG):
2192 local_dir = parent
2193 if options.verbose:
2194 print('local configuration: in %s' % parent)
2195 break
2196 (parent, tail) = os.path.split(parent)
2197
2198 if cli_conf and os.path.isfile(cli_conf):
2199 if options.verbose:
2200 print('cli configuration: %s' % cli_conf)
2201 config.read(cli_conf)
2202
2203 pep8_section = parser.prog
2204 if config.has_section(pep8_section):
2205 option_list = dict([(o.dest, o.type or o.action)
2206 for o in parser.option_list])
2207
2208 # First, read the default values
2209 (new_options, __) = parser.parse_args([])
2210
2211 # Second, parse the configuration
2212 for opt in config.options(pep8_section):
2213 if opt.replace('_', '-') not in parser.config_options:
2214 print(" unknown option '%s' ignored" % opt)
2215 continue
2216 if options.verbose > 1:
2217 print(" %s = %s" % (opt, config.get(pep8_section, opt)))
2218 normalized_opt = opt.replace('-', '_')
2219 opt_type = option_list[normalized_opt]
2220 if opt_type in ('int', 'count'):
2221 value = config.getint(pep8_section, opt)
2222 elif opt_type in ('store_true', 'store_false'):
2223 value = config.getboolean(pep8_section, opt)
2224 else:
2225 value = config.get(pep8_section, opt)
2226 if normalized_opt == 'exclude':
2227 value = normalize_paths(value, local_dir)
2228 setattr(new_options, normalized_opt, value)
2229
2230 # Third, overwrite with the command-line options
2231 (options, __) = parser.parse_args(arglist, values=new_options)
2232 options.doctest = options.testsuite = False
2233 return options
2234
2235
2236 def process_options(arglist=None, parse_argv=False, config_file=None,
2237 parser=None):
2238 """Process options passed either via arglist or via command line args.
2239
2240 Passing in the ``config_file`` parameter allows other tools, such as flake8
2241 to specify their own options to be processed in pycodestyle.
2242 """
2243 if not parser:
2244 parser = get_parser()
2245 if not parser.has_option('--config'):
2246 group = parser.add_option_group("Configuration", description=(
2247 "The project options are read from the [%s] section of the "
2248 "tox.ini file or the setup.cfg file located in any parent folder "
2249 "of the path(s) being processed. Allowed options are: %s." %
2250 (parser.prog, ', '.join(parser.config_options))))
2251 group.add_option('--config', metavar='path', default=config_file,
2252 help="user config file location")
2253 # Don't read the command line if the module is used as a library.
2254 if not arglist and not parse_argv:
2255 arglist = []
2256 # If parse_argv is True and arglist is None, arguments are
2257 # parsed from the command line (sys.argv)
2258 (options, args) = parser.parse_args(arglist)
2259 options.reporter = None
2260
2261 if options.ensure_value('testsuite', False):
2262 args.append(options.testsuite)
2263 elif not options.ensure_value('doctest', False):
2264 if parse_argv and not args:
2265 if options.diff or any(os.path.exists(name)
2266 for name in PROJECT_CONFIG):
2267 args = ['.']
2268 else:
2269 parser.error('input not specified')
2270 options = read_config(options, args, arglist, parser)
2271 options.reporter = parse_argv and options.quiet == 1 and FileReport
2272
2273 options.filename = _parse_multi_options(options.filename)
2274 options.exclude = normalize_paths(options.exclude)
2275 options.select = _parse_multi_options(options.select)
2276 options.ignore = _parse_multi_options(options.ignore)
2277
2278 if options.diff:
2279 options.reporter = DiffReport
2280 stdin = stdin_get_value()
2281 options.selected_lines = parse_udiff(stdin, options.filename, args[0])
2282 args = sorted(options.selected_lines)
2283
2284 return options, args
2285
2286
2287 def _parse_multi_options(options, split_token=','):
2288 r"""Split and strip and discard empties.
2289
2290 Turns the following:
2291
2292 A,
2293 B,
2294
2295 into ["A", "B"]
2296 """
2297 if options:
2298 return [o.strip() for o in options.split(split_token) if o.strip()]
2299 else:
2300 return options
2301
2302
2303 def _main():
2304 """Parse options and run checks on Python source."""
2305 import signal
2306
2307 # Handle "Broken pipe" gracefully
2308 try:
2309 signal.signal(signal.SIGPIPE, lambda signum, frame: sys.exit(1))
2310 except AttributeError:
2311 pass # not supported on Windows
2312
2313 style_guide = StyleGuide(parse_argv=True)
2314 options = style_guide.options
2315
2316 if options.doctest or options.testsuite:
2317 from testsuite.support import run_tests
2318 report = run_tests(style_guide)
2319 else:
2320 report = style_guide.check_files()
2321
2322 if options.statistics:
2323 report.print_statistics()
2324
2325 if options.benchmark:
2326 report.print_benchmark()
2327
2328 if options.testsuite and not options.quiet:
2329 report.print_results()
2330
2331 if report.total_errors:
2332 if options.count:
2333 sys.stderr.write(str(report.total_errors) + '\n')
2334 sys.exit(1)
2335
2336 if __name__ == '__main__':
2337 _main()
2338 #
2339 # eflag: noqa = M702

eric ide

mercurial