2525# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2626# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2727# SOFTWARE.
28-
2928r"""
3029Check Python source code formatting, according to PEP 8.
3130
4948"""
5049from __future__ import with_statement
5150
51+ import bisect
5252import inspect
5353import keyword
5454import os
5757import time
5858import tokenize
5959import warnings
60- import bisect
6160
6261try :
6362 from functools import lru_cache
@@ -78,7 +77,14 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
7877except ImportError :
7978 from ConfigParser import RawConfigParser
8079
81- __version__ = '2.7.0' # patched PY-37054, #989, #990, #1002
80+ # this is a performance hack. see https://bugs.python.org/issue43014
81+ if (
82+ sys .version_info < (3 , 10 ) and
83+ callable (getattr (tokenize , '_compile' , None ))
84+ ): # pragma: no cover (<py310)
85+ tokenize ._compile = lru_cache ()(tokenize ._compile ) # type: ignore
86+
87+ __version__ = '2.8.0' # patched PY-37054
8288
8389DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
8490DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
@@ -137,7 +143,7 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
137143RERAISE_COMMA_REGEX = re .compile (r'raise\s+\w+\s*,.*,\s*\w+\s*$' )
138144ERRORCODE_REGEX = re .compile (r'\b[A-Z]\d{3}\b' )
139145DOCSTRING_REGEX = re .compile (r'u?r?["\']' )
140- EXTRANEOUS_WHITESPACE_REGEX = re .compile (r'[\[({] | [\]}),;]| : (?!=)' )
146+ EXTRANEOUS_WHITESPACE_REGEX = re .compile (r'[\[({][ \t]|[ \t] [\]}),;:] (?!=)' )
141147WHITESPACE_AFTER_COMMA_REGEX = re .compile (r'[,;:]\s*(?: |\t)' )
142148COMPARE_SINGLETON_REGEX = re .compile (r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
143149 r'\s*(?(1)|(None|False|True))\b' )
@@ -162,8 +168,8 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
162168 'while' ,
163169 )))
164170)
165- DUNDER_REGEX = re .compile (r' ^__([^\s]+)__ = ' )
166- MATCH_CASE_REGEX = re .compile (r'^ \s*\b(?:match|case)(\s*)(?=.*\:)' )
171+ DUNDER_REGEX = re .compile (r" ^__([^\s]+)__(?::\s*[a-zA-Z.0-9_\[\]\"]+)? = " )
172+ BLANK_EXCEPT_REGEX = re .compile (r"except \s*:" )
167173
168174_checks = {'physical_line' : {}, 'logical_line' : {}, 'tree' : {}}
169175
@@ -463,7 +469,7 @@ def extraneous_whitespace(logical_line):
463469 text = match .group ()
464470 char = text .strip ()
465471 found = match .start ()
466- if text == char + ' ' :
472+ if text [ - 1 ]. isspace () :
467473 # assert char in '([{'
468474 yield found + 1 , "E201 whitespace after '%s'" % char
469475 elif line [found - 1 ] != ',' :
@@ -494,16 +500,6 @@ def whitespace_around_keywords(logical_line):
494500 elif len (after ) > 1 :
495501 yield match .start (2 ), "E271 multiple spaces after keyword"
496502
497- if sys .version_info >= (3 , 10 ):
498- match = MATCH_CASE_REGEX .match (logical_line )
499- if match :
500- if match [1 ] == ' ' :
501- return
502- if match [1 ] == '' :
503- yield match .start (1 ), "E275 missing whitespace after keyword"
504- else :
505- yield match .start (1 ), "E271 multiple spaces after keyword"
506-
507503
508504@register_check
509505def missing_whitespace_after_import_keyword (logical_line ):
@@ -556,7 +552,7 @@ def missing_whitespace(logical_line):
556552@register_check
557553def indentation (logical_line , previous_logical , indent_char ,
558554 indent_level , previous_indent_level ,
559- indent_size , indent_size_str ):
555+ indent_size ):
560556 r"""Use indent_size (PEP8 says 4) spaces per indentation level.
561557
562558 For really old code that you don't want to mess up, you can continue
@@ -580,7 +576,7 @@ def indentation(logical_line, previous_logical, indent_char,
580576 if indent_level % indent_size :
581577 yield 0 , tmpl % (
582578 1 + c ,
583- "indentation is not a multiple of " + indent_size_str ,
579+ "indentation is not a multiple of " + str ( indent_size ) ,
584580 )
585581 indent_expect = previous_logical .endswith (':' )
586582 if indent_expect and indent_level <= previous_indent_level :
@@ -597,8 +593,7 @@ def indentation(logical_line, previous_logical, indent_char,
597593
598594@register_check
599595def continued_indentation (logical_line , tokens , indent_level , hang_closing ,
600- indent_char , indent_size , indent_size_str , noqa ,
601- verbose ):
596+ indent_char , indent_size , noqa , verbose ):
602597 r"""Continuation lines indentation.
603598
604599 Continuation lines should align wrapped elements either vertically
@@ -925,7 +920,9 @@ def missing_whitespace_around_operator(logical_line, tokens):
925920 # ^
926921 # def f(a, b, /):
927922 # ^
928- prev_text == '/' and text in {',' , ')' } or
923+ # f = lambda a, /:
924+ # ^
925+ prev_text == '/' and text in {',' , ')' , ':' } or
929926 # def f(a, b, /):
930927 # ^
931928 prev_text == ')' and text == ':'
@@ -1416,8 +1413,10 @@ def comparison_to_singleton(logical_line, noqa):
14161413 None was set to some other value. The other value might have a type
14171414 (such as a container) that could be false in a boolean context!
14181415 """
1419- match = not noqa and COMPARE_SINGLETON_REGEX .search (logical_line )
1420- if match :
1416+ if noqa :
1417+ return
1418+
1419+ for match in COMPARE_SINGLETON_REGEX .finditer (logical_line ):
14211420 singleton = match .group (1 ) or match .group (3 )
14221421 same = (match .group (2 ) == '==' )
14231422
@@ -1491,8 +1490,7 @@ def bare_except(logical_line, noqa):
14911490 if noqa :
14921491 return
14931492
1494- regex = re .compile (r"except\s*:" )
1495- match = regex .match (logical_line )
1493+ match = BLANK_EXCEPT_REGEX .match (logical_line )
14961494 if match :
14971495 yield match .start (), "E722 do not use bare 'except'"
14981496
@@ -1993,8 +1991,6 @@ def __init__(self, filename=None, lines=None,
19931991 self .multiline = False # in a multiline string?
19941992 self .hang_closing = options .hang_closing
19951993 self .indent_size = options .indent_size
1996- self .indent_size_str = ({2 : 'two' , 4 : 'four' , 8 : 'eight' }
1997- .get (self .indent_size , str (self .indent_size )))
19981994 self .verbose = options .verbose
19991995 self .filename = filename
20001996 # Dictionary where a checker can store its custom state.
0 commit comments