4747import os .path
4848import sys
4949import traceback
50- from typing import Final , Iterable
50+ from typing import Final , Iterable , Iterator
5151
5252import mypy .build
5353import mypy .mixedtraverser
114114from mypy .stubdoc import ArgSig , FunctionSig
115115from mypy .stubgenc import InspectionStubGenerator , generate_stub_for_c_module
116116from mypy .stubutil import (
117+ TYPING_BUILTIN_REPLACEMENTS ,
117118 BaseStubGenerator ,
118119 CantImport ,
119120 ClassInfo ,
@@ -289,20 +290,19 @@ def visit_call_expr(self, node: CallExpr) -> str:
289290 raise ValueError (f"Unknown argument kind { kind } in call" )
290291 return f"{ callee } ({ ', ' .join (args )} )"
291292
293+ def _visit_ref_expr (self , node : NameExpr | MemberExpr ) -> str :
294+ fullname = self .stubgen .get_fullname (node )
295+ if fullname in TYPING_BUILTIN_REPLACEMENTS :
296+ return self .stubgen .add_name (TYPING_BUILTIN_REPLACEMENTS [fullname ], require = False )
297+ qualname = get_qualified_name (node )
298+ self .stubgen .import_tracker .require_name (qualname )
299+ return qualname
300+
292301 def visit_name_expr (self , node : NameExpr ) -> str :
293- self .stubgen .import_tracker .require_name (node .name )
294- return node .name
302+ return self ._visit_ref_expr (node )
295303
296304 def visit_member_expr (self , o : MemberExpr ) -> str :
297- node : Expression = o
298- trailer = ""
299- while isinstance (node , MemberExpr ):
300- trailer = "." + node .name + trailer
301- node = node .expr
302- if not isinstance (node , NameExpr ):
303- return ERROR_MARKER
304- self .stubgen .import_tracker .require_name (node .name )
305- return node .name + trailer
305+ return self ._visit_ref_expr (o )
306306
307307 def visit_str_expr (self , node : StrExpr ) -> str :
308308 return repr (node .value )
@@ -351,11 +351,17 @@ def find_defined_names(file: MypyFile) -> set[str]:
351351 return finder .names
352352
353353
354+ def get_assigned_names (lvalues : Iterable [Expression ]) -> Iterator [str ]:
355+ for lvalue in lvalues :
356+ if isinstance (lvalue , NameExpr ):
357+ yield lvalue .name
358+ elif isinstance (lvalue , TupleExpr ):
359+ yield from get_assigned_names (lvalue .items )
360+
361+
354362class DefinitionFinder (mypy .traverser .TraverserVisitor ):
355363 """Find names of things defined at the top level of a module."""
356364
357- # TODO: Assignment statements etc.
358-
359365 def __init__ (self ) -> None :
360366 # Short names of things defined at the top level.
361367 self .names : set [str ] = set ()
@@ -368,6 +374,10 @@ def visit_func_def(self, o: FuncDef) -> None:
368374 # Don't recurse, as we only keep track of top-level definitions.
369375 self .names .add (o .name )
370376
377+ def visit_assignment_stmt (self , o : AssignmentStmt ) -> None :
378+ for name in get_assigned_names (o .lvalues ):
379+ self .names .add (name )
380+
371381
372382def find_referenced_names (file : MypyFile ) -> set [str ]:
373383 finder = ReferenceFinder ()
@@ -1023,10 +1033,15 @@ def is_alias_expression(self, expr: Expression, top_level: bool = True) -> bool:
10231033 and isinstance (expr .node , (FuncDef , Decorator , MypyFile ))
10241034 or isinstance (expr .node , TypeInfo )
10251035 ) and not self .is_private_member (expr .node .fullname )
1026- elif (
1027- isinstance (expr , IndexExpr )
1028- and isinstance (expr .base , NameExpr )
1029- and not self .is_private_name (expr .base .name )
1036+ elif isinstance (expr , IndexExpr ) and (
1037+ (isinstance (expr .base , NameExpr ) and not self .is_private_name (expr .base .name ))
1038+ or ( # Also some known aliases that could be member expression
1039+ isinstance (expr .base , MemberExpr )
1040+ and not self .is_private_member (get_qualified_name (expr .base ))
1041+ and self .get_fullname (expr .base ).startswith (
1042+ ("builtins." , "typing." , "typing_extensions." , "collections.abc." )
1043+ )
1044+ )
10301045 ):
10311046 if isinstance (expr .index , TupleExpr ):
10321047 indices = expr .index .items
0 commit comments