57
57
DUMP_TYPE_STATS = 'dump-type-stats'
58
58
DUMP_INFER_STATS = 'dump-infer-stats'
59
59
SILENT_IMPORTS = 'silent-imports' # Silence imports of .py files
60
+ ALMOST_SILENT = 'almost-silent' # If SILENT_IMPORTS: report silenced imports as errors
60
61
INCREMENTAL = 'incremental' # Incremental mode: use the cache
61
62
FAST_PARSER = 'fast-parser' # Use experimental fast parser
62
63
# Disallow calling untyped functions from typed ones
@@ -941,7 +942,7 @@ def __init__(self,
941
942
manager : BuildManager ,
942
943
caller_state : 'State' = None ,
943
944
caller_line : int = 0 ,
944
- is_ancestor : bool = False ,
945
+ ancestor_for : 'State' = None ,
945
946
) -> None :
946
947
assert id or path or source is not None , "Neither id, path nor source given"
947
948
self .manager = manager
@@ -971,13 +972,18 @@ def __init__(self,
971
972
if path :
972
973
# In silent mode, don't import .py files, except from stubs.
973
974
if (SILENT_IMPORTS in manager .flags and
974
- path .endswith ('.py' ) and (caller_state or is_ancestor )):
975
+ path .endswith ('.py' ) and (caller_state or ancestor_for )):
975
976
# (Never silence builtins, even if it's a .py file;
976
977
# this can happen in tests!)
977
978
if (id != 'builtins' and
978
979
not ((caller_state and
979
980
caller_state .tree and
980
981
caller_state .tree .is_stub ))):
982
+ if ALMOST_SILENT in manager .flags :
983
+ if ancestor_for :
984
+ self .skipping_ancestor (id , path , ancestor_for )
985
+ else :
986
+ self .skipping_module (id , path )
981
987
path = None
982
988
manager .missing_modules .add (id )
983
989
raise ModuleNotFound
@@ -986,10 +992,12 @@ def __init__(self,
986
992
# misspelled module name, missing stub, module not in
987
993
# search path or the module has not been installed.
988
994
if caller_state :
989
- if not (SILENT_IMPORTS in manager .flags or
990
- (caller_state .tree is not None and
991
- (caller_line in caller_state .tree .ignored_lines or
992
- 'import' in caller_state .tree .weak_opts ))):
995
+ suppress_message = ((SILENT_IMPORTS in manager .flags and
996
+ ALMOST_SILENT not in manager .flags ) or
997
+ (caller_state .tree is not None and
998
+ (caller_line in caller_state .tree .ignored_lines or
999
+ 'import' in caller_state .tree .weak_opts )))
1000
+ if not suppress_message :
993
1001
save_import_context = manager .errors .import_context ()
994
1002
manager .errors .set_import_context (caller_state .import_context )
995
1003
manager .module_not_found (caller_state .xpath , caller_line , id )
@@ -1015,6 +1023,36 @@ def __init__(self,
1015
1023
# Parse the file (and then some) to get the dependencies.
1016
1024
self .parse_file ()
1017
1025
1026
+ def skipping_ancestor (self , id : str , path : str , ancestor_for : 'State' ) -> None :
1027
+ # TODO: Read the path (the __init__.py file) and return
1028
+ # immediately if it's empty or only contains comments.
1029
+ # But beware, some package may be the ancestor of many modules,
1030
+ # so we'd need to cache the decision.
1031
+ manager = self .manager
1032
+ manager .errors .set_import_context ([])
1033
+ manager .errors .set_file (ancestor_for .xpath )
1034
+ manager .errors .report (- 1 , "Ancestor package '%s' silently ignored" % (id ,),
1035
+ severity = 'note' , only_once = True )
1036
+ manager .errors .report (- 1 , "(Using --silent-imports, submodule passed on command line)" ,
1037
+ severity = 'note' , only_once = True )
1038
+ manager .errors .report (- 1 , "(This note brought to you by --almost-silent)" ,
1039
+ severity = 'note' , only_once = True )
1040
+
1041
+ def skipping_module (self , id : str , path : str ) -> None :
1042
+ assert self .caller_state , (id , path )
1043
+ manager = self .manager
1044
+ save_import_context = manager .errors .import_context ()
1045
+ manager .errors .set_import_context (self .caller_state .import_context )
1046
+ manager .errors .set_file (self .caller_state .xpath )
1047
+ line = self .caller_line
1048
+ manager .errors .report (line , "Import of '%s' silently ignored" % (id ,),
1049
+ severity = 'note' )
1050
+ manager .errors .report (line , "(Using --silent-imports, module not passed on command line)" ,
1051
+ severity = 'note' , only_once = True )
1052
+ manager .errors .report (line , "(This note courtesy of --almost-silent)" ,
1053
+ severity = 'note' , only_once = True )
1054
+ manager .errors .set_import_context (save_import_context )
1055
+
1018
1056
def add_ancestors (self ) -> None :
1019
1057
# All parent packages are new ancestors.
1020
1058
ancestors = []
@@ -1215,7 +1253,7 @@ def load_graph(sources: List[BuildSource], manager: BuildManager) -> Graph:
1215
1253
# TODO: Why not 'if dep not in st.dependencies' ?
1216
1254
# Ancestors don't have import context.
1217
1255
newst = State (id = dep , path = None , source = None , manager = manager ,
1218
- is_ancestor = True )
1256
+ ancestor_for = st )
1219
1257
else :
1220
1258
newst = State (id = dep , path = None , source = None , manager = manager ,
1221
1259
caller_state = st , caller_line = st .dep_line_map .get (dep , 1 ))
0 commit comments