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