@@ -295,9 +295,10 @@ def maximum_line_length(physical_line, max_line_length, multiline,
295295 # comments, but still report the error when the 72 first chars
296296 # are whitespaces.
297297 chunks = line .split ()
298- if ((len (chunks ) == 1 and multiline ) or
299- (len (chunks ) == 2 and chunks [0 ] == '#' )) and \
300- len (line ) - len (chunks [- 1 ]) < max_line_length - 7 :
298+ len_chunks = len (chunks )
299+ if ((len_chunks == 1 and multiline ) or
300+ (len_chunks == 2 and chunks [0 ] == '#' )) and \
301+ length - len (chunks [- 1 ]) < max_line_length - 7 :
301302 return
302303 if length > max_line_length :
303304 return (max_line_length , "E501 line too long "
@@ -406,8 +407,9 @@ def blank_lines(logical_line, blank_lines, indent_level, line_number,
406407 # Search backwards for a def ancestor or tree root
407408 # (top level).
408409 for line in lines [line_number - top_level_lines ::- 1 ]:
409- if line .strip () and expand_indent (line ) < ancestor_level :
410- ancestor_level = expand_indent (line )
410+ line_indents = expand_indent (line )
411+ if line .strip () and line_indents < ancestor_level :
412+ ancestor_level = line_indents
411413 nested = STARTSWITH_DEF_REGEX .match (line .lstrip ())
412414 if nested or ancestor_level == 0 :
413415 break
@@ -786,7 +788,7 @@ def whitespace_before_parameters(logical_line, tokens):
786788 E211: dict['key'] = list [index]
787789 """
788790 prev_type , prev_text , __ , prev_end , __ = tokens [0 ]
789- for index in range ( 1 , len ( tokens ) ):
791+ for index , _ in enumerate ( tokens ):
790792 token_type , text , start , end , __ = tokens [index ]
791793 if (
792794 token_type == tokenize .OP and
@@ -1160,6 +1162,14 @@ def imports_on_separate_lines(logical_line):
11601162 yield found , "E401 multiple imports on one line"
11611163
11621164
1165+ def is_string_literal (line ):
1166+ if line [0 ] in 'uUbB' :
1167+ line = line [1 :]
1168+ if line and line [0 ] in 'rR' :
1169+ line = line [1 :]
1170+ return line and (line [0 ] == '"' or line [0 ] == "'" )
1171+
1172+
11631173@register_check
11641174def module_imports_on_top_of_file (
11651175 logical_line , indent_level , checker_state , noqa ):
@@ -1178,12 +1188,6 @@ def module_imports_on_top_of_file(
11781188
11791189 Okay: if x:\n import os
11801190 """ # noqa
1181- def is_string_literal (line ):
1182- if line [0 ] in 'uUbB' :
1183- line = line [1 :]
1184- if line and line [0 ] in 'rR' :
1185- line = line [1 :]
1186- return line and (line [0 ] == '"' or line [0 ] == "'" )
11871191
11881192 allowed_keywords = (
11891193 'try' , 'except' , 'else' , 'finally' , 'with' , 'if' , 'elif' )
@@ -1576,7 +1580,8 @@ def ambiguous_identifier(logical_line, tokens):
15761580 brace_depth = 0
15771581 idents_to_avoid = ('l' , 'O' , 'I' )
15781582 prev_type , prev_text , prev_start , prev_end , __ = tokens [0 ]
1579- for index in range (1 , len (tokens )):
1583+ len_tokens = len (tokens )
1584+ for index in range (1 , len_tokens ):
15801585 token_type , text , start , end , line = tokens [index ]
15811586 ident = pos = None
15821587 # find function definitions
@@ -1601,32 +1606,55 @@ def ambiguous_identifier(logical_line, tokens):
16011606 pos = prev_start
16021607 # identifiers bound to values with 'as', 'for',
16031608 # 'global', or 'nonlocal'
1604- if prev_text in ('as' , 'for' , 'global' , 'nonlocal' ):
1605- if text in idents_to_avoid :
1606- ident = text
1607- pos = start
1609+ if prev_text in ('as' , 'for' , 'global' , 'nonlocal' ) and \
1610+ text in idents_to_avoid :
1611+ ident = text
1612+ pos = start
16081613 # function / lambda parameter definitions
16091614 if (
16101615 func_depth is not None and
16111616 not seen_colon and
1612- index < len ( tokens ) - 1 and tokens [index + 1 ][1 ] in ':,=)' and
1617+ index < len_tokens - 1 and tokens [index + 1 ][1 ] in ':,=)' and
16131618 prev_text in {'lambda' , ',' , '*' , '**' , '(' } and
16141619 text in idents_to_avoid
16151620 ):
16161621 ident = text
16171622 pos = start
1618- if prev_text == 'class' :
1619- if text in idents_to_avoid :
1620- yield start , "E742 ambiguous class definition '%s'" % text
1621- if prev_text == 'def' :
1622- if text in idents_to_avoid :
1623- yield start , "E743 ambiguous function definition '%s'" % text
1623+ if prev_text == 'class' and \
1624+ text in idents_to_avoid :
1625+ yield start , "E742 ambiguous class definition '%s'" % text
1626+ if prev_text == 'def' and \
1627+ text in idents_to_avoid :
1628+ yield start , "E743 ambiguous function definition '%s'" % text
16241629 if ident :
16251630 yield pos , "E741 ambiguous variable name '%s'" % ident
16261631 prev_text = text
16271632 prev_start = start
16281633
16291634
1635+ # https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
1636+ python_3000_valid = frozenset ([
1637+ '\n ' ,
1638+ '\\ ' ,
1639+ '\' ' ,
1640+ '"' ,
1641+ 'a' ,
1642+ 'b' ,
1643+ 'f' ,
1644+ 'n' ,
1645+ 'r' ,
1646+ 't' ,
1647+ 'v' ,
1648+ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
1649+ 'x' ,
1650+
1651+ # Escape sequences only recognized in string literals
1652+ 'N' ,
1653+ 'u' ,
1654+ 'U' ,
1655+ ])
1656+
1657+
16301658@register_check
16311659def python_3000_invalid_escape_sequence (logical_line , tokens , noqa ):
16321660 r"""Invalid escape sequences are deprecated in Python 3.6.
@@ -1637,27 +1665,7 @@ def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
16371665 if noqa :
16381666 return
16391667
1640- # https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
1641- valid = [
1642- '\n ' ,
1643- '\\ ' ,
1644- '\' ' ,
1645- '"' ,
1646- 'a' ,
1647- 'b' ,
1648- 'f' ,
1649- 'n' ,
1650- 'r' ,
1651- 't' ,
1652- 'v' ,
1653- '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
1654- 'x' ,
1655-
1656- # Escape sequences only recognized in string literals
1657- 'N' ,
1658- 'u' ,
1659- 'U' ,
1660- ]
1668+ valid = python_3000_valid
16611669
16621670 prefixes = []
16631671 for token_type , text , start , _ , _ in tokens :
@@ -1701,11 +1709,13 @@ def maximum_doc_length(logical_line, max_doc_length, noqa, tokens):
17011709 return
17021710
17031711 prev_token = None
1704- skip_lines = set ()
1712+ lines_to_skip = SKIP_COMMENTS .union ([tokenize .STRING ])
1713+ skip_lines = False
17051714 # Skip lines that
17061715 for token_type , text , start , end , line in tokens :
1707- if token_type not in SKIP_COMMENTS .union ([tokenize .STRING ]):
1708- skip_lines .add (line )
1716+ if token_type not in lines_to_skip :
1717+ skip_lines = True
1718+ break
17091719
17101720 for token_type , text , start , end , line in tokens :
17111721 # Skip lines that aren't pure strings
@@ -1715,19 +1725,22 @@ def maximum_doc_length(logical_line, max_doc_length, noqa, tokens):
17151725 # Only check comment-only lines
17161726 if prev_token is None or prev_token in SKIP_TOKENS :
17171727 lines = line .splitlines ()
1728+ lines_len = len (lines )
17181729 for line_num , physical_line in enumerate (lines ):
17191730 if start [0 ] + line_num == 1 and line .startswith ('#!' ):
17201731 return
17211732 length = len (physical_line )
17221733 chunks = physical_line .split ()
1723- if token_type == tokenize .COMMENT :
1724- if (len (chunks ) == 2 and
1725- length - len (chunks [- 1 ]) < MAX_DOC_LENGTH ):
1726- continue
1727- if len (chunks ) == 1 and line_num + 1 < len (lines ):
1728- if (len (chunks ) == 1 and
1729- length - len (chunks [- 1 ]) < MAX_DOC_LENGTH ):
1730- continue
1734+ len_chunks = len (chunks )
1735+ len_last_chunk = len (chunks [- 1 ]) if chunks else None
1736+ if token_type == tokenize .COMMENT and \
1737+ (len_chunks == 2 and
1738+ length - len_last_chunk < MAX_DOC_LENGTH ):
1739+ continue
1740+ if len_chunks == 1 and line_num + 1 < lines_len and \
1741+ (len_chunks == 1 and
1742+ length - len_last_chunk < MAX_DOC_LENGTH ):
1743+ continue
17311744 if length > max_doc_length :
17321745 doc_error = (start [0 ] + line_num , max_doc_length )
17331746 yield (doc_error , "W505 doc line too long "
@@ -2145,17 +2158,16 @@ def check_all(self, expected=None, line_offset=0):
21452158 parens += 1
21462159 elif text in '}])' :
21472160 parens -= 1
2148- elif not parens :
2149- if token_type in NEWLINE :
2150- if token_type == tokenize .NEWLINE :
2151- self .check_logical ()
2152- self .blank_before = 0
2153- elif len (self .tokens ) == 1 :
2154- # The physical line contains only this token.
2155- self .blank_lines += 1
2156- del self .tokens [0 ]
2157- else :
2158- self .check_logical ()
2161+ elif not parens and token_type in NEWLINE :
2162+ if token_type == tokenize .NEWLINE :
2163+ self .check_logical ()
2164+ self .blank_before = 0
2165+ elif len (self .tokens ) == 1 :
2166+ # The physical line contains only this token.
2167+ self .blank_lines += 1
2168+ del self .tokens [0 ]
2169+ else :
2170+ self .check_logical ()
21592171 if self .tokens :
21602172 self .check_physical (self .lines [- 1 ])
21612173 self .check_logical ()
0 commit comments