2 # pep8.py - Check Python source code formatting, according to PEP 8
3 # Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
4 # Copyright (C) 2009-2013 Florent Xicluna <florent.xicluna@gmail.com>
6 # Permission is hereby granted, free of charge, to any person
7 # obtaining a copy of this software and associated documentation files
8 # (the "Software"), to deal in the Software without restriction,
9 # including without limitation the rights to use, copy, modify, merge,
10 # publish, distribute, sublicense, and/or sell copies of the Software,
11 # and to permit persons to whom the Software is furnished to do so,
12 # subject to the following conditions:
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 Check Python source code formatting, according to PEP 8:
28 http://www.python.org/dev/peps/pep-0008/
30 For usage and a list of options, try this:
33 This program and its regression test suite live here:
34 http://github.com/jcrocholl/pep8
36 Groups of errors and warnings:
48 __version__ = '1.5.0a0'
57 from optparse import OptionParser
58 from fnmatch import fnmatch
60 from configparser import RawConfigParser
61 from io import TextIOWrapper
63 from ConfigParser import RawConfigParser
65 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'
66 DEFAULT_IGNORE = 'E123,E226,E24'
67 if sys.platform == 'win32':
68 DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
70 DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or
71 os.path.expanduser('~/.config'), 'pep8')
72 PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')
73 TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
76 'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
77 'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
81 SINGLETONS = frozenset(['False', 'None', 'True'])
82 KEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS
83 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
84 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])
85 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
86 WS_NEEDED_OPERATORS = frozenset([
87 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
88 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='])
89 WHITESPACE = frozenset(' \t')
90 SKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE,
91 tokenize.INDENT, tokenize.DEDENT])
92 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
94 INDENT_REGEX = re.compile(r'([ \t]*)')
95 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
96 RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$')
97 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
98 DOCSTRING_REGEX = re.compile(r'u?r?["\']')
99 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
100 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
101 COMPARE_SINGLETON_REGEX = re.compile(r'([=!]=)\s*(None|False|True)')
102 COMPARE_NEGATIVE_REGEX = re.compile(r'\b(not)\s+[^[({ ]+\s+(in|is)\s')
103 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
104 r'|\s*\(\s*([^)]*[^ )])\s*\))')
105 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
106 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
107 LAMBDA_REGEX = re.compile(r'\blambda\b')
108 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
110 # Work around Python < 2.6 behaviour, which does not generate NL after
111 # a comment which is on a line by itself.
112 COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
115 ##############################################################################
116 # Plugins (check functions) for physical lines
117 ##############################################################################
120 def tabs_or_spaces(physical_line, indent_char):
122 Never mix tabs and spaces.
124 The most popular way of indenting Python is with spaces only. The
125 second-most popular way is with tabs only. Code indented with a mixture
126 of tabs and spaces should be converted to using spaces exclusively. When
127 invoking the Python command line interpreter with the -t option, it issues
128 warnings about code that illegally mixes tabs and spaces. When using -tt
129 these warnings become errors. These options are highly recommended!
131 Okay: if a == 0:\n a = 1\n b = 1
132 E101: if a == 0:\n a = 1\n\tb = 1
134 indent = INDENT_REGEX.match(physical_line).group(1)
135 for offset, char in enumerate(indent):
136 if char != indent_char:
137 return offset, "E101 indentation contains mixed spaces and tabs"
140 def tabs_obsolete(physical_line):
142 For new projects, spaces-only are strongly recommended over tabs. Most
143 editors have features that make this easy to do.
145 Okay: if True:\n return
146 W191: if True:\n\treturn
148 indent = INDENT_REGEX.match(physical_line).group(1)
150 return indent.index('\t'), "W191 indentation contains tabs"
153 def trailing_whitespace(physical_line):
155 JCR: Trailing whitespace is superfluous.
156 FBM: Except when it occurs as part of a blank line (i.e. the line is
157 nothing but whitespace). According to Python docs[1] a line with only
158 whitespace is considered a blank line, and is to be ignored. However,
159 matching a blank line to its indentation level avoids mistakenly
160 terminating a multi-line statement (e.g. class declaration) when
161 pasting code into the standard Python interpreter.
163 [1] http://docs.python.org/reference/lexical_analysis.html#blank-lines
165 The warning returned varies on whether the line itself is blank, for easier
166 filtering for those who want to indent their blank lines.
170 W293: class Foo(object):\n \n bang = 12
172 physical_line = physical_line.rstrip('\n') # chr(10), newline
173 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
174 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
175 stripped = physical_line.rstrip(' \t\v')
176 if physical_line != stripped:
178 return len(stripped), "W291 trailing whitespace"
180 return 0, "W293 blank line contains whitespace"
183 def trailing_blank_lines(physical_line, lines, line_number):
185 JCR: Trailing blank lines are superfluous.
190 if not physical_line.rstrip() and line_number == len(lines):
191 return 0, "W391 blank line at end of file"
194 def missing_newline(physical_line):
196 JCR: The last line should have a newline.
198 Reports warning W292.
200 if physical_line.rstrip() == physical_line:
201 return len(physical_line), "W292 no newline at end of file"
204 def maximum_line_length(physical_line, max_line_length, multiline):
206 Limit all lines to a maximum of 79 characters.
208 There are still many devices around that are limited to 80 character
209 lines; plus, limiting windows to 80 characters makes it possible to have
210 several windows side-by-side. The default wrapping on such devices looks
211 ugly. Therefore, please limit all lines to a maximum of 79 characters.
212 For flowing long blocks of text (docstrings or comments), limiting the
213 length to 72 characters is recommended.
217 line = physical_line.rstrip()
219 if length > max_line_length and not noqa(line):
220 # Special case for long URLs in multi-line docstrings or comments,
221 # but still report the error when the 72 first chars are whitespaces.
222 chunks = line.split()
223 if ((len(chunks) == 1 and multiline) or
224 (len(chunks) == 2 and chunks[0] == '#')) and \
225 len(line) - len(chunks[-1]) < max_line_length - 7:
227 if hasattr(line, 'decode'): # Python 2
228 # The line could contain multi-byte characters
230 length = len(line.decode('utf-8'))
233 if length > max_line_length:
234 return (max_line_length, "E501 line too long "
235 "(%d > %d characters)" % (length, max_line_length))
238 ##############################################################################
239 # Plugins (check functions) for logical lines
240 ##############################################################################
243 def blank_lines(logical_line, blank_lines, indent_level, line_number,
244 previous_logical, previous_indent_level):
246 Separate top-level function and class definitions with two blank lines.
248 Method definitions inside a class are separated by a single blank line.
250 Extra blank lines may be used (sparingly) to separate groups of related
251 functions. Blank lines may be omitted between a bunch of related
252 one-liners (e.g. a set of dummy implementations).
254 Use blank lines in functions, sparingly, to indicate logical sections.
256 Okay: def a():\n pass\n\n\ndef b():\n pass
257 Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
259 E301: class Foo:\n b = 0\n def bar():\n pass
260 E302: def a():\n pass\n\ndef b(n):\n pass
261 E303: def a():\n pass\n\n\n\ndef b(n):\n pass
262 E303: def a():\n\n\n\n pass
263 E304: @decorator\n\ndef a():\n pass
265 if line_number < 3 and not previous_logical:
266 return # Don't expect blank lines before the first line
267 if previous_logical.startswith('@'):
269 yield 0, "E304 blank lines found after function decorator"
270 elif blank_lines > 2 or (indent_level and blank_lines == 2):
271 yield 0, "E303 too many blank lines (%d)" % blank_lines
272 elif logical_line.startswith(('def ', 'class ', '@')):
274 if not (blank_lines or previous_indent_level < indent_level or
275 DOCSTRING_REGEX.match(previous_logical)):
276 yield 0, "E301 expected 1 blank line, found 0"
277 elif blank_lines != 2:
278 yield 0, "E302 expected 2 blank lines, found %d" % blank_lines
281 def extraneous_whitespace(logical_line):
283 Avoid extraneous whitespace in the following situations:
285 - Immediately inside parentheses, brackets or braces.
287 - Immediately before a comma, semicolon, or colon.
289 Okay: spam(ham[1], {eggs: 2})
290 E201: spam( ham[1], {eggs: 2})
291 E201: spam(ham[ 1], {eggs: 2})
292 E201: spam(ham[1], { eggs: 2})
293 E202: spam(ham[1], {eggs: 2} )
294 E202: spam(ham[1 ], {eggs: 2})
295 E202: spam(ham[1], {eggs: 2 })
297 E203: if x == 4: print x, y; x, y = y , x
298 E203: if x == 4: print x, y ; x, y = y, x
299 E203: if x == 4 : print x, y; x, y = y, x
302 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
305 found = match.start()
306 if text == char + ' ':
307 # assert char in '([{'
308 yield found + 1, "E201 whitespace after '%s'" % char
309 elif line[found - 1] != ',':
310 code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
311 yield found, "%s whitespace before '%s'" % (code, char)
314 def whitespace_around_keywords(logical_line):
316 Avoid extraneous whitespace around keywords.
321 E273: True and\tFalse
322 E274: True\tand False
324 for match in KEYWORD_REGEX.finditer(logical_line):
325 before, after = match.groups()
328 yield match.start(1), "E274 tab before keyword"
329 elif len(before) > 1:
330 yield match.start(1), "E272 multiple spaces before keyword"
333 yield match.start(2), "E273 tab after keyword"
335 yield match.start(2), "E271 multiple spaces after keyword"
338 def missing_whitespace(logical_line):
340 JCR: Each comma, semicolon or colon should be followed by whitespace.
353 for index in range(len(line) - 1):
355 if char in ',;:' and line[index + 1] not in WHITESPACE:
356 before = line[:index]
357 if char == ':' and before.count('[') > before.count(']') and \
358 before.rfind('{') < before.rfind('['):
359 continue # Slice syntax, no space required
360 if char == ',' and line[index + 1] == ')':
361 continue # Allow tuple with only one element: (3,)
362 yield index, "E231 missing whitespace after '%s'" % char
365 def indentation(logical_line, previous_logical, indent_char,
366 indent_level, previous_indent_level):
368 Use 4 spaces per indentation level.
370 For really old code that you don't want to mess up, you can continue to
374 Okay: if a == 0:\n a = 1
377 Okay: for item in items:\n pass
378 E112: for item in items:\npass
383 if indent_char == ' ' and indent_level % 4:
384 yield 0, "E111 indentation is not a multiple of four"
385 indent_expect = previous_logical.endswith(':')
386 if indent_expect and indent_level <= previous_indent_level:
387 yield 0, "E112 expected an indented block"
388 if indent_level > previous_indent_level and not indent_expect:
389 yield 0, "E113 unexpected indentation"
392 def continued_indentation(logical_line, tokens, indent_level, hang_closing,
393 indent_char, noqa, verbose):
395 Continuation lines should align wrapped elements either vertically using
396 Python's implicit line joining inside parentheses, brackets and braces, or
397 using a hanging indent.
399 When using a hanging indent the following considerations should be applied:
401 - there should be no arguments on the first line, and
403 - further indentation should be used to clearly distinguish itself as a
413 E124: a = (24,\n 42\n)
414 E125: if (\n b):\n pass
418 E129: if (a or\n b):\n pass
419 E131: a = (\n 42\n 24)
421 first_row = tokens[0][2][0]
422 nrows = 1 + tokens[-1][2][0] - first_row
423 if noqa or nrows == 1:
426 # indent_next tells us whether the next block is indented; assuming
427 # that it is indented by 4 spaces, then we should not allow 4-space
428 # indents on the final continuation line; in turn, some other
429 # indents are allowed to have an extra 4 spaces.
430 indent_next = logical_line.endswith(':')
433 valid_hangs = (4,) if indent_char != '\t' else (4, 8)
434 # remember how many brackets were opened on each line
436 # relative indents of physical lines
437 rel_indent = [0] * nrows
438 # for each depth, collect a list of opening rows
440 # for each depth, memorize the hanging indentation
444 last_indent = tokens[0][2]
445 # for each depth, memorize the visual indent column
446 indent = [last_indent[1]]
448 print(">>> " + tokens[0][4].rstrip())
450 for token_type, text, start, end, line in tokens:
452 newline = row < start[0] - first_row
454 row = start[0] - first_row
455 newline = (not last_token_multiline and
456 token_type not in (tokenize.NL, tokenize.NEWLINE))
459 # this is the beginning of a continuation line.
462 print("... " + line.rstrip())
464 # record the initial indent.
465 rel_indent[row] = expand_indent(line) - indent_level
467 # identify closing bracket
468 close_bracket = (token_type == tokenize.OP and text in ']})')
470 # is the indent relative to an opening bracket line?
471 for open_row in reversed(open_rows[depth]):
472 hang = rel_indent[row] - rel_indent[open_row]
473 hanging_indent = hang in valid_hangs
477 hanging_indent = (hang == hangs[depth])
478 # is there any chance of visual indent?
479 visual_indent = (not close_bracket and hang > 0 and
480 indent_chances.get(start[1]))
482 if close_bracket and indent[depth]:
483 # closing bracket for visual indent
484 if start[1] != indent[depth]:
485 yield (start, "E124 closing bracket does not match "
486 "visual indentation")
487 elif close_bracket and not hang:
488 # closing bracket matches indentation of opening bracket's line
490 yield start, "E133 closing bracket is missing indentation"
491 elif indent[depth] and start[1] < indent[depth]:
492 if visual_indent is not True:
493 # visual indent is broken
494 yield (start, "E128 continuation line "
495 "under-indented for visual indent")
496 elif hanging_indent or (indent_next and rel_indent[row] == 8):
497 # hanging indent is verified
498 if close_bracket and not hang_closing:
499 yield (start, "E123 closing bracket does not match "
500 "indentation of opening bracket's line")
502 elif visual_indent is True:
503 # visual indent is verified
504 indent[depth] = start[1]
505 elif visual_indent in (text, str):
506 # ignore token lined up with matching one from a previous line
511 error = "E122", "missing indentation or outdented"
513 error = "E127", "over-indented for visual indent"
514 elif not close_bracket and hangs[depth]:
515 error = "E131", "unaligned for hanging indent"
519 error = "E126", "over-indented for hanging indent"
521 error = "E121", "under-indented for hanging indent"
522 yield start, "%s continuation line %s" % error
524 # look for visual indenting
525 if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)
526 and not indent[depth]):
527 indent[depth] = start[1]
528 indent_chances[start[1]] = True
530 print("bracket depth %s indent to %s" % (depth, start[1]))
531 # deal with implicit string concatenation
532 elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
533 text in ('u', 'ur', 'b', 'br')):
534 indent_chances[start[1]] = str
535 # special case for the "if" statement because len("if (") == 4
536 elif not indent_chances and not row and not depth and text == 'if':
537 indent_chances[end[1] + 1] = True
538 elif text == ':' and line[end[1]:].isspace():
539 open_rows[depth].append(row)
541 # keep track of bracket depth
542 if token_type == tokenize.OP:
547 if len(open_rows) == depth:
549 open_rows[depth].append(row)
552 print("bracket depth %s seen, col %s, visual min = %s" %
553 (depth, start[1], indent[depth]))
554 elif text in ')]}' and depth > 0:
555 # parent indents should not be more than this one
556 prev_indent = indent.pop() or last_indent[1]
558 for d in range(depth):
559 if indent[d] > prev_indent:
561 for ind in list(indent_chances):
562 if ind >= prev_indent:
563 del indent_chances[ind]
564 del open_rows[depth + 1:]
567 indent_chances[indent[depth]] = True
568 for idx in range(row, -1, -1):
572 assert len(indent) == depth + 1
573 if start[1] not in indent_chances:
574 # allow to line up tokens
575 indent_chances[start[1]] = text
577 last_token_multiline = (start[0] != end[0])
579 if indent_next and expand_indent(line) == indent_level + 4:
581 code = "E129 visually indented line"
583 code = "E125 continuation line"
584 yield (last_indent, "%s with same indent as next logical line" % code)
587 def whitespace_before_parameters(logical_line, tokens):
589 Avoid extraneous whitespace in the following situations:
591 - Immediately before the open parenthesis that starts the argument
592 list of a function call.
594 - Immediately before the open parenthesis that starts an indexing or
600 Okay: dict['key'] = list[index]
601 E211: dict ['key'] = list[index]
602 E211: dict['key'] = list [index]
604 prev_type, prev_text, __, prev_end, __ = tokens[0]
605 for index in range(1, len(tokens)):
606 token_type, text, start, end, __ = tokens[index]
607 if (token_type == tokenize.OP and
609 start != prev_end and
610 (prev_type == tokenize.NAME or prev_text in '}])') and
611 # Syntax "class A (B):" is allowed, but avoid it
612 (index < 2 or tokens[index - 2][1] != 'class') and
613 # Allow "return (a.foo for a in range(5))"
614 not keyword.iskeyword(prev_text)):
615 yield prev_end, "E211 whitespace before '%s'" % text
616 prev_type = token_type
621 def whitespace_around_operator(logical_line):
623 Avoid extraneous whitespace in the following situations:
625 - More than one space around an assignment (or other) operator to
626 align it with another.
634 for match in OPERATOR_REGEX.finditer(logical_line):
635 before, after = match.groups()
638 yield match.start(1), "E223 tab before operator"
639 elif len(before) > 1:
640 yield match.start(1), "E221 multiple spaces before operator"
643 yield match.start(2), "E224 tab after operator"
645 yield match.start(2), "E222 multiple spaces after operator"
648 def missing_whitespace_around_operator(logical_line, tokens):
650 - Always surround these binary operators with a single space on
651 either side: assignment (=), augmented assignment (+=, -= etc.),
652 comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not),
653 Booleans (and, or, not).
655 - Use spaces around arithmetic operators.
660 Okay: hypot2 = x * x + y * y
661 Okay: c = (a + b) * (a - b)
662 Okay: foo(bar, key='word', *args, **kwargs)
669 E226: c = (a+b) * (a-b)
670 E226: hypot2 = x*x + y*y
672 E228: msg = fmt%(errno, errmsg)
676 prev_type = tokenize.OP
677 prev_text = prev_end = None
678 for token_type, text, start, end, line in tokens:
679 if token_type in (tokenize.NL, tokenize.NEWLINE, tokenize.ERRORTOKEN):
680 # ERRORTOKEN is triggered by backticks in Python 3
682 if text in ('(', 'lambda'):
687 if start != prev_end:
688 # Found a (probably) needed space
689 if need_space is not True and not need_space[1]:
690 yield (need_space[0],
691 "E225 missing whitespace around operator")
693 elif text == '>' and prev_text in ('<', '-'):
694 # Tolerate the "<>" operator, even if running Python 3
695 # Deal with Python 3's annotated return value "->"
698 if need_space is True or need_space[1]:
699 # A needed trailing space was not found
700 yield prev_end, "E225 missing whitespace around operator"
702 code, optype = 'E226', 'arithmetic'
704 code, optype = 'E228', 'modulo'
705 elif prev_text not in ARITHMETIC_OP:
706 code, optype = 'E227', 'bitwise or shift'
707 yield (need_space[0], "%s missing whitespace "
708 "around %s operator" % (code, optype))
710 elif token_type == tokenize.OP and prev_end is not None:
711 if text == '=' and parens:
712 # Allow keyword args or defaults: foo(bar=None).
714 elif text in WS_NEEDED_OPERATORS:
716 elif text in UNARY_OPERATORS:
717 # Check if the operator is being used as a binary operator
718 # Allow unary operators: -123, -x, +1.
719 # Allow argument unpacking: foo(*args, **kwargs).
720 if prev_type == tokenize.OP:
721 binary_usage = (prev_text in '}])')
722 elif prev_type == tokenize.NAME:
723 binary_usage = (prev_text not in KEYWORDS)
725 binary_usage = (prev_type not in SKIP_TOKENS)
729 elif text in WS_OPTIONAL_OPERATORS:
732 if need_space is None:
733 # Surrounding space is optional, but ensure that
734 # trailing space matches opening space
735 need_space = (prev_end, start != prev_end)
736 elif need_space and start == prev_end:
737 # A needed opening space was not found
738 yield prev_end, "E225 missing whitespace around operator"
740 prev_type = token_type
745 def whitespace_around_comma(logical_line):
747 Avoid extraneous whitespace in the following situations:
749 - More than one space around an assignment (or other) operator to
750 align it with another.
752 Note: these checks are disabled by default
759 for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
760 found = m.start() + 1
761 if '\t' in m.group():
762 yield found, "E242 tab after '%s'" % m.group()[0]
764 yield found, "E241 multiple spaces after '%s'" % m.group()[0]
767 def whitespace_around_named_parameter_equals(logical_line, tokens):
769 Don't use spaces around the '=' sign when used to indicate a
770 keyword argument or a default parameter value.
772 Okay: def complex(real, imag=0.0):
773 Okay: return magic(r=real, i=imag)
774 Okay: boolean(a == b)
775 Okay: boolean(a != b)
776 Okay: boolean(a <= b)
777 Okay: boolean(a >= b)
779 E251: def complex(real, imag = 0.0):
780 E251: return magic(r = real, i = imag)
785 message = "E251 unexpected spaces around keyword / parameter equals"
786 for token_type, text, start, end, line in tokens:
789 if start != prev_end:
790 yield (prev_end, message)
791 elif token_type == tokenize.OP:
796 elif parens and text == '=':
798 if start != prev_end:
799 yield (prev_end, message)
803 def whitespace_before_comment(logical_line, tokens):
805 Separate inline comments by at least two spaces.
807 An inline comment is a comment on the same line as a statement. Inline
808 comments should be separated by at least two spaces from the statement.
809 They should start with a # and a single space.
811 Each line of a block comment starts with a # and a single space
812 (unless it is indented text inside the comment).
814 Okay: x = x + 1 # Increment x
815 Okay: x = x + 1 # Increment x
816 Okay: # Block comment
817 E261: x = x + 1 # Increment x
818 E262: x = x + 1 #Increment x
819 E262: x = x + 1 # Increment x
823 for token_type, text, start, end, line in tokens:
824 if token_type == tokenize.COMMENT:
825 inline_comment = line[:start[1]].strip()
827 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
829 "E261 at least two spaces before inline comment")
830 symbol, sp, comment = text.partition(' ')
831 bad_prefix = symbol not in ('#', '#:')
833 if bad_prefix or comment[:1].isspace():
834 yield start, "E262 inline comment should start with '# '"
836 if text.rstrip('#') and (start[0] > 1 or symbol[1] != '!'):
837 yield start, "E265 block comment should start with '# '"
838 elif token_type != tokenize.NL:
842 def imports_on_separate_lines(logical_line):
844 Imports should usually be on separate lines.
846 Okay: import os\nimport sys
849 Okay: from subprocess import Popen, PIPE
850 Okay: from myclas import MyClass
851 Okay: from foo.bar.yourclass import YourClass
853 Okay: import foo.bar.yourclass
856 if line.startswith('import '):
857 found = line.find(',')
858 if -1 < found and ';' not in line[:found]:
859 yield found, "E401 multiple imports on one line"
862 def compound_statements(logical_line):
864 Compound statements (multiple statements on the same line) are
865 generally discouraged.
867 While sometimes it's okay to put an if/for/while with a small body
868 on the same line, never do this for multi-clause statements. Also
869 avoid folding such long lines!
871 Okay: if foo == 'blah':\n do_blah_thing()
876 E701: if foo == 'blah': do_blah_thing()
877 E701: for x in lst: total += x
878 E701: while t < 10: t = delay()
879 E701: if foo == 'blah': do_blah_thing()
880 E701: else: do_non_blah_thing()
881 E701: try: something()
882 E701: finally: cleanup()
883 E701: if foo == 'blah': one(); two(); three()
885 E702: do_one(); do_two(); do_three()
886 E703: do_four(); # useless semicolon
889 last_char = len(line) - 1
890 found = line.find(':')
891 while -1 < found < last_char:
892 before = line[:found]
893 if (before.count('{') <= before.count('}') and # {'a': 1} (dict)
894 before.count('[') <= before.count(']') and # [1:2] (slice)
895 before.count('(') <= before.count(')') and # (Python 3 annotation)
896 not LAMBDA_REGEX.search(before)): # lambda x: x
897 yield found, "E701 multiple statements on one line (colon)"
898 found = line.find(':', found + 1)
899 found = line.find(';')
901 if found < last_char:
902 yield found, "E702 multiple statements on one line (semicolon)"
904 yield found, "E703 statement ends with a semicolon"
905 found = line.find(';', found + 1)
908 def explicit_line_join(logical_line, tokens):
910 Avoid explicit line join between brackets.
912 The preferred way of wrapping long lines is by using Python's implied line
913 continuation inside parentheses, brackets and braces. Long lines can be
914 broken over multiple lines by wrapping expressions in parentheses. These
915 should be used in preference to using a backslash for line continuation.
917 E502: aaa = [123, \\n 123]
918 E502: aaa = ("bbb " \\n "ccc")
920 Okay: aaa = [123,\n 123]
921 Okay: aaa = ("bbb "\n "ccc")
922 Okay: aaa = "bbb " \\n "ccc"
924 prev_start = prev_end = parens = 0
925 for token_type, text, start, end, line in tokens:
926 if start[0] != prev_start and parens and backslash:
927 yield backslash, "E502 the backslash is redundant between brackets"
928 if end[0] != prev_end:
929 if line.rstrip('\r\n').endswith('\\'):
930 backslash = (end[0], len(line.splitlines()[-1]) - 1)
933 prev_start = prev_end = end[0]
935 prev_start = start[0]
936 if token_type == tokenize.OP:
943 def comparison_to_singleton(logical_line, noqa):
945 Comparisons to singletons like None should always be done
946 with "is" or "is not", never the equality operators.
948 Okay: if arg is not None:
949 E711: if arg != None:
950 E712: if arg == True:
952 Also, beware of writing if x when you really mean if x is not None --
953 e.g. when testing whether a variable or argument that defaults to None was
954 set to some other value. The other value might have a type (such as a
955 container) that could be false in a boolean context!
957 match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
959 same = (match.group(1) == '==')
960 singleton = match.group(2)
961 msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
962 if singleton in ('None',):
966 nonzero = ((singleton == 'True' and same) or
967 (singleton == 'False' and not same))
968 msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
969 yield match.start(1), ("%s comparison to %s should be %s" %
970 (code, singleton, msg))
973 def comparison_negative(logical_line):
975 Negative comparison, either identity or membership, should be
976 done using "not in" and "is not".
978 Okay: if x not in y:\n pass
979 Okay: assert (X in Y or X is Z)
980 Okay: if not (X in Y):\n pass
981 Okay: zz = x is not y
983 E713: if not X.B in Y:\n pass
984 E714: if not X is Y:\n pass
985 E714: Z = not X.B is Y
987 match = COMPARE_NEGATIVE_REGEX.search(logical_line)
989 if match.group(2) == 'in':
990 msg = ("E713: Use the 'not in' "
991 "operator for collection membership evaluation")
993 msg = ("E714: Use the 'is not' "
994 "operator when testing for unequal identities")
995 yield match.start(1), msg
998 def comparison_type(logical_line):
1000 Object type comparisons should always use isinstance() instead of
1001 comparing types directly.
1003 Okay: if isinstance(obj, int):
1004 E721: if type(obj) is type(1):
1006 When checking if an object is a string, keep in mind that it might be a
1007 unicode string too! In Python 2.3, str and unicode have a common base
1008 class, basestring, so you can do:
1010 Okay: if isinstance(obj, basestring):
1011 Okay: if type(a1) is type(b1):
1013 match = COMPARE_TYPE_REGEX.search(logical_line)
1015 inst = match.group(1)
1016 if inst and isidentifier(inst) and inst not in SINGLETONS:
1017 return # Allow comparison for types which are not obvious
1018 yield match.start(), "E721 do not compare types, use 'isinstance()'"
1021 def python_3000_has_key(logical_line, noqa):
1023 The {}.has_key() method is removed in the Python 3.
1024 Use the 'in' operation instead.
1026 Okay: if "alph" in d:\n print d["alph"]
1027 W601: assert d.has_key('alph')
1029 pos = logical_line.find('.has_key(')
1030 if pos > -1 and not noqa:
1031 yield pos, "W601 .has_key() is deprecated, use 'in'"
1034 def python_3000_raise_comma(logical_line):
1036 When raising an exception, use "raise ValueError('message')"
1037 instead of the older form "raise ValueError, 'message'".
1039 The paren-using form is preferred because when the exception arguments
1040 are long or include string formatting, you don't need to use line
1041 continuation characters thanks to the containing parentheses. The older
1042 form is removed in Python 3.
1044 Okay: raise DummyError("Message")
1045 W602: raise DummyError, "Message"
1047 match = RAISE_COMMA_REGEX.match(logical_line)
1048 if match and not RERAISE_COMMA_REGEX.match(logical_line):
1049 yield match.end() - 1, "W602 deprecated form of raising exception"
1052 def python_3000_not_equal(logical_line):
1054 != can also be written <>, but this is an obsolete usage kept for
1055 backwards compatibility only. New code should always use !=.
1056 The older syntax is removed in Python 3.
1061 pos = logical_line.find('<>')
1063 yield pos, "W603 '<>' is deprecated, use '!='"
1066 def python_3000_backticks(logical_line):
1068 Backticks are removed in Python 3.
1071 Okay: val = repr(1 + 2)
1074 pos = logical_line.find('`')
1076 yield pos, "W604 backticks are deprecated, use 'repr()'"
1079 ##############################################################################
1081 ##############################################################################
1084 if '' == ''.encode():
1085 # Python 2: implicit encoding.
1086 def readlines(filename):
1089 return f.readlines()
1092 isidentifier = re.compile(r'[a-zA-Z_]\w*').match
1093 stdin_get_value = sys.stdin.read
1096 def readlines(filename):
1097 f = open(filename, 'rb')
1099 coding, lines = tokenize.detect_encoding(f.readline)
1100 f = TextIOWrapper(f, coding, line_buffering=True)
1101 return [l.decode(coding) for l in lines] + f.readlines()
1102 except (LookupError, SyntaxError, UnicodeError):
1104 # Fall back if files are improperly declared
1105 f = open(filename, encoding='latin-1')
1106 return f.readlines()
1109 isidentifier = str.isidentifier
1111 def stdin_get_value():
1112 return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1113 readlines.__doc__ = " Read the source code."
1114 noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
1117 def expand_indent(line):
1119 Return the amount of indentation.
1120 Tabs are expanded to the next multiple of 8.
1122 >>> expand_indent(' ')
1124 >>> expand_indent('\t')
1126 >>> expand_indent(' \t')
1128 >>> expand_indent(' \t')
1130 >>> expand_indent(' \t')
1133 if '\t' not in line:
1134 return len(line) - len(line.lstrip())
1138 result = result // 8 * 8 + 8
1146 def mute_string(text):
1148 Replace contents with 'xxx' to prevent syntax matching.
1150 >>> mute_string('"abc"')
1152 >>> mute_string("'''abc'''")
1154 >>> mute_string("r'abc'")
1157 # String modifiers (e.g. u or r)
1158 start = text.index(text[-1]) + 1
1161 if text[-3:] in ('"""', "'''"):
1164 return text[:start] + 'x' * (end - start) + text[end:]
1167 def parse_udiff(diff, patterns=None, parent='.'):
1168 """Return a dictionary of matching lines."""
1169 # For each file of the diff, the entry key is the filename,
1170 # and the value is a set of row numbers to consider.
1173 for line in diff.splitlines():
1178 if line[:3] == '@@ ':
1179 hunk_match = HUNK_REGEX.match(line)
1180 row, nrows = [int(g or '1') for g in hunk_match.groups()]
1181 rv[path].update(range(row, row + nrows))
1182 elif line[:3] == '+++':
1183 path = line[4:].split('\t', 1)[0]
1184 if path[:2] == 'b/':
1187 return dict([(os.path.join(parent, path), rows)
1188 for (path, rows) in rv.items()
1189 if rows and filename_match(path, patterns)])
1192 def normalize_paths(value, parent=os.curdir):
1193 """Parse a comma-separated list of paths.
1195 Return a list of absolute paths.
1197 if not value or isinstance(value, list):
1200 for path in value.split(','):
1202 path = os.path.abspath(os.path.join(parent, path))
1203 paths.append(path.rstrip('/'))
1207 def filename_match(filename, patterns, default=True):
1209 Check if patterns contains a pattern that matches filename.
1210 If patterns is unspecified, this always returns True.
1214 return any(fnmatch(filename, pattern) for pattern in patterns)
1217 ##############################################################################
1218 # Framework to run all checks
1219 ##############################################################################
1222 _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
1225 def register_check(check, codes=None):
1227 Register a new check object.
1229 def _add_check(check, kind, codes, args):
1230 if check in _checks[kind]:
1231 _checks[kind][check][0].extend(codes or [])
1233 _checks[kind][check] = (codes or [''], args)
1234 if inspect.isfunction(check):
1235 args = inspect.getargspec(check)[0]
1236 if args and args[0] in ('physical_line', 'logical_line'):
1238 codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
1239 _add_check(check, args[0], codes, args)
1240 elif inspect.isclass(check):
1241 if inspect.getargspec(check.__init__)[0][:2] == ['self', 'tree']:
1242 _add_check(check, 'tree', codes, None)
1245 def init_checks_registry():
1247 Register all globally visible functions where the first argument name
1248 is 'physical_line' or 'logical_line'.
1250 mod = inspect.getmodule(register_check)
1251 for (name, function) in inspect.getmembers(mod, inspect.isfunction):
1252 register_check(function)
1253 init_checks_registry()
1256 class Checker(object):
1258 Load a Python source file, tokenize it, check coding style.
1261 def __init__(self, filename=None, lines=None,
1262 options=None, report=None, **kwargs):
1264 options = StyleGuide(kwargs).options
1267 self._io_error = None
1268 self._physical_checks = options.physical_checks
1269 self._logical_checks = options.logical_checks
1270 self._ast_checks = options.ast_checks
1271 self.max_line_length = options.max_line_length
1272 self.multiline = False # in a multiline string?
1273 self.hang_closing = options.hang_closing
1274 self.verbose = options.verbose
1275 self.filename = filename
1276 if filename is None:
1277 self.filename = 'stdin'
1278 self.lines = lines or []
1279 elif filename == '-':
1280 self.filename = 'stdin'
1281 self.lines = stdin_get_value().splitlines(True)
1284 self.lines = readlines(filename)
1286 (exc_type, exc) = sys.exc_info()[:2]
1287 self._io_error = '%s: %s' % (exc_type.__name__, exc)
1292 ord0 = ord(self.lines[0][0])
1293 if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
1295 self.lines[0] = self.lines[0][1:]
1296 elif self.lines[0][:3] == '\xef\xbb\xbf':
1297 self.lines[0] = self.lines[0][3:]
1298 self.report = report or options.report
1299 self.report_error = self.report.error
1301 def report_invalid_syntax(self):
1302 (exc_type, exc) = sys.exc_info()[:2]
1303 if len(exc.args) > 1:
1304 offset = exc.args[1]
1306 offset = offset[1:3]
1309 self.report_error(offset[0], offset[1] or 0,
1310 'E901 %s: %s' % (exc_type.__name__, exc.args[0]),
1311 self.report_invalid_syntax)
1312 report_invalid_syntax.__doc__ = " Check if the syntax is valid."
1316 Get the next line from the input buffer.
1318 self.line_number += 1
1319 if self.line_number > len(self.lines):
1321 line = self.lines[self.line_number - 1]
1322 if self.indent_char is None and line[:1] in WHITESPACE:
1323 self.indent_char = line[0]
1326 def run_check(self, check, argument_names):
1331 for name in argument_names:
1332 arguments.append(getattr(self, name))
1333 return check(*arguments)
1335 def check_physical(self, line):
1337 Run all physical checks on a raw input line.
1339 self.physical_line = line
1340 for name, check, argument_names in self._physical_checks:
1341 result = self.run_check(check, argument_names)
1342 if result is not None:
1343 (offset, text) = result
1344 self.report_error(self.line_number, offset, text, check)
1345 if text[:4] == 'E101':
1346 self.indent_char = line[0]
1348 def build_tokens_line(self):
1350 Build a logical line from tokens.
1357 for token in self.tokens:
1358 (token_type, text) = token[0:2]
1359 if token_type == tokenize.COMMENT:
1360 comments.append(text)
1362 if token_type in SKIP_TOKENS:
1364 if token_type == tokenize.STRING:
1365 text = mute_string(text)
1367 (end_row, end) = previous[3]
1368 (start_row, start) = token[2]
1369 if end_row != start_row: # different row
1370 prev_text = self.lines[end_row - 1][end - 1]
1371 if prev_text == ',' or (prev_text not in '{[('
1372 and text not in '}])'):
1375 elif end != start: # different column
1376 fill = self.lines[end_row - 1][end:start]
1377 logical.append(fill)
1379 self.mapping.append((length, token))
1380 logical.append(text)
1383 self.logical_line = ''.join(logical)
1384 self.noqa = comments and noqa(''.join(comments))
1385 # With Python 2, if the line ends with '\r\r\n' the assertion fails
1386 # assert self.logical_line.strip() == self.logical_line
1388 def check_logical(self):
1390 Build a line from tokens and run all logical checks on it.
1392 self.build_tokens_line()
1393 self.report.increment_logical_line()
1394 token0 = self.mapping[0][1] if self.mapping else self.tokens[0]
1395 first_line = self.lines[token0[2][0] - 1]
1396 indent = first_line[:token0[2][1]]
1397 self.indent_level = expand_indent(indent)
1398 if self.verbose >= 2:
1399 print(self.logical_line[:80].rstrip())
1400 for name, check, argument_names in self._logical_checks:
1401 if self.verbose >= 4:
1403 for result in self.run_check(check, argument_names) or ():
1404 (offset, text) = result
1405 if isinstance(offset, tuple):
1406 (orig_number, orig_offset) = offset
1408 orig_number = token0[2][0]
1409 orig_offset = token0[2][1] + offset
1410 for token_offset, token in self.mapping:
1411 if offset >= token_offset:
1412 orig_number = token[2][0]
1413 orig_offset = (token[2][1] + offset - token_offset)
1414 self.report_error(orig_number, orig_offset, text, check)
1415 if self.logical_line:
1416 self.previous_indent_level = self.indent_level
1417 self.previous_logical = self.logical_line
1420 def check_ast(self):
1422 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
1423 except (SyntaxError, TypeError):
1424 return self.report_invalid_syntax()
1425 for name, cls, __ in self._ast_checks:
1426 checker = cls(tree, self.filename)
1427 for lineno, offset, text, check in checker.run():
1428 if not self.lines or not noqa(self.lines[lineno - 1]):
1429 self.report_error(lineno, offset, text, check)
1431 def generate_tokens(self):
1433 self.report_error(1, 0, 'E902 %s' % self._io_error, readlines)
1434 tokengen = tokenize.generate_tokens(self.readline)
1436 for token in tokengen:
1437 self.maybe_check_physical(token)
1439 except (SyntaxError, tokenize.TokenError):
1440 self.report_invalid_syntax()
1442 def maybe_check_physical(self, token):
1444 If appropriate (based on token), check current physical line(s).
1446 # Called after every token, but act only on end of line.
1447 if token[0] in (tokenize.NEWLINE, tokenize.NL):
1448 # Obviously, a newline token ends a single physical line.
1449 self.check_physical(token[4])
1450 elif token[0] == tokenize.STRING and '\n' in token[1]:
1451 # Less obviously, a string that contains newlines is a
1452 # multiline string, either triple-quoted or with internal
1453 # newlines backslash-escaped. Check every physical line in the
1454 # string *except* for the last one: its newline is outside of
1455 # the multiline string, so we consider it a regular physical
1456 # line, and will check it like any other physical line.
1459 # - we don't *completely* ignore the last line; if it contains
1460 # the magical "# noqa" comment, we disable all physical
1461 # checks for the entire multiline string
1462 # - have to wind self.line_number back because initially it
1463 # points to the last line of the string, and we want
1464 # check_physical() to give accurate feedback
1467 self.multiline = True
1468 self.line_number = token[2][0]
1469 for line in token[1].split('\n')[:-1]:
1470 self.check_physical(line + '\n')
1471 self.line_number += 1
1472 self.multiline = False
1474 def check_all(self, expected=None, line_offset=0):
1476 Run all checks on the input file.
1478 self.report.init_file(self.filename, self.lines, expected, line_offset)
1479 if self._ast_checks:
1481 self.line_number = 0
1482 self.indent_char = None
1483 self.indent_level = 0
1484 self.previous_indent_level = 0
1485 self.previous_logical = ''
1487 self.blank_lines = blank_lines_before_comment = 0
1489 for token in self.generate_tokens():
1490 self.tokens.append(token)
1491 token_type, text = token[0:2]
1492 if self.verbose >= 3:
1493 if token[2][0] == token[3][0]:
1494 pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
1496 pos = 'l.%s' % token[3][0]
1497 print('l.%s\t%s\t%s\t%r' %
1498 (token[2][0], pos, tokenize.tok_name[token[0]], text))
1499 if token_type == tokenize.OP:
1505 if token_type == tokenize.NEWLINE:
1506 if self.blank_lines < blank_lines_before_comment:
1507 self.blank_lines = blank_lines_before_comment
1508 self.check_logical()
1509 self.blank_lines = blank_lines_before_comment = 0
1510 elif token_type == tokenize.NL:
1511 if len(self.tokens) == 1:
1512 # The physical line contains only this token.
1513 self.blank_lines += 1
1516 self.check_logical()
1517 elif token_type == tokenize.COMMENT and len(self.tokens) == 1:
1518 if blank_lines_before_comment < self.blank_lines:
1519 blank_lines_before_comment = self.blank_lines
1520 self.blank_lines = 0
1522 # The comment also ends a physical line
1523 text = text.rstrip('\r\n')
1524 self.tokens = [(token_type, text) + token[2:]]
1525 self.check_logical()
1526 return self.report.get_file_results()
1529 class BaseReport(object):
1530 """Collect the results of the checks."""
1531 print_filename = False
1533 def __init__(self, options):
1534 self._benchmark_keys = options.benchmark_keys
1535 self._ignore_code = options.ignore_code
1538 self.total_errors = 0
1539 self.counters = dict.fromkeys(self._benchmark_keys, 0)
1543 """Start the timer."""
1544 self._start_time = time.time()
1547 """Stop the timer."""
1548 self.elapsed = time.time() - self._start_time
1550 def init_file(self, filename, lines, expected, line_offset):
1551 """Signal a new file."""
1552 self.filename = filename
1554 self.expected = expected or ()
1555 self.line_offset = line_offset
1556 self.file_errors = 0
1557 self.counters['files'] += 1
1558 self.counters['physical lines'] += len(lines)
1560 def increment_logical_line(self):
1561 """Signal a new logical line."""
1562 self.counters['logical lines'] += 1
1564 def error(self, line_number, offset, text, check):
1565 """Report an error, according to options."""
1567 if self._ignore_code(code):
1569 if code in self.counters:
1570 self.counters[code] += 1
1572 self.counters[code] = 1
1573 self.messages[code] = text[5:]
1574 # Don't care about expected errors or warnings
1575 if code in self.expected:
1577 if self.print_filename and not self.file_errors:
1578 print(self.filename)
1579 self.file_errors += 1
1580 self.total_errors += 1
1583 def get_file_results(self):
1584 """Return the count of errors and warnings for this file."""
1585 return self.file_errors
1587 def get_count(self, prefix=''):
1588 """Return the total count of errors and warnings."""
1589 return sum([self.counters[key]
1590 for key in self.messages if key.startswith(prefix)])
1592 def get_statistics(self, prefix=''):
1594 Get statistics for message codes that start with the prefix.
1596 prefix='' matches all errors and warnings
1597 prefix='E' matches all errors
1598 prefix='W' matches all warnings
1599 prefix='E4' matches all errors that have to do with imports
1601 return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
1602 for key in sorted(self.messages) if key.startswith(prefix)]
1604 def print_statistics(self, prefix=''):
1605 """Print overall statistics (number of errors and warnings)."""
1606 for line in self.get_statistics(prefix):
1609 def print_benchmark(self):
1610 """Print benchmark numbers."""
1611 print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
1613 for key in self._benchmark_keys:
1614 print('%-7d %s per second (%d total)' %
1615 (self.counters[key] / self.elapsed, key,
1616 self.counters[key]))
1619 class FileReport(BaseReport):
1620 """Collect the results of the checks and print only the filenames."""
1621 print_filename = True
1624 class StandardReport(BaseReport):
1625 """Collect and print the results of the checks."""
1627 def __init__(self, options):
1628 super(StandardReport, self).__init__(options)
1629 self._fmt = REPORT_FORMAT.get(options.format.lower(),
1631 self._repeat = options.repeat
1632 self._show_source = options.show_source
1633 self._show_pep8 = options.show_pep8
1635 def init_file(self, filename, lines, expected, line_offset):
1636 """Signal a new file."""
1637 self._deferred_print = []
1638 return super(StandardReport, self).init_file(
1639 filename, lines, expected, line_offset)
1641 def error(self, line_number, offset, text, check):
1642 """Report an error, according to options."""
1643 code = super(StandardReport, self).error(line_number, offset,
1645 if code and (self.counters[code] == 1 or self._repeat):
1646 self._deferred_print.append(
1647 (line_number, offset, code, text[5:], check.__doc__))
1650 def get_file_results(self):
1651 """Print the result and return the overall count for this file."""
1652 self._deferred_print.sort()
1653 for line_number, offset, code, text, doc in self._deferred_print:
1655 'path': self.filename,
1656 'row': self.line_offset + line_number, 'col': offset + 1,
1657 'code': code, 'text': text,
1659 if self._show_source:
1660 if line_number > len(self.lines):
1663 line = self.lines[line_number - 1]
1664 print(line.rstrip())
1665 print(' ' * offset + '^')
1666 if self._show_pep8 and doc:
1667 print(doc.lstrip('\n').rstrip())
1668 return self.file_errors
1671 class DiffReport(StandardReport):
1672 """Collect and print the results for the changed lines only."""
1674 def __init__(self, options):
1675 super(DiffReport, self).__init__(options)
1676 self._selected = options.selected_lines
1678 def error(self, line_number, offset, text, check):
1679 if line_number not in self._selected[self.filename]:
1681 return super(DiffReport, self).error(line_number, offset, text, check)
1684 class StyleGuide(object):
1685 """Initialize a PEP-8 instance with few options."""
1687 def __init__(self, *args, **kwargs):
1688 # build options from the command line
1689 self.checker_class = kwargs.pop('checker_class', Checker)
1690 parse_argv = kwargs.pop('parse_argv', False)
1691 config_file = kwargs.pop('config_file', None)
1692 parser = kwargs.pop('parser', None)
1693 # build options from dict
1694 options_dict = dict(*args, **kwargs)
1695 arglist = None if parse_argv else options_dict.get('paths', None)
1696 options, self.paths = process_options(
1697 arglist, parse_argv, config_file, parser)
1699 options.__dict__.update(options_dict)
1700 if 'paths' in options_dict:
1701 self.paths = options_dict['paths']
1703 self.runner = self.input_file
1704 self.options = options
1706 if not options.reporter:
1707 options.reporter = BaseReport if options.quiet else StandardReport
1709 options.select = tuple(options.select or ())
1710 if not (options.select or options.ignore or
1711 options.testsuite or options.doctest) and DEFAULT_IGNORE:
1712 # The default choice: ignore controversial checks
1713 options.ignore = tuple(DEFAULT_IGNORE.split(','))
1715 # Ignore all checks which are not explicitly selected
1716 options.ignore = ('',) if options.select else tuple(options.ignore)
1717 options.benchmark_keys = BENCHMARK_KEYS[:]
1718 options.ignore_code = self.ignore_code
1719 options.physical_checks = self.get_checks('physical_line')
1720 options.logical_checks = self.get_checks('logical_line')
1721 options.ast_checks = self.get_checks('tree')
1724 def init_report(self, reporter=None):
1725 """Initialize the report instance."""
1726 self.options.report = (reporter or self.options.reporter)(self.options)
1727 return self.options.report
1729 def check_files(self, paths=None):
1730 """Run all checks on the paths."""
1733 report = self.options.report
1734 runner = self.runner
1738 if os.path.isdir(path):
1739 self.input_dir(path)
1740 elif not self.excluded(path):
1742 except KeyboardInterrupt:
1743 print('... stopped')
1747 def input_file(self, filename, lines=None, expected=None, line_offset=0):
1748 """Run all checks on a Python source file."""
1749 if self.options.verbose:
1750 print('checking %s' % filename)
1751 fchecker = self.checker_class(
1752 filename, lines=lines, options=self.options)
1753 return fchecker.check_all(expected=expected, line_offset=line_offset)
1755 def input_dir(self, dirname):
1756 """Check all files in this directory and all subdirectories."""
1757 dirname = dirname.rstrip('/')
1758 if self.excluded(dirname):
1760 counters = self.options.report.counters
1761 verbose = self.options.verbose
1762 filepatterns = self.options.filename
1763 runner = self.runner
1764 for root, dirs, files in os.walk(dirname):
1766 print('directory ' + root)
1767 counters['directories'] += 1
1768 for subdir in sorted(dirs):
1769 if self.excluded(subdir, root):
1771 for filename in sorted(files):
1772 # contain a pattern that matches?
1773 if ((filename_match(filename, filepatterns) and
1774 not self.excluded(filename, root))):
1775 runner(os.path.join(root, filename))
1777 def excluded(self, filename, parent=None):
1779 Check if options.exclude contains a pattern that matches filename.
1781 if not self.options.exclude:
1783 basename = os.path.basename(filename)
1784 if filename_match(basename, self.options.exclude):
1787 filename = os.path.join(parent, filename)
1788 filename = os.path.abspath(filename)
1789 return filename_match(filename, self.options.exclude)
1791 def ignore_code(self, code):
1793 Check if the error code should be ignored.
1795 If 'options.select' contains a prefix of the error code,
1796 return False. Else, if 'options.ignore' contains a prefix of
1797 the error code, return True.
1799 if len(code) < 4 and any(s.startswith(code)
1800 for s in self.options.select):
1802 return (code.startswith(self.options.ignore) and
1803 not code.startswith(self.options.select))
1805 def get_checks(self, argument_name):
1807 Find all globally visible functions where the first argument name
1808 starts with argument_name and which contain selected tests.
1811 for check, attrs in _checks[argument_name].items():
1812 (codes, args) = attrs
1813 if any(not (code and self.ignore_code(code)) for code in codes):
1814 checks.append((check.__name__, check, args))
1815 return sorted(checks)
1818 def get_parser(prog='pep8', version=__version__):
1819 parser = OptionParser(prog=prog, version=version,
1820 usage="%prog [options] input ...")
1821 parser.config_options = [
1822 'exclude', 'filename', 'select', 'ignore', 'max-line-length',
1823 'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
1824 'show-source', 'statistics', 'verbose']
1825 parser.add_option('-v', '--verbose', default=0, action='count',
1826 help="print status messages, or debug with -vv")
1827 parser.add_option('-q', '--quiet', default=0, action='count',
1828 help="report only file names, or nothing with -qq")
1829 parser.add_option('-r', '--repeat', default=True, action='store_true',
1830 help="(obsolete) show all occurrences of the same error")
1831 parser.add_option('--first', action='store_false', dest='repeat',
1832 help="show first occurrence of each error")
1833 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
1834 help="exclude files or directories which match these "
1835 "comma separated patterns (default: %default)")
1836 parser.add_option('--filename', metavar='patterns', default='*.py',
1837 help="when parsing directories, only check filenames "
1838 "matching these comma separated patterns "
1839 "(default: %default)")
1840 parser.add_option('--select', metavar='errors', default='',
1841 help="select errors and warnings (e.g. E,W6)")
1842 parser.add_option('--ignore', metavar='errors', default='',
1843 help="skip errors and warnings (e.g. E4,W)")
1844 parser.add_option('--show-source', action='store_true',
1845 help="show source code for each error")
1846 parser.add_option('--show-pep8', action='store_true',
1847 help="show text of PEP 8 for each error "
1848 "(implies --first)")
1849 parser.add_option('--statistics', action='store_true',
1850 help="count errors and warnings")
1851 parser.add_option('--count', action='store_true',
1852 help="print total number of errors and warnings "
1853 "to standard error and set exit code to 1 if "
1854 "total is not null")
1855 parser.add_option('--max-line-length', type='int', metavar='n',
1856 default=MAX_LINE_LENGTH,
1857 help="set maximum allowed line length "
1858 "(default: %default)")
1859 parser.add_option('--hang-closing', action='store_true',
1860 help="hang closing bracket instead of matching "
1861 "indentation of opening bracket's line")
1862 parser.add_option('--format', metavar='format', default='default',
1863 help="set the error format [default|pylint|<custom>]")
1864 parser.add_option('--diff', action='store_true',
1865 help="report only lines changed according to the "
1866 "unified diff received on STDIN")
1867 group = parser.add_option_group("Testing Options")
1868 if os.path.exists(TESTSUITE_PATH):
1869 group.add_option('--testsuite', metavar='dir',
1870 help="run regression tests from dir")
1871 group.add_option('--doctest', action='store_true',
1872 help="run doctest on myself")
1873 group.add_option('--benchmark', action='store_true',
1874 help="measure processing speed")
1878 def read_config(options, args, arglist, parser):
1879 """Read both user configuration and local configuration."""
1880 config = RawConfigParser()
1882 user_conf = options.config
1883 if user_conf and os.path.isfile(user_conf):
1885 print('user configuration: %s' % user_conf)
1886 config.read(user_conf)
1888 local_dir = os.curdir
1889 parent = tail = args and os.path.abspath(os.path.commonprefix(args))
1891 if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):
1894 print('local configuration: in %s' % parent)
1896 (parent, tail) = os.path.split(parent)
1898 pep8_section = parser.prog
1899 if config.has_section(pep8_section):
1900 option_list = dict([(o.dest, o.type or o.action)
1901 for o in parser.option_list])
1903 # First, read the default values
1904 (new_options, __) = parser.parse_args([])
1906 # Second, parse the configuration
1907 for opt in config.options(pep8_section):
1908 if options.verbose > 1:
1909 print(" %s = %s" % (opt, config.get(pep8_section, opt)))
1910 if opt.replace('_', '-') not in parser.config_options:
1911 print("Unknown option: '%s'\n not in [%s]" %
1912 (opt, ' '.join(parser.config_options)))
1914 normalized_opt = opt.replace('-', '_')
1915 opt_type = option_list[normalized_opt]
1916 if opt_type in ('int', 'count'):
1917 value = config.getint(pep8_section, opt)
1918 elif opt_type == 'string':
1919 value = config.get(pep8_section, opt)
1920 if normalized_opt == 'exclude':
1921 value = normalize_paths(value, local_dir)
1923 assert opt_type in ('store_true', 'store_false')
1924 value = config.getboolean(pep8_section, opt)
1925 setattr(new_options, normalized_opt, value)
1927 # Third, overwrite with the command-line options
1928 (options, __) = parser.parse_args(arglist, values=new_options)
1929 options.doctest = options.testsuite = False
1933 def process_options(arglist=None, parse_argv=False, config_file=None,
1935 """Process options passed either via arglist or via command line args."""
1937 parser = get_parser()
1938 if not parser.has_option('--config'):
1939 if config_file is True:
1940 config_file = DEFAULT_CONFIG
1941 group = parser.add_option_group("Configuration", description=(
1942 "The project options are read from the [%s] section of the "
1943 "tox.ini file or the setup.cfg file located in any parent folder "
1944 "of the path(s) being processed. Allowed options are: %s." %
1945 (parser.prog, ', '.join(parser.config_options))))
1946 group.add_option('--config', metavar='path', default=config_file,
1947 help="user config file location (default: %default)")
1948 # Don't read the command line if the module is used as a library.
1949 if not arglist and not parse_argv:
1951 # If parse_argv is True and arglist is None, arguments are
1952 # parsed from the command line (sys.argv)
1953 (options, args) = parser.parse_args(arglist)
1954 options.reporter = None
1956 if options.ensure_value('testsuite', False):
1957 args.append(options.testsuite)
1958 elif not options.ensure_value('doctest', False):
1959 if parse_argv and not args:
1960 if options.diff or any(os.path.exists(name)
1961 for name in PROJECT_CONFIG):
1964 parser.error('input not specified')
1965 options = read_config(options, args, arglist, parser)
1966 options.reporter = parse_argv and options.quiet == 1 and FileReport
1968 options.filename = options.filename and options.filename.split(',')
1969 options.exclude = normalize_paths(options.exclude)
1970 options.select = options.select and options.select.split(',')
1971 options.ignore = options.ignore and options.ignore.split(',')
1974 options.reporter = DiffReport
1975 stdin = stdin_get_value()
1976 options.selected_lines = parse_udiff(stdin, options.filename, args[0])
1977 args = sorted(options.selected_lines)
1979 return options, args
1983 """Parse options and run checks on Python source."""
1984 pep8style = StyleGuide(parse_argv=True, config_file=True)
1985 options = pep8style.options
1986 if options.doctest or options.testsuite:
1987 from testsuite.support import run_tests
1988 report = run_tests(pep8style)
1990 report = pep8style.check_files()
1991 if options.statistics:
1992 report.print_statistics()
1993 if options.benchmark:
1994 report.print_benchmark()
1995 if options.testsuite and not options.quiet:
1996 report.print_results()
1997 if report.total_errors:
1999 sys.stderr.write(str(report.total_errors) + '\n')
2002 if __name__ == '__main__':