1import pytest
2import pickle
3
4import networkx as nx
5
6
7class TestAtlasView:
8    # node->data
9    def setup(self):
10        self.d = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}}
11        self.av = nx.classes.coreviews.AtlasView(self.d)
12
13    def test_pickle(self):
14        view = self.av
15        pview = pickle.loads(pickle.dumps(view, -1))
16        assert view == pview
17        assert view.__slots__ == pview.__slots__
18        pview = pickle.loads(pickle.dumps(view))
19        assert view == pview
20        assert view.__slots__ == pview.__slots__
21
22    def test_len(self):
23        assert len(self.av) == len(self.d)
24
25    def test_iter(self):
26        assert list(self.av) == list(self.d)
27
28    def test_getitem(self):
29        assert self.av[1] is self.d[1]
30        assert self.av[2]["color"] == 1
31        pytest.raises(KeyError, self.av.__getitem__, 3)
32
33    def test_copy(self):
34        avcopy = self.av.copy()
35        assert avcopy[0] == self.av[0]
36        assert avcopy == self.av
37        assert avcopy[0] is not self.av[0]
38        assert avcopy is not self.av
39        avcopy[5] = {}
40        assert avcopy != self.av
41
42        avcopy[0]["ht"] = 4
43        assert avcopy[0] != self.av[0]
44        self.av[0]["ht"] = 4
45        assert avcopy[0] == self.av[0]
46        del self.av[0]["ht"]
47
48        assert not hasattr(self.av, "__setitem__")
49
50    def test_items(self):
51        assert sorted(self.av.items()) == sorted(self.d.items())
52
53    def test_str(self):
54        out = str(self.d)
55        assert str(self.av) == out
56
57    def test_repr(self):
58        out = "AtlasView(" + str(self.d) + ")"
59        assert repr(self.av) == out
60
61
62class TestAdjacencyView:
63    # node->nbr->data
64    def setup(self):
65        dd = {"color": "blue", "weight": 1.2}
66        self.nd = {0: dd, 1: {}, 2: {"color": 1}}
67        self.adj = {3: self.nd, 0: {3: dd}, 1: {}, 2: {3: {"color": 1}}}
68        self.adjview = nx.classes.coreviews.AdjacencyView(self.adj)
69
70    def test_pickle(self):
71        view = self.adjview
72        pview = pickle.loads(pickle.dumps(view, -1))
73        assert view == pview
74        assert view.__slots__ == pview.__slots__
75
76    def test_len(self):
77        assert len(self.adjview) == len(self.adj)
78
79    def test_iter(self):
80        assert list(self.adjview) == list(self.adj)
81
82    def test_getitem(self):
83        assert self.adjview[1] is not self.adj[1]
84        assert self.adjview[3][0] is self.adjview[0][3]
85        assert self.adjview[2][3]["color"] == 1
86        pytest.raises(KeyError, self.adjview.__getitem__, 4)
87
88    def test_copy(self):
89        avcopy = self.adjview.copy()
90        assert avcopy[0] == self.adjview[0]
91        assert avcopy[0] is not self.adjview[0]
92
93        avcopy[2][3]["ht"] = 4
94        assert avcopy[2] != self.adjview[2]
95        self.adjview[2][3]["ht"] = 4
96        assert avcopy[2] == self.adjview[2]
97        del self.adjview[2][3]["ht"]
98
99        assert not hasattr(self.adjview, "__setitem__")
100
101    def test_items(self):
102        view_items = sorted((n, dict(d)) for n, d in self.adjview.items())
103        assert view_items == sorted(self.adj.items())
104
105    def test_str(self):
106        out = str(dict(self.adj))
107        assert str(self.adjview) == out
108
109    def test_repr(self):
110        out = self.adjview.__class__.__name__ + "(" + str(self.adj) + ")"
111        assert repr(self.adjview) == out
112
113
114class TestMultiAdjacencyView(TestAdjacencyView):
115    # node->nbr->key->data
116    def setup(self):
117        dd = {"color": "blue", "weight": 1.2}
118        self.kd = {0: dd, 1: {}, 2: {"color": 1}}
119        self.nd = {3: self.kd, 0: {3: dd}, 1: {0: {}}, 2: {3: {"color": 1}}}
120        self.adj = {3: self.nd, 0: {3: {3: dd}}, 1: {}, 2: {3: {8: {}}}}
121        self.adjview = nx.classes.coreviews.MultiAdjacencyView(self.adj)
122
123    def test_getitem(self):
124        assert self.adjview[1] is not self.adj[1]
125        assert self.adjview[3][0][3] is self.adjview[0][3][3]
126        assert self.adjview[3][2][3]["color"] == 1
127        pytest.raises(KeyError, self.adjview.__getitem__, 4)
128
129    def test_copy(self):
130        avcopy = self.adjview.copy()
131        assert avcopy[0] == self.adjview[0]
132        assert avcopy[0] is not self.adjview[0]
133
134        avcopy[2][3][8]["ht"] = 4
135        assert avcopy[2] != self.adjview[2]
136        self.adjview[2][3][8]["ht"] = 4
137        assert avcopy[2] == self.adjview[2]
138        del self.adjview[2][3][8]["ht"]
139
140        assert not hasattr(self.adjview, "__setitem__")
141
142
143class TestUnionAtlas:
144    # node->data
145    def setup(self):
146        self.s = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}}
147        self.p = {3: {"color": "blue", "weight": 1.2}, 4: {}, 2: {"watch": 2}}
148        self.av = nx.classes.coreviews.UnionAtlas(self.s, self.p)
149
150    def test_pickle(self):
151        view = self.av
152        pview = pickle.loads(pickle.dumps(view, -1))
153        assert view == pview
154        assert view.__slots__ == pview.__slots__
155
156    def test_len(self):
157        assert len(self.av) == len(self.s) + len(self.p)
158
159    def test_iter(self):
160        assert set(self.av) == set(self.s) | set(self.p)
161
162    def test_getitem(self):
163        assert self.av[0] is self.s[0]
164        assert self.av[4] is self.p[4]
165        assert self.av[2]["color"] == 1
166        pytest.raises(KeyError, self.av[2].__getitem__, "watch")
167        pytest.raises(KeyError, self.av.__getitem__, 8)
168
169    def test_copy(self):
170        avcopy = self.av.copy()
171        assert avcopy[0] == self.av[0]
172        assert avcopy[0] is not self.av[0]
173        assert avcopy is not self.av
174        avcopy[5] = {}
175        assert avcopy != self.av
176
177        avcopy[0]["ht"] = 4
178        assert avcopy[0] != self.av[0]
179        self.av[0]["ht"] = 4
180        assert avcopy[0] == self.av[0]
181        del self.av[0]["ht"]
182
183        assert not hasattr(self.av, "__setitem__")
184
185    def test_items(self):
186        expected = dict(self.p.items())
187        expected.update(self.s)
188        assert sorted(self.av.items()) == sorted(expected.items())
189
190    def test_str(self):
191        out = str(dict(self.av))
192        assert str(self.av) == out
193
194    def test_repr(self):
195        out = f"{self.av.__class__.__name__}({self.s}, {self.p})"
196        assert repr(self.av) == out
197
198
199class TestUnionAdjacency:
200    # node->nbr->data
201    def setup(self):
202        dd = {"color": "blue", "weight": 1.2}
203        self.nd = {0: dd, 1: {}, 2: {"color": 1}}
204        self.s = {3: self.nd, 0: {}, 1: {}, 2: {3: {"color": 1}}}
205        self.p = {3: {}, 0: {3: dd}, 1: {0: {}}, 2: {1: {"color": 1}}}
206        self.adjview = nx.classes.coreviews.UnionAdjacency(self.s, self.p)
207
208    def test_pickle(self):
209        view = self.adjview
210        pview = pickle.loads(pickle.dumps(view, -1))
211        assert view == pview
212        assert view.__slots__ == pview.__slots__
213
214    def test_len(self):
215        assert len(self.adjview) == len(self.s)
216
217    def test_iter(self):
218        assert sorted(self.adjview) == sorted(self.s)
219
220    def test_getitem(self):
221        assert self.adjview[1] is not self.s[1]
222        assert self.adjview[3][0] is self.adjview[0][3]
223        assert self.adjview[2][3]["color"] == 1
224        pytest.raises(KeyError, self.adjview.__getitem__, 4)
225
226    def test_copy(self):
227        avcopy = self.adjview.copy()
228        assert avcopy[0] == self.adjview[0]
229        assert avcopy[0] is not self.adjview[0]
230
231        avcopy[2][3]["ht"] = 4
232        assert avcopy[2] != self.adjview[2]
233        self.adjview[2][3]["ht"] = 4
234        assert avcopy[2] == self.adjview[2]
235        del self.adjview[2][3]["ht"]
236
237        assert not hasattr(self.adjview, "__setitem__")
238
239    def test_str(self):
240        out = str(dict(self.adjview))
241        assert str(self.adjview) == out
242
243    def test_repr(self):
244        clsname = self.adjview.__class__.__name__
245        out = f"{clsname}({self.s}, {self.p})"
246        assert repr(self.adjview) == out
247
248
249class TestUnionMultiInner(TestUnionAdjacency):
250    # nbr->key->data
251    def setup(self):
252        dd = {"color": "blue", "weight": 1.2}
253        self.kd = {7: {}, "ekey": {}, 9: {"color": 1}}
254        self.s = {3: self.kd, 0: {7: dd}, 1: {}, 2: {"key": {"color": 1}}}
255        self.p = {3: {}, 0: {3: dd}, 1: {}, 2: {1: {"span": 2}}}
256        self.adjview = nx.classes.coreviews.UnionMultiInner(self.s, self.p)
257
258    def test_len(self):
259        assert len(self.adjview) == len(self.s) + len(self.p)
260
261    def test_getitem(self):
262        assert self.adjview[1] is not self.s[1]
263        assert self.adjview[0][7] is self.adjview[0][3]
264        assert self.adjview[2]["key"]["color"] == 1
265        assert self.adjview[2][1]["span"] == 2
266        pytest.raises(KeyError, self.adjview.__getitem__, 4)
267        pytest.raises(KeyError, self.adjview[1].__getitem__, "key")
268
269    def test_copy(self):
270        avcopy = self.adjview.copy()
271        assert avcopy[0] == self.adjview[0]
272        assert avcopy[0] is not self.adjview[0]
273
274        avcopy[2][1]["width"] = 8
275        assert avcopy[2] != self.adjview[2]
276        self.adjview[2][1]["width"] = 8
277        assert avcopy[2] == self.adjview[2]
278        del self.adjview[2][1]["width"]
279
280        assert not hasattr(self.adjview, "__setitem__")
281        assert hasattr(avcopy, "__setitem__")
282
283
284class TestUnionMultiAdjacency(TestUnionAdjacency):
285    # node->nbr->key->data
286    def setup(self):
287        dd = {"color": "blue", "weight": 1.2}
288        self.kd = {7: {}, 8: {}, 9: {"color": 1}}
289        self.nd = {3: self.kd, 0: {9: dd}, 1: {8: {}}, 2: {9: {"color": 1}}}
290        self.s = {3: self.nd, 0: {3: {7: dd}}, 1: {}, 2: {3: {8: {}}}}
291        self.p = {3: {}, 0: {3: {9: dd}}, 1: {}, 2: {1: {8: {}}}}
292        self.adjview = nx.classes.coreviews.UnionMultiAdjacency(self.s, self.p)
293
294    def test_getitem(self):
295        assert self.adjview[1] is not self.s[1]
296        assert self.adjview[3][0][9] is self.adjview[0][3][9]
297        assert self.adjview[3][2][9]["color"] == 1
298        pytest.raises(KeyError, self.adjview.__getitem__, 4)
299
300    def test_copy(self):
301        avcopy = self.adjview.copy()
302        assert avcopy[0] == self.adjview[0]
303        assert avcopy[0] is not self.adjview[0]
304
305        avcopy[2][3][8]["ht"] = 4
306        assert avcopy[2] != self.adjview[2]
307        self.adjview[2][3][8]["ht"] = 4
308        assert avcopy[2] == self.adjview[2]
309        del self.adjview[2][3][8]["ht"]
310
311        assert not hasattr(self.adjview, "__setitem__")
312        assert hasattr(avcopy, "__setitem__")
313
314
315class TestFilteredGraphs:
316    def setup(self):
317        self.Graphs = [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
318
319    def test_hide_show_nodes(self):
320        SubGraph = nx.graphviews.subgraph_view
321        for Graph in self.Graphs:
322            G = nx.path_graph(4, Graph)
323            SG = G.subgraph([2, 3])
324            RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
325            assert SG.nodes == RG.nodes
326            assert SG.edges == RG.edges
327            SGC = SG.copy()
328            RGC = RG.copy()
329            assert SGC.nodes == RGC.nodes
330            assert SGC.edges == RGC.edges
331
332    def test_str_repr(self):
333        SubGraph = nx.graphviews.subgraph_view
334        for Graph in self.Graphs:
335            G = nx.path_graph(4, Graph)
336            SG = G.subgraph([2, 3])
337            RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
338            str(SG.adj)
339            str(RG.adj)
340            repr(SG.adj)
341            repr(RG.adj)
342            str(SG.adj[2])
343            str(RG.adj[2])
344            repr(SG.adj[2])
345            repr(RG.adj[2])
346
347    def test_copy(self):
348        SubGraph = nx.graphviews.subgraph_view
349        for Graph in self.Graphs:
350            G = nx.path_graph(4, Graph)
351            SG = G.subgraph([2, 3])
352            RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
353            RsG = SubGraph(G, nx.filters.show_nodes([2, 3]))
354            assert G.adj.copy() == G.adj
355            assert G.adj[2].copy() == G.adj[2]
356            assert SG.adj.copy() == SG.adj
357            assert SG.adj[2].copy() == SG.adj[2]
358            assert RG.adj.copy() == RG.adj
359            assert RG.adj[2].copy() == RG.adj[2]
360            assert RsG.adj.copy() == RsG.adj
361            assert RsG.adj[2].copy() == RsG.adj[2]
362
363    def test_filtered_copy(self):
364        # TODO: This function can be removed when filtered.copy()
365        # deprecation expires
366        SubGraph = nx.graphviews.subgraph_view
367        for Graph in self.Graphs:
368            G = nx.path_graph(4, Graph)
369            SG = G.subgraph([2, 3])
370            RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
371            RsG = SubGraph(G, nx.filters.show_nodes([2, 3]))
372            # test FilterAtlas & co in these subgraphs
373            assert SG._node.copy() == SG._node
374            assert SG.adj._atlas.copy() == SG.adj._atlas
375            assert SG.adj[2]._atlas.copy() == SG.adj[2]._atlas
376            assert SG.adj[2]._atlas[3].copy() == SG.adj[2]._atlas[3]
377            assert RG.adj._atlas.copy() == RG.adj._atlas
378            assert RG.adj[2]._atlas.copy() == RG.adj[2]._atlas
379            assert RG.adj[2]._atlas[3].copy() == RG.adj[2]._atlas[3]
380            assert RG._node.copy() == RG._node
381            assert RsG.adj._atlas.copy() == RsG.adj._atlas
382            assert RsG.adj[2]._atlas.copy() == RsG.adj[2]._atlas
383            assert RsG.adj[2]._atlas[3].copy() == RsG.adj[2]._atlas[3]
384            assert RsG._node.copy() == RsG._node
385            # test MultiFilterInner
386            if G.is_multigraph():
387                assert SG.adj[2]._atlas[3][0].copy() == SG.adj[2]._atlas[3][0]
388                assert RG.adj[2]._atlas[3][0].copy() == RG.adj[2]._atlas[3][0]
389                assert RsG.adj[2]._atlas[3][0].copy() == RsG.adj[2]._atlas[3][0]
390
391            # test deprecation
392            # FilterAtlas.copy()
393            pytest.deprecated_call(SG._node.copy)
394            # FilterAdjacency.copy()
395            pytest.deprecated_call(SG.adj._atlas.copy)
396            # FilterMultiAdjacency.copy()
397            if G.is_multigraph():
398                pytest.deprecated_call(SG.adj._atlas.copy)
399            # FilterMultiInner.copy()
400            if G.is_multigraph():
401                pytest.deprecated_call(SG.adj[2]._atlas.copy)
402
403            SSG = SG.subgraph([2])
404            assert list(SSG) == [2]
405
406            # check case when node_ok is small
407            G = nx.complete_graph(9, Graph)
408            SG = G.subgraph([2, 3])
409            RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
410            RsG = SubGraph(G, nx.filters.show_nodes([2, 3, 4, 5, 6, 7, 8]))
411            assert SG.adj._atlas.copy() == SG.adj._atlas
412            assert SG.adj[2]._atlas.copy() == SG.adj[2]._atlas
413            assert SG.adj[2]._atlas[3].copy() == SG.adj[2]._atlas[3]
414            assert SG._node.copy() == SG._node
415            assert RG.adj._atlas.copy() == RG.adj._atlas
416            assert RG.adj[2]._atlas.copy() == RG.adj[2]._atlas
417            assert RG.adj[2]._atlas[3].copy() == RG.adj[2]._atlas[3]
418            assert RG._node.copy() == RG._node
419            assert RsG.adj._atlas.copy() == RsG.adj._atlas
420            assert RsG.adj[2]._atlas.copy() == RsG.adj[2]._atlas
421            assert RsG.adj[2]._atlas[3].copy() == RsG.adj[2]._atlas[3]
422            assert RsG._node.copy() == RsG._node
423            # test MultiFilterInner
424            if G.is_multigraph():
425                assert SG.adj[2][3]._atlas.copy() == SG.adj[2][3]._atlas
426                assert RG.adj[2][3]._atlas.copy() == RG.adj[2][3]._atlas
427                assert RsG.adj[2][3]._atlas.copy() == RsG.adj[2][3]._atlas
428
429            SSG = SG.subgraph([2])
430            assert list(SSG) == [2]
431