Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/networkx/readwrite/tests/test_gml.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 from ast import literal_eval | |
2 import codecs | |
3 from contextlib import contextmanager | |
4 import io | |
5 import pytest | |
6 import networkx as nx | |
7 from networkx.readwrite.gml import literal_stringizer, literal_destringizer | |
8 import os | |
9 import tempfile | |
10 from textwrap import dedent | |
11 | |
12 | |
13 class TestGraph: | |
14 @classmethod | |
15 def setup_class(cls): | |
16 cls.simple_data = """Creator "me" | |
17 Version "xx" | |
18 graph [ | |
19 comment "This is a sample graph" | |
20 directed 1 | |
21 IsPlanar 1 | |
22 pos [ x 0 y 1 ] | |
23 node [ | |
24 id 1 | |
25 label "Node 1" | |
26 pos [ x 1 y 1 ] | |
27 ] | |
28 node [ | |
29 id 2 | |
30 pos [ x 1 y 2 ] | |
31 label "Node 2" | |
32 ] | |
33 node [ | |
34 id 3 | |
35 label "Node 3" | |
36 pos [ x 1 y 3 ] | |
37 ] | |
38 edge [ | |
39 source 1 | |
40 target 2 | |
41 label "Edge from node 1 to node 2" | |
42 color [line "blue" thickness 3] | |
43 | |
44 ] | |
45 edge [ | |
46 source 2 | |
47 target 3 | |
48 label "Edge from node 2 to node 3" | |
49 ] | |
50 edge [ | |
51 source 3 | |
52 target 1 | |
53 label "Edge from node 3 to node 1" | |
54 ] | |
55 ] | |
56 """ | |
57 | |
58 def test_parse_gml_cytoscape_bug(self): | |
59 # example from issue #321, originally #324 in trac | |
60 cytoscape_example = """ | |
61 Creator "Cytoscape" | |
62 Version 1.0 | |
63 graph [ | |
64 node [ | |
65 root_index -3 | |
66 id -3 | |
67 graphics [ | |
68 x -96.0 | |
69 y -67.0 | |
70 w 40.0 | |
71 h 40.0 | |
72 fill "#ff9999" | |
73 type "ellipse" | |
74 outline "#666666" | |
75 outline_width 1.5 | |
76 ] | |
77 label "node2" | |
78 ] | |
79 node [ | |
80 root_index -2 | |
81 id -2 | |
82 graphics [ | |
83 x 63.0 | |
84 y 37.0 | |
85 w 40.0 | |
86 h 40.0 | |
87 fill "#ff9999" | |
88 type "ellipse" | |
89 outline "#666666" | |
90 outline_width 1.5 | |
91 ] | |
92 label "node1" | |
93 ] | |
94 node [ | |
95 root_index -1 | |
96 id -1 | |
97 graphics [ | |
98 x -31.0 | |
99 y -17.0 | |
100 w 40.0 | |
101 h 40.0 | |
102 fill "#ff9999" | |
103 type "ellipse" | |
104 outline "#666666" | |
105 outline_width 1.5 | |
106 ] | |
107 label "node0" | |
108 ] | |
109 edge [ | |
110 root_index -2 | |
111 target -2 | |
112 source -1 | |
113 graphics [ | |
114 width 1.5 | |
115 fill "#0000ff" | |
116 type "line" | |
117 Line [ | |
118 ] | |
119 source_arrow 0 | |
120 target_arrow 3 | |
121 ] | |
122 label "DirectedEdge" | |
123 ] | |
124 edge [ | |
125 root_index -1 | |
126 target -1 | |
127 source -3 | |
128 graphics [ | |
129 width 1.5 | |
130 fill "#0000ff" | |
131 type "line" | |
132 Line [ | |
133 ] | |
134 source_arrow 0 | |
135 target_arrow 3 | |
136 ] | |
137 label "DirectedEdge" | |
138 ] | |
139 ] | |
140 """ | |
141 nx.parse_gml(cytoscape_example) | |
142 | |
143 def test_parse_gml(self): | |
144 G = nx.parse_gml(self.simple_data, label="label") | |
145 assert sorted(G.nodes()) == ["Node 1", "Node 2", "Node 3"] | |
146 assert [e for e in sorted(G.edges())] == [ | |
147 ("Node 1", "Node 2"), | |
148 ("Node 2", "Node 3"), | |
149 ("Node 3", "Node 1"), | |
150 ] | |
151 | |
152 assert [e for e in sorted(G.edges(data=True))] == [ | |
153 ( | |
154 "Node 1", | |
155 "Node 2", | |
156 { | |
157 "color": {"line": "blue", "thickness": 3}, | |
158 "label": "Edge from node 1 to node 2", | |
159 }, | |
160 ), | |
161 ("Node 2", "Node 3", {"label": "Edge from node 2 to node 3"}), | |
162 ("Node 3", "Node 1", {"label": "Edge from node 3 to node 1"}), | |
163 ] | |
164 | |
165 def test_read_gml(self): | |
166 (fd, fname) = tempfile.mkstemp() | |
167 fh = open(fname, "w") | |
168 fh.write(self.simple_data) | |
169 fh.close() | |
170 Gin = nx.read_gml(fname, label="label") | |
171 G = nx.parse_gml(self.simple_data, label="label") | |
172 assert sorted(G.nodes(data=True)) == sorted(Gin.nodes(data=True)) | |
173 assert sorted(G.edges(data=True)) == sorted(Gin.edges(data=True)) | |
174 os.close(fd) | |
175 os.unlink(fname) | |
176 | |
177 def test_labels_are_strings(self): | |
178 # GML requires labels to be strings (i.e., in quotes) | |
179 answer = """graph [ | |
180 node [ | |
181 id 0 | |
182 label "1203" | |
183 ] | |
184 ]""" | |
185 G = nx.Graph() | |
186 G.add_node(1203) | |
187 data = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) | |
188 assert data == answer | |
189 | |
190 def test_relabel_duplicate(self): | |
191 data = """ | |
192 graph | |
193 [ | |
194 label "" | |
195 directed 1 | |
196 node | |
197 [ | |
198 id 0 | |
199 label "same" | |
200 ] | |
201 node | |
202 [ | |
203 id 1 | |
204 label "same" | |
205 ] | |
206 ] | |
207 """ | |
208 fh = io.BytesIO(data.encode("UTF-8")) | |
209 fh.seek(0) | |
210 pytest.raises(nx.NetworkXError, nx.read_gml, fh, label="label") | |
211 | |
212 def test_tuplelabels(self): | |
213 # https://github.com/networkx/networkx/pull/1048 | |
214 # Writing tuple labels to GML failed. | |
215 G = nx.OrderedGraph() | |
216 G.add_edge((0, 1), (1, 0)) | |
217 data = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) | |
218 answer = """graph [ | |
219 node [ | |
220 id 0 | |
221 label "(0,1)" | |
222 ] | |
223 node [ | |
224 id 1 | |
225 label "(1,0)" | |
226 ] | |
227 edge [ | |
228 source 0 | |
229 target 1 | |
230 ] | |
231 ]""" | |
232 assert data == answer | |
233 | |
234 def test_quotes(self): | |
235 # https://github.com/networkx/networkx/issues/1061 | |
236 # Encoding quotes as HTML entities. | |
237 G = nx.path_graph(1) | |
238 G.name = "path_graph(1)" | |
239 attr = 'This is "quoted" and this is a copyright: ' + chr(169) | |
240 G.nodes[0]["demo"] = attr | |
241 fobj = tempfile.NamedTemporaryFile() | |
242 nx.write_gml(G, fobj) | |
243 fobj.seek(0) | |
244 # Should be bytes in 2.x and 3.x | |
245 data = fobj.read().strip().decode("ascii") | |
246 answer = """graph [ | |
247 name "path_graph(1)" | |
248 node [ | |
249 id 0 | |
250 label "0" | |
251 demo "This is "quoted" and this is a copyright: ©" | |
252 ] | |
253 ]""" | |
254 assert data == answer | |
255 | |
256 def test_unicode_node(self): | |
257 node = "node" + chr(169) | |
258 G = nx.Graph() | |
259 G.add_node(node) | |
260 fobj = tempfile.NamedTemporaryFile() | |
261 nx.write_gml(G, fobj) | |
262 fobj.seek(0) | |
263 # Should be bytes in 2.x and 3.x | |
264 data = fobj.read().strip().decode("ascii") | |
265 answer = """graph [ | |
266 node [ | |
267 id 0 | |
268 label "node©" | |
269 ] | |
270 ]""" | |
271 assert data == answer | |
272 | |
273 def test_float_label(self): | |
274 node = 1.0 | |
275 G = nx.Graph() | |
276 G.add_node(node) | |
277 fobj = tempfile.NamedTemporaryFile() | |
278 nx.write_gml(G, fobj) | |
279 fobj.seek(0) | |
280 # Should be bytes in 2.x and 3.x | |
281 data = fobj.read().strip().decode("ascii") | |
282 answer = """graph [ | |
283 node [ | |
284 id 0 | |
285 label "1.0" | |
286 ] | |
287 ]""" | |
288 assert data == answer | |
289 | |
290 def test_name(self): | |
291 G = nx.parse_gml('graph [ name "x" node [ id 0 label "x" ] ]') | |
292 assert "x" == G.graph["name"] | |
293 G = nx.parse_gml('graph [ node [ id 0 label "x" ] ]') | |
294 assert "" == G.name | |
295 assert "name" not in G.graph | |
296 | |
297 def test_graph_types(self): | |
298 for directed in [None, False, True]: | |
299 for multigraph in [None, False, True]: | |
300 gml = "graph [" | |
301 if directed is not None: | |
302 gml += " directed " + str(int(directed)) | |
303 if multigraph is not None: | |
304 gml += " multigraph " + str(int(multigraph)) | |
305 gml += ' node [ id 0 label "0" ]' | |
306 gml += " edge [ source 0 target 0 ]" | |
307 gml += " ]" | |
308 G = nx.parse_gml(gml) | |
309 assert bool(directed) == G.is_directed() | |
310 assert bool(multigraph) == G.is_multigraph() | |
311 gml = "graph [\n" | |
312 if directed is True: | |
313 gml += " directed 1\n" | |
314 if multigraph is True: | |
315 gml += " multigraph 1\n" | |
316 gml += """ node [ | |
317 id 0 | |
318 label "0" | |
319 ] | |
320 edge [ | |
321 source 0 | |
322 target 0 | |
323 """ | |
324 if multigraph: | |
325 gml += " key 0\n" | |
326 gml += " ]\n]" | |
327 assert gml == "\n".join(nx.generate_gml(G)) | |
328 | |
329 def test_data_types(self): | |
330 data = [ | |
331 True, | |
332 False, | |
333 10 ** 20, | |
334 -2e33, | |
335 "'", | |
336 '"&&&""', | |
337 [{(b"\xfd",): "\x7f", chr(0x4444): (1, 2)}, (2, "3")], | |
338 ] | |
339 try: # fails under IronPython | |
340 data.append(chr(0x14444)) | |
341 except ValueError: | |
342 data.append(chr(0x1444)) | |
343 data.append(literal_eval("{2.3j, 1 - 2.3j, ()}")) | |
344 G = nx.Graph() | |
345 G.name = data | |
346 G.graph["data"] = data | |
347 G.add_node(0, int=-1, data=dict(data=data)) | |
348 G.add_edge(0, 0, float=-2.5, data=data) | |
349 gml = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) | |
350 G = nx.parse_gml(gml, destringizer=literal_destringizer) | |
351 assert data == G.name | |
352 assert {"name": data, "data": data} == G.graph | |
353 assert list(G.nodes(data=True)) == [(0, dict(int=-1, data=dict(data=data)))] | |
354 assert list(G.edges(data=True)) == [(0, 0, dict(float=-2.5, data=data))] | |
355 G = nx.Graph() | |
356 G.graph["data"] = "frozenset([1, 2, 3])" | |
357 G = nx.parse_gml(nx.generate_gml(G), destringizer=literal_eval) | |
358 assert G.graph["data"] == "frozenset([1, 2, 3])" | |
359 | |
360 def test_escape_unescape(self): | |
361 gml = """graph [ | |
362 name "&"䑄��&unknown;" | |
363 ]""" | |
364 G = nx.parse_gml(gml) | |
365 assert ( | |
366 '&"\x0f' + chr(0x4444) + "��&unknown;" | |
367 == G.name | |
368 ) | |
369 gml = "\n".join(nx.generate_gml(G)) | |
370 alnu = "#1234567890;&#x1234567890abcdef" | |
371 answer = ( | |
372 """graph [ | |
373 name "&"䑄&""" | |
374 + alnu | |
375 + """;&unknown;" | |
376 ]""" | |
377 ) | |
378 assert answer == gml | |
379 | |
380 def test_exceptions(self): | |
381 pytest.raises(ValueError, literal_destringizer, "(") | |
382 pytest.raises(ValueError, literal_destringizer, "frozenset([1, 2, 3])") | |
383 pytest.raises(ValueError, literal_destringizer, literal_destringizer) | |
384 pytest.raises(ValueError, literal_stringizer, frozenset([1, 2, 3])) | |
385 pytest.raises(ValueError, literal_stringizer, literal_stringizer) | |
386 with tempfile.TemporaryFile() as f: | |
387 f.write(codecs.BOM_UTF8 + b"graph[]") | |
388 f.seek(0) | |
389 pytest.raises(nx.NetworkXError, nx.read_gml, f) | |
390 | |
391 def assert_parse_error(gml): | |
392 pytest.raises(nx.NetworkXError, nx.parse_gml, gml) | |
393 | |
394 assert_parse_error(["graph [\n\n", "]"]) | |
395 assert_parse_error("") | |
396 assert_parse_error('Creator ""') | |
397 assert_parse_error("0") | |
398 assert_parse_error("graph ]") | |
399 assert_parse_error("graph [ 1 ]") | |
400 assert_parse_error("graph [ 1.E+2 ]") | |
401 assert_parse_error('graph [ "A" ]') | |
402 assert_parse_error("graph [ ] graph ]") | |
403 assert_parse_error("graph [ ] graph [ ]") | |
404 assert_parse_error("graph [ data [1, 2, 3] ]") | |
405 assert_parse_error("graph [ node [ ] ]") | |
406 assert_parse_error("graph [ node [ id 0 ] ]") | |
407 nx.parse_gml('graph [ node [ id "a" ] ]', label="id") | |
408 assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 0 label 1 ] ]") | |
409 assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 1 label 0 ] ]") | |
410 assert_parse_error("graph [ node [ id 0 label 0 ] edge [ ] ]") | |
411 assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 ] ]") | |
412 nx.parse_gml("graph [edge [ source 0 target 0 ] node [ id 0 label 0 ] ]") | |
413 assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 1 target 0 ] ]") | |
414 assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 target 1 ] ]") | |
415 assert_parse_error( | |
416 "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " | |
417 "edge [ source 0 target 1 ] edge [ source 1 target 0 ] ]" | |
418 ) | |
419 nx.parse_gml( | |
420 "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " | |
421 "edge [ source 0 target 1 ] edge [ source 1 target 0 ] " | |
422 "directed 1 ]" | |
423 ) | |
424 nx.parse_gml( | |
425 "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " | |
426 "edge [ source 0 target 1 ] edge [ source 0 target 1 ]" | |
427 "multigraph 1 ]" | |
428 ) | |
429 nx.parse_gml( | |
430 "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " | |
431 "edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 ]" | |
432 "multigraph 1 ]" | |
433 ) | |
434 assert_parse_error( | |
435 "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " | |
436 "edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 key 0 ]" | |
437 "multigraph 1 ]" | |
438 ) | |
439 nx.parse_gml( | |
440 "graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " | |
441 "edge [ source 0 target 1 key 0 ] edge [ source 1 target 0 key 0 ]" | |
442 "directed 1 multigraph 1 ]" | |
443 ) | |
444 | |
445 # Tests for string convertable alphanumeric id and label values | |
446 nx.parse_gml("graph [edge [ source a target a ] node [ id a label b ] ]") | |
447 nx.parse_gml( | |
448 "graph [ node [ id n42 label 0 ] node [ id x43 label 1 ]" | |
449 "edge [ source n42 target x43 key 0 ]" | |
450 "edge [ source x43 target n42 key 0 ]" | |
451 "directed 1 multigraph 1 ]" | |
452 ) | |
453 assert_parse_error( | |
454 "graph [edge [ source u'u\4200' target u'u\4200' ] " | |
455 + "node [ id u'u\4200' label b ] ]" | |
456 ) | |
457 | |
458 def assert_generate_error(*args, **kwargs): | |
459 pytest.raises( | |
460 nx.NetworkXError, lambda: list(nx.generate_gml(*args, **kwargs)) | |
461 ) | |
462 | |
463 G = nx.Graph() | |
464 G.graph[3] = 3 | |
465 assert_generate_error(G) | |
466 G = nx.Graph() | |
467 G.graph["3"] = 3 | |
468 assert_generate_error(G) | |
469 G = nx.Graph() | |
470 G.graph["data"] = frozenset([1, 2, 3]) | |
471 assert_generate_error(G, stringizer=literal_stringizer) | |
472 G = nx.Graph() | |
473 G.graph["data"] = [] | |
474 assert_generate_error(G) | |
475 assert_generate_error(G, stringizer=len) | |
476 | |
477 def test_label_kwarg(self): | |
478 G = nx.parse_gml(self.simple_data, label="id") | |
479 assert sorted(G.nodes) == [1, 2, 3] | |
480 labels = [G.nodes[n]["label"] for n in sorted(G.nodes)] | |
481 assert labels == ["Node 1", "Node 2", "Node 3"] | |
482 | |
483 G = nx.parse_gml(self.simple_data, label=None) | |
484 assert sorted(G.nodes) == [1, 2, 3] | |
485 labels = [G.nodes[n]["label"] for n in sorted(G.nodes)] | |
486 assert labels == ["Node 1", "Node 2", "Node 3"] | |
487 | |
488 def test_outofrange_integers(self): | |
489 # GML restricts integers to 32 signed bits. | |
490 # Check that we honor this restriction on export | |
491 G = nx.Graph() | |
492 # Test export for numbers that barely fit or don't fit into 32 bits, | |
493 # and 3 numbers in the middle | |
494 numbers = { | |
495 "toosmall": (-(2 ** 31)) - 1, | |
496 "small": -(2 ** 31), | |
497 "med1": -4, | |
498 "med2": 0, | |
499 "med3": 17, | |
500 "big": (2 ** 31) - 1, | |
501 "toobig": 2 ** 31, | |
502 } | |
503 G.add_node("Node", **numbers) | |
504 | |
505 fd, fname = tempfile.mkstemp() | |
506 try: | |
507 nx.write_gml(G, fname) | |
508 # Check that the export wrote the nonfitting numbers as strings | |
509 G2 = nx.read_gml(fname) | |
510 for attr, value in G2.nodes["Node"].items(): | |
511 if attr == "toosmall" or attr == "toobig": | |
512 assert type(value) == str | |
513 else: | |
514 assert type(value) == int | |
515 finally: | |
516 os.close(fd) | |
517 os.unlink(fname) | |
518 | |
519 | |
520 @contextmanager | |
521 def byte_file(): | |
522 _file_handle = io.BytesIO() | |
523 yield _file_handle | |
524 _file_handle.seek(0) | |
525 | |
526 | |
527 class TestPropertyLists: | |
528 def test_writing_graph_with_multi_element_property_list(self): | |
529 g = nx.Graph() | |
530 g.add_node("n1", properties=["element", 0, 1, 2.5, True, False]) | |
531 with byte_file() as f: | |
532 nx.write_gml(g, f) | |
533 result = f.read().decode() | |
534 | |
535 assert result == dedent( | |
536 """\ | |
537 graph [ | |
538 node [ | |
539 id 0 | |
540 label "n1" | |
541 properties "element" | |
542 properties 0 | |
543 properties 1 | |
544 properties 2.5 | |
545 properties 1 | |
546 properties 0 | |
547 ] | |
548 ] | |
549 """ | |
550 ) | |
551 | |
552 def test_writing_graph_with_one_element_property_list(self): | |
553 g = nx.Graph() | |
554 g.add_node("n1", properties=["element"]) | |
555 with byte_file() as f: | |
556 nx.write_gml(g, f) | |
557 result = f.read().decode() | |
558 | |
559 assert result == dedent( | |
560 """\ | |
561 graph [ | |
562 node [ | |
563 id 0 | |
564 label "n1" | |
565 properties "_networkx_list_start" | |
566 properties "element" | |
567 ] | |
568 ] | |
569 """ | |
570 ) | |
571 | |
572 def test_reading_graph_with_list_property(self): | |
573 with byte_file() as f: | |
574 f.write( | |
575 dedent( | |
576 """ | |
577 graph [ | |
578 node [ | |
579 id 0 | |
580 label "n1" | |
581 properties "element" | |
582 properties 0 | |
583 properties 1 | |
584 properties 2.5 | |
585 ] | |
586 ] | |
587 """ | |
588 ).encode("ascii") | |
589 ) | |
590 f.seek(0) | |
591 graph = nx.read_gml(f) | |
592 assert graph.nodes(data=True)["n1"] == {"properties": ["element", 0, 1, 2.5]} | |
593 | |
594 def test_reading_graph_with_single_element_list_property(self): | |
595 with byte_file() as f: | |
596 f.write( | |
597 dedent( | |
598 """ | |
599 graph [ | |
600 node [ | |
601 id 0 | |
602 label "n1" | |
603 properties "_networkx_list_start" | |
604 properties "element" | |
605 ] | |
606 ] | |
607 """ | |
608 ).encode("ascii") | |
609 ) | |
610 f.seek(0) | |
611 graph = nx.read_gml(f) | |
612 assert graph.nodes(data=True)["n1"] == {"properties": ["element"]} |