80 # this is a performance hack. see https://bugs.python.org/issue43014 |
80 # this is a performance hack. see https://bugs.python.org/issue43014 |
81 if ( |
81 if ( |
82 sys.version_info < (3, 10) and |
82 sys.version_info < (3, 10) and |
83 callable(getattr(tokenize, '_compile', None)) |
83 callable(getattr(tokenize, '_compile', None)) |
84 ): # pragma: no cover (<py310) |
84 ): # pragma: no cover (<py310) |
85 tokenize._compile = lru_cache()(tokenize._compile) # type: ignore |
85 tokenize._compile = lru_cache(tokenize._compile) # type: ignore |
86 |
86 |
87 __version__ = '2.10.0-eric' |
87 __version__ = '2.11.0-eric' |
88 |
88 |
89 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox' |
89 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox' |
90 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504' |
90 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504' |
91 try: |
91 try: |
92 if sys.platform == 'win32': |
92 if sys.platform == 'win32': # pragma: win32 cover |
93 USER_CONFIG = os.path.expanduser(r'~\.pycodestyle') |
93 USER_CONFIG = os.path.expanduser(r'~\.pycodestyle') |
94 else: |
94 else: # pragma: win32 no cover |
95 USER_CONFIG = os.path.join( |
95 USER_CONFIG = os.path.join( |
96 os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), |
96 os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), |
97 'pycodestyle' |
97 'pycodestyle' |
98 ) |
98 ) |
99 except ImportError: |
99 except ImportError: |
100 USER_CONFIG = None |
100 USER_CONFIG = None |
101 |
101 |
102 PROJECT_CONFIG = ('setup.cfg', 'tox.ini') |
102 PROJECT_CONFIG = ('setup.cfg', 'tox.ini') |
103 TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite') |
|
104 MAX_LINE_LENGTH = 79 |
103 MAX_LINE_LENGTH = 79 |
105 # Number of blank lines between various code parts. |
104 # Number of blank lines between various code parts. |
106 BLANK_LINES_CONFIG = { |
105 BLANK_LINES_CONFIG = { |
107 # Top level class and function. |
106 # Top level class and function. |
108 'top_level': 2, |
107 'top_level': 2, |
120 SINGLETONS = frozenset(['False', 'None', 'True']) |
119 SINGLETONS = frozenset(['False', 'None', 'True']) |
121 KEYWORDS = frozenset(keyword.kwlist + ['print', 'async']) - SINGLETONS |
120 KEYWORDS = frozenset(keyword.kwlist + ['print', 'async']) - SINGLETONS |
122 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-']) |
121 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-']) |
123 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-', '@']) |
122 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-', '@']) |
124 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%']) |
123 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%']) |
125 ASSIGNMENT_EXPRESSION_OP = [':='] if sys.version_info >= (3, 8) else [] |
|
126 WS_NEEDED_OPERATORS = frozenset([ |
124 WS_NEEDED_OPERATORS = frozenset([ |
127 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>', |
125 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<', '>', |
128 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=', |
126 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=', |
129 'and', 'in', 'is', 'or', '->'] + |
127 'and', 'in', 'is', 'or', '->', ':=']) |
130 ASSIGNMENT_EXPRESSION_OP) |
|
131 WHITESPACE = frozenset(' \t\xa0') |
128 WHITESPACE = frozenset(' \t\xa0') |
132 NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE]) |
129 NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE]) |
133 SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT]) |
130 SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT]) |
134 # ERRORTOKEN is triggered by backticks in Python 3 |
131 # ERRORTOKEN is triggered by backticks in Python 3 |
135 SKIP_COMMENTS = SKIP_TOKENS.union([tokenize.COMMENT, tokenize.ERRORTOKEN]) |
132 SKIP_COMMENTS = SKIP_TOKENS.union([tokenize.COMMENT, tokenize.ERRORTOKEN]) |
136 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines'] |
133 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines'] |
137 |
134 |
138 INDENT_REGEX = re.compile(r'([ \t]*)') |
135 INDENT_REGEX = re.compile(r'([ \t]*)') |
139 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,') |
|
140 RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$') |
|
141 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b') |
136 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b') |
142 DOCSTRING_REGEX = re.compile(r'u?r?["\']') |
137 DOCSTRING_REGEX = re.compile(r'u?r?["\']') |
143 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({][ \t]|[ \t][\]}),;:](?!=)') |
138 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({][ \t]|[ \t][\]}),;:](?!=)') |
144 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)') |
139 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)') |
145 COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)' |
140 COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)' |
146 r'\s*(?(1)|(None|False|True))\b') |
141 r'\s*(?(1)|(None|False|True))\b') |
147 COMPARE_NEGATIVE_REGEX = re.compile(r'\b(?<!is\s)(not)\s+[^][)(}{ ]+\s+' |
142 COMPARE_NEGATIVE_REGEX = re.compile(r'\b(?<!is\s)(not)\s+[^][)(}{ ]+\s+' |
148 r'(in|is)\s') |
143 r'(in|is)\s') |
149 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s+type(?:s.\w+Type' |
144 COMPARE_TYPE_REGEX = re.compile( |
150 r'|\s*\(\s*([^)]*[^ )])\s*\))') |
145 r'[=!]=\s+type(?:\s*\(\s*([^)]*[^ )])\s*\))' |
|
146 r'|\btype(?:\s*\(\s*([^)]*[^ )])\s*\))\s+[=!]=' |
|
147 ) |
151 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS)) |
148 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS)) |
152 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)') |
149 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)') |
153 LAMBDA_REGEX = re.compile(r'\blambda\b') |
150 LAMBDA_REGEX = re.compile(r'\blambda\b') |
154 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$') |
151 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$') |
155 STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b') |
152 STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b') |
515 # appear e.g. as "if x is None:", and async/await, which were |
518 # appear e.g. as "if x is None:", and async/await, which were |
516 # valid identifier names in old Python versions. |
519 # valid identifier names in old Python versions. |
517 if (tok0.end == tok1.start and |
520 if (tok0.end == tok1.start and |
518 keyword.iskeyword(tok0.string) and |
521 keyword.iskeyword(tok0.string) and |
519 tok0.string not in SINGLETONS and |
522 tok0.string not in SINGLETONS and |
520 tok0.string not in ('async', 'await') and |
|
521 not (tok0.string == 'except' and tok1.string == '*') and |
523 not (tok0.string == 'except' and tok1.string == '*') and |
522 not (tok0.string == 'yield' and tok1.string == ')') and |
524 not (tok0.string == 'yield' and tok1.string == ')') and |
523 tok1.string not in ':\n'): |
525 tok1.string not in ':\n'): |
524 yield tok0.end, "E275 missing whitespace after keyword" |
526 yield tok0.end, "E275 missing whitespace after keyword" |
525 |
|
526 |
|
527 @register_check |
|
528 def missing_whitespace(logical_line): |
|
529 r"""Each comma, semicolon or colon should be followed by whitespace. |
|
530 |
|
531 Okay: [a, b] |
|
532 Okay: (3,) |
|
533 Okay: a[3,] = 1 |
|
534 Okay: a[1:4] |
|
535 Okay: a[:4] |
|
536 Okay: a[1:] |
|
537 Okay: a[1:4:2] |
|
538 E231: ['a','b'] |
|
539 E231: foo(bar,baz) |
|
540 E231: [{'a':'b'}] |
|
541 """ |
|
542 line = logical_line |
|
543 for index in range(len(line) - 1): |
|
544 char = line[index] |
|
545 next_char = line[index + 1] |
|
546 if char in ',;:' and next_char not in WHITESPACE: |
|
547 before = line[:index] |
|
548 if char == ':' and before.count('[') > before.count(']') and \ |
|
549 before.rfind('{') < before.rfind('['): |
|
550 continue # Slice syntax, no space required |
|
551 if char == ',' and next_char in ')]': |
|
552 continue # Allow tuple with only one element: (3,) |
|
553 if char == ':' and next_char == '=' and sys.version_info >= (3, 8): |
|
554 continue # Allow assignment expression |
|
555 yield index, "E231 missing whitespace after '%s'", char |
|
556 |
527 |
557 |
528 |
558 @register_check |
529 @register_check |
559 def indentation(logical_line, previous_logical, indent_char, |
530 def indentation(logical_line, previous_logical, indent_char, |
560 indent_level, previous_indent_level, |
531 indent_level, previous_indent_level, |
741 indent[depth] = start[1] |
712 indent[depth] = start[1] |
742 indent_chances[start[1]] = True |
713 indent_chances[start[1]] = True |
743 if verbose >= 4: |
714 if verbose >= 4: |
744 print(f"bracket depth {depth} indent to {start[1]}") |
715 print(f"bracket depth {depth} indent to {start[1]}") |
745 # deal with implicit string concatenation |
716 # deal with implicit string concatenation |
746 elif (token_type in (tokenize.STRING, tokenize.COMMENT) or |
717 elif token_type in (tokenize.STRING, tokenize.COMMENT, FSTRING_START): |
747 text in ('u', 'ur', 'b', 'br')): |
|
748 indent_chances[start[1]] = str |
718 indent_chances[start[1]] = str |
749 # visual indent after assert/raise/with |
719 # visual indent after assert/raise/with |
750 elif not row and not depth and text in ["assert", "raise", "with"]: |
720 elif not row and not depth and text in ["assert", "raise", "with"]: |
751 indent_chances[end[1] + 1] = True |
721 indent_chances[end[1] + 1] = True |
752 # special case for the "if" statement because len("if (") == 4 |
722 # special case for the "if" statement because len("if (") == 4 |
830 (prev_type == tokenize.NAME or prev_text in '}])') and |
800 (prev_type == tokenize.NAME or prev_text in '}])') and |
831 # Syntax "class A (B):" is allowed, but avoid it |
801 # Syntax "class A (B):" is allowed, but avoid it |
832 (index < 2 or tokens[index - 2][1] != 'class') and |
802 (index < 2 or tokens[index - 2][1] != 'class') and |
833 # Allow "return (a.foo for a in range(5))" |
803 # Allow "return (a.foo for a in range(5))" |
834 not keyword.iskeyword(prev_text) and |
804 not keyword.iskeyword(prev_text) and |
835 # 'match' and 'case' are only soft keywords |
|
836 ( |
805 ( |
837 sys.version_info < (3, 9) or |
806 sys.version_info < (3, 9) or |
|
807 # 3.12+: type is a soft keyword but no braces after |
|
808 prev_text == 'type' or |
838 not keyword.issoftkeyword(prev_text) |
809 not keyword.issoftkeyword(prev_text) |
839 ) |
810 ) |
840 ): |
811 ): |
841 yield prev_end, "E211 whitespace before '%s'", text |
812 yield prev_end, "E211 whitespace before '%s'", text |
842 prev_type = token_type |
813 prev_type = token_type |
867 elif len(after) > 1: |
838 elif len(after) > 1: |
868 yield match.start(2), "E222 multiple spaces after operator" |
839 yield match.start(2), "E222 multiple spaces after operator" |
869 |
840 |
870 |
841 |
871 @register_check |
842 @register_check |
872 def missing_whitespace_around_operator(logical_line, tokens): |
843 def missing_whitespace(logical_line, tokens): |
873 r"""Surround operators with a single space on either side. |
844 r"""Surround operators with the correct amount of whitespace. |
874 |
845 |
875 - Always surround these binary operators with a single space on |
846 - Always surround these binary operators with a single space on |
876 either side: assignment (=), augmented assignment (+=, -= etc.), |
847 either side: assignment (=), augmented assignment (+=, -= etc.), |
877 comparisons (==, <, >, !=, <=, >=, in, not in, is, is not), |
848 comparisons (==, <, >, !=, <=, >=, in, not in, is, is not), |
878 Booleans (and, or, not). |
849 Booleans (and, or, not). |
|
850 |
|
851 - Each comma, semicolon or colon should be followed by whitespace. |
879 |
852 |
880 - If operators with different priorities are used, consider adding |
853 - If operators with different priorities are used, consider adding |
881 whitespace around the operators with the lowest priorities. |
854 whitespace around the operators with the lowest priorities. |
882 |
855 |
883 Okay: i = i + 1 |
856 Okay: i = i + 1 |
885 Okay: x = x * 2 - 1 |
858 Okay: x = x * 2 - 1 |
886 Okay: hypot2 = x * x + y * y |
859 Okay: hypot2 = x * x + y * y |
887 Okay: c = (a + b) * (a - b) |
860 Okay: c = (a + b) * (a - b) |
888 Okay: foo(bar, key='word', *args, **kwargs) |
861 Okay: foo(bar, key='word', *args, **kwargs) |
889 Okay: alpha[:-i] |
862 Okay: alpha[:-i] |
|
863 Okay: [a, b] |
|
864 Okay: (3,) |
|
865 Okay: a[3,] = 1 |
|
866 Okay: a[1:4] |
|
867 Okay: a[:4] |
|
868 Okay: a[1:] |
|
869 Okay: a[1:4:2] |
890 |
870 |
891 E225: i=i+1 |
871 E225: i=i+1 |
892 E225: submitted +=1 |
872 E225: submitted +=1 |
893 E225: x = x /2 - 1 |
873 E225: x = x /2 - 1 |
894 E225: z = x **y |
874 E225: z = x **y |
895 E225: z = 1and 1 |
875 E225: z = 1and 1 |
896 E226: c = (a+b) * (a-b) |
876 E226: c = (a+b) * (a-b) |
897 E226: hypot2 = x*x + y*y |
877 E226: hypot2 = x*x + y*y |
898 E227: c = a|b |
878 E227: c = a|b |
899 E228: msg = fmt%(errno, errmsg) |
879 E228: msg = fmt%(errno, errmsg) |
900 """ |
880 E231: ['a','b'] |
901 parens = 0 |
881 E231: foo(bar,baz) |
|
882 E231: [{'a':'b'}] |
|
883 """ |
902 need_space = False |
884 need_space = False |
903 prev_type = tokenize.OP |
885 prev_type = tokenize.OP |
904 prev_text = prev_end = None |
886 prev_text = prev_end = None |
905 operator_types = (tokenize.OP, tokenize.NAME) |
887 operator_types = (tokenize.OP, tokenize.NAME) |
|
888 brace_stack = [] |
906 for token_type, text, start, end, line in tokens: |
889 for token_type, text, start, end, line in tokens: |
|
890 if token_type == tokenize.OP and text in {'[', '(', '{'}: |
|
891 brace_stack.append(text) |
|
892 elif token_type == FSTRING_START: # pragma: >=3.12 cover |
|
893 brace_stack.append('f') |
|
894 elif token_type == tokenize.NAME and text == 'lambda': |
|
895 brace_stack.append('l') |
|
896 elif brace_stack: |
|
897 if token_type == tokenize.OP and text in {']', ')', '}'}: |
|
898 brace_stack.pop() |
|
899 elif token_type == FSTRING_END: # pragma: >=3.12 cover |
|
900 brace_stack.pop() |
|
901 elif ( |
|
902 brace_stack[-1] == 'l' and |
|
903 token_type == tokenize.OP and |
|
904 text == ':' |
|
905 ): |
|
906 brace_stack.pop() |
|
907 |
907 if token_type in SKIP_COMMENTS: |
908 if token_type in SKIP_COMMENTS: |
908 continue |
909 continue |
909 if text in ('(', 'lambda'): |
910 |
910 parens += 1 |
911 if token_type == tokenize.OP and text in {',', ';', ':'}: |
911 elif text == ')': |
912 next_char = line[end[1]:end[1] + 1] |
912 parens -= 1 |
913 if next_char not in WHITESPACE and next_char not in '\r\n': |
|
914 # slice |
|
915 if text == ':' and brace_stack[-1:] == ['[']: |
|
916 pass |
|
917 # 3.12+ fstring format specifier |
|
918 elif text == ':' and brace_stack[-2:] == ['f', '{']: # pragma: >=3.12 cover # noqa: E501 |
|
919 pass |
|
920 # tuple (and list for some reason?) |
|
921 elif text == ',' and next_char in ')]': |
|
922 pass |
|
923 else: |
|
924 yield start, f'E231 missing whitespace after {text!r}', text |
|
925 |
913 if need_space: |
926 if need_space: |
914 if start != prev_end: |
927 if start != prev_end: |
915 # Found a (probably) needed space |
928 # Found a (probably) needed space |
916 if need_space is not True and not need_space[1]: |
929 if need_space is not True and not need_space[1]: |
917 yield (need_space[0], |
930 yield (need_space[0], |
918 "E225 missing whitespace around operator") |
931 "E225 missing whitespace around operator") |
919 need_space = False |
932 need_space = False |
920 elif text == '>' and prev_text in ('<', '-'): |
|
921 # Tolerate the "<>" operator, even if running Python 3 |
|
922 # Deal with Python 3's annotated return value "->" |
|
923 pass |
|
924 elif ( |
933 elif ( |
925 # def f(a, /, b): |
934 # def f(a, /, b): |
926 # ^ |
935 # ^ |
927 # def f(a, b, /): |
936 # def f(a, b, /): |
928 # ^ |
937 # ^ |
948 code, optype = 'E227', 'bitwise or shift' |
957 code, optype = 'E227', 'bitwise or shift' |
949 yield (need_space[0], "%s missing whitespace " |
958 yield (need_space[0], "%s missing whitespace " |
950 "around %s operator" % (code, optype)) |
959 "around %s operator" % (code, optype)) |
951 need_space = False |
960 need_space = False |
952 elif token_type in operator_types and prev_end is not None: |
961 elif token_type in operator_types and prev_end is not None: |
953 if text == '=' and parens: |
962 if ( |
954 # Allow keyword args or defaults: foo(bar=None). |
963 text == '=' and ( |
|
964 # allow lambda default args: lambda x=None: None |
|
965 brace_stack[-1:] == ['l'] or |
|
966 # allow keyword args or defaults: foo(bar=None). |
|
967 brace_stack[-1:] == ['('] or |
|
968 # allow python 3.8 fstring repr specifier |
|
969 brace_stack[-2:] == ['f', '{'] |
|
970 ) |
|
971 ): |
955 pass |
972 pass |
956 elif text in WS_NEEDED_OPERATORS: |
973 elif text in WS_NEEDED_OPERATORS: |
957 need_space = True |
974 need_space = True |
958 elif text in UNARY_OPERATORS: |
975 elif text in UNARY_OPERATORS: |
959 # Check if the operator is used as a binary operator |
976 # Check if the operator is used as a binary operator |
1227 found = line.find(':') |
1240 found = line.find(':') |
1228 prev_found = 0 |
1241 prev_found = 0 |
1229 counts = {char: 0 for char in '{}[]()'} |
1242 counts = {char: 0 for char in '{}[]()'} |
1230 while -1 < found < last_char: |
1243 while -1 < found < last_char: |
1231 update_counts(line[prev_found:found], counts) |
1244 update_counts(line[prev_found:found], counts) |
1232 if ((counts['{'] <= counts['}'] and # {'a': 1} (dict) |
1245 if ( |
1233 counts['['] <= counts[']'] and # [1:2] (slice) |
1246 counts['{'] <= counts['}'] and # {'a': 1} (dict) |
1234 counts['('] <= counts[')']) and # (annotation) |
1247 counts['['] <= counts[']'] and # [1:2] (slice) |
1235 not (sys.version_info >= (3, 8) and |
1248 counts['('] <= counts[')'] and # (annotation) |
1236 line[found + 1] == '=')): # assignment expression |
1249 line[found + 1] != '=' # assignment expression |
|
1250 ): |
1237 lambda_kw = LAMBDA_REGEX.search(line, 0, found) |
1251 lambda_kw = LAMBDA_REGEX.search(line, 0, found) |
1238 if lambda_kw: |
1252 if lambda_kw: |
1239 before = line[:lambda_kw.start()].rstrip() |
1253 before = line[:lambda_kw.start()].rstrip() |
1240 if before[-1:] == '=' and before[:-1].strip().isidentifier(): |
1254 if before[-1:] == '=' and before[:-1].strip().isidentifier(): |
1241 yield 0, ("E731 do not assign a lambda expression, use a " |
1255 yield 0, ("E731 do not assign a lambda expression, use a " |
1467 r"""Object type comparisons should always use isinstance(). |
1481 r"""Object type comparisons should always use isinstance(). |
1468 |
1482 |
1469 Do not compare types directly. |
1483 Do not compare types directly. |
1470 |
1484 |
1471 Okay: if isinstance(obj, int): |
1485 Okay: if isinstance(obj, int): |
1472 E721: if type(obj) is type(1): |
1486 Okay: if type(obj) is int: |
1473 |
1487 E721: if type(obj) == type(1): |
1474 When checking if an object is a string, keep in mind that it might |
|
1475 be a unicode string too! In Python 2.3, str and unicode have a |
|
1476 common base class, basestring, so you can do: |
|
1477 |
|
1478 Okay: if isinstance(obj, basestring): |
|
1479 Okay: if type(a1) is type(b1): |
|
1480 """ |
1488 """ |
1481 match = COMPARE_TYPE_REGEX.search(logical_line) |
1489 match = COMPARE_TYPE_REGEX.search(logical_line) |
1482 if match and not noqa: |
1490 if match and not noqa: |
1483 inst = match.group(1) |
1491 inst = match.group(1) |
1484 if inst and inst.isidentifier() and inst not in SINGLETONS: |
1492 if inst and inst.isidentifier() and inst not in SINGLETONS: |
1485 return # Allow comparison for types which are not obvious |
1493 return # Allow comparison for types which are not obvious |
1486 yield match.start(), "E721 do not compare types, use 'isinstance()'" |
1494 yield ( |
|
1495 match.start(), |
|
1496 "E721 do not compare types, for exact checks use `is` / `is not`, " |
|
1497 "for instance checks use `isinstance()`", |
|
1498 ) |
1487 |
1499 |
1488 |
1500 |
1489 @register_check |
1501 @register_check |
1490 def bare_except(logical_line, noqa): |
1502 def bare_except(logical_line, noqa): |
1491 r"""When catching exceptions, mention specific exceptions when |
1503 r"""When catching exceptions, mention specific exceptions when |
1602 prev_text = text |
1614 prev_text = text |
1603 prev_start = start |
1615 prev_start = start |
1604 |
1616 |
1605 |
1617 |
1606 @register_check |
1618 @register_check |
1607 def python_3000_has_key(logical_line, noqa): |
|
1608 r"""The {}.has_key() method is removed in Python 3: use the 'in' |
|
1609 operator. |
|
1610 |
|
1611 Okay: if "alph" in d:\n print d["alph"] |
|
1612 W601: assert d.has_key('alph') |
|
1613 """ |
|
1614 pos = logical_line.find('.has_key(') |
|
1615 if pos > -1 and not noqa: |
|
1616 yield pos, "W601 .has_key() is deprecated, use 'in'" |
|
1617 |
|
1618 |
|
1619 @register_check |
|
1620 def python_3000_raise_comma(logical_line): |
|
1621 r"""When raising an exception, use "raise ValueError('message')". |
|
1622 |
|
1623 The older form is removed in Python 3. |
|
1624 |
|
1625 Okay: raise DummyError("Message") |
|
1626 W602: raise DummyError, "Message" |
|
1627 """ |
|
1628 match = RAISE_COMMA_REGEX.match(logical_line) |
|
1629 if match and not RERAISE_COMMA_REGEX.match(logical_line): |
|
1630 yield match.end() - 1, "W602 deprecated form of raising exception" |
|
1631 |
|
1632 |
|
1633 @register_check |
|
1634 def python_3000_not_equal(logical_line): |
|
1635 r"""New code should always use != instead of <>. |
|
1636 |
|
1637 The older syntax is removed in Python 3. |
|
1638 |
|
1639 Okay: if a != 'no': |
|
1640 W603: if a <> 'no': |
|
1641 """ |
|
1642 pos = logical_line.find('<>') |
|
1643 if pos > -1: |
|
1644 yield pos, "W603 '<>' is deprecated, use '!='" |
|
1645 |
|
1646 |
|
1647 @register_check |
|
1648 def python_3000_backticks(logical_line): |
|
1649 r"""Use repr() instead of backticks in Python 3. |
|
1650 |
|
1651 Okay: val = repr(1 + 2) |
|
1652 W604: val = `1 + 2` |
|
1653 """ |
|
1654 pos = logical_line.find('`') |
|
1655 if pos > -1: |
|
1656 yield pos, "W604 backticks are deprecated, use 'repr()'" |
|
1657 |
|
1658 |
|
1659 @register_check |
|
1660 def python_3000_invalid_escape_sequence(logical_line, tokens, noqa): |
1619 def python_3000_invalid_escape_sequence(logical_line, tokens, noqa): |
1661 r"""Invalid escape sequences are deprecated in Python 3.6. |
1620 r"""Invalid escape sequences are deprecated in Python 3.6. |
1662 |
1621 |
1663 Okay: regex = r'\.png$' |
1622 Okay: regex = r'\.png$' |
1664 W605: regex = '\.png$' |
1623 W605: regex = '\.png$' |
1686 'N', |
1645 'N', |
1687 'u', |
1646 'u', |
1688 'U', |
1647 'U', |
1689 ] |
1648 ] |
1690 |
1649 |
1691 for token_type, text, start, end, line in tokens: |
1650 prefixes = [] |
1692 if token_type == tokenize.STRING: |
1651 for token_type, text, start, _, _ in tokens: |
1693 start_line, start_col = start |
1652 if token_type in {tokenize.STRING, FSTRING_START}: |
1694 quote = text[-3:] if text[-3:] in ('"""', "'''") else text[-1] |
|
1695 # Extract string modifiers (e.g. u or r) |
1653 # Extract string modifiers (e.g. u or r) |
1696 quote_pos = text.index(quote) |
1654 prefixes.append(text[:text.index(text[-1])].lower()) |
1697 prefix = text[:quote_pos].lower() |
1655 |
1698 start = quote_pos + len(quote) |
1656 if token_type in {tokenize.STRING, FSTRING_MIDDLE}: |
1699 string = text[start:-len(quote)] |
1657 if 'r' not in prefixes[-1]: |
1700 |
1658 start_line, start_col = start |
1701 if 'r' not in prefix: |
1659 pos = text.find('\\') |
1702 pos = string.find('\\') |
|
1703 while pos >= 0: |
1660 while pos >= 0: |
1704 pos += 1 |
1661 pos += 1 |
1705 if string[pos] not in valid: |
1662 if text[pos] not in valid: |
1706 line = start_line + string.count('\n', 0, pos) |
1663 line = start_line + text.count('\n', 0, pos) |
1707 if line == start_line: |
1664 if line == start_line: |
1708 col = start_col + len(prefix) + len(quote) + pos |
1665 col = start_col + pos |
1709 else: |
1666 else: |
1710 col = pos - string.rfind('\n', 0, pos) - 1 |
1667 col = pos - text.rfind('\n', 0, pos) - 1 |
1711 yield ( |
1668 yield ( |
1712 (line, col - 1), |
1669 (line, col - 1), |
1713 "W605 invalid escape sequence '\\%s'", |
1670 f"W605 invalid escape sequence '\\{text[pos]}'", |
1714 string[pos], |
1671 text[pos], |
1715 ) |
1672 ) |
1716 pos = string.find('\\', pos + 1) |
1673 pos = text.find('\\', pos + 1) |
1717 |
1674 |
1718 |
1675 if token_type in {tokenize.STRING, FSTRING_END}: |
1719 @register_check |
1676 prefixes.pop() |
1720 def python_3000_async_await_keywords(logical_line, tokens): |
|
1721 """'async' and 'await' are reserved keywords starting at Python 3.7. |
|
1722 |
|
1723 W606: async = 42 |
|
1724 W606: await = 42 |
|
1725 Okay: async def read(db):\n data = await db.fetch('SELECT ...') |
|
1726 """ |
|
1727 # The Python tokenize library before Python 3.5 recognizes |
|
1728 # async/await as a NAME token. Therefore, use a state machine to |
|
1729 # look for the possible async/await constructs as defined by the |
|
1730 # Python grammar: |
|
1731 # https://docs.python.org/3/reference/grammar.html |
|
1732 |
|
1733 state = None |
|
1734 for token_type, text, start, end, line in tokens: |
|
1735 error = False |
|
1736 |
|
1737 if token_type == tokenize.NL: |
|
1738 continue |
|
1739 |
|
1740 if state is None: |
|
1741 if token_type == tokenize.NAME: |
|
1742 if text == 'async': |
|
1743 state = ('async_stmt', start) |
|
1744 elif text == 'await': |
|
1745 state = ('await', start) |
|
1746 elif (token_type == tokenize.NAME and |
|
1747 text in ('def', 'for')): |
|
1748 state = ('define', start) |
|
1749 |
|
1750 elif state[0] == 'async_stmt': |
|
1751 if token_type == tokenize.NAME and text in ('def', 'with', 'for'): |
|
1752 # One of funcdef, with_stmt, or for_stmt. Return to |
|
1753 # looking for async/await names. |
|
1754 state = None |
|
1755 else: |
|
1756 error = True |
|
1757 elif state[0] == 'await': |
|
1758 if token_type == tokenize.NAME: |
|
1759 # An await expression. Return to looking for async/await |
|
1760 # names. |
|
1761 state = None |
|
1762 elif token_type == tokenize.OP and text == '(': |
|
1763 state = None |
|
1764 else: |
|
1765 error = True |
|
1766 elif state[0] == 'define': |
|
1767 if token_type == tokenize.NAME and text in ('async', 'await'): |
|
1768 error = True |
|
1769 else: |
|
1770 state = None |
|
1771 |
|
1772 if error: |
|
1773 yield ( |
|
1774 state[1], |
|
1775 "W606 'async' and 'await' are reserved keywords starting with " |
|
1776 "Python 3.7", |
|
1777 ) |
|
1778 state = None |
|
1779 |
|
1780 # Last token |
|
1781 if state is not None: |
|
1782 yield ( |
|
1783 state[1], |
|
1784 "W606 'async' and 'await' are reserved keywords starting with " |
|
1785 "Python 3.7", |
|
1786 ) |
|
1787 |
1677 |
1788 |
1678 |
1789 ######################################################################## |
1679 ######################################################################## |
1790 @register_check |
1680 @register_check |
1791 def maximum_doc_length(logical_line, max_doc_length, noqa, tokens): |
1681 def maximum_doc_length(logical_line, max_doc_length, noqa, tokens): |
2185 |
2061 |
2186 def maybe_check_physical(self, token, prev_physical): |
2062 def maybe_check_physical(self, token, prev_physical): |
2187 """If appropriate for token, check current physical line(s).""" |
2063 """If appropriate for token, check current physical line(s).""" |
2188 # Called after every token, but act only on end of line. |
2064 # Called after every token, but act only on end of line. |
2189 |
2065 |
|
2066 if token.type == FSTRING_START: # pragma: >=3.12 cover |
|
2067 self.fstring_start = token.start[0] |
2190 # a newline token ends a single physical line. |
2068 # a newline token ends a single physical line. |
2191 if _is_eol_token(token): |
2069 elif _is_eol_token(token): |
2192 # if the file does not end with a newline, the NEWLINE |
2070 # if the file does not end with a newline, the NEWLINE |
2193 # token is inserted by the parser, but it does not contain |
2071 # token is inserted by the parser, but it does not contain |
2194 # the previous physical line in `token[4]` |
2072 # the previous physical line in `token[4]` |
2195 if token[4] == '': |
2073 if token.line == '': |
2196 self.check_physical(prev_physical) |
2074 self.check_physical(prev_physical) |
2197 else: |
2075 else: |
2198 self.check_physical(token[4]) |
2076 self.check_physical(token.line) |
2199 elif token[0] == tokenize.STRING and '\n' in token[1]: |
2077 elif ( |
|
2078 token.type == tokenize.STRING and '\n' in token.string or |
|
2079 token.type == FSTRING_END |
|
2080 ): |
2200 # Less obviously, a string that contains newlines is a |
2081 # Less obviously, a string that contains newlines is a |
2201 # multiline string, either triple-quoted or with internal |
2082 # multiline string, either triple-quoted or with internal |
2202 # newlines backslash-escaped. Check every physical line in |
2083 # newlines backslash-escaped. Check every physical line in |
2203 # the string *except* for the last one: its newline is |
2084 # the string *except* for the last one: its newline is |
2204 # outside of the multiline string, so we consider it a |
2085 # outside of the multiline string, so we consider it a |
2210 # contains the magical "# noqa" comment, we disable all |
2091 # contains the magical "# noqa" comment, we disable all |
2211 # physical checks for the entire multiline string |
2092 # physical checks for the entire multiline string |
2212 # - have to wind self.line_number back because initially it |
2093 # - have to wind self.line_number back because initially it |
2213 # points to the last line of the string, and we want |
2094 # points to the last line of the string, and we want |
2214 # check_physical() to give accurate feedback |
2095 # check_physical() to give accurate feedback |
2215 if noqa(token[4]): |
2096 if noqa(token.line): |
2216 return |
2097 return |
|
2098 if token.type == FSTRING_END: # pragma: >=3.12 cover |
|
2099 start = self.fstring_start |
|
2100 else: |
|
2101 start = token.start[0] |
|
2102 end = token.end[0] |
|
2103 |
2217 self.multiline = True |
2104 self.multiline = True |
2218 self.line_number = token[2][0] |
2105 self.line_number = start |
2219 _, src, (_, offset), _, _ = token |
2106 for line_number in range(start, end): |
2220 src = self.lines[self.line_number - 1][:offset] + src |
2107 self.check_physical(self.lines[line_number - 1] + '\n') |
2221 for line in src.split('\n')[:-1]: |
|
2222 self.check_physical(line + '\n') |
|
2223 self.line_number += 1 |
2108 self.line_number += 1 |
2224 self.multiline = False |
2109 self.multiline = False |
2225 |
2110 |
2226 def check_all(self, expected=None, line_offset=0): |
2111 def check_all(self, expected=None, line_offset=0): |
2227 """Run all checks on the input file.""" |
2112 """Run all checks on the input file.""" |
2485 |
2370 |
2486 if not options.reporter: |
2371 if not options.reporter: |
2487 options.reporter = BaseReport if options.quiet else StandardReport |
2372 options.reporter = BaseReport if options.quiet else StandardReport |
2488 |
2373 |
2489 options.select = tuple(options.select or ()) |
2374 options.select = tuple(options.select or ()) |
2490 # if not (options.select or options.ignore or |
2375 # if not (options.select or options.ignore) and DEFAULT_IGNORE: |
2491 # options.testsuite or options.doctest) and DEFAULT_IGNORE: |
|
2492 # # The default choice: ignore controversial checks |
2376 # # The default choice: ignore controversial checks |
2493 # options.ignore = tuple(DEFAULT_IGNORE.split(',')) |
2377 # options.ignore = tuple(DEFAULT_IGNORE.split(',')) |
2494 # else: |
2378 # else: |
2495 # # Ignore all checks which are not explicitly selected or all if no |
2379 # # Ignore all checks which are not explicitly selected |
2496 # options.ignore = ('',) if options.select else tuple(options.ignore) |
2380 # options.ignore = ('',) if options.select else tuple(options.ignore) |
2497 |
2381 |
2498 # check is ignored or explicitly selected |
|
2499 options.ignore = ('',) if options.select else tuple(options.ignore) |
2382 options.ignore = ('',) if options.select else tuple(options.ignore) |
2500 options.benchmark_keys = BENCHMARK_KEYS[:] |
2383 options.benchmark_keys = BENCHMARK_KEYS[:] |
2501 options.ignore_code = self.ignore_code |
2384 options.ignore_code = self.ignore_code |
2502 options.physical_checks = self.get_checks('physical_line') |
2385 options.physical_checks = self.get_checks('physical_line') |
2503 options.logical_checks = self.get_checks('logical_line') |
2386 options.logical_checks = self.get_checks('logical_line') |
2659 help="set the error format [default|pylint|<custom>]") |
2542 help="set the error format [default|pylint|<custom>]") |
2660 parser.add_option('--diff', action='store_true', |
2543 parser.add_option('--diff', action='store_true', |
2661 help="report changes only within line number ranges in " |
2544 help="report changes only within line number ranges in " |
2662 "the unified diff received on STDIN") |
2545 "the unified diff received on STDIN") |
2663 group = parser.add_option_group("Testing Options") |
2546 group = parser.add_option_group("Testing Options") |
2664 if os.path.exists(TESTSUITE_PATH): |
|
2665 group.add_option('--testsuite', metavar='dir', |
|
2666 help="run regression tests from dir") |
|
2667 group.add_option('--doctest', action='store_true', |
|
2668 help="run doctest on myself") |
|
2669 group.add_option('--benchmark', action='store_true', |
2547 group.add_option('--benchmark', action='store_true', |
2670 help="measure processing speed") |
2548 help="measure processing speed") |
2671 return parser |
2549 return parser |
2672 |
2550 |
2673 |
2551 |
2773 |
2650 |
2774 # If explicitly specified verbosity, override any `-v` CLI flag |
2651 # If explicitly specified verbosity, override any `-v` CLI flag |
2775 if verbose is not None: |
2652 if verbose is not None: |
2776 options.verbose = verbose |
2653 options.verbose = verbose |
2777 |
2654 |
2778 if options.ensure_value('testsuite', False): |
2655 if parse_argv and not args: |
2779 args.append(options.testsuite) |
2656 if options.diff or any(os.path.exists(name) |
2780 elif not options.ensure_value('doctest', False): |
2657 for name in PROJECT_CONFIG): |
2781 if parse_argv and not args: |
2658 args = ['.'] |
2782 if options.diff or any(os.path.exists(name) |
2659 else: |
2783 for name in PROJECT_CONFIG): |
2660 parser.error('input not specified') |
2784 args = ['.'] |
2661 options = read_config(options, args, arglist, parser) |
2785 else: |
2662 options.reporter = parse_argv and options.quiet == 1 and FileReport |
2786 parser.error('input not specified') |
|
2787 options = read_config(options, args, arglist, parser) |
|
2788 options.reporter = parse_argv and options.quiet == 1 and FileReport |
|
2789 |
2663 |
2790 options.filename = _parse_multi_options(options.filename) |
2664 options.filename = _parse_multi_options(options.filename) |
2791 options.exclude = normalize_paths(options.exclude) |
2665 options.exclude = normalize_paths(options.exclude) |
2792 options.select = _parse_multi_options(options.select) |
2666 options.select = _parse_multi_options(options.select) |
2793 options.ignore = _parse_multi_options(options.ignore) |
2667 options.ignore = _parse_multi_options(options.ignore) |