@@ -1626,8 +1626,14 @@ class State:
1626
1626
meta = None # type: Optional[CacheMeta]
1627
1627
data = None # type: Optional[str]
1628
1628
tree = None # type: Optional[MypyFile]
1629
+ # We keep both a list and set of dependencies. A set because it makes it efficient to
1630
+ # prevent duplicates and the list because I am afraid of changing the order of
1631
+ # iteration over dependencies.
1632
+ # They should be managed with add_dependency and suppress_dependency.
1629
1633
dependencies = None # type: List[str] # Modules directly imported by the module
1634
+ dependencies_set = None # type: Set[str] # The same but as a set for deduplication purposes
1630
1635
suppressed = None # type: List[str] # Suppressed/missing dependencies
1636
+ suppressed_set = None # type: Set[str] # Suppressed/missing dependencies
1631
1637
priorities = None # type: Dict[str, int]
1632
1638
1633
1639
# Map each dependency to the line number where it is first imported
@@ -1735,7 +1741,9 @@ def __init__(self,
1735
1741
# Make copies, since we may modify these and want to
1736
1742
# compare them to the originals later.
1737
1743
self .dependencies = list (self .meta .dependencies )
1744
+ self .dependencies_set = set (self .dependencies )
1738
1745
self .suppressed = list (self .meta .suppressed )
1746
+ self .suppressed_set = set (self .suppressed )
1739
1747
all_deps = self .dependencies + self .suppressed
1740
1748
assert len (all_deps ) == len (self .meta .dep_prios )
1741
1749
self .priorities = {id : pri
@@ -1925,13 +1933,15 @@ def fix_suppressed_dependencies(self, graph: Graph) -> None:
1925
1933
new_dependencies = []
1926
1934
entry_points = self .manager .source_set .source_modules
1927
1935
for dep in self .dependencies + self .suppressed :
1928
- ignored = dep in self .suppressed and dep not in entry_points
1936
+ ignored = dep in self .suppressed_set and dep not in entry_points
1929
1937
if ignored or dep not in graph :
1930
1938
new_suppressed .append (dep )
1931
1939
else :
1932
1940
new_dependencies .append (dep )
1933
1941
self .dependencies = new_dependencies
1942
+ self .dependencies_set = set (new_dependencies )
1934
1943
self .suppressed = new_suppressed
1944
+ self .suppressed_set = set (new_suppressed )
1935
1945
1936
1946
# Methods for processing modules from source code.
1937
1947
@@ -2039,6 +2049,22 @@ def semantic_analysis_pass1(self) -> None:
2039
2049
with self .wrap_context ():
2040
2050
first .visit_file (self .tree , self .xpath , self .id , options )
2041
2051
2052
+ def add_dependency (self , dep : str ) -> None :
2053
+ if dep not in self .dependencies_set :
2054
+ self .dependencies .append (dep )
2055
+ self .dependencies_set .add (dep )
2056
+ if dep in self .suppressed_set :
2057
+ self .suppressed .remove (dep )
2058
+ self .suppressed_set .remove (dep )
2059
+
2060
+ def suppress_dependency (self , dep : str ) -> None :
2061
+ if dep in self .dependencies_set :
2062
+ self .dependencies .remove (dep )
2063
+ self .dependencies_set .remove (dep )
2064
+ if dep not in self .suppressed_set :
2065
+ self .suppressed .append (dep )
2066
+ self .suppressed_set .add (dep )
2067
+
2042
2068
def compute_dependencies (self ) -> None :
2043
2069
"""Compute a module's dependencies after parsing it.
2044
2070
@@ -2052,28 +2078,27 @@ def compute_dependencies(self) -> None:
2052
2078
# Compute (direct) dependencies.
2053
2079
# Add all direct imports (this is why we needed the first pass).
2054
2080
# Also keep track of each dependency's source line.
2055
- dependencies = []
2056
- priorities = {} # type: Dict[str, int] # id -> priority
2057
- dep_line_map = {} # type: Dict[str, int] # id -> line
2081
+ # Missing dependencies will be moved from dependencies to
2082
+ # suppressed when they fail to be loaded in load_graph.
2083
+
2084
+ self .dependencies = []
2085
+ self .dependencies_set = set ()
2086
+ self .suppressed = []
2087
+ self .suppressed_set = set ()
2088
+ self .priorities = {} # id -> priority
2089
+ self .dep_line_map = {} # id -> line
2058
2090
dep_entries = (manager .all_imported_modules_in_file (self .tree ) +
2059
2091
self .manager .plugin .get_additional_deps (self .tree ))
2060
2092
for pri , id , line in dep_entries :
2061
- priorities [id ] = min (pri , priorities .get (id , PRI_ALL ))
2093
+ self . priorities [id ] = min (pri , self . priorities .get (id , PRI_ALL ))
2062
2094
if id == self .id :
2063
2095
continue
2064
- if id not in dep_line_map :
2065
- dependencies . append ( id )
2066
- dep_line_map [id ] = line
2096
+ self . add_dependency ( id )
2097
+ if id not in self . dep_line_map :
2098
+ self . dep_line_map [id ] = line
2067
2099
# Every module implicitly depends on builtins.
2068
- if self .id != 'builtins' and 'builtins' not in dep_line_map :
2069
- dependencies .append ('builtins' )
2070
-
2071
- # Missing dependencies will be moved from dependencies to
2072
- # suppressed when they fail to be loaded in load_graph.
2073
- self .dependencies = dependencies
2074
- self .suppressed = []
2075
- self .priorities = priorities
2076
- self .dep_line_map = dep_line_map
2100
+ if self .id != 'builtins' :
2101
+ self .add_dependency ('builtins' )
2077
2102
2078
2103
self .check_blockers () # Can fail due to bogus relative imports
2079
2104
@@ -2085,7 +2110,7 @@ def semantic_analysis(self) -> None:
2085
2110
self .manager .semantic_analyzer .visit_file (self .tree , self .xpath , self .options , patches )
2086
2111
self .patches = patches
2087
2112
for dep in self .manager .semantic_analyzer .imports :
2088
- self .dependencies . append (dep )
2113
+ self .add_dependency (dep )
2089
2114
self .priorities [dep ] = PRI_LOW
2090
2115
2091
2116
def semantic_analysis_pass_three (self ) -> None :
@@ -2157,11 +2182,11 @@ def _patch_indirect_dependencies(self,
2157
2182
for dep in sorted (extra ):
2158
2183
if dep not in self .manager .modules :
2159
2184
continue
2160
- if dep not in self .suppressed and dep not in self .manager .missing_modules :
2161
- self .dependencies . append (dep )
2185
+ if dep not in self .suppressed_set and dep not in self .manager .missing_modules :
2186
+ self .add_dependency (dep )
2162
2187
self .priorities [dep ] = PRI_INDIRECT
2163
- elif dep not in self .suppressed and dep in self .manager .missing_modules :
2164
- self .suppressed . append (dep )
2188
+ elif dep not in self .suppressed_set and dep in self .manager .missing_modules :
2189
+ self .suppress_dependency (dep )
2165
2190
2166
2191
def compute_fine_grained_deps (self ) -> Dict [str , Set [str ]]:
2167
2192
assert self .tree is not None
@@ -2204,6 +2229,8 @@ def write_cache(self) -> None:
2204
2229
dep_prios = self .dependency_priorities ()
2205
2230
dep_lines = self .dependency_lines ()
2206
2231
assert self .source_hash is not None
2232
+ assert len (set (self .dependencies )) == len (self .dependencies ), (
2233
+ "Duplicates in dependencies list for {} ({})" .format (self .id , self .dependencies ))
2207
2234
new_interface_hash , self .meta = write_cache (
2208
2235
self .id , self .path , self .tree ,
2209
2236
list (self .dependencies ), list (self .suppressed ), list (self .child_modules ),
@@ -2733,7 +2760,7 @@ def load_graph(sources: List[BuildSource], manager: BuildManager,
2733
2760
# comment about this in `State.__init__()`.
2734
2761
added = []
2735
2762
for dep in st .ancestors + dependencies + st .suppressed :
2736
- ignored = dep in st .suppressed and dep not in entry_points
2763
+ ignored = dep in st .suppressed_set and dep not in entry_points
2737
2764
if ignored and dep not in added :
2738
2765
manager .missing_modules .add (dep )
2739
2766
elif dep not in graph :
@@ -2747,20 +2774,17 @@ def load_graph(sources: List[BuildSource], manager: BuildManager,
2747
2774
newst = State (id = dep , path = None , source = None , manager = manager ,
2748
2775
caller_state = st , caller_line = st .dep_line_map .get (dep , 1 ))
2749
2776
except ModuleNotFound :
2750
- if dep in st .dependencies :
2751
- st .dependencies .remove (dep )
2752
- st .suppressed .append (dep )
2777
+ if dep in st .dependencies_set :
2778
+ st .suppress_dependency (dep )
2753
2779
else :
2754
2780
assert newst .id not in graph , newst .id
2755
2781
graph [newst .id ] = newst
2756
2782
new .append (newst )
2757
2783
if dep in st .ancestors and dep in graph :
2758
2784
graph [dep ].child_modules .add (st .id )
2759
- if dep in graph and dep in st .suppressed :
2785
+ if dep in graph and dep in st .suppressed_set :
2760
2786
# Previously suppressed file is now visible
2761
- if dep in st .suppressed :
2762
- st .suppressed .remove (dep )
2763
- st .dependencies .append (dep )
2787
+ st .add_dependency (dep )
2764
2788
manager .plugin .set_modules (manager .modules )
2765
2789
return graph
2766
2790
0 commit comments