@@ -1405,23 +1405,14 @@ def visit_import_from(self, imp: ImportFrom) -> None:
1405
1405
# If it is still not resolved, check for a module level __getattr__
1406
1406
if (module and not node and (module .is_stub or self .options .python_version >= (3 , 7 ))
1407
1407
and '__getattr__' in module .names ):
1408
- getattr_defn = module .names ['__getattr__' ]
1409
- if isinstance (getattr_defn .node , (FuncDef , Var )):
1410
- if isinstance (getattr_defn .node .type , CallableType ):
1411
- typ = getattr_defn .node .type .ret_type
1412
- else :
1413
- typ = AnyType (TypeOfAny .from_error )
1414
- if as_id :
1415
- name = as_id
1416
- else :
1417
- name = id
1418
- ast_node = Var (name , type = typ )
1419
- if self .type :
1420
- ast_node ._fullname = self .type .fullname () + "." + name
1421
- else :
1422
- ast_node ._fullname = self .qualified_name (name )
1423
- symbol = SymbolTableNode (GDEF , ast_node )
1424
- self .add_symbol (name , symbol , imp )
1408
+ name = as_id if as_id else id
1409
+ if self .type :
1410
+ fullname = self .type .fullname () + "." + name
1411
+ else :
1412
+ fullname = self .qualified_name (name )
1413
+ gvar = self .create_getattr_var (module .names ['__getattr__' ], name , fullname )
1414
+ if gvar :
1415
+ self .add_symbol (name , gvar , imp )
1425
1416
continue
1426
1417
if node and node .kind != UNBOUND_IMPORTED and not node .module_hidden :
1427
1418
if not node :
@@ -3087,6 +3078,12 @@ def lookup_qualified(self, name: str, ctx: Context,
3087
3078
n = names .get (parts [i ], None )
3088
3079
if n and isinstance (n .node , ImportedName ):
3089
3080
n = self .dereference_module_cross_ref (n )
3081
+ elif '__getattr__' in names :
3082
+ gvar = self .create_getattr_var (names ['__getattr__' ],
3083
+ parts [i ], parts [i ])
3084
+ if gvar :
3085
+ names [name ] = gvar
3086
+ n = gvar
3090
3087
# TODO: What if node is Var or FuncDef?
3091
3088
# Currently, missing these cases results in controversial behavior, when
3092
3089
# lookup_qualified(x.y.z) returns Var(x).
@@ -3102,6 +3099,22 @@ def lookup_qualified(self, name: str, ctx: Context,
3102
3099
return n
3103
3100
return None
3104
3101
3102
+ def create_getattr_var (self , getattr_defn : SymbolTableNode ,
3103
+ name : str , fullname : str ) -> Optional [SymbolTableNode ]:
3104
+ """Create a dummy global symbol using __getattr__ return type.
3105
+
3106
+ If not possible, return None.
3107
+ """
3108
+ if isinstance (getattr_defn .node , (FuncDef , Var )):
3109
+ if isinstance (getattr_defn .node .type , CallableType ):
3110
+ typ = getattr_defn .node .type .ret_type
3111
+ else :
3112
+ typ = AnyType (TypeOfAny .from_error )
3113
+ v = Var (name , type = typ )
3114
+ v ._fullname = fullname
3115
+ return SymbolTableNode (GDEF , v )
3116
+ return None
3117
+
3105
3118
def rebind_symbol_table_node (self , n : SymbolTableNode ) -> Optional [SymbolTableNode ]:
3106
3119
"""If node refers to old version of module, return reference to new version.
3107
3120
0 commit comments