Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/classes/coreviews.py: 41%
182 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
1"""Views of core data structures such as nested Mappings (e.g. dict-of-dicts).
2These ``Views`` often restrict element access, with either the entire view or
3layers of nested mappings being read-only.
4"""
5from collections.abc import Mapping
7__all__ = [
8 "AtlasView",
9 "AdjacencyView",
10 "MultiAdjacencyView",
11 "UnionAtlas",
12 "UnionAdjacency",
13 "UnionMultiInner",
14 "UnionMultiAdjacency",
15 "FilterAtlas",
16 "FilterAdjacency",
17 "FilterMultiInner",
18 "FilterMultiAdjacency",
19]
22class AtlasView(Mapping):
23 """An AtlasView is a Read-only Mapping of Mappings.
25 It is a View into a dict-of-dict data structure.
26 The inner level of dict is read-write. But the
27 outer level is read-only.
29 See Also
30 ========
31 AdjacencyView: View into dict-of-dict-of-dict
32 MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict
33 """
35 __slots__ = ("_atlas",)
37 def __getstate__(self):
38 return {"_atlas": self._atlas}
40 def __setstate__(self, state):
41 self._atlas = state["_atlas"]
43 def __init__(self, d):
44 self._atlas = d
46 def __len__(self):
47 return len(self._atlas)
49 def __iter__(self):
50 return iter(self._atlas)
52 def __getitem__(self, key):
53 return self._atlas[key]
55 def copy(self):
56 return {n: self[n].copy() for n in self._atlas}
58 def __str__(self):
59 return str(self._atlas) # {nbr: self[nbr] for nbr in self})
61 def __repr__(self):
62 return f"{self.__class__.__name__}({self._atlas!r})"
65class AdjacencyView(AtlasView):
66 """An AdjacencyView is a Read-only Map of Maps of Maps.
68 It is a View into a dict-of-dict-of-dict data structure.
69 The inner level of dict is read-write. But the
70 outer levels are read-only.
72 See Also
73 ========
74 AtlasView: View into dict-of-dict
75 MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict
76 """
78 __slots__ = () # Still uses AtlasView slots names _atlas
80 def __getitem__(self, name):
81 return AtlasView(self._atlas[name])
83 def copy(self):
84 return {n: self[n].copy() for n in self._atlas}
87class MultiAdjacencyView(AdjacencyView):
88 """An MultiAdjacencyView is a Read-only Map of Maps of Maps of Maps.
90 It is a View into a dict-of-dict-of-dict-of-dict data structure.
91 The inner level of dict is read-write. But the
92 outer levels are read-only.
94 See Also
95 ========
96 AtlasView: View into dict-of-dict
97 AdjacencyView: View into dict-of-dict-of-dict
98 """
100 __slots__ = () # Still uses AtlasView slots names _atlas
102 def __getitem__(self, name):
103 return AdjacencyView(self._atlas[name])
105 def copy(self):
106 return {n: self[n].copy() for n in self._atlas}
109class UnionAtlas(Mapping):
110 """A read-only union of two atlases (dict-of-dict).
112 The two dict-of-dicts represent the inner dict of
113 an Adjacency: `G.succ[node]` and `G.pred[node]`.
114 The inner level of dict of both hold attribute key:value
115 pairs and is read-write. But the outer level is read-only.
117 See Also
118 ========
119 UnionAdjacency: View into dict-of-dict-of-dict
120 UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict
121 """
123 __slots__ = ("_succ", "_pred")
125 def __getstate__(self):
126 return {"_succ": self._succ, "_pred": self._pred}
128 def __setstate__(self, state):
129 self._succ = state["_succ"]
130 self._pred = state["_pred"]
132 def __init__(self, succ, pred):
133 self._succ = succ
134 self._pred = pred
136 def __len__(self):
137 return len(self._succ.keys() | self._pred.keys())
139 def __iter__(self):
140 return iter(set(self._succ.keys()) | set(self._pred.keys()))
142 def __getitem__(self, key):
143 try:
144 return self._succ[key]
145 except KeyError:
146 return self._pred[key]
148 def copy(self):
149 result = {nbr: dd.copy() for nbr, dd in self._succ.items()}
150 for nbr, dd in self._pred.items():
151 if nbr in result:
152 result[nbr].update(dd)
153 else:
154 result[nbr] = dd.copy()
155 return result
157 def __str__(self):
158 return str({nbr: self[nbr] for nbr in self})
160 def __repr__(self):
161 return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})"
164class UnionAdjacency(Mapping):
165 """A read-only union of dict Adjacencies as a Map of Maps of Maps.
167 The two input dict-of-dict-of-dicts represent the union of
168 `G.succ` and `G.pred`. Return values are UnionAtlas
169 The inner level of dict is read-write. But the
170 middle and outer levels are read-only.
172 succ : a dict-of-dict-of-dict {node: nbrdict}
173 pred : a dict-of-dict-of-dict {node: nbrdict}
174 The keys for the two dicts should be the same
176 See Also
177 ========
178 UnionAtlas: View into dict-of-dict
179 UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict
180 """
182 __slots__ = ("_succ", "_pred")
184 def __getstate__(self):
185 return {"_succ": self._succ, "_pred": self._pred}
187 def __setstate__(self, state):
188 self._succ = state["_succ"]
189 self._pred = state["_pred"]
191 def __init__(self, succ, pred):
192 # keys must be the same for two input dicts
193 assert len(set(succ.keys()) ^ set(pred.keys())) == 0
194 self._succ = succ
195 self._pred = pred
197 def __len__(self):
198 return len(self._succ) # length of each dict should be the same
200 def __iter__(self):
201 return iter(self._succ)
203 def __getitem__(self, nbr):
204 return UnionAtlas(self._succ[nbr], self._pred[nbr])
206 def copy(self):
207 return {n: self[n].copy() for n in self._succ}
209 def __str__(self):
210 return str({nbr: self[nbr] for nbr in self})
212 def __repr__(self):
213 return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})"
216class UnionMultiInner(UnionAtlas):
217 """A read-only union of two inner dicts of MultiAdjacencies.
219 The two input dict-of-dict-of-dicts represent the union of
220 `G.succ[node]` and `G.pred[node]` for MultiDiGraphs.
221 Return values are UnionAtlas.
222 The inner level of dict is read-write. But the outer levels are read-only.
224 See Also
225 ========
226 UnionAtlas: View into dict-of-dict
227 UnionAdjacency: View into dict-of-dict-of-dict
228 UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict
229 """
231 __slots__ = () # Still uses UnionAtlas slots names _succ, _pred
233 def __getitem__(self, node):
234 in_succ = node in self._succ
235 in_pred = node in self._pred
236 if in_succ:
237 if in_pred:
238 return UnionAtlas(self._succ[node], self._pred[node])
239 return UnionAtlas(self._succ[node], {})
240 return UnionAtlas({}, self._pred[node])
242 def copy(self):
243 nodes = set(self._succ.keys()) | set(self._pred.keys())
244 return {n: self[n].copy() for n in nodes}
247class UnionMultiAdjacency(UnionAdjacency):
248 """A read-only union of two dict MultiAdjacencies.
250 The two input dict-of-dict-of-dict-of-dicts represent the union of
251 `G.succ` and `G.pred` for MultiDiGraphs. Return values are UnionAdjacency.
252 The inner level of dict is read-write. But the outer levels are read-only.
254 See Also
255 ========
256 UnionAtlas: View into dict-of-dict
257 UnionMultiInner: View into dict-of-dict-of-dict
258 """
260 __slots__ = () # Still uses UnionAdjacency slots names _succ, _pred
262 def __getitem__(self, node):
263 return UnionMultiInner(self._succ[node], self._pred[node])
266class FilterAtlas(Mapping): # nodedict, nbrdict, keydict
267 def __init__(self, d, NODE_OK):
268 self._atlas = d
269 self.NODE_OK = NODE_OK
271 def __len__(self):
272 return sum(1 for n in self)
274 def __iter__(self):
275 try: # check that NODE_OK has attr 'nodes'
276 node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
277 except AttributeError:
278 node_ok_shorter = False
279 if node_ok_shorter:
280 return (n for n in self.NODE_OK.nodes if n in self._atlas)
281 return (n for n in self._atlas if self.NODE_OK(n))
283 def __getitem__(self, key):
284 if key in self._atlas and self.NODE_OK(key):
285 return self._atlas[key]
286 raise KeyError(f"Key {key} not found")
288 def __str__(self):
289 return str({nbr: self[nbr] for nbr in self})
291 def __repr__(self):
292 return f"{self.__class__.__name__}({self._atlas!r}, {self.NODE_OK!r})"
295class FilterAdjacency(Mapping): # edgedict
296 def __init__(self, d, NODE_OK, EDGE_OK):
297 self._atlas = d
298 self.NODE_OK = NODE_OK
299 self.EDGE_OK = EDGE_OK
301 def __len__(self):
302 return sum(1 for n in self)
304 def __iter__(self):
305 try: # check that NODE_OK has attr 'nodes'
306 node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
307 except AttributeError:
308 node_ok_shorter = False
309 if node_ok_shorter:
310 return (n for n in self.NODE_OK.nodes if n in self._atlas)
311 return (n for n in self._atlas if self.NODE_OK(n))
313 def __getitem__(self, node):
314 if node in self._atlas and self.NODE_OK(node):
316 def new_node_ok(nbr):
317 return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr)
319 return FilterAtlas(self._atlas[node], new_node_ok)
320 raise KeyError(f"Key {node} not found")
322 def __str__(self):
323 return str({nbr: self[nbr] for nbr in self})
325 def __repr__(self):
326 name = self.__class__.__name__
327 return f"{name}({self._atlas!r}, {self.NODE_OK!r}, {self.EDGE_OK!r})"
330class FilterMultiInner(FilterAdjacency): # muliedge_seconddict
331 def __iter__(self):
332 try: # check that NODE_OK has attr 'nodes'
333 node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
334 except AttributeError:
335 node_ok_shorter = False
336 if node_ok_shorter:
337 my_nodes = (n for n in self.NODE_OK.nodes if n in self._atlas)
338 else:
339 my_nodes = (n for n in self._atlas if self.NODE_OK(n))
340 for n in my_nodes:
341 some_keys_ok = False
342 for key in self._atlas[n]:
343 if self.EDGE_OK(n, key):
344 some_keys_ok = True
345 break
346 if some_keys_ok is True:
347 yield n
349 def __getitem__(self, nbr):
350 if nbr in self._atlas and self.NODE_OK(nbr):
352 def new_node_ok(key):
353 return self.EDGE_OK(nbr, key)
355 return FilterAtlas(self._atlas[nbr], new_node_ok)
356 raise KeyError(f"Key {nbr} not found")
359class FilterMultiAdjacency(FilterAdjacency): # multiedgedict
360 def __getitem__(self, node):
361 if node in self._atlas and self.NODE_OK(node):
363 def edge_ok(nbr, key):
364 return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr, key)
366 return FilterMultiInner(self._atlas[node], self.NODE_OK, edge_ok)
367 raise KeyError(f"Key {node} not found")