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

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 

6 

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] 

20 

21 

22class AtlasView(Mapping): 

23 """An AtlasView is a Read-only Mapping of Mappings. 

24 

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. 

28 

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 """ 

34 

35 __slots__ = ("_atlas",) 

36 

37 def __getstate__(self): 

38 return {"_atlas": self._atlas} 

39 

40 def __setstate__(self, state): 

41 self._atlas = state["_atlas"] 

42 

43 def __init__(self, d): 

44 self._atlas = d 

45 

46 def __len__(self): 

47 return len(self._atlas) 

48 

49 def __iter__(self): 

50 return iter(self._atlas) 

51 

52 def __getitem__(self, key): 

53 return self._atlas[key] 

54 

55 def copy(self): 

56 return {n: self[n].copy() for n in self._atlas} 

57 

58 def __str__(self): 

59 return str(self._atlas) # {nbr: self[nbr] for nbr in self}) 

60 

61 def __repr__(self): 

62 return f"{self.__class__.__name__}({self._atlas!r})" 

63 

64 

65class AdjacencyView(AtlasView): 

66 """An AdjacencyView is a Read-only Map of Maps of Maps. 

67 

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. 

71 

72 See Also 

73 ======== 

74 AtlasView: View into dict-of-dict 

75 MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict 

76 """ 

77 

78 __slots__ = () # Still uses AtlasView slots names _atlas 

79 

80 def __getitem__(self, name): 

81 return AtlasView(self._atlas[name]) 

82 

83 def copy(self): 

84 return {n: self[n].copy() for n in self._atlas} 

85 

86 

87class MultiAdjacencyView(AdjacencyView): 

88 """An MultiAdjacencyView is a Read-only Map of Maps of Maps of Maps. 

89 

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. 

93 

94 See Also 

95 ======== 

96 AtlasView: View into dict-of-dict 

97 AdjacencyView: View into dict-of-dict-of-dict 

98 """ 

99 

100 __slots__ = () # Still uses AtlasView slots names _atlas 

101 

102 def __getitem__(self, name): 

103 return AdjacencyView(self._atlas[name]) 

104 

105 def copy(self): 

106 return {n: self[n].copy() for n in self._atlas} 

107 

108 

109class UnionAtlas(Mapping): 

110 """A read-only union of two atlases (dict-of-dict). 

111 

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. 

116 

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 """ 

122 

123 __slots__ = ("_succ", "_pred") 

124 

125 def __getstate__(self): 

126 return {"_succ": self._succ, "_pred": self._pred} 

127 

128 def __setstate__(self, state): 

129 self._succ = state["_succ"] 

130 self._pred = state["_pred"] 

131 

132 def __init__(self, succ, pred): 

133 self._succ = succ 

134 self._pred = pred 

135 

136 def __len__(self): 

137 return len(self._succ.keys() | self._pred.keys()) 

138 

139 def __iter__(self): 

140 return iter(set(self._succ.keys()) | set(self._pred.keys())) 

141 

142 def __getitem__(self, key): 

143 try: 

144 return self._succ[key] 

145 except KeyError: 

146 return self._pred[key] 

147 

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 

156 

157 def __str__(self): 

158 return str({nbr: self[nbr] for nbr in self}) 

159 

160 def __repr__(self): 

161 return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})" 

162 

163 

164class UnionAdjacency(Mapping): 

165 """A read-only union of dict Adjacencies as a Map of Maps of Maps. 

166 

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. 

171 

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 

175 

176 See Also 

177 ======== 

178 UnionAtlas: View into dict-of-dict 

179 UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict 

180 """ 

181 

182 __slots__ = ("_succ", "_pred") 

183 

184 def __getstate__(self): 

185 return {"_succ": self._succ, "_pred": self._pred} 

186 

187 def __setstate__(self, state): 

188 self._succ = state["_succ"] 

189 self._pred = state["_pred"] 

190 

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 

196 

197 def __len__(self): 

198 return len(self._succ) # length of each dict should be the same 

199 

200 def __iter__(self): 

201 return iter(self._succ) 

202 

203 def __getitem__(self, nbr): 

204 return UnionAtlas(self._succ[nbr], self._pred[nbr]) 

205 

206 def copy(self): 

207 return {n: self[n].copy() for n in self._succ} 

208 

209 def __str__(self): 

210 return str({nbr: self[nbr] for nbr in self}) 

211 

212 def __repr__(self): 

213 return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})" 

214 

215 

216class UnionMultiInner(UnionAtlas): 

217 """A read-only union of two inner dicts of MultiAdjacencies. 

218 

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. 

223 

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 """ 

230 

231 __slots__ = () # Still uses UnionAtlas slots names _succ, _pred 

232 

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]) 

241 

242 def copy(self): 

243 nodes = set(self._succ.keys()) | set(self._pred.keys()) 

244 return {n: self[n].copy() for n in nodes} 

245 

246 

247class UnionMultiAdjacency(UnionAdjacency): 

248 """A read-only union of two dict MultiAdjacencies. 

249 

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. 

253 

254 See Also 

255 ======== 

256 UnionAtlas: View into dict-of-dict 

257 UnionMultiInner: View into dict-of-dict-of-dict 

258 """ 

259 

260 __slots__ = () # Still uses UnionAdjacency slots names _succ, _pred 

261 

262 def __getitem__(self, node): 

263 return UnionMultiInner(self._succ[node], self._pred[node]) 

264 

265 

266class FilterAtlas(Mapping): # nodedict, nbrdict, keydict 

267 def __init__(self, d, NODE_OK): 

268 self._atlas = d 

269 self.NODE_OK = NODE_OK 

270 

271 def __len__(self): 

272 return sum(1 for n in self) 

273 

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)) 

282 

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") 

287 

288 def __str__(self): 

289 return str({nbr: self[nbr] for nbr in self}) 

290 

291 def __repr__(self): 

292 return f"{self.__class__.__name__}({self._atlas!r}, {self.NODE_OK!r})" 

293 

294 

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 

300 

301 def __len__(self): 

302 return sum(1 for n in self) 

303 

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)) 

312 

313 def __getitem__(self, node): 

314 if node in self._atlas and self.NODE_OK(node): 

315 

316 def new_node_ok(nbr): 

317 return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr) 

318 

319 return FilterAtlas(self._atlas[node], new_node_ok) 

320 raise KeyError(f"Key {node} not found") 

321 

322 def __str__(self): 

323 return str({nbr: self[nbr] for nbr in self}) 

324 

325 def __repr__(self): 

326 name = self.__class__.__name__ 

327 return f"{name}({self._atlas!r}, {self.NODE_OK!r}, {self.EDGE_OK!r})" 

328 

329 

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 

348 

349 def __getitem__(self, nbr): 

350 if nbr in self._atlas and self.NODE_OK(nbr): 

351 

352 def new_node_ok(key): 

353 return self.EDGE_OK(nbr, key) 

354 

355 return FilterAtlas(self._atlas[nbr], new_node_ok) 

356 raise KeyError(f"Key {nbr} not found") 

357 

358 

359class FilterMultiAdjacency(FilterAdjacency): # multiedgedict 

360 def __getitem__(self, node): 

361 if node in self._atlas and self.NODE_OK(node): 

362 

363 def edge_ok(nbr, key): 

364 return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr, key) 

365 

366 return FilterMultiInner(self._atlas[node], self.NODE_OK, edge_ok) 

367 raise KeyError(f"Key {node} not found")