Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pycodestyle.py: 68%
1343 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:57 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:57 +0000
1#!/usr/bin/env python
2# pycodestyle.py - Check Python source code formatting, according to
3# PEP 8
4#
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.
28r"""
29Check Python source code formatting, according to PEP 8.
31For usage and a list of options, try this:
32$ python pycodestyle.py -h
34This program and its regression test suite live here:
35https://github.com/pycqa/pycodestyle
37Groups of errors and warnings:
38E errors
39W warnings
40100 indentation
41200 whitespace
42300 blank lines
43400 imports
44500 line length
45600 deprecation
46700 statements
47900 syntax error
48"""
49import bisect
50import configparser
51import inspect
52import io
53import keyword
54import os
55import re
56import sys
57import time
58import tokenize
59import warnings
60from fnmatch import fnmatch
61from functools import lru_cache
62from optparse import OptionParser
64# this is a performance hack. see https://bugs.python.org/issue43014
65if (
66 sys.version_info < (3, 10) and
67 callable(getattr(tokenize, '_compile', None))
68): # pragma: no cover (<py310)
69 tokenize._compile = lru_cache(tokenize._compile) # type: ignore
71__version__ = '2.11.1'
73DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
74DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
75try:
76 if sys.platform == 'win32': # pragma: win32 cover
77 USER_CONFIG = os.path.expanduser(r'~\.pycodestyle')
78 else: # pragma: win32 no cover
79 USER_CONFIG = os.path.join(
80 os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
81 'pycodestyle'
82 )
83except ImportError:
84 USER_CONFIG = None
86PROJECT_CONFIG = ('setup.cfg', 'tox.ini')
87MAX_LINE_LENGTH = 79
88# Number of blank lines between various code parts.
89BLANK_LINES_CONFIG = {
90 # Top level class and function.
91 'top_level': 2,
92 # Methods and nested class and function.
93 'method': 1,
94}
95MAX_DOC_LENGTH = 72
96INDENT_SIZE = 4
97REPORT_FORMAT = {
98 'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
99 'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
100}
102PyCF_ONLY_AST = 1024
103SINGLETONS = frozenset(['False', 'None', 'True'])
104KEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS
105UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
106ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-', '@'])
107WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
108WS_NEEDED_OPERATORS = frozenset([
109 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<', '>',
110 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=',
111 'and', 'in', 'is', 'or', '->', ':='])
112WHITESPACE = frozenset(' \t\xa0')
113NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
114SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT])
115# ERRORTOKEN is triggered by backticks in Python 3
116SKIP_COMMENTS = SKIP_TOKENS.union([tokenize.COMMENT, tokenize.ERRORTOKEN])
117BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
119INDENT_REGEX = re.compile(r'([ \t]*)')
120ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
121DOCSTRING_REGEX = re.compile(r'u?r?["\']')
122EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({][ \t]|[ \t][\]}),;:](?!=)')
123WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
124COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
125 r'\s*(?(1)|(None|False|True))\b')
126COMPARE_NEGATIVE_REGEX = re.compile(r'\b(?<!is\s)(not)\s+[^][)(}{ ]+\s+'
127 r'(in|is)\s')
128COMPARE_TYPE_REGEX = re.compile(
129 r'[=!]=\s+type(?:\s*\(\s*([^)]*[^ )])\s*\))'
130 r'|\btype(?:\s*\(\s*([^)]*[^ )])\s*\))\s+[=!]='
131)
132KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
133OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)')
134LAMBDA_REGEX = re.compile(r'\blambda\b')
135HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
136STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b')
137STARTSWITH_TOP_LEVEL_REGEX = re.compile(r'^(async\s+def\s+|def\s+|class\s+|@)')
138STARTSWITH_INDENT_STATEMENT_REGEX = re.compile(
139 r'^\s*({})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
140 'def', 'async def',
141 'for', 'async for',
142 'if', 'elif', 'else',
143 'try', 'except', 'finally',
144 'with', 'async with',
145 'class',
146 'while',
147 )))
148)
149DUNDER_REGEX = re.compile(r"^__([^\s]+)__(?::\s*[a-zA-Z.0-9_\[\]\"]+)? = ")
150BLANK_EXCEPT_REGEX = re.compile(r"except\s*:")
152if sys.version_info >= (3, 12): # pragma: >=3.12 cover
153 FSTRING_START = tokenize.FSTRING_START
154 FSTRING_MIDDLE = tokenize.FSTRING_MIDDLE
155 FSTRING_END = tokenize.FSTRING_END
156else: # pragma: <3.12 cover
157 FSTRING_START = FSTRING_MIDDLE = FSTRING_END = -1
159_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
162def _get_parameters(function):
163 return [parameter.name
164 for parameter
165 in inspect.signature(function).parameters.values()
166 if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
169def register_check(check, codes=None):
170 """Register a new check object."""
171 def _add_check(check, kind, codes, args):
172 if check in _checks[kind]:
173 _checks[kind][check][0].extend(codes or [])
174 else:
175 _checks[kind][check] = (codes or [''], args)
176 if inspect.isfunction(check):
177 args = _get_parameters(check)
178 if args and args[0] in ('physical_line', 'logical_line'):
179 if codes is None:
180 codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
181 _add_check(check, args[0], codes, args)
182 elif inspect.isclass(check):
183 if _get_parameters(check.__init__)[:2] == ['self', 'tree']:
184 _add_check(check, 'tree', codes, None)
185 return check
188########################################################################
189# Plugins (check functions) for physical lines
190########################################################################
192@register_check
193def tabs_or_spaces(physical_line, indent_char):
194 r"""Never mix tabs and spaces.
196 The most popular way of indenting Python is with spaces only. The
197 second-most popular way is with tabs only. Code indented with a
198 mixture of tabs and spaces should be converted to using spaces
199 exclusively. When invoking the Python command line interpreter with
200 the -t option, it issues warnings about code that illegally mixes
201 tabs and spaces. When using -tt these warnings become errors.
202 These options are highly recommended!
204 Okay: if a == 0:\n a = 1\n b = 1
205 """
206 indent = INDENT_REGEX.match(physical_line).group(1)
207 for offset, char in enumerate(indent):
208 if char != indent_char:
209 return offset, "E101 indentation contains mixed spaces and tabs"
212@register_check
213def tabs_obsolete(physical_line):
214 r"""On new projects, spaces-only are strongly recommended over tabs.
216 Okay: if True:\n return
217 W191: if True:\n\treturn
218 """
219 indent = INDENT_REGEX.match(physical_line).group(1)
220 if '\t' in indent:
221 return indent.index('\t'), "W191 indentation contains tabs"
224@register_check
225def trailing_whitespace(physical_line):
226 r"""Trailing whitespace is superfluous.
228 The warning returned varies on whether the line itself is blank,
229 for easier filtering for those who want to indent their blank lines.
231 Okay: spam(1)\n#
232 W291: spam(1) \n#
233 W293: class Foo(object):\n \n bang = 12
234 """
235 physical_line = physical_line.rstrip('\n') # chr(10), newline
236 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
237 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
238 stripped = physical_line.rstrip(' \t\v')
239 if physical_line != stripped:
240 if stripped:
241 return len(stripped), "W291 trailing whitespace"
242 else:
243 return 0, "W293 blank line contains whitespace"
246@register_check
247def trailing_blank_lines(physical_line, lines, line_number, total_lines):
248 r"""Trailing blank lines are superfluous.
250 Okay: spam(1)
251 W391: spam(1)\n
253 However the last line should end with a new line (warning W292).
254 """
255 if line_number == total_lines:
256 stripped_last_line = physical_line.rstrip('\r\n')
257 if physical_line and not stripped_last_line:
258 return 0, "W391 blank line at end of file"
259 if stripped_last_line == physical_line:
260 return len(lines[-1]), "W292 no newline at end of file"
263@register_check
264def maximum_line_length(physical_line, max_line_length, multiline,
265 line_number, noqa):
266 r"""Limit all lines to a maximum of 79 characters.
268 There are still many devices around that are limited to 80 character
269 lines; plus, limiting windows to 80 characters makes it possible to
270 have several windows side-by-side. The default wrapping on such
271 devices looks ugly. Therefore, please limit all lines to a maximum
272 of 79 characters. For flowing long blocks of text (docstrings or
273 comments), limiting the length to 72 characters is recommended.
275 Reports error E501.
276 """
277 line = physical_line.rstrip()
278 length = len(line)
279 if length > max_line_length and not noqa:
280 # Special case: ignore long shebang lines.
281 if line_number == 1 and line.startswith('#!'):
282 return
283 # Special case for long URLs in multi-line docstrings or
284 # comments, but still report the error when the 72 first chars
285 # are whitespaces.
286 chunks = line.split()
287 if ((len(chunks) == 1 and multiline) or
288 (len(chunks) == 2 and chunks[0] == '#')) and \
289 len(line) - len(chunks[-1]) < max_line_length - 7:
290 return
291 if length > max_line_length:
292 return (max_line_length, "E501 line too long "
293 "(%d > %d characters)" % (length, max_line_length))
296########################################################################
297# Plugins (check functions) for logical lines
298########################################################################
301def _is_one_liner(logical_line, indent_level, lines, line_number):
302 if not STARTSWITH_TOP_LEVEL_REGEX.match(logical_line):
303 return False
305 line_idx = line_number - 1
307 if line_idx < 1:
308 prev_indent = 0
309 else:
310 prev_indent = expand_indent(lines[line_idx - 1])
312 if prev_indent > indent_level:
313 return False
315 while line_idx < len(lines):
316 line = lines[line_idx].strip()
317 if not line.startswith('@') and STARTSWITH_TOP_LEVEL_REGEX.match(line):
318 break
319 else:
320 line_idx += 1
321 else:
322 return False # invalid syntax: EOF while searching for def/class
324 next_idx = line_idx + 1
325 while next_idx < len(lines):
326 if lines[next_idx].strip():
327 break
328 else:
329 next_idx += 1
330 else:
331 return True # line is last in the file
333 return expand_indent(lines[next_idx]) <= indent_level
336@register_check
337def blank_lines(logical_line, blank_lines, indent_level, line_number,
338 blank_before, previous_logical,
339 previous_unindented_logical_line, previous_indent_level,
340 lines):
341 r"""Separate top-level function and class definitions with two blank
342 lines.
344 Method definitions inside a class are separated by a single blank
345 line.
347 Extra blank lines may be used (sparingly) to separate groups of
348 related functions. Blank lines may be omitted between a bunch of
349 related one-liners (e.g. a set of dummy implementations).
351 Use blank lines in functions, sparingly, to indicate logical
352 sections.
354 Okay: def a():\n pass\n\n\ndef b():\n pass
355 Okay: def a():\n pass\n\n\nasync def b():\n pass
356 Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
357 Okay: default = 1\nfoo = 1
358 Okay: classify = 1\nfoo = 1
360 E301: class Foo:\n b = 0\n def bar():\n pass
361 E302: def a():\n pass\n\ndef b(n):\n pass
362 E302: def a():\n pass\n\nasync def b(n):\n pass
363 E303: def a():\n pass\n\n\n\ndef b(n):\n pass
364 E303: def a():\n\n\n\n pass
365 E304: @decorator\n\ndef a():\n pass
366 E305: def a():\n pass\na()
367 E306: def a():\n def b():\n pass\n def c():\n pass
368 """ # noqa
369 top_level_lines = BLANK_LINES_CONFIG['top_level']
370 method_lines = BLANK_LINES_CONFIG['method']
372 if not previous_logical and blank_before < top_level_lines:
373 return # Don't expect blank lines before the first line
374 if previous_logical.startswith('@'):
375 if blank_lines:
376 yield 0, "E304 blank lines found after function decorator"
377 elif (blank_lines > top_level_lines or
378 (indent_level and blank_lines == method_lines + 1)
379 ):
380 yield 0, "E303 too many blank lines (%d)" % blank_lines
381 elif STARTSWITH_TOP_LEVEL_REGEX.match(logical_line):
382 # allow a group of one-liners
383 if (
384 _is_one_liner(logical_line, indent_level, lines, line_number) and
385 blank_before == 0
386 ):
387 return
388 if indent_level:
389 if not (blank_before == method_lines or
390 previous_indent_level < indent_level or
391 DOCSTRING_REGEX.match(previous_logical)
392 ):
393 ancestor_level = indent_level
394 nested = False
395 # Search backwards for a def ancestor or tree root
396 # (top level).
397 for line in lines[line_number - top_level_lines::-1]:
398 if line.strip() and expand_indent(line) < ancestor_level:
399 ancestor_level = expand_indent(line)
400 nested = STARTSWITH_DEF_REGEX.match(line.lstrip())
401 if nested or ancestor_level == 0:
402 break
403 if nested:
404 yield 0, "E306 expected %s blank line before a " \
405 "nested definition, found 0" % (method_lines,)
406 else:
407 yield 0, "E301 expected {} blank line, found 0".format(
408 method_lines)
409 elif blank_before != top_level_lines:
410 yield 0, "E302 expected %s blank lines, found %d" % (
411 top_level_lines, blank_before)
412 elif (logical_line and
413 not indent_level and
414 blank_before != top_level_lines and
415 previous_unindented_logical_line.startswith(('def ', 'class '))
416 ):
417 yield 0, "E305 expected %s blank lines after " \
418 "class or function definition, found %d" % (
419 top_level_lines, blank_before)
422@register_check
423def extraneous_whitespace(logical_line):
424 r"""Avoid extraneous whitespace.
426 Avoid extraneous whitespace in these situations:
427 - Immediately inside parentheses, brackets or braces.
428 - Immediately before a comma, semicolon, or colon.
430 Okay: spam(ham[1], {eggs: 2})
431 E201: spam( ham[1], {eggs: 2})
432 E201: spam(ham[ 1], {eggs: 2})
433 E201: spam(ham[1], { eggs: 2})
434 E202: spam(ham[1], {eggs: 2} )
435 E202: spam(ham[1 ], {eggs: 2})
436 E202: spam(ham[1], {eggs: 2 })
438 E203: if x == 4: print x, y; x, y = y , x
439 E203: if x == 4: print x, y ; x, y = y, x
440 E203: if x == 4 : print x, y; x, y = y, x
441 """
442 line = logical_line
443 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
444 text = match.group()
445 char = text.strip()
446 found = match.start()
447 if text[-1].isspace():
448 # assert char in '([{'
449 yield found + 1, "E201 whitespace after '%s'" % char
450 elif line[found - 1] != ',':
451 code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
452 yield found, f"{code} whitespace before '{char}'"
455@register_check
456def whitespace_around_keywords(logical_line):
457 r"""Avoid extraneous whitespace around keywords.
459 Okay: True and False
460 E271: True and False
461 E272: True and False
462 E273: True and\tFalse
463 E274: True\tand False
464 """
465 for match in KEYWORD_REGEX.finditer(logical_line):
466 before, after = match.groups()
468 if '\t' in before:
469 yield match.start(1), "E274 tab before keyword"
470 elif len(before) > 1:
471 yield match.start(1), "E272 multiple spaces before keyword"
473 if '\t' in after:
474 yield match.start(2), "E273 tab after keyword"
475 elif len(after) > 1:
476 yield match.start(2), "E271 multiple spaces after keyword"
479@register_check
480def missing_whitespace_after_keyword(logical_line, tokens):
481 r"""Keywords should be followed by whitespace.
483 Okay: from foo import (bar, baz)
484 E275: from foo import(bar, baz)
485 E275: from importable.module import(bar, baz)
486 E275: if(foo): bar
487 """
488 for tok0, tok1 in zip(tokens, tokens[1:]):
489 # This must exclude the True/False/None singletons, which can
490 # appear e.g. as "if x is None:", and async/await, which were
491 # valid identifier names in old Python versions.
492 if (tok0.end == tok1.start and
493 tok0.type == tokenize.NAME and
494 keyword.iskeyword(tok0.string) and
495 tok0.string not in SINGLETONS and
496 not (tok0.string == 'except' and tok1.string == '*') and
497 not (tok0.string == 'yield' and tok1.string == ')') and
498 tok1.string not in ':\n'):
499 yield tok0.end, "E275 missing whitespace after keyword"
502@register_check
503def indentation(logical_line, previous_logical, indent_char,
504 indent_level, previous_indent_level,
505 indent_size):
506 r"""Use indent_size (PEP8 says 4) spaces per indentation level.
508 For really old code that you don't want to mess up, you can continue
509 to use 8-space tabs.
511 Okay: a = 1
512 Okay: if a == 0:\n a = 1
513 E111: a = 1
514 E114: # a = 1
516 Okay: for item in items:\n pass
517 E112: for item in items:\npass
518 E115: for item in items:\n# Hi\n pass
520 Okay: a = 1\nb = 2
521 E113: a = 1\n b = 2
522 E116: a = 1\n # b = 2
523 """
524 c = 0 if logical_line else 3
525 tmpl = "E11%d %s" if logical_line else "E11%d %s (comment)"
526 if indent_level % indent_size:
527 yield 0, tmpl % (
528 1 + c,
529 "indentation is not a multiple of " + str(indent_size),
530 )
531 indent_expect = previous_logical.endswith(':')
532 if indent_expect and indent_level <= previous_indent_level:
533 yield 0, tmpl % (2 + c, "expected an indented block")
534 elif not indent_expect and indent_level > previous_indent_level:
535 yield 0, tmpl % (3 + c, "unexpected indentation")
537 if indent_expect:
538 expected_indent_amount = 8 if indent_char == '\t' else 4
539 expected_indent_level = previous_indent_level + expected_indent_amount
540 if indent_level > expected_indent_level:
541 yield 0, tmpl % (7, 'over-indented')
544@register_check
545def continued_indentation(logical_line, tokens, indent_level, hang_closing,
546 indent_char, indent_size, noqa, verbose):
547 r"""Continuation lines indentation.
549 Continuation lines should align wrapped elements either vertically
550 using Python's implicit line joining inside parentheses, brackets
551 and braces, or using a hanging indent.
553 When using a hanging indent these considerations should be applied:
554 - there should be no arguments on the first line, and
555 - further indentation should be used to clearly distinguish itself
556 as a continuation line.
558 Okay: a = (\n)
559 E123: a = (\n )
561 Okay: a = (\n 42)
562 E121: a = (\n 42)
563 E122: a = (\n42)
564 E123: a = (\n 42\n )
565 E124: a = (24,\n 42\n)
566 E125: if (\n b):\n pass
567 E126: a = (\n 42)
568 E127: a = (24,\n 42)
569 E128: a = (24,\n 42)
570 E129: if (a or\n b):\n pass
571 E131: a = (\n 42\n 24)
572 """
573 first_row = tokens[0][2][0]
574 nrows = 1 + tokens[-1][2][0] - first_row
575 if noqa or nrows == 1:
576 return
578 # indent_next tells us whether the next block is indented; assuming
579 # that it is indented by 4 spaces, then we should not allow 4-space
580 # indents on the final continuation line; in turn, some other
581 # indents are allowed to have an extra 4 spaces.
582 indent_next = logical_line.endswith(':')
584 row = depth = 0
585 valid_hangs = (indent_size,) if indent_char != '\t' \
586 else (indent_size, indent_size * 2)
587 # remember how many brackets were opened on each line
588 parens = [0] * nrows
589 # relative indents of physical lines
590 rel_indent = [0] * nrows
591 # for each depth, collect a list of opening rows
592 open_rows = [[0]]
593 # for each depth, memorize the hanging indentation
594 hangs = [None]
595 # visual indents
596 indent_chances = {}
597 last_indent = tokens[0][2]
598 visual_indent = None
599 last_token_multiline = False
600 # for each depth, memorize the visual indent column
601 indent = [last_indent[1]]
602 if verbose >= 3:
603 print(">>> " + tokens[0][4].rstrip())
605 for token_type, text, start, end, line in tokens:
607 newline = row < start[0] - first_row
608 if newline:
609 row = start[0] - first_row
610 newline = not last_token_multiline and token_type not in NEWLINE
612 if newline:
613 # this is the beginning of a continuation line.
614 last_indent = start
615 if verbose >= 3:
616 print("... " + line.rstrip())
618 # record the initial indent.
619 rel_indent[row] = expand_indent(line) - indent_level
621 # identify closing bracket
622 close_bracket = (token_type == tokenize.OP and text in ']})')
624 # is the indent relative to an opening bracket line?
625 for open_row in reversed(open_rows[depth]):
626 hang = rel_indent[row] - rel_indent[open_row]
627 hanging_indent = hang in valid_hangs
628 if hanging_indent:
629 break
630 if hangs[depth]:
631 hanging_indent = (hang == hangs[depth])
632 # is there any chance of visual indent?
633 visual_indent = (not close_bracket and hang > 0 and
634 indent_chances.get(start[1]))
636 if close_bracket and indent[depth]:
637 # closing bracket for visual indent
638 if start[1] != indent[depth]:
639 yield (start, "E124 closing bracket does not match "
640 "visual indentation")
641 elif close_bracket and not hang:
642 # closing bracket matches indentation of opening
643 # bracket's line
644 if hang_closing:
645 yield start, "E133 closing bracket is missing indentation"
646 elif indent[depth] and start[1] < indent[depth]:
647 if visual_indent is not True:
648 # visual indent is broken
649 yield (start, "E128 continuation line "
650 "under-indented for visual indent")
651 elif hanging_indent or (indent_next and
652 rel_indent[row] == 2 * indent_size):
653 # hanging indent is verified
654 if close_bracket and not hang_closing:
655 yield (start, "E123 closing bracket does not match "
656 "indentation of opening bracket's line")
657 hangs[depth] = hang
658 elif visual_indent is True:
659 # visual indent is verified
660 indent[depth] = start[1]
661 elif visual_indent in (text, str):
662 # ignore token lined up with matching one from a
663 # previous line
664 pass
665 else:
666 # indent is broken
667 if hang <= 0:
668 error = "E122", "missing indentation or outdented"
669 elif indent[depth]:
670 error = "E127", "over-indented for visual indent"
671 elif not close_bracket and hangs[depth]:
672 error = "E131", "unaligned for hanging indent"
673 else:
674 hangs[depth] = hang
675 if hang > indent_size:
676 error = "E126", "over-indented for hanging indent"
677 else:
678 error = "E121", "under-indented for hanging indent"
679 yield start, "%s continuation line %s" % error
681 # look for visual indenting
682 if (parens[row] and
683 token_type not in (tokenize.NL, tokenize.COMMENT) and
684 not indent[depth]):
685 indent[depth] = start[1]
686 indent_chances[start[1]] = True
687 if verbose >= 4:
688 print(f"bracket depth {depth} indent to {start[1]}")
689 # deal with implicit string concatenation
690 elif token_type in (tokenize.STRING, tokenize.COMMENT, FSTRING_START):
691 indent_chances[start[1]] = str
692 # visual indent after assert/raise/with
693 elif not row and not depth and text in ["assert", "raise", "with"]:
694 indent_chances[end[1] + 1] = True
695 # special case for the "if" statement because len("if (") == 4
696 elif not indent_chances and not row and not depth and text == 'if':
697 indent_chances[end[1] + 1] = True
698 elif text == ':' and line[end[1]:].isspace():
699 open_rows[depth].append(row)
701 # keep track of bracket depth
702 if token_type == tokenize.OP:
703 if text in '([{':
704 depth += 1
705 indent.append(0)
706 hangs.append(None)
707 if len(open_rows) == depth:
708 open_rows.append([])
709 open_rows[depth].append(row)
710 parens[row] += 1
711 if verbose >= 4:
712 print("bracket depth %s seen, col %s, visual min = %s" %
713 (depth, start[1], indent[depth]))
714 elif text in ')]}' and depth > 0:
715 # parent indents should not be more than this one
716 prev_indent = indent.pop() or last_indent[1]
717 hangs.pop()
718 for d in range(depth):
719 if indent[d] > prev_indent:
720 indent[d] = 0
721 for ind in list(indent_chances):
722 if ind >= prev_indent:
723 del indent_chances[ind]
724 del open_rows[depth + 1:]
725 depth -= 1
726 if depth:
727 indent_chances[indent[depth]] = True
728 for idx in range(row, -1, -1):
729 if parens[idx]:
730 parens[idx] -= 1
731 break
732 assert len(indent) == depth + 1
733 if start[1] not in indent_chances:
734 # allow lining up tokens
735 indent_chances[start[1]] = text
737 last_token_multiline = (start[0] != end[0])
738 if last_token_multiline:
739 rel_indent[end[0] - first_row] = rel_indent[row]
741 if indent_next and expand_indent(line) == indent_level + indent_size:
742 pos = (start[0], indent[0] + indent_size)
743 if visual_indent:
744 code = "E129 visually indented line"
745 else:
746 code = "E125 continuation line"
747 yield pos, "%s with same indent as next logical line" % code
750@register_check
751def whitespace_before_parameters(logical_line, tokens):
752 r"""Avoid extraneous whitespace.
754 Avoid extraneous whitespace in the following situations:
755 - before the open parenthesis that starts the argument list of a
756 function call.
757 - before the open parenthesis that starts an indexing or slicing.
759 Okay: spam(1)
760 E211: spam (1)
762 Okay: dict['key'] = list[index]
763 E211: dict ['key'] = list[index]
764 E211: dict['key'] = list [index]
765 """
766 prev_type, prev_text, __, prev_end, __ = tokens[0]
767 for index in range(1, len(tokens)):
768 token_type, text, start, end, __ = tokens[index]
769 if (
770 token_type == tokenize.OP and
771 text in '([' and
772 start != prev_end and
773 (prev_type == tokenize.NAME or prev_text in '}])') and
774 # Syntax "class A (B):" is allowed, but avoid it
775 (index < 2 or tokens[index - 2][1] != 'class') and
776 # Allow "return (a.foo for a in range(5))"
777 not keyword.iskeyword(prev_text) and
778 (
779 sys.version_info < (3, 9) or
780 # 3.12+: type is a soft keyword but no braces after
781 prev_text == 'type' or
782 not keyword.issoftkeyword(prev_text)
783 )
784 ):
785 yield prev_end, "E211 whitespace before '%s'" % text
786 prev_type = token_type
787 prev_text = text
788 prev_end = end
791@register_check
792def whitespace_around_operator(logical_line):
793 r"""Avoid extraneous whitespace around an operator.
795 Okay: a = 12 + 3
796 E221: a = 4 + 5
797 E222: a = 4 + 5
798 E223: a = 4\t+ 5
799 E224: a = 4 +\t5
800 """
801 for match in OPERATOR_REGEX.finditer(logical_line):
802 before, after = match.groups()
804 if '\t' in before:
805 yield match.start(1), "E223 tab before operator"
806 elif len(before) > 1:
807 yield match.start(1), "E221 multiple spaces before operator"
809 if '\t' in after:
810 yield match.start(2), "E224 tab after operator"
811 elif len(after) > 1:
812 yield match.start(2), "E222 multiple spaces after operator"
815@register_check
816def missing_whitespace(logical_line, tokens):
817 r"""Surround operators with the correct amount of whitespace.
819 - Always surround these binary operators with a single space on
820 either side: assignment (=), augmented assignment (+=, -= etc.),
821 comparisons (==, <, >, !=, <=, >=, in, not in, is, is not),
822 Booleans (and, or, not).
824 - Each comma, semicolon or colon should be followed by whitespace.
826 - If operators with different priorities are used, consider adding
827 whitespace around the operators with the lowest priorities.
829 Okay: i = i + 1
830 Okay: submitted += 1
831 Okay: x = x * 2 - 1
832 Okay: hypot2 = x * x + y * y
833 Okay: c = (a + b) * (a - b)
834 Okay: foo(bar, key='word', *args, **kwargs)
835 Okay: alpha[:-i]
836 Okay: [a, b]
837 Okay: (3,)
838 Okay: a[3,] = 1
839 Okay: a[1:4]
840 Okay: a[:4]
841 Okay: a[1:]
842 Okay: a[1:4:2]
844 E225: i=i+1
845 E225: submitted +=1
846 E225: x = x /2 - 1
847 E225: z = x **y
848 E225: z = 1and 1
849 E226: c = (a+b) * (a-b)
850 E226: hypot2 = x*x + y*y
851 E227: c = a|b
852 E228: msg = fmt%(errno, errmsg)
853 E231: ['a','b']
854 E231: foo(bar,baz)
855 E231: [{'a':'b'}]
856 """
857 need_space = False
858 prev_type = tokenize.OP
859 prev_text = prev_end = None
860 operator_types = (tokenize.OP, tokenize.NAME)
861 brace_stack = []
862 for token_type, text, start, end, line in tokens:
863 if token_type == tokenize.OP and text in {'[', '(', '{'}:
864 brace_stack.append(text)
865 elif token_type == FSTRING_START: # pragma: >=3.12 cover
866 brace_stack.append('f')
867 elif token_type == tokenize.NAME and text == 'lambda':
868 brace_stack.append('l')
869 elif brace_stack:
870 if token_type == tokenize.OP and text in {']', ')', '}'}:
871 brace_stack.pop()
872 elif token_type == FSTRING_END: # pragma: >=3.12 cover
873 brace_stack.pop()
874 elif (
875 brace_stack[-1] == 'l' and
876 token_type == tokenize.OP and
877 text == ':'
878 ):
879 brace_stack.pop()
881 if token_type in SKIP_COMMENTS:
882 continue
884 if token_type == tokenize.OP and text in {',', ';', ':'}:
885 next_char = line[end[1]:end[1] + 1]
886 if next_char not in WHITESPACE and next_char not in '\r\n':
887 # slice
888 if text == ':' and brace_stack[-1:] == ['[']:
889 pass
890 # 3.12+ fstring format specifier
891 elif text == ':' and brace_stack[-2:] == ['f', '{']: # pragma: >=3.12 cover # noqa: E501
892 pass
893 # tuple (and list for some reason?)
894 elif text == ',' and next_char in ')]':
895 pass
896 else:
897 yield start, f'E231 missing whitespace after {text!r}'
899 if need_space:
900 if start != prev_end:
901 # Found a (probably) needed space
902 if need_space is not True and not need_space[1]:
903 yield (need_space[0],
904 "E225 missing whitespace around operator")
905 need_space = False
906 elif (
907 # def f(a, /, b):
908 # ^
909 # def f(a, b, /):
910 # ^
911 # f = lambda a, /:
912 # ^
913 prev_text == '/' and text in {',', ')', ':'} or
914 # def f(a, b, /):
915 # ^
916 prev_text == ')' and text == ':'
917 ):
918 # Tolerate the "/" operator in function definition
919 # For more info see PEP570
920 pass
921 else:
922 if need_space is True or need_space[1]:
923 # A needed trailing space was not found
924 yield prev_end, "E225 missing whitespace around operator"
925 elif prev_text != '**':
926 code, optype = 'E226', 'arithmetic'
927 if prev_text == '%':
928 code, optype = 'E228', 'modulo'
929 elif prev_text not in ARITHMETIC_OP:
930 code, optype = 'E227', 'bitwise or shift'
931 yield (need_space[0], "%s missing whitespace "
932 "around %s operator" % (code, optype))
933 need_space = False
934 elif token_type in operator_types and prev_end is not None:
935 if (
936 text == '=' and (
937 # allow lambda default args: lambda x=None: None
938 brace_stack[-1:] == ['l'] or
939 # allow keyword args or defaults: foo(bar=None).
940 brace_stack[-1:] == ['('] or
941 # allow python 3.8 fstring repr specifier
942 brace_stack[-2:] == ['f', '{']
943 )
944 ):
945 pass
946 elif text in WS_NEEDED_OPERATORS:
947 need_space = True
948 elif text in UNARY_OPERATORS:
949 # Check if the operator is used as a binary operator
950 # Allow unary operators: -123, -x, +1.
951 # Allow argument unpacking: foo(*args, **kwargs).
952 if prev_type == tokenize.OP and prev_text in '}])' or (
953 prev_type != tokenize.OP and
954 prev_text not in KEYWORDS and (
955 sys.version_info < (3, 9) or
956 not keyword.issoftkeyword(prev_text)
957 )
958 ):
959 need_space = None
960 elif text in WS_OPTIONAL_OPERATORS:
961 need_space = None
963 if need_space is None:
964 # Surrounding space is optional, but ensure that
965 # trailing space matches opening space
966 need_space = (prev_end, start != prev_end)
967 elif need_space and start == prev_end:
968 # A needed opening space was not found
969 yield prev_end, "E225 missing whitespace around operator"
970 need_space = False
971 prev_type = token_type
972 prev_text = text
973 prev_end = end
976@register_check
977def whitespace_around_comma(logical_line):
978 r"""Avoid extraneous whitespace after a comma or a colon.
980 Note: these checks are disabled by default
982 Okay: a = (1, 2)
983 E241: a = (1, 2)
984 E242: a = (1,\t2)
985 """
986 line = logical_line
987 for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
988 found = m.start() + 1
989 if '\t' in m.group():
990 yield found, "E242 tab after '%s'" % m.group()[0]
991 else:
992 yield found, "E241 multiple spaces after '%s'" % m.group()[0]
995@register_check
996def whitespace_around_named_parameter_equals(logical_line, tokens):
997 r"""Don't use spaces around the '=' sign in function arguments.
999 Don't use spaces around the '=' sign when used to indicate a
1000 keyword argument or a default parameter value, except when
1001 using a type annotation.
1003 Okay: def complex(real, imag=0.0):
1004 Okay: return magic(r=real, i=imag)
1005 Okay: boolean(a == b)
1006 Okay: boolean(a != b)
1007 Okay: boolean(a <= b)
1008 Okay: boolean(a >= b)
1009 Okay: def foo(arg: int = 42):
1010 Okay: async def foo(arg: int = 42):
1012 E251: def complex(real, imag = 0.0):
1013 E251: return magic(r = real, i = imag)
1014 E252: def complex(real, image: float=0.0):
1015 """
1016 parens = 0
1017 no_space = False
1018 require_space = False
1019 prev_end = None
1020 annotated_func_arg = False
1021 in_def = bool(STARTSWITH_DEF_REGEX.match(logical_line))
1023 message = "E251 unexpected spaces around keyword / parameter equals"
1024 missing_message = "E252 missing whitespace around parameter equals"
1026 for token_type, text, start, end, line in tokens:
1027 if token_type == tokenize.NL:
1028 continue
1029 if no_space:
1030 no_space = False
1031 if start != prev_end:
1032 yield (prev_end, message)
1033 if require_space:
1034 require_space = False
1035 if start == prev_end:
1036 yield (prev_end, missing_message)
1037 if token_type == tokenize.OP:
1038 if text in '([':
1039 parens += 1
1040 elif text in ')]':
1041 parens -= 1
1042 elif in_def and text == ':' and parens == 1:
1043 annotated_func_arg = True
1044 elif parens == 1 and text == ',':
1045 annotated_func_arg = False
1046 elif parens and text == '=':
1047 if annotated_func_arg and parens == 1:
1048 require_space = True
1049 if start == prev_end:
1050 yield (prev_end, missing_message)
1051 else:
1052 no_space = True
1053 if start != prev_end:
1054 yield (prev_end, message)
1055 if not parens:
1056 annotated_func_arg = False
1058 prev_end = end
1061@register_check
1062def whitespace_before_comment(logical_line, tokens):
1063 """Separate inline comments by at least two spaces.
1065 An inline comment is a comment on the same line as a statement.
1066 Inline comments should be separated by at least two spaces from the
1067 statement. They should start with a # and a single space.
1069 Each line of a block comment starts with a # and one or multiple
1070 spaces as there can be indented text inside the comment.
1072 Okay: x = x + 1 # Increment x
1073 Okay: x = x + 1 # Increment x
1074 Okay: # Block comments:
1075 Okay: # - Block comment list
1076 Okay: # \xa0- Block comment list
1077 E261: x = x + 1 # Increment x
1078 E262: x = x + 1 #Increment x
1079 E262: x = x + 1 # Increment x
1080 E262: x = x + 1 # \xa0Increment x
1081 E265: #Block comment
1082 E266: ### Block comment
1083 """
1084 prev_end = (0, 0)
1085 for token_type, text, start, end, line in tokens:
1086 if token_type == tokenize.COMMENT:
1087 inline_comment = line[:start[1]].strip()
1088 if inline_comment:
1089 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
1090 yield (prev_end,
1091 "E261 at least two spaces before inline comment")
1092 symbol, sp, comment = text.partition(' ')
1093 bad_prefix = symbol not in '#:' and (symbol.lstrip('#')[:1] or '#')
1094 if inline_comment:
1095 if bad_prefix or comment[:1] in WHITESPACE:
1096 yield start, "E262 inline comment should start with '# '"
1097 elif bad_prefix and (bad_prefix != '!' or start[0] > 1):
1098 if bad_prefix != '#':
1099 yield start, "E265 block comment should start with '# '"
1100 elif comment:
1101 yield start, "E266 too many leading '#' for block comment"
1102 elif token_type != tokenize.NL:
1103 prev_end = end
1106@register_check
1107def imports_on_separate_lines(logical_line):
1108 r"""Place imports on separate lines.
1110 Okay: import os\nimport sys
1111 E401: import sys, os
1113 Okay: from subprocess import Popen, PIPE
1114 Okay: from myclas import MyClass
1115 Okay: from foo.bar.yourclass import YourClass
1116 Okay: import myclass
1117 Okay: import foo.bar.yourclass
1118 """
1119 line = logical_line
1120 if line.startswith('import '):
1121 found = line.find(',')
1122 if -1 < found and ';' not in line[:found]:
1123 yield found, "E401 multiple imports on one line"
1126@register_check
1127def module_imports_on_top_of_file(
1128 logical_line, indent_level, checker_state, noqa):
1129 r"""Place imports at the top of the file.
1131 Always put imports at the top of the file, just after any module
1132 comments and docstrings, and before module globals and constants.
1134 Okay: import os
1135 Okay: # this is a comment\nimport os
1136 Okay: '''this is a module docstring'''\nimport os
1137 Okay: r'''this is a module docstring'''\nimport os
1138 E402: a=1\nimport os
1139 E402: 'One string'\n"Two string"\nimport os
1140 E402: a=1\nfrom sys import x
1142 Okay: if x:\n import os
1143 """ # noqa
1144 def is_string_literal(line):
1145 if line[0] in 'uUbB':
1146 line = line[1:]
1147 if line and line[0] in 'rR':
1148 line = line[1:]
1149 return line and (line[0] == '"' or line[0] == "'")
1151 allowed_keywords = (
1152 'try', 'except', 'else', 'finally', 'with', 'if', 'elif')
1154 if indent_level: # Allow imports in conditional statement/function
1155 return
1156 if not logical_line: # Allow empty lines or comments
1157 return
1158 if noqa:
1159 return
1160 line = logical_line
1161 if line.startswith('import ') or line.startswith('from '):
1162 if checker_state.get('seen_non_imports', False):
1163 yield 0, "E402 module level import not at top of file"
1164 elif re.match(DUNDER_REGEX, line):
1165 return
1166 elif any(line.startswith(kw) for kw in allowed_keywords):
1167 # Allow certain keywords intermixed with imports in order to
1168 # support conditional or filtered importing
1169 return
1170 elif is_string_literal(line):
1171 # The first literal is a docstring, allow it. Otherwise, report
1172 # error.
1173 if checker_state.get('seen_docstring', False):
1174 checker_state['seen_non_imports'] = True
1175 else:
1176 checker_state['seen_docstring'] = True
1177 else:
1178 checker_state['seen_non_imports'] = True
1181@register_check
1182def compound_statements(logical_line):
1183 r"""Compound statements (on the same line) are generally
1184 discouraged.
1186 While sometimes it's okay to put an if/for/while with a small body
1187 on the same line, never do this for multi-clause statements.
1188 Also avoid folding such long lines!
1190 Always use a def statement instead of an assignment statement that
1191 binds a lambda expression directly to a name.
1193 Okay: if foo == 'blah':\n do_blah_thing()
1194 Okay: do_one()
1195 Okay: do_two()
1196 Okay: do_three()
1198 E701: if foo == 'blah': do_blah_thing()
1199 E701: for x in lst: total += x
1200 E701: while t < 10: t = delay()
1201 E701: if foo == 'blah': do_blah_thing()
1202 E701: else: do_non_blah_thing()
1203 E701: try: something()
1204 E701: finally: cleanup()
1205 E701: if foo == 'blah': one(); two(); three()
1206 E702: do_one(); do_two(); do_three()
1207 E703: do_four(); # useless semicolon
1208 E704: def f(x): return 2*x
1209 E731: f = lambda x: 2*x
1210 """
1211 line = logical_line
1212 last_char = len(line) - 1
1213 found = line.find(':')
1214 prev_found = 0
1215 counts = {char: 0 for char in '{}[]()'}
1216 while -1 < found < last_char:
1217 update_counts(line[prev_found:found], counts)
1218 if (
1219 counts['{'] <= counts['}'] and # {'a': 1} (dict)
1220 counts['['] <= counts[']'] and # [1:2] (slice)
1221 counts['('] <= counts[')'] and # (annotation)
1222 line[found + 1] != '=' # assignment expression
1223 ):
1224 lambda_kw = LAMBDA_REGEX.search(line, 0, found)
1225 if lambda_kw:
1226 before = line[:lambda_kw.start()].rstrip()
1227 if before[-1:] == '=' and before[:-1].strip().isidentifier():
1228 yield 0, ("E731 do not assign a lambda expression, use a "
1229 "def")
1230 break
1231 if STARTSWITH_DEF_REGEX.match(line):
1232 yield 0, "E704 multiple statements on one line (def)"
1233 elif STARTSWITH_INDENT_STATEMENT_REGEX.match(line):
1234 yield found, "E701 multiple statements on one line (colon)"
1235 prev_found = found
1236 found = line.find(':', found + 1)
1237 found = line.find(';')
1238 while -1 < found:
1239 if found < last_char:
1240 yield found, "E702 multiple statements on one line (semicolon)"
1241 else:
1242 yield found, "E703 statement ends with a semicolon"
1243 found = line.find(';', found + 1)
1246@register_check
1247def explicit_line_join(logical_line, tokens):
1248 r"""Avoid explicit line join between brackets.
1250 The preferred way of wrapping long lines is by using Python's
1251 implied line continuation inside parentheses, brackets and braces.
1252 Long lines can be broken over multiple lines by wrapping expressions
1253 in parentheses. These should be used in preference to using a
1254 backslash for line continuation.
1256 E502: aaa = [123, \\n 123]
1257 E502: aaa = ("bbb " \\n "ccc")
1259 Okay: aaa = [123,\n 123]
1260 Okay: aaa = ("bbb "\n "ccc")
1261 Okay: aaa = "bbb " \\n "ccc"
1262 Okay: aaa = 123 # \\
1263 """
1264 prev_start = prev_end = parens = 0
1265 comment = False
1266 backslash = None
1267 for token_type, text, start, end, line in tokens:
1268 if token_type == tokenize.COMMENT:
1269 comment = True
1270 if start[0] != prev_start and parens and backslash and not comment:
1271 yield backslash, "E502 the backslash is redundant between brackets"
1272 if end[0] != prev_end:
1273 if line.rstrip('\r\n').endswith('\\'):
1274 backslash = (end[0], len(line.splitlines()[-1]) - 1)
1275 else:
1276 backslash = None
1277 prev_start = prev_end = end[0]
1278 else:
1279 prev_start = start[0]
1280 if token_type == tokenize.OP:
1281 if text in '([{':
1282 parens += 1
1283 elif text in ')]}':
1284 parens -= 1
1287# The % character is strictly speaking a binary operator, but the
1288# common usage seems to be to put it next to the format parameters,
1289# after a line break.
1290_SYMBOLIC_OPS = frozenset("()[]{},:.;@=%~") | frozenset(("...",))
1293def _is_binary_operator(token_type, text):
1294 return (
1295 token_type == tokenize.OP or
1296 text in {'and', 'or'}
1297 ) and (
1298 text not in _SYMBOLIC_OPS
1299 )
1302def _break_around_binary_operators(tokens):
1303 """Private function to reduce duplication.
1305 This factors out the shared details between
1306 :func:`break_before_binary_operator` and
1307 :func:`break_after_binary_operator`.
1308 """
1309 line_break = False
1310 unary_context = True
1311 # Previous non-newline token types and text
1312 previous_token_type = None
1313 previous_text = None
1314 for token_type, text, start, end, line in tokens:
1315 if token_type == tokenize.COMMENT:
1316 continue
1317 if ('\n' in text or '\r' in text) and token_type != tokenize.STRING:
1318 line_break = True
1319 else:
1320 yield (token_type, text, previous_token_type, previous_text,
1321 line_break, unary_context, start)
1322 unary_context = text in '([{,;'
1323 line_break = False
1324 previous_token_type = token_type
1325 previous_text = text
1328@register_check
1329def break_before_binary_operator(logical_line, tokens):
1330 r"""
1331 Avoid breaks before binary operators.
1333 The preferred place to break around a binary operator is after the
1334 operator, not before it.
1336 W503: (width == 0\n + height == 0)
1337 W503: (width == 0\n and height == 0)
1338 W503: var = (1\n & ~2)
1339 W503: var = (1\n / -2)
1340 W503: var = (1\n + -1\n + -2)
1342 Okay: foo(\n -x)
1343 Okay: foo(x\n [])
1344 Okay: x = '''\n''' + ''
1345 Okay: foo(x,\n -y)
1346 Okay: foo(x, # comment\n -y)
1347 """
1348 for context in _break_around_binary_operators(tokens):
1349 (token_type, text, previous_token_type, previous_text,
1350 line_break, unary_context, start) = context
1351 if (_is_binary_operator(token_type, text) and line_break and
1352 not unary_context and
1353 not _is_binary_operator(previous_token_type,
1354 previous_text)):
1355 yield start, "W503 line break before binary operator"
1358@register_check
1359def break_after_binary_operator(logical_line, tokens):
1360 r"""
1361 Avoid breaks after binary operators.
1363 The preferred place to break around a binary operator is before the
1364 operator, not after it.
1366 W504: (width == 0 +\n height == 0)
1367 W504: (width == 0 and\n height == 0)
1368 W504: var = (1 &\n ~2)
1370 Okay: foo(\n -x)
1371 Okay: foo(x\n [])
1372 Okay: x = '''\n''' + ''
1373 Okay: x = '' + '''\n'''
1374 Okay: foo(x,\n -y)
1375 Okay: foo(x, # comment\n -y)
1377 The following should be W504 but unary_context is tricky with these
1378 Okay: var = (1 /\n -2)
1379 Okay: var = (1 +\n -1 +\n -2)
1380 """
1381 prev_start = None
1382 for context in _break_around_binary_operators(tokens):
1383 (token_type, text, previous_token_type, previous_text,
1384 line_break, unary_context, start) = context
1385 if (_is_binary_operator(previous_token_type, previous_text) and
1386 line_break and
1387 not unary_context and
1388 not _is_binary_operator(token_type, text)):
1389 yield prev_start, "W504 line break after binary operator"
1390 prev_start = start
1393@register_check
1394def comparison_to_singleton(logical_line, noqa):
1395 r"""Comparison to singletons should use "is" or "is not".
1397 Comparisons to singletons like None should always be done
1398 with "is" or "is not", never the equality operators.
1400 Okay: if arg is not None:
1401 E711: if arg != None:
1402 E711: if None == arg:
1403 E712: if arg == True:
1404 E712: if False == arg:
1406 Also, beware of writing if x when you really mean if x is not None
1407 -- e.g. when testing whether a variable or argument that defaults to
1408 None was set to some other value. The other value might have a type
1409 (such as a container) that could be false in a boolean context!
1410 """
1411 if noqa:
1412 return
1414 for match in COMPARE_SINGLETON_REGEX.finditer(logical_line):
1415 singleton = match.group(1) or match.group(3)
1416 same = (match.group(2) == '==')
1418 msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
1419 if singleton in ('None',):
1420 code = 'E711'
1421 else:
1422 code = 'E712'
1423 nonzero = ((singleton == 'True' and same) or
1424 (singleton == 'False' and not same))
1425 msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
1426 yield match.start(2), ("%s comparison to %s should be %s" %
1427 (code, singleton, msg))
1430@register_check
1431def comparison_negative(logical_line):
1432 r"""Negative comparison should be done using "not in" and "is not".
1434 Okay: if x not in y:\n pass
1435 Okay: assert (X in Y or X is Z)
1436 Okay: if not (X in Y):\n pass
1437 Okay: zz = x is not y
1438 E713: Z = not X in Y
1439 E713: if not X.B in Y:\n pass
1440 E714: if not X is Y:\n pass
1441 E714: Z = not X.B is Y
1442 """
1443 match = COMPARE_NEGATIVE_REGEX.search(logical_line)
1444 if match:
1445 pos = match.start(1)
1446 if match.group(2) == 'in':
1447 yield pos, "E713 test for membership should be 'not in'"
1448 else:
1449 yield pos, "E714 test for object identity should be 'is not'"
1452@register_check
1453def comparison_type(logical_line, noqa):
1454 r"""Object type comparisons should `is` / `is not` / `isinstance()`.
1456 Do not compare types directly.
1458 Okay: if isinstance(obj, int):
1459 Okay: if type(obj) is int:
1460 E721: if type(obj) == type(1):
1461 """
1462 match = COMPARE_TYPE_REGEX.search(logical_line)
1463 if match and not noqa:
1464 inst = match.group(1)
1465 if inst and inst.isidentifier() and inst not in SINGLETONS:
1466 return # Allow comparison for types which are not obvious
1467 yield (
1468 match.start(),
1469 "E721 do not compare types, for exact checks use `is` / `is not`, "
1470 "for instance checks use `isinstance()`",
1471 )
1474@register_check
1475def bare_except(logical_line, noqa):
1476 r"""When catching exceptions, mention specific exceptions when
1477 possible.
1479 Okay: except Exception:
1480 Okay: except BaseException:
1481 E722: except:
1482 """
1483 if noqa:
1484 return
1486 match = BLANK_EXCEPT_REGEX.match(logical_line)
1487 if match:
1488 yield match.start(), "E722 do not use bare 'except'"
1491@register_check
1492def ambiguous_identifier(logical_line, tokens):
1493 r"""Never use the characters 'l', 'O', or 'I' as variable names.
1495 In some fonts, these characters are indistinguishable from the
1496 numerals one and zero. When tempted to use 'l', use 'L' instead.
1498 Okay: L = 0
1499 Okay: o = 123
1500 Okay: i = 42
1501 E741: l = 0
1502 E741: O = 123
1503 E741: I = 42
1505 Variables can be bound in several other contexts, including class
1506 and function definitions, lambda functions, 'global' and 'nonlocal'
1507 statements, exception handlers, and 'with' and 'for' statements.
1508 In addition, we have a special handling for function parameters.
1510 Okay: except AttributeError as o:
1511 Okay: with lock as L:
1512 Okay: foo(l=12)
1513 Okay: foo(l=I)
1514 Okay: for a in foo(l=12):
1515 Okay: lambda arg: arg * l
1516 Okay: lambda a=l[I:5]: None
1517 Okay: lambda x=a.I: None
1518 Okay: if l >= 12:
1519 E741: except AttributeError as O:
1520 E741: with lock as l:
1521 E741: global I
1522 E741: nonlocal l
1523 E741: def foo(l):
1524 E741: def foo(l=12):
1525 E741: l = foo(l=12)
1526 E741: for l in range(10):
1527 E741: [l for l in lines if l]
1528 E741: lambda l: None
1529 E741: lambda a=x[1:5], l: None
1530 E741: lambda **l:
1531 E741: def f(**l):
1532 E742: class I(object):
1533 E743: def l(x):
1534 """
1535 func_depth = None # set to brace depth if 'def' or 'lambda' is found
1536 seen_colon = False # set to true if we're done with function parameters
1537 brace_depth = 0
1538 idents_to_avoid = ('l', 'O', 'I')
1539 prev_type, prev_text, prev_start, prev_end, __ = tokens[0]
1540 for index in range(1, len(tokens)):
1541 token_type, text, start, end, line = tokens[index]
1542 ident = pos = None
1543 # find function definitions
1544 if prev_text in {'def', 'lambda'}:
1545 func_depth = brace_depth
1546 seen_colon = False
1547 elif (
1548 func_depth is not None and
1549 text == ':' and
1550 brace_depth == func_depth
1551 ):
1552 seen_colon = True
1553 # update parameter parentheses level
1554 if text in '([{':
1555 brace_depth += 1
1556 elif text in ')]}':
1557 brace_depth -= 1
1558 # identifiers on the lhs of an assignment operator
1559 if text == ':=' or (text == '=' and brace_depth == 0):
1560 if prev_text in idents_to_avoid:
1561 ident = prev_text
1562 pos = prev_start
1563 # identifiers bound to values with 'as', 'for',
1564 # 'global', or 'nonlocal'
1565 if prev_text in ('as', 'for', 'global', 'nonlocal'):
1566 if text in idents_to_avoid:
1567 ident = text
1568 pos = start
1569 # function / lambda parameter definitions
1570 if (
1571 func_depth is not None and
1572 not seen_colon and
1573 index < len(tokens) - 1 and tokens[index + 1][1] in ':,=)' and
1574 prev_text in {'lambda', ',', '*', '**', '('} and
1575 text in idents_to_avoid
1576 ):
1577 ident = text
1578 pos = start
1579 if prev_text == 'class':
1580 if text in idents_to_avoid:
1581 yield start, "E742 ambiguous class definition '%s'" % text
1582 if prev_text == 'def':
1583 if text in idents_to_avoid:
1584 yield start, "E743 ambiguous function definition '%s'" % text
1585 if ident:
1586 yield pos, "E741 ambiguous variable name '%s'" % ident
1587 prev_text = text
1588 prev_start = start
1591@register_check
1592def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
1593 r"""Invalid escape sequences are deprecated in Python 3.6.
1595 Okay: regex = r'\.png$'
1596 W605: regex = '\.png$'
1597 """
1598 if noqa:
1599 return
1601 # https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
1602 valid = [
1603 '\n',
1604 '\\',
1605 '\'',
1606 '"',
1607 'a',
1608 'b',
1609 'f',
1610 'n',
1611 'r',
1612 't',
1613 'v',
1614 '0', '1', '2', '3', '4', '5', '6', '7',
1615 'x',
1617 # Escape sequences only recognized in string literals
1618 'N',
1619 'u',
1620 'U',
1621 ]
1623 prefixes = []
1624 for token_type, text, start, _, _ in tokens:
1625 if token_type in {tokenize.STRING, FSTRING_START}:
1626 # Extract string modifiers (e.g. u or r)
1627 prefixes.append(text[:text.index(text[-1])].lower())
1629 if token_type in {tokenize.STRING, FSTRING_MIDDLE}:
1630 if 'r' not in prefixes[-1]:
1631 start_line, start_col = start
1632 pos = text.find('\\')
1633 while pos >= 0:
1634 pos += 1
1635 if text[pos] not in valid:
1636 line = start_line + text.count('\n', 0, pos)
1637 if line == start_line:
1638 col = start_col + pos
1639 else:
1640 col = pos - text.rfind('\n', 0, pos) - 1
1641 yield (
1642 (line, col - 1),
1643 f"W605 invalid escape sequence '\\{text[pos]}'"
1644 )
1645 pos = text.find('\\', pos + 1)
1647 if token_type in {tokenize.STRING, FSTRING_END}:
1648 prefixes.pop()
1651########################################################################
1652@register_check
1653def maximum_doc_length(logical_line, max_doc_length, noqa, tokens):
1654 r"""Limit all doc lines to a maximum of 72 characters.
1656 For flowing long blocks of text (docstrings or comments), limiting
1657 the length to 72 characters is recommended.
1659 Reports warning W505
1660 """
1661 if max_doc_length is None or noqa:
1662 return
1664 prev_token = None
1665 skip_lines = set()
1666 # Skip lines that
1667 for token_type, text, start, end, line in tokens:
1668 if token_type not in SKIP_COMMENTS.union([tokenize.STRING]):
1669 skip_lines.add(line)
1671 for token_type, text, start, end, line in tokens:
1672 # Skip lines that aren't pure strings
1673 if token_type == tokenize.STRING and skip_lines:
1674 continue
1675 if token_type in (tokenize.STRING, tokenize.COMMENT):
1676 # Only check comment-only lines
1677 if prev_token is None or prev_token in SKIP_TOKENS:
1678 lines = line.splitlines()
1679 for line_num, physical_line in enumerate(lines):
1680 if start[0] + line_num == 1 and line.startswith('#!'):
1681 return
1682 length = len(physical_line)
1683 chunks = physical_line.split()
1684 if token_type == tokenize.COMMENT:
1685 if (len(chunks) == 2 and
1686 length - len(chunks[-1]) < MAX_DOC_LENGTH):
1687 continue
1688 if len(chunks) == 1 and line_num + 1 < len(lines):
1689 if (len(chunks) == 1 and
1690 length - len(chunks[-1]) < MAX_DOC_LENGTH):
1691 continue
1692 if length > max_doc_length:
1693 doc_error = (start[0] + line_num, max_doc_length)
1694 yield (doc_error, "W505 doc line too long "
1695 "(%d > %d characters)"
1696 % (length, max_doc_length))
1697 prev_token = token_type
1700########################################################################
1701# Helper functions
1702########################################################################
1705def readlines(filename):
1706 """Read the source code."""
1707 try:
1708 with tokenize.open(filename) as f:
1709 return f.readlines()
1710 except (LookupError, SyntaxError, UnicodeError):
1711 # Fall back if file encoding is improperly declared
1712 with open(filename, encoding='latin-1') as f:
1713 return f.readlines()
1716def stdin_get_value():
1717 """Read the value from stdin."""
1718 return io.TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1721noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search)
1724def expand_indent(line):
1725 r"""Return the amount of indentation.
1727 Tabs are expanded to the next multiple of 8.
1728 """
1729 line = line.rstrip('\n\r')
1730 if '\t' not in line:
1731 return len(line) - len(line.lstrip())
1732 result = 0
1733 for char in line:
1734 if char == '\t':
1735 result = result // 8 * 8 + 8
1736 elif char == ' ':
1737 result += 1
1738 else:
1739 break
1740 return result
1743def mute_string(text):
1744 """Replace contents with 'xxx' to prevent syntax matching."""
1745 # String modifiers (e.g. u or r)
1746 start = text.index(text[-1]) + 1
1747 end = len(text) - 1
1748 # Triple quotes
1749 if text[-3:] in ('"""', "'''"):
1750 start += 2
1751 end -= 2
1752 return text[:start] + 'x' * (end - start) + text[end:]
1755def parse_udiff(diff, patterns=None, parent='.'):
1756 """Return a dictionary of matching lines."""
1757 # For each file of the diff, the entry key is the filename,
1758 # and the value is a set of row numbers to consider.
1759 rv = {}
1760 path = nrows = None
1761 for line in diff.splitlines():
1762 if nrows:
1763 if line[:1] != '-':
1764 nrows -= 1
1765 continue
1766 if line[:3] == '@@ ':
1767 hunk_match = HUNK_REGEX.match(line)
1768 (row, nrows) = (int(g or '1') for g in hunk_match.groups())
1769 rv[path].update(range(row, row + nrows))
1770 elif line[:3] == '+++':
1771 path = line[4:].split('\t', 1)[0]
1772 # Git diff will use (i)ndex, (w)ork tree, (c)ommit and
1773 # (o)bject instead of a/b/c/d as prefixes for patches
1774 if path[:2] in ('b/', 'w/', 'i/'):
1775 path = path[2:]
1776 rv[path] = set()
1777 return {
1778 os.path.join(parent, filepath): rows
1779 for (filepath, rows) in rv.items()
1780 if rows and filename_match(filepath, patterns)
1781 }
1784def normalize_paths(value, parent=os.curdir):
1785 """Parse a comma-separated list of paths.
1787 Return a list of absolute paths.
1788 """
1789 if not value:
1790 return []
1791 if isinstance(value, list):
1792 return value
1793 paths = []
1794 for path in value.split(','):
1795 path = path.strip()
1796 if '/' in path:
1797 path = os.path.abspath(os.path.join(parent, path))
1798 paths.append(path.rstrip('/'))
1799 return paths
1802def filename_match(filename, patterns, default=True):
1803 """Check if patterns contains a pattern that matches filename.
1805 If patterns is unspecified, this always returns True.
1806 """
1807 if not patterns:
1808 return default
1809 return any(fnmatch(filename, pattern) for pattern in patterns)
1812def update_counts(s, counts):
1813 r"""Adds one to the counts of each appearance of characters in s,
1814 for characters in counts"""
1815 for char in s:
1816 if char in counts:
1817 counts[char] += 1
1820def _is_eol_token(token):
1821 return token[0] in NEWLINE or token[4][token[3][1]:].lstrip() == '\\\n'
1824########################################################################
1825# Framework to run all checks
1826########################################################################
1829class Checker:
1830 """Load a Python source file, tokenize it, check coding style."""
1832 def __init__(self, filename=None, lines=None,
1833 options=None, report=None, **kwargs):
1834 if options is None:
1835 options = StyleGuide(kwargs).options
1836 else:
1837 assert not kwargs
1838 self._io_error = None
1839 self._physical_checks = options.physical_checks
1840 self._logical_checks = options.logical_checks
1841 self._ast_checks = options.ast_checks
1842 self.max_line_length = options.max_line_length
1843 self.max_doc_length = options.max_doc_length
1844 self.indent_size = options.indent_size
1845 self.fstring_start = 0
1846 self.multiline = False # in a multiline string?
1847 self.hang_closing = options.hang_closing
1848 self.indent_size = options.indent_size
1849 self.verbose = options.verbose
1850 self.filename = filename
1851 # Dictionary where a checker can store its custom state.
1852 self._checker_states = {}
1853 if filename is None:
1854 self.filename = 'stdin'
1855 self.lines = lines or []
1856 elif filename == '-':
1857 self.filename = 'stdin'
1858 self.lines = stdin_get_value().splitlines(True)
1859 elif lines is None:
1860 try:
1861 self.lines = readlines(filename)
1862 except OSError:
1863 (exc_type, exc) = sys.exc_info()[:2]
1864 self._io_error = f'{exc_type.__name__}: {exc}'
1865 self.lines = []
1866 else:
1867 self.lines = lines
1868 if self.lines:
1869 ord0 = ord(self.lines[0][0])
1870 if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
1871 if ord0 == 0xfeff:
1872 self.lines[0] = self.lines[0][1:]
1873 elif self.lines[0][:3] == '\xef\xbb\xbf':
1874 self.lines[0] = self.lines[0][3:]
1875 self.report = report or options.report
1876 self.report_error = self.report.error
1877 self.noqa = False
1879 def report_invalid_syntax(self):
1880 """Check if the syntax is valid."""
1881 (exc_type, exc) = sys.exc_info()[:2]
1882 if len(exc.args) > 1:
1883 offset = exc.args[1]
1884 if len(offset) > 2:
1885 offset = offset[1:3]
1886 else:
1887 offset = (1, 0)
1888 self.report_error(offset[0], offset[1] or 0,
1889 f'E901 {exc_type.__name__}: {exc.args[0]}',
1890 self.report_invalid_syntax)
1892 def readline(self):
1893 """Get the next line from the input buffer."""
1894 if self.line_number >= self.total_lines:
1895 return ''
1896 line = self.lines[self.line_number]
1897 self.line_number += 1
1898 if self.indent_char is None and line[:1] in WHITESPACE:
1899 self.indent_char = line[0]
1900 return line
1902 def run_check(self, check, argument_names):
1903 """Run a check plugin."""
1904 arguments = []
1905 for name in argument_names:
1906 arguments.append(getattr(self, name))
1907 return check(*arguments)
1909 def init_checker_state(self, name, argument_names):
1910 """Prepare custom state for the specific checker plugin."""
1911 if 'checker_state' in argument_names:
1912 self.checker_state = self._checker_states.setdefault(name, {})
1914 def check_physical(self, line):
1915 """Run all physical checks on a raw input line."""
1916 self.physical_line = line
1917 for name, check, argument_names in self._physical_checks:
1918 self.init_checker_state(name, argument_names)
1919 result = self.run_check(check, argument_names)
1920 if result is not None:
1921 (offset, text) = result
1922 self.report_error(self.line_number, offset, text, check)
1923 if text[:4] == 'E101':
1924 self.indent_char = line[0]
1926 def build_tokens_line(self):
1927 """Build a logical line from tokens."""
1928 logical = []
1929 comments = []
1930 length = 0
1931 prev_row = prev_col = mapping = None
1932 for token_type, text, start, end, line in self.tokens:
1933 if token_type in SKIP_TOKENS:
1934 continue
1935 if not mapping:
1936 mapping = [(0, start)]
1937 if token_type == tokenize.COMMENT:
1938 comments.append(text)
1939 continue
1940 if token_type == tokenize.STRING:
1941 text = mute_string(text)
1942 elif token_type == FSTRING_MIDDLE: # pragma: >=3.12 cover
1943 text = 'x' * len(text)
1944 if prev_row:
1945 (start_row, start_col) = start
1946 if prev_row != start_row: # different row
1947 prev_text = self.lines[prev_row - 1][prev_col - 1]
1948 if prev_text == ',' or (prev_text not in '{[(' and
1949 text not in '}])'):
1950 text = ' ' + text
1951 elif prev_col != start_col: # different column
1952 text = line[prev_col:start_col] + text
1953 logical.append(text)
1954 length += len(text)
1955 mapping.append((length, end))
1956 (prev_row, prev_col) = end
1957 self.logical_line = ''.join(logical)
1958 self.noqa = comments and noqa(''.join(comments))
1959 return mapping
1961 def check_logical(self):
1962 """Build a line from tokens and run all logical checks on it."""
1963 self.report.increment_logical_line()
1964 mapping = self.build_tokens_line()
1965 if not mapping:
1966 return
1968 mapping_offsets = [offset for offset, _ in mapping]
1969 (start_row, start_col) = mapping[0][1]
1970 start_line = self.lines[start_row - 1]
1971 self.indent_level = expand_indent(start_line[:start_col])
1972 if self.blank_before < self.blank_lines:
1973 self.blank_before = self.blank_lines
1974 if self.verbose >= 2:
1975 print(self.logical_line[:80].rstrip())
1976 for name, check, argument_names in self._logical_checks:
1977 if self.verbose >= 4:
1978 print(' ' + name)
1979 self.init_checker_state(name, argument_names)
1980 for offset, text in self.run_check(check, argument_names) or ():
1981 if not isinstance(offset, tuple):
1982 # As mappings are ordered, bisecting is a fast way
1983 # to find a given offset in them.
1984 token_offset, pos = mapping[bisect.bisect_left(
1985 mapping_offsets, offset)]
1986 offset = (pos[0], pos[1] + offset - token_offset)
1987 self.report_error(offset[0], offset[1], text, check)
1988 if self.logical_line:
1989 self.previous_indent_level = self.indent_level
1990 self.previous_logical = self.logical_line
1991 if not self.indent_level:
1992 self.previous_unindented_logical_line = self.logical_line
1993 self.blank_lines = 0
1994 self.tokens = []
1996 def check_ast(self):
1997 """Build the file's AST and run all AST checks."""
1998 try:
1999 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
2000 except (ValueError, SyntaxError, TypeError):
2001 return self.report_invalid_syntax()
2002 for name, cls, __ in self._ast_checks:
2003 checker = cls(tree, self.filename)
2004 for lineno, offset, text, check in checker.run():
2005 if not self.lines or not noqa(self.lines[lineno - 1]):
2006 self.report_error(lineno, offset, text, check)
2008 def generate_tokens(self):
2009 """Tokenize file, run physical line checks and yield tokens."""
2010 if self._io_error:
2011 self.report_error(1, 0, 'E902 %s' % self._io_error, readlines)
2012 tokengen = tokenize.generate_tokens(self.readline)
2013 try:
2014 prev_physical = ''
2015 for token in tokengen:
2016 if token[2][0] > self.total_lines:
2017 return
2018 self.noqa = token[4] and noqa(token[4])
2019 self.maybe_check_physical(token, prev_physical)
2020 yield token
2021 prev_physical = token[4]
2022 except (SyntaxError, tokenize.TokenError):
2023 self.report_invalid_syntax()
2025 def maybe_check_physical(self, token, prev_physical):
2026 """If appropriate for token, check current physical line(s)."""
2027 # Called after every token, but act only on end of line.
2029 if token.type == FSTRING_START: # pragma: >=3.12 cover
2030 self.fstring_start = token.start[0]
2031 # a newline token ends a single physical line.
2032 elif _is_eol_token(token):
2033 # if the file does not end with a newline, the NEWLINE
2034 # token is inserted by the parser, but it does not contain
2035 # the previous physical line in `token[4]`
2036 if token.line == '':
2037 self.check_physical(prev_physical)
2038 else:
2039 self.check_physical(token.line)
2040 elif (
2041 token.type == tokenize.STRING and '\n' in token.string or
2042 token.type == FSTRING_END
2043 ):
2044 # Less obviously, a string that contains newlines is a
2045 # multiline string, either triple-quoted or with internal
2046 # newlines backslash-escaped. Check every physical line in
2047 # the string *except* for the last one: its newline is
2048 # outside of the multiline string, so we consider it a
2049 # regular physical line, and will check it like any other
2050 # physical line.
2051 #
2052 # Subtleties:
2053 # - we don't *completely* ignore the last line; if it
2054 # contains the magical "# noqa" comment, we disable all
2055 # physical checks for the entire multiline string
2056 # - have to wind self.line_number back because initially it
2057 # points to the last line of the string, and we want
2058 # check_physical() to give accurate feedback
2059 if noqa(token.line):
2060 return
2061 if token.type == FSTRING_END: # pragma: >=3.12 cover
2062 start = self.fstring_start
2063 else:
2064 start = token.start[0]
2065 end = token.end[0]
2067 self.multiline = True
2068 self.line_number = start
2069 for line_number in range(start, end):
2070 self.check_physical(self.lines[line_number - 1] + '\n')
2071 self.line_number += 1
2072 self.multiline = False
2074 def check_all(self, expected=None, line_offset=0):
2075 """Run all checks on the input file."""
2076 self.report.init_file(self.filename, self.lines, expected, line_offset)
2077 self.total_lines = len(self.lines)
2078 if self._ast_checks:
2079 self.check_ast()
2080 self.line_number = 0
2081 self.indent_char = None
2082 self.indent_level = self.previous_indent_level = 0
2083 self.previous_logical = ''
2084 self.previous_unindented_logical_line = ''
2085 self.tokens = []
2086 self.blank_lines = self.blank_before = 0
2087 parens = 0
2088 for token in self.generate_tokens():
2089 self.tokens.append(token)
2090 token_type, text = token[0:2]
2091 if self.verbose >= 3:
2092 if token[2][0] == token[3][0]:
2093 pos = '[{}:{}]'.format(token[2][1] or '', token[3][1])
2094 else:
2095 pos = 'l.%s' % token[3][0]
2096 print('l.%s\t%s\t%s\t%r' %
2097 (token[2][0], pos, tokenize.tok_name[token[0]], text))
2098 if token_type == tokenize.OP:
2099 if text in '([{':
2100 parens += 1
2101 elif text in '}])':
2102 parens -= 1
2103 elif not parens:
2104 if token_type in NEWLINE:
2105 if token_type == tokenize.NEWLINE:
2106 self.check_logical()
2107 self.blank_before = 0
2108 elif len(self.tokens) == 1:
2109 # The physical line contains only this token.
2110 self.blank_lines += 1
2111 del self.tokens[0]
2112 else:
2113 self.check_logical()
2114 if self.tokens:
2115 self.check_physical(self.lines[-1])
2116 self.check_logical()
2117 return self.report.get_file_results()
2120class BaseReport:
2121 """Collect the results of the checks."""
2123 print_filename = False
2125 def __init__(self, options):
2126 self._benchmark_keys = options.benchmark_keys
2127 self._ignore_code = options.ignore_code
2128 # Results
2129 self.elapsed = 0
2130 self.total_errors = 0
2131 self.counters = dict.fromkeys(self._benchmark_keys, 0)
2132 self.messages = {}
2134 def start(self):
2135 """Start the timer."""
2136 self._start_time = time.time()
2138 def stop(self):
2139 """Stop the timer."""
2140 self.elapsed = time.time() - self._start_time
2142 def init_file(self, filename, lines, expected, line_offset):
2143 """Signal a new file."""
2144 self.filename = filename
2145 self.lines = lines
2146 self.expected = expected or ()
2147 self.line_offset = line_offset
2148 self.file_errors = 0
2149 self.counters['files'] += 1
2150 self.counters['physical lines'] += len(lines)
2152 def increment_logical_line(self):
2153 """Signal a new logical line."""
2154 self.counters['logical lines'] += 1
2156 def error(self, line_number, offset, text, check):
2157 """Report an error, according to options."""
2158 code = text[:4]
2159 if self._ignore_code(code):
2160 return
2161 if code in self.counters:
2162 self.counters[code] += 1
2163 else:
2164 self.counters[code] = 1
2165 self.messages[code] = text[5:]
2166 # Don't care about expected errors or warnings
2167 if code in self.expected:
2168 return
2169 if self.print_filename and not self.file_errors:
2170 print(self.filename)
2171 self.file_errors += 1
2172 self.total_errors += 1
2173 return code
2175 def get_file_results(self):
2176 """Return the count of errors and warnings for this file."""
2177 return self.file_errors
2179 def get_count(self, prefix=''):
2180 """Return the total count of errors and warnings."""
2181 return sum(self.counters[key]
2182 for key in self.messages if key.startswith(prefix))
2184 def get_statistics(self, prefix=''):
2185 """Get statistics for message codes that start with the prefix.
2187 prefix='' matches all errors and warnings
2188 prefix='E' matches all errors
2189 prefix='W' matches all warnings
2190 prefix='E4' matches all errors that have to do with imports
2191 """
2192 return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
2193 for key in sorted(self.messages) if key.startswith(prefix)]
2195 def print_statistics(self, prefix=''):
2196 """Print overall statistics (number of errors and warnings)."""
2197 for line in self.get_statistics(prefix):
2198 print(line)
2200 def print_benchmark(self):
2201 """Print benchmark numbers."""
2202 print('{:<7.2f} {}'.format(self.elapsed, 'seconds elapsed'))
2203 if self.elapsed:
2204 for key in self._benchmark_keys:
2205 print('%-7d %s per second (%d total)' %
2206 (self.counters[key] / self.elapsed, key,
2207 self.counters[key]))
2210class FileReport(BaseReport):
2211 """Collect the results of the checks and print the filenames."""
2213 print_filename = True
2216class StandardReport(BaseReport):
2217 """Collect and print the results of the checks."""
2219 def __init__(self, options):
2220 super().__init__(options)
2221 self._fmt = REPORT_FORMAT.get(options.format.lower(),
2222 options.format)
2223 self._repeat = options.repeat
2224 self._show_source = options.show_source
2225 self._show_pep8 = options.show_pep8
2227 def init_file(self, filename, lines, expected, line_offset):
2228 """Signal a new file."""
2229 self._deferred_print = []
2230 return super().init_file(
2231 filename, lines, expected, line_offset)
2233 def error(self, line_number, offset, text, check):
2234 """Report an error, according to options."""
2235 code = super().error(line_number, offset, text, check)
2236 if code and (self.counters[code] == 1 or self._repeat):
2237 self._deferred_print.append(
2238 (line_number, offset, code, text[5:], check.__doc__))
2239 return code
2241 def get_file_results(self):
2242 """Print results and return the overall count for this file."""
2243 self._deferred_print.sort()
2244 for line_number, offset, code, text, doc in self._deferred_print:
2245 print(self._fmt % {
2246 'path': self.filename,
2247 'row': self.line_offset + line_number, 'col': offset + 1,
2248 'code': code, 'text': text,
2249 })
2250 if self._show_source:
2251 if line_number > len(self.lines):
2252 line = ''
2253 else:
2254 line = self.lines[line_number - 1]
2255 print(line.rstrip())
2256 print(re.sub(r'\S', ' ', line[:offset]) + '^')
2257 if self._show_pep8 and doc:
2258 print(' ' + doc.strip())
2260 # stdout is block buffered when not stdout.isatty().
2261 # line can be broken where buffer boundary since other
2262 # processes write to same file.
2263 # flush() after print() to avoid buffer boundary.
2264 # Typical buffer size is 8192. line written safely when
2265 # len(line) < 8192.
2266 sys.stdout.flush()
2267 return self.file_errors
2270class DiffReport(StandardReport):
2271 """Collect and print the results for the changed lines only."""
2273 def __init__(self, options):
2274 super().__init__(options)
2275 self._selected = options.selected_lines
2277 def error(self, line_number, offset, text, check):
2278 if line_number not in self._selected[self.filename]:
2279 return
2280 return super().error(line_number, offset, text, check)
2283class StyleGuide:
2284 """Initialize a PEP-8 instance with few options."""
2286 def __init__(self, *args, **kwargs):
2287 # build options from the command line
2288 self.checker_class = kwargs.pop('checker_class', Checker)
2289 parse_argv = kwargs.pop('parse_argv', False)
2290 config_file = kwargs.pop('config_file', False)
2291 parser = kwargs.pop('parser', None)
2292 # build options from dict
2293 options_dict = dict(*args, **kwargs)
2294 arglist = None if parse_argv else options_dict.get('paths', None)
2295 verbose = options_dict.get('verbose', None)
2296 options, self.paths = process_options(
2297 arglist, parse_argv, config_file, parser, verbose)
2298 if options_dict:
2299 options.__dict__.update(options_dict)
2300 if 'paths' in options_dict:
2301 self.paths = options_dict['paths']
2303 self.runner = self.input_file
2304 self.options = options
2306 if not options.reporter:
2307 options.reporter = BaseReport if options.quiet else StandardReport
2309 options.select = tuple(options.select or ())
2310 if not (options.select or options.ignore) and DEFAULT_IGNORE:
2311 # The default choice: ignore controversial checks
2312 options.ignore = tuple(DEFAULT_IGNORE.split(','))
2313 else:
2314 # Ignore all checks which are not explicitly selected
2315 options.ignore = ('',) if options.select else tuple(options.ignore)
2316 options.benchmark_keys = BENCHMARK_KEYS[:]
2317 options.ignore_code = self.ignore_code
2318 options.physical_checks = self.get_checks('physical_line')
2319 options.logical_checks = self.get_checks('logical_line')
2320 options.ast_checks = self.get_checks('tree')
2321 self.init_report()
2323 def init_report(self, reporter=None):
2324 """Initialize the report instance."""
2325 self.options.report = (reporter or self.options.reporter)(self.options)
2326 return self.options.report
2328 def check_files(self, paths=None):
2329 """Run all checks on the paths."""
2330 if paths is None:
2331 paths = self.paths
2332 report = self.options.report
2333 runner = self.runner
2334 report.start()
2335 try:
2336 for path in paths:
2337 if os.path.isdir(path):
2338 self.input_dir(path)
2339 elif not self.excluded(path):
2340 runner(path)
2341 except KeyboardInterrupt:
2342 print('... stopped')
2343 report.stop()
2344 return report
2346 def input_file(self, filename, lines=None, expected=None, line_offset=0):
2347 """Run all checks on a Python source file."""
2348 if self.options.verbose:
2349 print('checking %s' % filename)
2350 fchecker = self.checker_class(
2351 filename, lines=lines, options=self.options)
2352 return fchecker.check_all(expected=expected, line_offset=line_offset)
2354 def input_dir(self, dirname):
2355 """Check all files in this directory and all subdirectories."""
2356 dirname = dirname.rstrip('/')
2357 if self.excluded(dirname):
2358 return 0
2359 counters = self.options.report.counters
2360 verbose = self.options.verbose
2361 filepatterns = self.options.filename
2362 runner = self.runner
2363 for root, dirs, files in os.walk(dirname):
2364 if verbose:
2365 print('directory ' + root)
2366 counters['directories'] += 1
2367 for subdir in sorted(dirs):
2368 if self.excluded(subdir, root):
2369 dirs.remove(subdir)
2370 for filename in sorted(files):
2371 # contain a pattern that matches?
2372 if (
2373 filename_match(filename, filepatterns) and
2374 not self.excluded(filename, root)
2375 ):
2376 runner(os.path.join(root, filename))
2378 def excluded(self, filename, parent=None):
2379 """Check if the file should be excluded.
2381 Check if 'options.exclude' contains a pattern matching filename.
2382 """
2383 if not self.options.exclude:
2384 return False
2385 basename = os.path.basename(filename)
2386 if filename_match(basename, self.options.exclude):
2387 return True
2388 if parent:
2389 filename = os.path.join(parent, filename)
2390 filename = os.path.abspath(filename)
2391 return filename_match(filename, self.options.exclude)
2393 def ignore_code(self, code):
2394 """Check if the error code should be ignored.
2396 If 'options.select' contains a prefix of the error code,
2397 return False. Else, if 'options.ignore' contains a prefix of
2398 the error code, return True.
2399 """
2400 if len(code) < 4 and any(s.startswith(code)
2401 for s in self.options.select):
2402 return False
2403 return (code.startswith(self.options.ignore) and
2404 not code.startswith(self.options.select))
2406 def get_checks(self, argument_name):
2407 """Get all the checks for this category.
2409 Find all globally visible functions where the first argument
2410 name starts with argument_name and which contain selected tests.
2411 """
2412 checks = []
2413 for check, attrs in _checks[argument_name].items():
2414 (codes, args) = attrs
2415 if any(not (code and self.ignore_code(code)) for code in codes):
2416 checks.append((check.__name__, check, args))
2417 return sorted(checks)
2420def get_parser(prog='pycodestyle', version=__version__):
2421 """Create the parser for the program."""
2422 parser = OptionParser(prog=prog, version=version,
2423 usage="%prog [options] input ...")
2424 parser.config_options = [
2425 'exclude', 'filename', 'select', 'ignore', 'max-line-length',
2426 'max-doc-length', 'indent-size', 'hang-closing', 'count', 'format',
2427 'quiet', 'show-pep8', 'show-source', 'statistics', 'verbose']
2428 parser.add_option('-v', '--verbose', default=0, action='count',
2429 help="print status messages, or debug with -vv")
2430 parser.add_option('-q', '--quiet', default=0, action='count',
2431 help="report only file names, or nothing with -qq")
2432 parser.add_option('-r', '--repeat', default=True, action='store_true',
2433 help="(obsolete) show all occurrences of the same error")
2434 parser.add_option('--first', action='store_false', dest='repeat',
2435 help="show first occurrence of each error")
2436 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
2437 help="exclude files or directories which match these "
2438 "comma separated patterns (default: %default)")
2439 parser.add_option('--filename', metavar='patterns', default='*.py',
2440 help="when parsing directories, only check filenames "
2441 "matching these comma separated patterns "
2442 "(default: %default)")
2443 parser.add_option('--select', metavar='errors', default='',
2444 help="select errors and warnings (e.g. E,W6)")
2445 parser.add_option('--ignore', metavar='errors', default='',
2446 help="skip errors and warnings (e.g. E4,W) "
2447 "(default: %s)" % DEFAULT_IGNORE)
2448 parser.add_option('--show-source', action='store_true',
2449 help="show source code for each error")
2450 parser.add_option('--show-pep8', action='store_true',
2451 help="show text of PEP 8 for each error "
2452 "(implies --first)")
2453 parser.add_option('--statistics', action='store_true',
2454 help="count errors and warnings")
2455 parser.add_option('--count', action='store_true',
2456 help="print total number of errors and warnings "
2457 "to standard error and set exit code to 1 if "
2458 "total is not null")
2459 parser.add_option('--max-line-length', type='int', metavar='n',
2460 default=MAX_LINE_LENGTH,
2461 help="set maximum allowed line length "
2462 "(default: %default)")
2463 parser.add_option('--max-doc-length', type='int', metavar='n',
2464 default=None,
2465 help="set maximum allowed doc line length and perform "
2466 "these checks (unchecked if not set)")
2467 parser.add_option('--indent-size', type='int', metavar='n',
2468 default=INDENT_SIZE,
2469 help="set how many spaces make up an indent "
2470 "(default: %default)")
2471 parser.add_option('--hang-closing', action='store_true',
2472 help="hang closing bracket instead of matching "
2473 "indentation of opening bracket's line")
2474 parser.add_option('--format', metavar='format', default='default',
2475 help="set the error format [default|pylint|<custom>]")
2476 parser.add_option('--diff', action='store_true',
2477 help="report changes only within line number ranges in "
2478 "the unified diff received on STDIN")
2479 group = parser.add_option_group("Testing Options")
2480 group.add_option('--benchmark', action='store_true',
2481 help="measure processing speed")
2482 return parser
2485def read_config(options, args, arglist, parser):
2486 """Read and parse configurations.
2488 If a config file is specified on the command line with the
2489 "--config" option, then only it is used for configuration.
2491 Otherwise, the user configuration (~/.config/pycodestyle) and any
2492 local configurations in the current directory or above will be
2493 merged together (in that order) using the read method of
2494 ConfigParser.
2495 """
2496 config = configparser.RawConfigParser()
2498 cli_conf = options.config
2500 local_dir = os.curdir
2502 if USER_CONFIG and os.path.isfile(USER_CONFIG):
2503 if options.verbose:
2504 print('user configuration: %s' % USER_CONFIG)
2505 config.read(USER_CONFIG)
2507 parent = tail = args and os.path.abspath(os.path.commonprefix(args))
2508 while tail:
2509 if config.read(os.path.join(parent, fn) for fn in PROJECT_CONFIG):
2510 local_dir = parent
2511 if options.verbose:
2512 print('local configuration: in %s' % parent)
2513 break
2514 (parent, tail) = os.path.split(parent)
2516 if cli_conf and os.path.isfile(cli_conf):
2517 if options.verbose:
2518 print('cli configuration: %s' % cli_conf)
2519 config.read(cli_conf)
2521 pycodestyle_section = None
2522 if config.has_section(parser.prog):
2523 pycodestyle_section = parser.prog
2524 elif config.has_section('pep8'):
2525 pycodestyle_section = 'pep8' # Deprecated
2526 warnings.warn('[pep8] section is deprecated. Use [pycodestyle].')
2528 if pycodestyle_section:
2529 option_list = {o.dest: o.type or o.action for o in parser.option_list}
2531 # First, read the default values
2532 (new_options, __) = parser.parse_args([])
2534 # Second, parse the configuration
2535 for opt in config.options(pycodestyle_section):
2536 if opt.replace('_', '-') not in parser.config_options:
2537 print(" unknown option '%s' ignored" % opt)
2538 continue
2539 if options.verbose > 1:
2540 print(" {} = {}".format(opt,
2541 config.get(pycodestyle_section, opt)))
2542 normalized_opt = opt.replace('-', '_')
2543 opt_type = option_list[normalized_opt]
2544 if opt_type in ('int', 'count'):
2545 value = config.getint(pycodestyle_section, opt)
2546 elif opt_type in ('store_true', 'store_false'):
2547 value = config.getboolean(pycodestyle_section, opt)
2548 else:
2549 value = config.get(pycodestyle_section, opt)
2550 if normalized_opt == 'exclude':
2551 value = normalize_paths(value, local_dir)
2552 setattr(new_options, normalized_opt, value)
2554 # Third, overwrite with the command-line options
2555 (options, __) = parser.parse_args(arglist, values=new_options)
2556 return options
2559def process_options(arglist=None, parse_argv=False, config_file=None,
2560 parser=None, verbose=None):
2561 """Process options passed either via arglist or command line args.
2563 Passing in the ``config_file`` parameter allows other tools, such as
2564 flake8 to specify their own options to be processed in pycodestyle.
2565 """
2566 if not parser:
2567 parser = get_parser()
2568 if not parser.has_option('--config'):
2569 group = parser.add_option_group("Configuration", description=(
2570 "The project options are read from the [%s] section of the "
2571 "tox.ini file or the setup.cfg file located in any parent folder "
2572 "of the path(s) being processed. Allowed options are: %s." %
2573 (parser.prog, ', '.join(parser.config_options))))
2574 group.add_option('--config', metavar='path', default=config_file,
2575 help="user config file location")
2576 # Don't read the command line if the module is used as a library.
2577 if not arglist and not parse_argv:
2578 arglist = []
2579 # If parse_argv is True and arglist is None, arguments are
2580 # parsed from the command line (sys.argv)
2581 (options, args) = parser.parse_args(arglist)
2582 options.reporter = None
2584 # If explicitly specified verbosity, override any `-v` CLI flag
2585 if verbose is not None:
2586 options.verbose = verbose
2588 if parse_argv and not args:
2589 if options.diff or any(os.path.exists(name)
2590 for name in PROJECT_CONFIG):
2591 args = ['.']
2592 else:
2593 parser.error('input not specified')
2594 options = read_config(options, args, arglist, parser)
2595 options.reporter = parse_argv and options.quiet == 1 and FileReport
2597 options.filename = _parse_multi_options(options.filename)
2598 options.exclude = normalize_paths(options.exclude)
2599 options.select = _parse_multi_options(options.select)
2600 options.ignore = _parse_multi_options(options.ignore)
2602 if options.diff:
2603 options.reporter = DiffReport
2604 stdin = stdin_get_value()
2605 options.selected_lines = parse_udiff(stdin, options.filename, args[0])
2606 args = sorted(options.selected_lines)
2608 return options, args
2611def _parse_multi_options(options, split_token=','):
2612 r"""Split and strip and discard empties.
2614 Turns the following:
2616 A,
2617 B,
2619 into ["A", "B"]
2620 """
2621 if options:
2622 return [o.strip() for o in options.split(split_token) if o.strip()]
2623 else:
2624 return options
2627def _main():
2628 """Parse options and run checks on Python source."""
2629 import signal
2631 # Handle "Broken pipe" gracefully
2632 try:
2633 signal.signal(signal.SIGPIPE, lambda signum, frame: sys.exit(1))
2634 except AttributeError:
2635 pass # not supported on Windows
2637 style_guide = StyleGuide(parse_argv=True)
2638 options = style_guide.options
2640 report = style_guide.check_files()
2642 if options.statistics:
2643 report.print_statistics()
2645 if options.benchmark:
2646 report.print_benchmark()
2648 if report.total_errors:
2649 if options.count:
2650 sys.stderr.write(str(report.total_errors) + '\n')
2651 sys.exit(1)
2654if __name__ == '__main__':
2655 _main()