@@ -281,6 +281,7 @@ def default_lib_path(data_dir: str, pyversion: Tuple[int, int]) -> List[str]:
281
281
('data_mtime' , float ), # mtime of data_json
282
282
('data_json' , str ), # path of <id>.data.json
283
283
('suppressed' , List [str ]), # dependencies that weren't imported
284
+ ('child_modules' , List [str ]), # all submodules of the given module
284
285
('options' , Optional [Dict [str , bool ]]), # build options
285
286
('dep_prios' , List [int ]),
286
287
])
@@ -726,6 +727,7 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> Optional[Cache
726
727
meta .get ('data_mtime' ),
727
728
data_json ,
728
729
meta .get ('suppressed' , []),
730
+ meta .get ('child_modules' , []),
729
731
meta .get ('options' ),
730
732
meta .get ('dep_prios' , []),
731
733
)
@@ -749,6 +751,7 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> Optional[Cache
749
751
if st .st_mtime != m .mtime or st .st_size != m .size :
750
752
manager .log ('Metadata abandoned because of modified file {}' .format (path ))
751
753
return None
754
+
752
755
# It's a match on (id, path, mtime, size).
753
756
# Check data_json; assume if its mtime matches it's good.
754
757
# TODO: stat() errors
@@ -777,7 +780,7 @@ def random_string() -> str:
777
780
778
781
def write_cache (id : str , path : str , tree : MypyFile ,
779
782
dependencies : List [str ], suppressed : List [str ],
780
- dep_prios : List [int ],
783
+ child_modules : List [ str ], dep_prios : List [int ],
781
784
manager : BuildManager ) -> None :
782
785
"""Write cache files for a module.
783
786
@@ -817,6 +820,7 @@ def write_cache(id: str, path: str, tree: MypyFile,
817
820
'data_mtime' : data_mtime ,
818
821
'dependencies' : dependencies ,
819
822
'suppressed' : suppressed ,
823
+ 'child_modules' : child_modules ,
820
824
'options' : select_options_affecting_cache (manager .options ),
821
825
'dep_prios' : dep_prios ,
822
826
}
@@ -999,6 +1003,9 @@ class State:
999
1003
# Parent package, its parent, etc.
1000
1004
ancestors = None # type: Optional[List[str]]
1001
1005
1006
+ # A list of all direct submodules of a given module
1007
+ child_modules = None # type: Optional[Set[str]]
1008
+
1002
1009
# List of (path, line number) tuples giving context for import
1003
1010
import_context = None # type: List[Tuple[str, int]]
1004
1011
@@ -1096,11 +1103,13 @@ def __init__(self,
1096
1103
assert len (self .meta .dependencies ) == len (self .meta .dep_prios )
1097
1104
self .priorities = {id : pri
1098
1105
for id , pri in zip (self .meta .dependencies , self .meta .dep_prios )}
1106
+ self .child_modules = set (self .meta .child_modules )
1099
1107
self .dep_line_map = {}
1100
1108
else :
1101
1109
# Parse the file (and then some) to get the dependencies.
1102
1110
self .parse_file ()
1103
1111
self .suppressed = []
1112
+ self .child_modules = set ()
1104
1113
1105
1114
def skipping_ancestor (self , id : str , path : str , ancestor_for : 'State' ) -> None :
1106
1115
# TODO: Read the path (the __init__.py file) and return
@@ -1147,7 +1156,13 @@ def is_fresh(self) -> bool:
1147
1156
# self.meta.dependencies when a dependency is dropped due to
1148
1157
# suppression by --silent-imports. However when a suppressed
1149
1158
# dependency is added back we find out later in the process.
1150
- return self .meta is not None and self .dependencies == self .meta .dependencies
1159
+ return (self .meta is not None
1160
+ and self .dependencies == self .meta .dependencies
1161
+ and self .child_modules == set (self .meta .child_modules ))
1162
+
1163
+ def has_new_submodules (self ) -> bool :
1164
+ """Return if this module has new submodules after being loaded from a warm cache."""
1165
+ return self .meta is not None and self .child_modules != set (self .meta .child_modules )
1151
1166
1152
1167
def mark_stale (self ) -> None :
1153
1168
"""Throw away the cache data for this file, marking it as stale."""
@@ -1308,7 +1323,7 @@ def write_cache(self) -> None:
1308
1323
if self .path and self .manager .options .incremental and not self .manager .errors .is_errors ():
1309
1324
dep_prios = [self .priorities .get (dep , PRI_HIGH ) for dep in self .dependencies ]
1310
1325
write_cache (self .id , self .path , self .tree ,
1311
- list (self .dependencies ), list (self .suppressed ),
1326
+ list (self .dependencies ), list (self .suppressed ), list ( self . child_modules ),
1312
1327
dep_prios ,
1313
1328
self .manager )
1314
1329
@@ -1366,6 +1381,11 @@ def load_graph(sources: List[BuildSource], manager: BuildManager) -> Graph:
1366
1381
assert newst .id not in graph , newst .id
1367
1382
graph [newst .id ] = newst
1368
1383
new .append (newst )
1384
+ if dep in st .ancestors and dep in graph :
1385
+ graph [dep ].child_modules .add (st .id )
1386
+ for id , g in graph .items ():
1387
+ if g .has_new_submodules ():
1388
+ g .parse_file ()
1369
1389
return graph
1370
1390
1371
1391
0 commit comments