66
77from .alias_helper import (
88 as_alias_handler ,
9+ fully_qualify_alias_labels ,
910 handle_aliases_in_init_files ,
1011 handle_fdid_aliases ,
1112 not_as_alias_handler ,
@@ -624,6 +625,11 @@ def add_blackbox_or_builtin_call(self, node, blackbox): # noqa: C901
624625
625626 call_function_label = call_label_visitor .result [:call_label_visitor .result .find ('(' )]
626627
628+ # Check if function call matches a blackbox/built-in alias and if so, resolve it
629+ # This resolves aliases like "from os import system as mysys" as: mysys -> os.system
630+ local_definitions = self .module_definitions_stack [- 1 ]
631+ call_function_label = fully_qualify_alias_labels (call_function_label , local_definitions .import_alias_mapping )
632+
627633 # Create e.g. ~call_1 = ret_func_foo
628634 LHS = CALL_IDENTIFIER + 'call_' + str (saved_function_call_index )
629635 RHS = 'ret_' + call_function_label + '('
@@ -810,7 +816,7 @@ def add_module( # noqa: C901
810816 module_path = module [1 ]
811817
812818 parent_definitions = self .module_definitions_stack [- 1 ]
813- # The only place the import_alias_mapping is updated
819+ # Here, in `visit_Import` and in `visit_ImportFrom` are the only places the ` import_alias_mapping` is updated
814820 parent_definitions .import_alias_mapping .update (import_alias_mapping )
815821 parent_definitions .import_names = local_names
816822
@@ -919,10 +925,10 @@ def from_directory_import(
919925 if init_exists and not skip_init :
920926 package_name = os .path .split (module_path )[1 ]
921927 return self .add_module (
922- (module [0 ], init_file_location ),
923- package_name ,
924- local_names ,
925- import_alias_mapping ,
928+ module = (module [0 ], init_file_location ),
929+ module_or_package_name = package_name ,
930+ local_names = local_names ,
931+ import_alias_mapping = import_alias_mapping ,
926932 is_init = True ,
927933 from_from = True
928934 )
@@ -932,10 +938,10 @@ def from_directory_import(
932938 new_init_file_location = os .path .join (full_name , '__init__.py' )
933939 if os .path .isfile (new_init_file_location ):
934940 self .add_module (
935- (real_name , new_init_file_location ),
936- real_name ,
937- local_names ,
938- import_alias_mapping ,
941+ module = (real_name , new_init_file_location ),
942+ module_or_package_name = real_name ,
943+ local_names = local_names ,
944+ import_alias_mapping = import_alias_mapping ,
939945 is_init = True ,
940946 from_from = True ,
941947 from_fdid = True
@@ -945,10 +951,10 @@ def from_directory_import(
945951 else :
946952 file_module = (real_name , full_name + '.py' )
947953 self .add_module (
948- file_module ,
949- real_name ,
950- local_names ,
951- import_alias_mapping ,
954+ module = file_module ,
955+ module_or_package_name = real_name ,
956+ local_names = local_names ,
957+ import_alias_mapping = import_alias_mapping ,
952958 from_from = True
953959 )
954960 return IgnoredNode ()
@@ -959,10 +965,10 @@ def import_package(self, module, module_name, local_name, import_alias_mapping):
959965 init_exists = os .path .isfile (init_file_location )
960966 if init_exists :
961967 return self .add_module (
962- (module [0 ], init_file_location ),
963- module_name ,
964- local_name ,
965- import_alias_mapping ,
968+ module = (module [0 ], init_file_location ),
969+ module_or_package_name = module_name ,
970+ local_names = local_name ,
971+ import_alias_mapping = import_alias_mapping ,
966972 is_init = True
967973 )
968974 else :
@@ -1005,10 +1011,10 @@ def handle_relative_import(self, node):
10051011 # Is it a file?
10061012 if name_with_dir .endswith ('.py' ):
10071013 return self .add_module (
1008- (node .module , name_with_dir ),
1009- None ,
1010- as_alias_handler (node .names ),
1011- retrieve_import_alias_mapping (node .names ),
1014+ module = (node .module , name_with_dir ),
1015+ module_or_package_name = None ,
1016+ local_names = as_alias_handler (node .names ),
1017+ import_alias_mapping = retrieve_import_alias_mapping (node .names ),
10121018 from_from = True
10131019 )
10141020 return self .from_directory_import (
@@ -1031,10 +1037,10 @@ def visit_Import(self, node):
10311037 retrieve_import_alias_mapping (node .names )
10321038 )
10331039 return self .add_module (
1034- module ,
1035- name .name ,
1036- name .asname ,
1037- retrieve_import_alias_mapping (node .names )
1040+ module = module ,
1041+ module_or_package_name = name .name ,
1042+ local_names = name .asname ,
1043+ import_alias_mapping = retrieve_import_alias_mapping (node .names )
10381044 )
10391045 for module in self .project_modules :
10401046 if name .name == module [0 ]:
@@ -1046,55 +1052,69 @@ def visit_Import(self, node):
10461052 retrieve_import_alias_mapping (node .names )
10471053 )
10481054 return self .add_module (
1049- module ,
1050- name .name ,
1051- name .asname ,
1052- retrieve_import_alias_mapping (node .names )
1055+ module = module ,
1056+ module_or_package_name = name .name ,
1057+ local_names = name .asname ,
1058+ import_alias_mapping = retrieve_import_alias_mapping (node .names )
10531059 )
10541060 for alias in node .names :
1061+ # The module is uninspectable (so blackbox or built-in). If it has an alias, we remember
1062+ # the alias so we can do fully qualified name resolution for blackbox- and built-in trigger words
1063+ # e.g. we want a call to "os.system" be recognised, even if we do "import os as myos"
1064+ if alias .asname is not None and alias .asname != alias .name :
1065+ local_definitions = self .module_definitions_stack [- 1 ]
1066+ local_definitions .import_alias_mapping [name .asname ] = alias .name
10551067 if alias .name not in uninspectable_modules :
1056- log .warn ("Cannot inspect module %s" , alias .name )
1068+ log .warning ("Cannot inspect module %s" , alias .name )
10571069 uninspectable_modules .add (alias .name ) # Don't repeatedly warn about this
10581070 return IgnoredNode ()
10591071
10601072 def visit_ImportFrom (self , node ):
10611073 # Is it relative?
10621074 if node .level > 0 :
10631075 return self .handle_relative_import (node )
1064- else :
1065- for module in self .local_modules :
1066- if node .module == module [0 ]:
1067- if os .path .isdir (module [1 ]):
1068- return self .from_directory_import (
1069- module ,
1070- not_as_alias_handler (node .names ),
1071- as_alias_handler (node .names )
1072- )
1073- return self .add_module (
1076+ # not relative
1077+ for module in self .local_modules :
1078+ if node .module == module [0 ]:
1079+ if os .path .isdir (module [1 ]):
1080+ return self .from_directory_import (
10741081 module ,
1075- None ,
1076- as_alias_handler (node .names ),
1077- retrieve_import_alias_mapping (node .names ),
1078- from_from = True
1082+ not_as_alias_handler (node .names ),
1083+ as_alias_handler (node .names )
10791084 )
1080- for module in self .project_modules :
1081- name = module [0 ]
1082- if node .module == name :
1083- if os .path .isdir (module [1 ]):
1084- return self .from_directory_import (
1085- module ,
1086- not_as_alias_handler (node .names ),
1087- as_alias_handler (node .names ),
1088- retrieve_import_alias_mapping (node .names )
1089- )
1090- return self .add_module (
1085+ return self .add_module (
1086+ module = module ,
1087+ module_or_package_name = None ,
1088+ local_names = as_alias_handler (node .names ),
1089+ import_alias_mapping = retrieve_import_alias_mapping (node .names ),
1090+ from_from = True
1091+ )
1092+ for module in self .project_modules :
1093+ name = module [0 ]
1094+ if node .module == name :
1095+ if os .path .isdir (module [1 ]):
1096+ return self .from_directory_import (
10911097 module ,
1092- None ,
1098+ not_as_alias_handler ( node . names ) ,
10931099 as_alias_handler (node .names ),
1094- retrieve_import_alias_mapping (node .names ),
1095- from_from = True
1100+ retrieve_import_alias_mapping (node .names )
10961101 )
1102+ return self .add_module (
1103+ module = module ,
1104+ module_or_package_name = None ,
1105+ local_names = as_alias_handler (node .names ),
1106+ import_alias_mapping = retrieve_import_alias_mapping (node .names ),
1107+ from_from = True
1108+ )
1109+
1110+ # Remember aliases for uninspectable modules such that we can label them fully qualified
1111+ # e.g. we want a call to "os.system" be recognised, even if we do "from os import system"
1112+ # from os import system as mysystem -> module=os, name=system, asname=mysystem
1113+ for name in node .names :
1114+ local_definitions = self .module_definitions_stack [- 1 ]
1115+ local_definitions .import_alias_mapping [name .asname or name .name ] = "{}.{}" .format (node .module , name .name )
1116+
10971117 if node .module not in uninspectable_modules :
1098- log .warn ("Cannot inspect module %s" , node .module )
1118+ log .warning ("Cannot inspect module %s" , node .module )
10991119 uninspectable_modules .add (node .module )
11001120 return IgnoredNode ()
0 commit comments