135135LAMBDA_REGEX = re .compile (r'\blambda\b' )
136136HUNK_REGEX = re .compile (r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$' )
137137STARTSWITH_DEF_REGEX = re .compile (r'^(async\s+def|def)\b' )
138+ STARTSWITH_GENERIC_REGEX = re .compile (r'^(async\s+def|def|class|type)\s+\w+\[' )
138139STARTSWITH_TOP_LEVEL_REGEX = re .compile (r'^(async\s+def\s+|def\s+|class\s+|@)' )
139140STARTSWITH_INDENT_STATEMENT_REGEX = re .compile (
140141 r'^\s*({})\b' .format ('|' .join (s .replace (' ' , r'\s+' ) for s in (
@@ -1019,12 +1020,13 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
10191020 E251: return magic(r = real, i = imag)
10201021 E252: def complex(real, image: float=0.0):
10211022 """
1022- parens = 0
1023+ paren_stack = []
10231024 no_space = False
10241025 require_space = False
10251026 prev_end = None
10261027 annotated_func_arg = False
10271028 in_def = bool (STARTSWITH_DEF_REGEX .match (logical_line ))
1029+ in_generic = bool (STARTSWITH_GENERIC_REGEX .match (logical_line ))
10281030
10291031 message = "E251 unexpected spaces around keyword / parameter equals"
10301032 missing_message = "E252 missing whitespace around parameter equals"
@@ -1042,23 +1044,31 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
10421044 yield (prev_end , missing_message )
10431045 if token_type == tokenize .OP :
10441046 if text in '([' :
1045- parens += 1
1046- elif text in ')]' :
1047- parens -= 1
1048- elif in_def and text == ':' and parens == 1 :
1047+ paren_stack .append (text )
1048+ elif text in ')]' and paren_stack :
1049+ paren_stack .pop ()
1050+ elif (
1051+ text == ':' and (
1052+ # def f(arg: tp = default): ...
1053+ (in_def and paren_stack == ['(' ]) or
1054+ # def f[T: tp = default](): ...
1055+ # class C[T: tp = default](): ...
1056+ (in_generic and paren_stack == ['[' ])
1057+ )
1058+ ):
10491059 annotated_func_arg = True
1050- elif parens == 1 and text == ',' :
1060+ elif len ( paren_stack ) == 1 and text == ',' :
10511061 annotated_func_arg = False
1052- elif parens and text == '=' :
1053- if annotated_func_arg and parens == 1 :
1062+ elif paren_stack and text == '=' :
1063+ if annotated_func_arg and len ( paren_stack ) == 1 :
10541064 require_space = True
10551065 if start == prev_end :
10561066 yield (prev_end , missing_message )
10571067 else :
10581068 no_space = True
10591069 if start != prev_end :
10601070 yield (prev_end , message )
1061- if not parens :
1071+ if not paren_stack :
10621072 annotated_func_arg = False
10631073
10641074 prev_end = end
0 commit comments