52
52
from mypy .version import __version__
53
53
from mypy .plugin import Plugin , DefaultPlugin , ChainedPlugin
54
54
from mypy .defaults import PYTHON3_VERSION_MIN
55
+ from mypy .server .deps import get_dependencies
55
56
56
57
57
58
PYTHON_EXTENSIONS = ['.pyi' , '.py' ]
@@ -1183,6 +1184,7 @@ def compute_hash(text: str) -> str:
1183
1184
1184
1185
1185
1186
def write_cache (id : str , path : str , tree : MypyFile ,
1187
+ serialized_fine_grained_deps : Dict [str , List [str ]],
1186
1188
dependencies : List [str ], suppressed : List [str ],
1187
1189
child_modules : List [str ], dep_prios : List [int ],
1188
1190
old_interface_hash : str , source_hash : str ,
@@ -1221,7 +1223,9 @@ def write_cache(id: str, path: str, tree: MypyFile,
1221
1223
assert os .path .dirname (meta_json ) == parent
1222
1224
1223
1225
# Serialize data and analyze interface
1224
- data = tree .serialize ()
1226
+ data = {'tree' : tree .serialize (),
1227
+ 'fine_grained_deps' : serialized_fine_grained_deps ,
1228
+ }
1225
1229
if manager .options .debug_cache :
1226
1230
data_str = json .dumps (data , indent = 2 , sort_keys = True )
1227
1231
else :
@@ -1523,6 +1527,8 @@ class State:
1523
1527
# Whether the module has an error or any of its dependencies have one.
1524
1528
transitive_error = False
1525
1529
1530
+ fine_grained_deps = None # type: Dict[str, Set[str]]
1531
+
1526
1532
# Type checker used for checking this file. Use type_checker() for
1527
1533
# access and to construct this on demand.
1528
1534
_type_checker = None # type: Optional[TypeChecker]
@@ -1551,6 +1557,7 @@ def __init__(self,
1551
1557
self .id = id or '__main__'
1552
1558
self .options = manager .options .clone_for_module (self .id )
1553
1559
self ._type_checker = None
1560
+ self .fine_grained_deps = {}
1554
1561
if not path and source is None :
1555
1562
assert id is not None
1556
1563
file_id = id
@@ -1734,7 +1741,9 @@ def load_tree(self) -> None:
1734
1741
with open (self .meta .data_json ) as f :
1735
1742
data = json .load (f )
1736
1743
# TODO: Assert data file wasn't changed.
1737
- self .tree = MypyFile .deserialize (data )
1744
+ self .tree = MypyFile .deserialize (data ['tree' ])
1745
+ self .fine_grained_deps = {k : set (v ) for k , v in data ['fine_grained_deps' ].items ()}
1746
+
1738
1747
self .manager .modules [self .id ] = self .tree
1739
1748
self .manager .add_stats (fresh_trees = 1 )
1740
1749
@@ -1977,6 +1986,19 @@ def _patch_indirect_dependencies(self,
1977
1986
elif dep not in self .suppressed and dep in self .manager .missing_modules :
1978
1987
self .suppressed .append (dep )
1979
1988
1989
+ def compute_fine_grained_deps (self ) -> None :
1990
+ assert self .tree is not None
1991
+ if '/typeshed/' in self .xpath or self .xpath .startswith ('typeshed/' ):
1992
+ # We don't track changes to typeshed -- the assumption is that they are only changed
1993
+ # as part of mypy updates, which will invalidate everything anyway.
1994
+ #
1995
+ # TODO: Not a reliable test, as we could have a package named typeshed.
1996
+ # TODO: Consider relaxing this -- maybe allow some typeshed changes to be tracked.
1997
+ return
1998
+ self .fine_grained_deps = get_dependencies (target = self .tree ,
1999
+ type_map = self .type_map (),
2000
+ python_version = self .options .python_version )
2001
+
1980
2002
def valid_references (self ) -> Set [str ]:
1981
2003
assert self .ancestors is not None
1982
2004
valid_refs = set (self .dependencies + self .suppressed + self .ancestors )
@@ -2003,6 +2025,7 @@ def write_cache(self) -> None:
2003
2025
dep_prios = self .dependency_priorities ()
2004
2026
new_interface_hash , self .meta = write_cache (
2005
2027
self .id , self .path , self .tree ,
2028
+ {k : list (v ) for k , v in self .fine_grained_deps .items ()},
2006
2029
list (self .dependencies ), list (self .suppressed ), list (self .child_modules ),
2007
2030
dep_prios , self .interface_hash , self .source_hash , self .ignore_all ,
2008
2031
self .manager )
@@ -2534,6 +2557,8 @@ def process_stale_scc(graph: Graph, scc: List[str], manager: BuildManager) -> No
2534
2557
graph [id ].transitive_error = True
2535
2558
for id in stale :
2536
2559
graph [id ].finish_passes ()
2560
+ if manager .options .cache_fine_grained :
2561
+ graph [id ].compute_fine_grained_deps ()
2537
2562
graph [id ].generate_unused_ignore_notes ()
2538
2563
manager .flush_errors (manager .errors .file_messages (graph [id ].xpath ), False )
2539
2564
graph [id ].write_cache ()
0 commit comments