@@ -160,8 +160,7 @@ def full_components(self) -> list[Component]:
160160 @property
161161 def code_str (self ) -> str :
162162 """Code representation of components."""
163- break_on = set (NameBreak )
164- breaks = [i for i , c in enumerate (self .components ) if c .name in break_on ]
163+ breaks = [i for i , c in enumerate (self .components ) if c .name in NameBreak ]
165164 start_ix = breaks [- 1 ] + 1 if breaks else 0
166165 return "." .join (c .name for c in self .components [start_ix :])
167166
@@ -214,20 +213,16 @@ def split(self) -> list[Name]:
214213 return [self .to_name (i ) for i in items ]
215214
216215
217- def track_parents (func ):
218- """
219- Track a stack of nodes to determine the position of the current node.
220-
221- Uses and increments the surrounding classes :attr:`_parents`.
222- """
216+ def maybe_resolve_result (func ):
217+ """Track a stack of nodes to determine the position of the current node."""
223218
224219 @wraps (func )
225220 def wrapper (self : ImportTrackerVisitor , * args , ** kwargs ):
226221 self ._parents += 1
227222 result = func (self , * args , ** kwargs )
228223 self ._parents -= 1
229224 if not self ._parents :
230- self .dispatch_result (result )
225+ self ._resolve_assign_or_pending_access (result )
231226 return result
232227
233228 return wrapper
@@ -259,7 +254,7 @@ def __init__(self, doctree_node) -> None:
259254 # Holds references to the values of previous nesting levels.
260255 self .outer_scopes_stack : list [dict [str , list [Component ]]] = []
261256
262- def save_access (self , access : Access ) -> None :
257+ def save_accessed_names (self , access : Access ) -> None :
263258 """Convert Access to Names to store in the visitor for aggregation."""
264259 names = access .split () if not self ._no_split else [Access .to_name (access )]
265260 self .accessed .extend (names )
@@ -272,7 +267,7 @@ def no_split(self) -> Generator[None, None, None]:
272267 self ._no_split = old
273268
274269 @contextmanager
275- def reset_parents (self ) -> Generator [None , None , None ]:
270+ def track_independently (self ) -> Generator [None , None , None ]:
276271 """Reset parents state for the duration of the context."""
277272 self ._parents , old = (0 , self ._parents )
278273 yield
@@ -288,7 +283,7 @@ def visit(self, node: ast.AST):
288283 if isinstance (node , self .track_nodes ):
289284 return super ().visit (node )
290285
291- with self .reset_parents ():
286+ with self .track_independently ():
292287 return super ().visit (node )
293288
294289 def overwrite_name (self , name : str ) -> None :
@@ -307,7 +302,7 @@ def assign_name(self, name: str, components: list[Component]) -> None:
307302 self .overwrite_name (name )
308303 self .pseudo_scopes_stack [- 1 ][name ] = components
309304
310- def create_access (
305+ def _create_access (
311306 self , scope_key : str , new_components : list [Component ]
312307 ) -> Access | None :
313308 """Create access from scope."""
@@ -316,7 +311,7 @@ def create_access(
316311 return None
317312
318313 access = Access (LinkContext .none , prior , new_components )
319- self .save_access (access )
314+ self .save_accessed_names (access )
320315 return access
321316
322317 def resolve_pending_access (self , pending : PendingAccess ) -> Access | None :
@@ -328,14 +323,14 @@ def resolve_pending_access(self, pending: PendingAccess) -> Access | None:
328323 self .overwrite_name (components [0 ].name )
329324 return None
330325
331- access = self .create_access (components [0 ].name , components )
326+ access = self ._create_access (components [0 ].name , components )
332327 if context == "del" :
333328 self .overwrite_name (components [0 ].name )
334329 return access
335330
336331 def resolve_assignment (self , assignment : Assignment ) -> Access | None :
337332 """Resolve access for assignment values and targets."""
338- access = self .dispatch_result (assignment .value )
333+ access = self ._resolve_assign_or_pending_access (assignment .value )
339334 self ._resolve_assign_targets (assignment , access )
340335 return access
341336
@@ -348,9 +343,9 @@ def _resolve_assign_targets(self, assignment: Assignment, access: Access) -> Non
348343 value = access if len (assign .elements ) <= 1 else None
349344
350345 for target in assign .elements :
351- self ._resolve_assign_target (target , value )
346+ self ._resolve_single_assign_target (target , value )
352347
353- def _resolve_assign_target (
348+ def _resolve_single_assign_target (
354349 self , target : PendingAccess | None , value : Access | None
355350 ) -> None :
356351 if target is None :
@@ -362,16 +357,16 @@ def _resolve_assign_target(
362357 self .overwrite_name (comp .name )
363358 else :
364359 self .assign_name (comp .name , value .full_components )
365- self .create_access (comp .name , target .components )
360+ self ._create_access (comp .name , target .components )
366361 else :
367362 self .resolve_pending_access (target )
368363
369364 def create_simple_access (self , name : str , lineno : int ) -> None :
370365 """Create single-component access to scope."""
371366 component = Component (name , lineno , lineno , "load" )
372- self .create_access (component .name , [component ])
367+ self ._create_access (component .name , [component ])
373368
374- def dispatch_result (
369+ def _resolve_assign_or_pending_access (
375370 self , result : PendingAccess | Assignment | None
376371 ) -> Access | None :
377372 """Determine the appropriate processing after tracking an access chain."""
@@ -430,14 +425,14 @@ def visit_Import(self, node: ast.Import | ast.ImportFrom, prefix: str = "") -> N
430425 prefix_parts = prefix .rstrip ("." ).split ("." ) if prefix else []
431426 prefix_components = [Component (n , * linenos (node ), "load" ) for n in prefix_parts ]
432427 if prefix :
433- self .save_access (Access (LinkContext .import_from , [], prefix_components ))
428+ self .save_accessed_names (Access (LinkContext .import_from , [], prefix_components ))
434429
435430 for import_name , alias in zip (import_names , aliases , strict = True ):
436431 if not import_star :
437432 components = [
438433 Component (n , * linenos (node ), "load" ) for n in import_name .split ("." )
439434 ]
440- self .save_access (
435+ self .save_accessed_names (
441436 Access (LinkContext .import_target , [], components , prefix_components )
442437 )
443438
@@ -460,26 +455,26 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
460455 else :
461456 self .visit_Import (node , prefix = node .module + "." )
462457
463- @track_parents
458+ @maybe_resolve_result
464459 def visit_Name (self , node : ast .Name ) -> PendingAccess :
465- """Visit a Name node ."""
460+ """Create the initial pending access chain ."""
466461 return PendingAccess ([Component .from_ast (node )])
467462
468- @track_parents
463+ @maybe_resolve_result
469464 def visit_Attribute (self , node : ast .Attribute ) -> PendingAccess | None :
470- """Visit an Attribute node ."""
465+ """Add attribute access to an existing access chain ."""
471466 inner : PendingAccess | None = self .visit (node .value )
472467 if inner is not None :
473468 inner .components .append (Component .from_ast (node ))
474469 return inner
475470
476- @track_parents
471+ @maybe_resolve_result
477472 def visit_Call (self , node : ast .Call ) -> PendingAccess | None :
478- """Visit a Call node ."""
473+ """Add call to an existing access chain and separately visit args ."""
479474 inner : PendingAccess | None = self .visit (node .func )
480475 if inner is not None :
481476 inner .components .append (Component .from_ast (node ))
482- with self .reset_parents ():
477+ with self .track_independently ():
483478 for arg in node .args + node .keywords :
484479 self .visit (arg )
485480 if hasattr (node , "starargs" ):
@@ -488,7 +483,7 @@ def visit_Call(self, node: ast.Call) -> PendingAccess | None:
488483 self .visit (node .kwargs )
489484 return inner
490485
491- @track_parents
486+ @maybe_resolve_result
492487 def visit_Tuple (self , node : ast .Tuple ) -> list [PendingAccess ] | None :
493488 """Visit a Tuple node."""
494489 if isinstance (node .ctx , ast .Store ):
@@ -500,12 +495,12 @@ def visit_Tuple(self, node: ast.Tuple) -> list[PendingAccess] | None:
500495 else :
501496 accesses .extend (ret )
502497 return accesses
503- with self .reset_parents ():
498+ with self .track_independently ():
504499 for element in node .elts :
505500 self .visit (element )
506501 return None
507502
508- @track_parents
503+ @maybe_resolve_result
509504 def visit_Assign (self , node : ast .Assign ) -> Assignment :
510505 """Visit an Assign node."""
511506 value = self .visit (node .value )
@@ -517,7 +512,7 @@ def visit_Assign(self, node: ast.Assign) -> Assignment:
517512 targets .append (AssignTarget (target ))
518513 return Assignment (targets , value )
519514
520- @track_parents
515+ @maybe_resolve_result
521516 def visit_AnnAssign (self , node : ast .AnnAssign ) -> Assignment :
522517 """Visit an AnnAssign node."""
523518 value = self .visit (node .value ) if node .value is not None else None
@@ -541,17 +536,17 @@ def visit_AugAssign(self, node: ast.AugAssign) -> None:
541536 self .visit (node .target )
542537 self .in_augassign = temp
543538
544- @track_parents
539+ @maybe_resolve_result
545540 def visit_NamedExpr (self , node : ast .NamedExpr ) -> Assignment :
546541 """Visit a NamedExpr node."""
547542 value = self .visit (node .value )
548543 target = self .visit (node .target )
549544 return Assignment ([AssignTarget ([target ])], value )
550545
551- @track_parents
546+ @maybe_resolve_result
552547 def visit_MatchClass (self , node : ast .AST ) -> None :
553548 """Visit a match case class as a series of assignments."""
554- with self .reset_parents ():
549+ with self .track_independently ():
555550 cls = self .visit (node .cls )
556551
557552 accesses = []
@@ -577,7 +572,7 @@ def visit_MatchClass(self, node: ast.AST) -> None:
577572 for assign in assigns :
578573 self .resolve_assignment (assign )
579574
580- @track_parents
575+ @maybe_resolve_result
581576 def visit_MatchAs (self , node : ast .AST ) -> PendingAccess :
582577 """Track match alias names."""
583578 return PendingAccess ([Component .from_ast (node )])
@@ -645,7 +640,7 @@ def visit_FunctionDef(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> Non
645640 inner .visit (n )
646641 self .accessed .extend (inner .accessed )
647642
648- @track_parents
643+ @maybe_resolve_result
649644 def visit_arg (self , arg : ast .arg ) -> Assignment :
650645 """Handle function argument and its annotation."""
651646 target = PendingAccess ([Component .from_ast (arg )])
0 commit comments