@@ -2282,20 +2282,38 @@ def _is_variable_violation(
2282
2282
elif isinstance (defframe , nodes .ClassDef ) and isinstance (
2283
2283
frame , nodes .FunctionDef
2284
2284
):
2285
- # Special rule for function return annotations,
2286
- # using a name defined earlier in the class containing the function.
2287
- if node is frame .returns and defframe .parent_of (frame .returns ):
2288
- annotation_return = True
2289
- if frame .returns .name in defframe .locals :
2290
- definition = defframe .locals [node .name ][0 ]
2291
- if definition .lineno is None or definition .lineno < frame .lineno :
2292
- # Detect class assignments with a name defined earlier in the
2293
- # class. In this case, no warning should be raised.
2294
- maybe_before_assign = False
2285
+ # Special rules for function return annotations.
2286
+ if node is frame .returns :
2287
+ # Using a name defined earlier in the class containing the function.
2288
+ if defframe .parent_of (frame .returns ):
2289
+ annotation_return = True
2290
+ if frame .returns .name in defframe .locals :
2291
+ definition = defframe .locals [node .name ][0 ]
2292
+ # no warning raised if a name was defined earlier in the class
2293
+ maybe_before_assign = (
2294
+ definition .lineno is not None
2295
+ and definition .lineno >= frame .lineno
2296
+ )
2295
2297
else :
2296
2298
maybe_before_assign = True
2297
- else :
2298
- maybe_before_assign = True
2299
+ # Using a name defined in the module if this is a nested function.
2300
+ elif (
2301
+ # defframe is the class containing the function.
2302
+ # It shouldn't be nested: expect its parent to be a module.
2303
+ (defframe_parent := next (defframe .node_ancestors ()))
2304
+ and isinstance (defframe_parent , nodes .Module )
2305
+ # frame is the function inside the class.
2306
+ and (frame_ancestors := tuple (frame .node_ancestors ()))
2307
+ # Does that function have any functions as ancestors?
2308
+ and any (
2309
+ isinstance (ancestor , nodes .FunctionDef )
2310
+ for ancestor in frame_ancestors
2311
+ )
2312
+ # And is its last ancestor the same module as the class's?
2313
+ and frame_ancestors [- 1 ] is defframe_parent
2314
+ ):
2315
+ annotation_return = True
2316
+ maybe_before_assign = False
2299
2317
if isinstance (node .parent , nodes .Arguments ):
2300
2318
maybe_before_assign = stmt .fromlineno <= defstmt .fromlineno
2301
2319
elif is_recursive_klass :
0 commit comments