test_graphml.py 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
  1. import io
  2. import os
  3. import tempfile
  4. import pytest
  5. import networkx as nx
  6. from networkx.readwrite.graphml import GraphMLWriter
  7. from networkx.utils import edges_equal, nodes_equal
  8. class BaseGraphML:
  9. @classmethod
  10. def setup_class(cls):
  11. cls.simple_directed_data = """<?xml version="1.0" encoding="UTF-8"?>
  12. <!-- This file was written by the JAVA GraphML Library.-->
  13. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  14. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  15. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  16. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  17. <graph id="G" edgedefault="directed">
  18. <node id="n0"/>
  19. <node id="n1"/>
  20. <node id="n2"/>
  21. <node id="n3"/>
  22. <node id="n4"/>
  23. <node id="n5"/>
  24. <node id="n6"/>
  25. <node id="n7"/>
  26. <node id="n8"/>
  27. <node id="n9"/>
  28. <node id="n10"/>
  29. <edge id="foo" source="n0" target="n2"/>
  30. <edge source="n1" target="n2"/>
  31. <edge source="n2" target="n3"/>
  32. <edge source="n3" target="n5"/>
  33. <edge source="n3" target="n4"/>
  34. <edge source="n4" target="n6"/>
  35. <edge source="n6" target="n5"/>
  36. <edge source="n5" target="n7"/>
  37. <edge source="n6" target="n8"/>
  38. <edge source="n8" target="n7"/>
  39. <edge source="n8" target="n9"/>
  40. </graph>
  41. </graphml>"""
  42. cls.simple_directed_graph = nx.DiGraph()
  43. cls.simple_directed_graph.add_node("n10")
  44. cls.simple_directed_graph.add_edge("n0", "n2", id="foo")
  45. cls.simple_directed_graph.add_edge("n0", "n2")
  46. cls.simple_directed_graph.add_edges_from(
  47. [
  48. ("n1", "n2"),
  49. ("n2", "n3"),
  50. ("n3", "n5"),
  51. ("n3", "n4"),
  52. ("n4", "n6"),
  53. ("n6", "n5"),
  54. ("n5", "n7"),
  55. ("n6", "n8"),
  56. ("n8", "n7"),
  57. ("n8", "n9"),
  58. ]
  59. )
  60. cls.simple_directed_fh = io.BytesIO(cls.simple_directed_data.encode("UTF-8"))
  61. cls.attribute_data = """<?xml version="1.0" encoding="UTF-8"?>
  62. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  63. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  64. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  65. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  66. <key id="d0" for="node" attr.name="color" attr.type="string">
  67. <default>yellow</default>
  68. </key>
  69. <key id="d1" for="edge" attr.name="weight" attr.type="double"/>
  70. <graph id="G" edgedefault="directed">
  71. <node id="n0">
  72. <data key="d0">green</data>
  73. </node>
  74. <node id="n1"/>
  75. <node id="n2">
  76. <data key="d0">blue</data>
  77. </node>
  78. <node id="n3">
  79. <data key="d0">red</data>
  80. </node>
  81. <node id="n4"/>
  82. <node id="n5">
  83. <data key="d0">turquoise</data>
  84. </node>
  85. <edge id="e0" source="n0" target="n2">
  86. <data key="d1">1.0</data>
  87. </edge>
  88. <edge id="e1" source="n0" target="n1">
  89. <data key="d1">1.0</data>
  90. </edge>
  91. <edge id="e2" source="n1" target="n3">
  92. <data key="d1">2.0</data>
  93. </edge>
  94. <edge id="e3" source="n3" target="n2"/>
  95. <edge id="e4" source="n2" target="n4"/>
  96. <edge id="e5" source="n3" target="n5"/>
  97. <edge id="e6" source="n5" target="n4">
  98. <data key="d1">1.1</data>
  99. </edge>
  100. </graph>
  101. </graphml>
  102. """
  103. cls.attribute_graph = nx.DiGraph(id="G")
  104. cls.attribute_graph.graph["node_default"] = {"color": "yellow"}
  105. cls.attribute_graph.add_node("n0", color="green")
  106. cls.attribute_graph.add_node("n2", color="blue")
  107. cls.attribute_graph.add_node("n3", color="red")
  108. cls.attribute_graph.add_node("n4")
  109. cls.attribute_graph.add_node("n5", color="turquoise")
  110. cls.attribute_graph.add_edge("n0", "n2", id="e0", weight=1.0)
  111. cls.attribute_graph.add_edge("n0", "n1", id="e1", weight=1.0)
  112. cls.attribute_graph.add_edge("n1", "n3", id="e2", weight=2.0)
  113. cls.attribute_graph.add_edge("n3", "n2", id="e3")
  114. cls.attribute_graph.add_edge("n2", "n4", id="e4")
  115. cls.attribute_graph.add_edge("n3", "n5", id="e5")
  116. cls.attribute_graph.add_edge("n5", "n4", id="e6", weight=1.1)
  117. cls.attribute_fh = io.BytesIO(cls.attribute_data.encode("UTF-8"))
  118. cls.node_attribute_default_data = """<?xml version="1.0" encoding="UTF-8"?>
  119. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  120. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  121. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  122. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  123. <key id="d0" for="node" attr.name="boolean_attribute" attr.type="boolean"><default>false</default></key>
  124. <key id="d1" for="node" attr.name="int_attribute" attr.type="int"><default>0</default></key>
  125. <key id="d2" for="node" attr.name="long_attribute" attr.type="long"><default>0</default></key>
  126. <key id="d3" for="node" attr.name="float_attribute" attr.type="float"><default>0.0</default></key>
  127. <key id="d4" for="node" attr.name="double_attribute" attr.type="double"><default>0.0</default></key>
  128. <key id="d5" for="node" attr.name="string_attribute" attr.type="string"><default>Foo</default></key>
  129. <graph id="G" edgedefault="directed">
  130. <node id="n0"/>
  131. <node id="n1"/>
  132. <edge id="e0" source="n0" target="n1"/>
  133. </graph>
  134. </graphml>
  135. """
  136. cls.node_attribute_default_graph = nx.DiGraph(id="G")
  137. cls.node_attribute_default_graph.graph["node_default"] = {
  138. "boolean_attribute": False,
  139. "int_attribute": 0,
  140. "long_attribute": 0,
  141. "float_attribute": 0.0,
  142. "double_attribute": 0.0,
  143. "string_attribute": "Foo",
  144. }
  145. cls.node_attribute_default_graph.add_node("n0")
  146. cls.node_attribute_default_graph.add_node("n1")
  147. cls.node_attribute_default_graph.add_edge("n0", "n1", id="e0")
  148. cls.node_attribute_default_fh = io.BytesIO(
  149. cls.node_attribute_default_data.encode("UTF-8")
  150. )
  151. cls.attribute_named_key_ids_data = """<?xml version='1.0' encoding='utf-8'?>
  152. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  153. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  154. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  155. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  156. <key id="edge_prop" for="edge" attr.name="edge_prop" attr.type="string"/>
  157. <key id="prop2" for="node" attr.name="prop2" attr.type="string"/>
  158. <key id="prop1" for="node" attr.name="prop1" attr.type="string"/>
  159. <graph edgedefault="directed">
  160. <node id="0">
  161. <data key="prop1">val1</data>
  162. <data key="prop2">val2</data>
  163. </node>
  164. <node id="1">
  165. <data key="prop1">val_one</data>
  166. <data key="prop2">val2</data>
  167. </node>
  168. <edge source="0" target="1">
  169. <data key="edge_prop">edge_value</data>
  170. </edge>
  171. </graph>
  172. </graphml>
  173. """
  174. cls.attribute_named_key_ids_graph = nx.DiGraph()
  175. cls.attribute_named_key_ids_graph.add_node("0", prop1="val1", prop2="val2")
  176. cls.attribute_named_key_ids_graph.add_node("1", prop1="val_one", prop2="val2")
  177. cls.attribute_named_key_ids_graph.add_edge("0", "1", edge_prop="edge_value")
  178. fh = io.BytesIO(cls.attribute_named_key_ids_data.encode("UTF-8"))
  179. cls.attribute_named_key_ids_fh = fh
  180. cls.attribute_numeric_type_data = """<?xml version='1.0' encoding='utf-8'?>
  181. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  182. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  183. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  184. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  185. <key attr.name="weight" attr.type="double" for="node" id="d1" />
  186. <key attr.name="weight" attr.type="double" for="edge" id="d0" />
  187. <graph edgedefault="directed">
  188. <node id="n0">
  189. <data key="d1">1</data>
  190. </node>
  191. <node id="n1">
  192. <data key="d1">2.0</data>
  193. </node>
  194. <edge source="n0" target="n1">
  195. <data key="d0">1</data>
  196. </edge>
  197. <edge source="n1" target="n0">
  198. <data key="d0">k</data>
  199. </edge>
  200. <edge source="n1" target="n1">
  201. <data key="d0">1.0</data>
  202. </edge>
  203. </graph>
  204. </graphml>
  205. """
  206. cls.attribute_numeric_type_graph = nx.DiGraph()
  207. cls.attribute_numeric_type_graph.add_node("n0", weight=1)
  208. cls.attribute_numeric_type_graph.add_node("n1", weight=2.0)
  209. cls.attribute_numeric_type_graph.add_edge("n0", "n1", weight=1)
  210. cls.attribute_numeric_type_graph.add_edge("n1", "n1", weight=1.0)
  211. fh = io.BytesIO(cls.attribute_numeric_type_data.encode("UTF-8"))
  212. cls.attribute_numeric_type_fh = fh
  213. cls.simple_undirected_data = """<?xml version="1.0" encoding="UTF-8"?>
  214. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  215. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  216. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  217. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  218. <graph id="G">
  219. <node id="n0"/>
  220. <node id="n1"/>
  221. <node id="n2"/>
  222. <node id="n10"/>
  223. <edge id="foo" source="n0" target="n2"/>
  224. <edge source="n1" target="n2"/>
  225. <edge source="n2" target="n3"/>
  226. </graph>
  227. </graphml>"""
  228. # <edge source="n8" target="n10" directed="false"/>
  229. cls.simple_undirected_graph = nx.Graph()
  230. cls.simple_undirected_graph.add_node("n10")
  231. cls.simple_undirected_graph.add_edge("n0", "n2", id="foo")
  232. cls.simple_undirected_graph.add_edges_from([("n1", "n2"), ("n2", "n3")])
  233. fh = io.BytesIO(cls.simple_undirected_data.encode("UTF-8"))
  234. cls.simple_undirected_fh = fh
  235. cls.undirected_multigraph_data = """<?xml version="1.0" encoding="UTF-8"?>
  236. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  237. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  238. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  239. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  240. <graph id="G">
  241. <node id="n0"/>
  242. <node id="n1"/>
  243. <node id="n2"/>
  244. <node id="n10"/>
  245. <edge id="e0" source="n0" target="n2"/>
  246. <edge id="e1" source="n1" target="n2"/>
  247. <edge id="e2" source="n2" target="n1"/>
  248. </graph>
  249. </graphml>"""
  250. cls.undirected_multigraph = nx.MultiGraph()
  251. cls.undirected_multigraph.add_node("n10")
  252. cls.undirected_multigraph.add_edge("n0", "n2", id="e0")
  253. cls.undirected_multigraph.add_edge("n1", "n2", id="e1")
  254. cls.undirected_multigraph.add_edge("n2", "n1", id="e2")
  255. fh = io.BytesIO(cls.undirected_multigraph_data.encode("UTF-8"))
  256. cls.undirected_multigraph_fh = fh
  257. cls.undirected_multigraph_no_multiedge_data = """<?xml version="1.0" encoding="UTF-8"?>
  258. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  259. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  260. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  261. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  262. <graph id="G">
  263. <node id="n0"/>
  264. <node id="n1"/>
  265. <node id="n2"/>
  266. <node id="n10"/>
  267. <edge id="e0" source="n0" target="n2"/>
  268. <edge id="e1" source="n1" target="n2"/>
  269. <edge id="e2" source="n2" target="n3"/>
  270. </graph>
  271. </graphml>"""
  272. cls.undirected_multigraph_no_multiedge = nx.MultiGraph()
  273. cls.undirected_multigraph_no_multiedge.add_node("n10")
  274. cls.undirected_multigraph_no_multiedge.add_edge("n0", "n2", id="e0")
  275. cls.undirected_multigraph_no_multiedge.add_edge("n1", "n2", id="e1")
  276. cls.undirected_multigraph_no_multiedge.add_edge("n2", "n3", id="e2")
  277. fh = io.BytesIO(cls.undirected_multigraph_no_multiedge_data.encode("UTF-8"))
  278. cls.undirected_multigraph_no_multiedge_fh = fh
  279. cls.multigraph_only_ids_for_multiedges_data = """<?xml version="1.0" encoding="UTF-8"?>
  280. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  281. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  282. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  283. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  284. <graph id="G">
  285. <node id="n0"/>
  286. <node id="n1"/>
  287. <node id="n2"/>
  288. <node id="n10"/>
  289. <edge source="n0" target="n2"/>
  290. <edge id="e1" source="n1" target="n2"/>
  291. <edge id="e2" source="n2" target="n1"/>
  292. </graph>
  293. </graphml>"""
  294. cls.multigraph_only_ids_for_multiedges = nx.MultiGraph()
  295. cls.multigraph_only_ids_for_multiedges.add_node("n10")
  296. cls.multigraph_only_ids_for_multiedges.add_edge("n0", "n2")
  297. cls.multigraph_only_ids_for_multiedges.add_edge("n1", "n2", id="e1")
  298. cls.multigraph_only_ids_for_multiedges.add_edge("n2", "n1", id="e2")
  299. fh = io.BytesIO(cls.multigraph_only_ids_for_multiedges_data.encode("UTF-8"))
  300. cls.multigraph_only_ids_for_multiedges_fh = fh
  301. class TestReadGraphML(BaseGraphML):
  302. def test_read_simple_directed_graphml(self):
  303. G = self.simple_directed_graph
  304. H = nx.read_graphml(self.simple_directed_fh)
  305. assert sorted(G.nodes()) == sorted(H.nodes())
  306. assert sorted(G.edges()) == sorted(H.edges())
  307. assert sorted(G.edges(data=True)) == sorted(H.edges(data=True))
  308. self.simple_directed_fh.seek(0)
  309. PG = nx.parse_graphml(self.simple_directed_data)
  310. assert sorted(G.nodes()) == sorted(PG.nodes())
  311. assert sorted(G.edges()) == sorted(PG.edges())
  312. assert sorted(G.edges(data=True)) == sorted(PG.edges(data=True))
  313. def test_read_simple_undirected_graphml(self):
  314. G = self.simple_undirected_graph
  315. H = nx.read_graphml(self.simple_undirected_fh)
  316. assert nodes_equal(G.nodes(), H.nodes())
  317. assert edges_equal(G.edges(), H.edges())
  318. self.simple_undirected_fh.seek(0)
  319. PG = nx.parse_graphml(self.simple_undirected_data)
  320. assert nodes_equal(G.nodes(), PG.nodes())
  321. assert edges_equal(G.edges(), PG.edges())
  322. def test_read_undirected_multigraph_graphml(self):
  323. G = self.undirected_multigraph
  324. H = nx.read_graphml(self.undirected_multigraph_fh)
  325. assert nodes_equal(G.nodes(), H.nodes())
  326. assert edges_equal(G.edges(), H.edges())
  327. self.undirected_multigraph_fh.seek(0)
  328. PG = nx.parse_graphml(self.undirected_multigraph_data)
  329. assert nodes_equal(G.nodes(), PG.nodes())
  330. assert edges_equal(G.edges(), PG.edges())
  331. def test_read_undirected_multigraph_no_multiedge_graphml(self):
  332. G = self.undirected_multigraph_no_multiedge
  333. H = nx.read_graphml(self.undirected_multigraph_no_multiedge_fh)
  334. assert nodes_equal(G.nodes(), H.nodes())
  335. assert edges_equal(G.edges(), H.edges())
  336. self.undirected_multigraph_no_multiedge_fh.seek(0)
  337. PG = nx.parse_graphml(self.undirected_multigraph_no_multiedge_data)
  338. assert nodes_equal(G.nodes(), PG.nodes())
  339. assert edges_equal(G.edges(), PG.edges())
  340. def test_read_undirected_multigraph_only_ids_for_multiedges_graphml(self):
  341. G = self.multigraph_only_ids_for_multiedges
  342. H = nx.read_graphml(self.multigraph_only_ids_for_multiedges_fh)
  343. assert nodes_equal(G.nodes(), H.nodes())
  344. assert edges_equal(G.edges(), H.edges())
  345. self.multigraph_only_ids_for_multiedges_fh.seek(0)
  346. PG = nx.parse_graphml(self.multigraph_only_ids_for_multiedges_data)
  347. assert nodes_equal(G.nodes(), PG.nodes())
  348. assert edges_equal(G.edges(), PG.edges())
  349. def test_read_attribute_graphml(self):
  350. G = self.attribute_graph
  351. H = nx.read_graphml(self.attribute_fh)
  352. assert nodes_equal(G.nodes(True), sorted(H.nodes(data=True)))
  353. ge = sorted(G.edges(data=True))
  354. he = sorted(H.edges(data=True))
  355. for a, b in zip(ge, he):
  356. assert a == b
  357. self.attribute_fh.seek(0)
  358. PG = nx.parse_graphml(self.attribute_data)
  359. assert sorted(G.nodes(True)) == sorted(PG.nodes(data=True))
  360. ge = sorted(G.edges(data=True))
  361. he = sorted(PG.edges(data=True))
  362. for a, b in zip(ge, he):
  363. assert a == b
  364. def test_node_default_attribute_graphml(self):
  365. G = self.node_attribute_default_graph
  366. H = nx.read_graphml(self.node_attribute_default_fh)
  367. assert G.graph["node_default"] == H.graph["node_default"]
  368. def test_directed_edge_in_undirected(self):
  369. s = """<?xml version="1.0" encoding="UTF-8"?>
  370. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  371. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  372. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  373. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  374. <graph id="G">
  375. <node id="n0"/>
  376. <node id="n1"/>
  377. <node id="n2"/>
  378. <edge source="n0" target="n1"/>
  379. <edge source="n1" target="n2" directed='true'/>
  380. </graph>
  381. </graphml>"""
  382. fh = io.BytesIO(s.encode("UTF-8"))
  383. pytest.raises(nx.NetworkXError, nx.read_graphml, fh)
  384. pytest.raises(nx.NetworkXError, nx.parse_graphml, s)
  385. def test_undirected_edge_in_directed(self):
  386. s = """<?xml version="1.0" encoding="UTF-8"?>
  387. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  388. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  389. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  390. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  391. <graph id="G" edgedefault='directed'>
  392. <node id="n0"/>
  393. <node id="n1"/>
  394. <node id="n2"/>
  395. <edge source="n0" target="n1"/>
  396. <edge source="n1" target="n2" directed='false'/>
  397. </graph>
  398. </graphml>"""
  399. fh = io.BytesIO(s.encode("UTF-8"))
  400. pytest.raises(nx.NetworkXError, nx.read_graphml, fh)
  401. pytest.raises(nx.NetworkXError, nx.parse_graphml, s)
  402. def test_key_raise(self):
  403. s = """<?xml version="1.0" encoding="UTF-8"?>
  404. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  405. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  406. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  407. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  408. <key id="d0" for="node" attr.name="color" attr.type="string">
  409. <default>yellow</default>
  410. </key>
  411. <key id="d1" for="edge" attr.name="weight" attr.type="double"/>
  412. <graph id="G" edgedefault="directed">
  413. <node id="n0">
  414. <data key="d0">green</data>
  415. </node>
  416. <node id="n1"/>
  417. <node id="n2">
  418. <data key="d0">blue</data>
  419. </node>
  420. <edge id="e0" source="n0" target="n2">
  421. <data key="d2">1.0</data>
  422. </edge>
  423. </graph>
  424. </graphml>
  425. """
  426. fh = io.BytesIO(s.encode("UTF-8"))
  427. pytest.raises(nx.NetworkXError, nx.read_graphml, fh)
  428. pytest.raises(nx.NetworkXError, nx.parse_graphml, s)
  429. def test_hyperedge_raise(self):
  430. s = """<?xml version="1.0" encoding="UTF-8"?>
  431. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  432. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  433. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  434. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  435. <key id="d0" for="node" attr.name="color" attr.type="string">
  436. <default>yellow</default>
  437. </key>
  438. <key id="d1" for="edge" attr.name="weight" attr.type="double"/>
  439. <graph id="G" edgedefault="directed">
  440. <node id="n0">
  441. <data key="d0">green</data>
  442. </node>
  443. <node id="n1"/>
  444. <node id="n2">
  445. <data key="d0">blue</data>
  446. </node>
  447. <hyperedge id="e0" source="n0" target="n2">
  448. <endpoint node="n0"/>
  449. <endpoint node="n1"/>
  450. <endpoint node="n2"/>
  451. </hyperedge>
  452. </graph>
  453. </graphml>
  454. """
  455. fh = io.BytesIO(s.encode("UTF-8"))
  456. pytest.raises(nx.NetworkXError, nx.read_graphml, fh)
  457. pytest.raises(nx.NetworkXError, nx.parse_graphml, s)
  458. def test_multigraph_keys(self):
  459. # Test that reading multigraphs uses edge id attributes as keys
  460. s = """<?xml version="1.0" encoding="UTF-8"?>
  461. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  462. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  463. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  464. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  465. <graph id="G" edgedefault="directed">
  466. <node id="n0"/>
  467. <node id="n1"/>
  468. <edge id="e0" source="n0" target="n1"/>
  469. <edge id="e1" source="n0" target="n1"/>
  470. </graph>
  471. </graphml>
  472. """
  473. fh = io.BytesIO(s.encode("UTF-8"))
  474. G = nx.read_graphml(fh)
  475. expected = [("n0", "n1", "e0"), ("n0", "n1", "e1")]
  476. assert sorted(G.edges(keys=True)) == expected
  477. fh.seek(0)
  478. H = nx.parse_graphml(s)
  479. assert sorted(H.edges(keys=True)) == expected
  480. def test_preserve_multi_edge_data(self):
  481. """
  482. Test that data and keys of edges are preserved on consequent
  483. write and reads
  484. """
  485. G = nx.MultiGraph()
  486. G.add_node(1)
  487. G.add_node(2)
  488. G.add_edges_from(
  489. [
  490. # edges with no data, no keys:
  491. (1, 2),
  492. # edges with only data:
  493. (1, 2, {"key": "data_key1"}),
  494. (1, 2, {"id": "data_id2"}),
  495. (1, 2, {"key": "data_key3", "id": "data_id3"}),
  496. # edges with both data and keys:
  497. (1, 2, 103, {"key": "data_key4"}),
  498. (1, 2, 104, {"id": "data_id5"}),
  499. (1, 2, 105, {"key": "data_key6", "id": "data_id7"}),
  500. ]
  501. )
  502. fh = io.BytesIO()
  503. nx.write_graphml(G, fh)
  504. fh.seek(0)
  505. H = nx.read_graphml(fh, node_type=int)
  506. assert edges_equal(G.edges(data=True, keys=True), H.edges(data=True, keys=True))
  507. assert G._adj == H._adj
  508. Gadj = {
  509. str(node): {
  510. str(nbr): {str(ekey): dd for ekey, dd in key_dict.items()}
  511. for nbr, key_dict in nbr_dict.items()
  512. }
  513. for node, nbr_dict in G._adj.items()
  514. }
  515. fh.seek(0)
  516. HH = nx.read_graphml(fh, node_type=str, edge_key_type=str)
  517. assert Gadj == HH._adj
  518. fh.seek(0)
  519. string_fh = fh.read()
  520. HH = nx.parse_graphml(string_fh, node_type=str, edge_key_type=str)
  521. assert Gadj == HH._adj
  522. def test_yfiles_extension(self):
  523. data = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  524. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  525. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  526. xmlns:y="http://www.yworks.com/xml/graphml"
  527. xmlns:yed="http://www.yworks.com/xml/yed/3"
  528. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  529. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  530. <!--Created by yFiles for Java 2.7-->
  531. <key for="graphml" id="d0" yfiles.type="resources"/>
  532. <key attr.name="url" attr.type="string" for="node" id="d1"/>
  533. <key attr.name="description" attr.type="string" for="node" id="d2"/>
  534. <key for="node" id="d3" yfiles.type="nodegraphics"/>
  535. <key attr.name="Description" attr.type="string" for="graph" id="d4">
  536. <default/>
  537. </key>
  538. <key attr.name="url" attr.type="string" for="edge" id="d5"/>
  539. <key attr.name="description" attr.type="string" for="edge" id="d6"/>
  540. <key for="edge" id="d7" yfiles.type="edgegraphics"/>
  541. <graph edgedefault="directed" id="G">
  542. <node id="n0">
  543. <data key="d3">
  544. <y:ShapeNode>
  545. <y:Geometry height="30.0" width="30.0" x="125.0" y="100.0"/>
  546. <y:Fill color="#FFCC00" transparent="false"/>
  547. <y:BorderStyle color="#000000" type="line" width="1.0"/>
  548. <y:NodeLabel alignment="center" autoSizePolicy="content"
  549. borderDistance="0.0" fontFamily="Dialog" fontSize="13"
  550. fontStyle="plain" hasBackgroundColor="false" hasLineColor="false"
  551. height="19.1328125" modelName="internal" modelPosition="c"
  552. textColor="#000000" visible="true" width="12.27099609375"
  553. x="8.864501953125" y="5.43359375">1</y:NodeLabel>
  554. <y:Shape type="rectangle"/>
  555. </y:ShapeNode>
  556. </data>
  557. </node>
  558. <node id="n1">
  559. <data key="d3">
  560. <y:ShapeNode>
  561. <y:Geometry height="30.0" width="30.0" x="183.0" y="205.0"/>
  562. <y:Fill color="#FFCC00" transparent="false"/>
  563. <y:BorderStyle color="#000000" type="line" width="1.0"/>
  564. <y:NodeLabel alignment="center" autoSizePolicy="content"
  565. borderDistance="0.0" fontFamily="Dialog" fontSize="13"
  566. fontStyle="plain" hasBackgroundColor="false" hasLineColor="false"
  567. height="19.1328125" modelName="internal" modelPosition="c"
  568. textColor="#000000" visible="true" width="12.27099609375"
  569. x="8.864501953125" y="5.43359375">2</y:NodeLabel>
  570. <y:Shape type="rectangle"/>
  571. </y:ShapeNode>
  572. </data>
  573. </node>
  574. <node id="n2">
  575. <data key="d6" xml:space="preserve"><![CDATA[description
  576. line1
  577. line2]]></data>
  578. <data key="d3">
  579. <y:GenericNode configuration="com.yworks.flowchart.terminator">
  580. <y:Geometry height="40.0" width="80.0" x="950.0" y="286.0"/>
  581. <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
  582. <y:BorderStyle color="#000000" type="line" width="1.0"/>
  583. <y:NodeLabel alignment="center" autoSizePolicy="content"
  584. fontFamily="Dialog" fontSize="12" fontStyle="plain"
  585. hasBackgroundColor="false" hasLineColor="false" height="17.96875"
  586. horizontalTextPosition="center" iconTextGap="4" modelName="custom"
  587. textColor="#000000" verticalTextPosition="bottom" visible="true"
  588. width="67.984375" x="6.0078125" xml:space="preserve"
  589. y="11.015625">3<y:LabelModel>
  590. <y:SmartNodeLabelModel distance="4.0"/></y:LabelModel>
  591. <y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0"
  592. labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0"
  593. offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
  594. </y:GenericNode>
  595. </data>
  596. </node>
  597. <edge id="e0" source="n0" target="n1">
  598. <data key="d7">
  599. <y:PolyLineEdge>
  600. <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
  601. <y:LineStyle color="#000000" type="line" width="1.0"/>
  602. <y:Arrows source="none" target="standard"/>
  603. <y:BendStyle smoothed="false"/>
  604. </y:PolyLineEdge>
  605. </data>
  606. </edge>
  607. </graph>
  608. <data key="d0">
  609. <y:Resources/>
  610. </data>
  611. </graphml>
  612. """
  613. fh = io.BytesIO(data.encode("UTF-8"))
  614. G = nx.read_graphml(fh, force_multigraph=True)
  615. assert list(G.edges()) == [("n0", "n1")]
  616. assert G.has_edge("n0", "n1", key="e0")
  617. assert G.nodes["n0"]["label"] == "1"
  618. assert G.nodes["n1"]["label"] == "2"
  619. assert G.nodes["n2"]["label"] == "3"
  620. assert G.nodes["n0"]["shape_type"] == "rectangle"
  621. assert G.nodes["n1"]["shape_type"] == "rectangle"
  622. assert G.nodes["n2"]["shape_type"] == "com.yworks.flowchart.terminator"
  623. assert G.nodes["n2"]["description"] == "description\nline1\nline2"
  624. fh.seek(0)
  625. G = nx.read_graphml(fh)
  626. assert list(G.edges()) == [("n0", "n1")]
  627. assert G["n0"]["n1"]["id"] == "e0"
  628. assert G.nodes["n0"]["label"] == "1"
  629. assert G.nodes["n1"]["label"] == "2"
  630. assert G.nodes["n2"]["label"] == "3"
  631. assert G.nodes["n0"]["shape_type"] == "rectangle"
  632. assert G.nodes["n1"]["shape_type"] == "rectangle"
  633. assert G.nodes["n2"]["shape_type"] == "com.yworks.flowchart.terminator"
  634. assert G.nodes["n2"]["description"] == "description\nline1\nline2"
  635. H = nx.parse_graphml(data, force_multigraph=True)
  636. assert list(H.edges()) == [("n0", "n1")]
  637. assert H.has_edge("n0", "n1", key="e0")
  638. assert H.nodes["n0"]["label"] == "1"
  639. assert H.nodes["n1"]["label"] == "2"
  640. assert H.nodes["n2"]["label"] == "3"
  641. H = nx.parse_graphml(data)
  642. assert list(H.edges()) == [("n0", "n1")]
  643. assert H["n0"]["n1"]["id"] == "e0"
  644. assert H.nodes["n0"]["label"] == "1"
  645. assert H.nodes["n1"]["label"] == "2"
  646. assert H.nodes["n2"]["label"] == "3"
  647. def test_bool(self):
  648. s = """<?xml version="1.0" encoding="UTF-8"?>
  649. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  650. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  651. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  652. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  653. <key id="d0" for="node" attr.name="test" attr.type="boolean">
  654. <default>false</default>
  655. </key>
  656. <graph id="G" edgedefault="directed">
  657. <node id="n0">
  658. <data key="d0">true</data>
  659. </node>
  660. <node id="n1"/>
  661. <node id="n2">
  662. <data key="d0">false</data>
  663. </node>
  664. <node id="n3">
  665. <data key="d0">FaLsE</data>
  666. </node>
  667. <node id="n4">
  668. <data key="d0">True</data>
  669. </node>
  670. <node id="n5">
  671. <data key="d0">0</data>
  672. </node>
  673. <node id="n6">
  674. <data key="d0">1</data>
  675. </node>
  676. </graph>
  677. </graphml>
  678. """
  679. fh = io.BytesIO(s.encode("UTF-8"))
  680. G = nx.read_graphml(fh)
  681. H = nx.parse_graphml(s)
  682. for graph in [G, H]:
  683. assert graph.nodes["n0"]["test"]
  684. assert not graph.nodes["n2"]["test"]
  685. assert not graph.nodes["n3"]["test"]
  686. assert graph.nodes["n4"]["test"]
  687. assert not graph.nodes["n5"]["test"]
  688. assert graph.nodes["n6"]["test"]
  689. def test_graphml_header_line(self):
  690. good = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  691. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  692. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  693. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  694. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  695. <key id="d0" for="node" attr.name="test" attr.type="boolean">
  696. <default>false</default>
  697. </key>
  698. <graph id="G">
  699. <node id="n0">
  700. <data key="d0">true</data>
  701. </node>
  702. </graph>
  703. </graphml>
  704. """
  705. bad = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  706. <graphml>
  707. <key id="d0" for="node" attr.name="test" attr.type="boolean">
  708. <default>false</default>
  709. </key>
  710. <graph id="G">
  711. <node id="n0">
  712. <data key="d0">true</data>
  713. </node>
  714. </graph>
  715. </graphml>
  716. """
  717. ugly = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  718. <graphml xmlns="https://ghghgh">
  719. <key id="d0" for="node" attr.name="test" attr.type="boolean">
  720. <default>false</default>
  721. </key>
  722. <graph id="G">
  723. <node id="n0">
  724. <data key="d0">true</data>
  725. </node>
  726. </graph>
  727. </graphml>
  728. """
  729. for s in (good, bad):
  730. fh = io.BytesIO(s.encode("UTF-8"))
  731. G = nx.read_graphml(fh)
  732. H = nx.parse_graphml(s)
  733. for graph in [G, H]:
  734. assert graph.nodes["n0"]["test"]
  735. fh = io.BytesIO(ugly.encode("UTF-8"))
  736. pytest.raises(nx.NetworkXError, nx.read_graphml, fh)
  737. pytest.raises(nx.NetworkXError, nx.parse_graphml, ugly)
  738. def test_read_attributes_with_groups(self):
  739. data = """\
  740. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  741. <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
  742. <!--Created by yEd 3.17-->
  743. <key attr.name="Description" attr.type="string" for="graph" id="d0"/>
  744. <key for="port" id="d1" yfiles.type="portgraphics"/>
  745. <key for="port" id="d2" yfiles.type="portgeometry"/>
  746. <key for="port" id="d3" yfiles.type="portuserdata"/>
  747. <key attr.name="CustomProperty" attr.type="string" for="node" id="d4">
  748. <default/>
  749. </key>
  750. <key attr.name="url" attr.type="string" for="node" id="d5"/>
  751. <key attr.name="description" attr.type="string" for="node" id="d6"/>
  752. <key for="node" id="d7" yfiles.type="nodegraphics"/>
  753. <key for="graphml" id="d8" yfiles.type="resources"/>
  754. <key attr.name="url" attr.type="string" for="edge" id="d9"/>
  755. <key attr.name="description" attr.type="string" for="edge" id="d10"/>
  756. <key for="edge" id="d11" yfiles.type="edgegraphics"/>
  757. <graph edgedefault="directed" id="G">
  758. <data key="d0"/>
  759. <node id="n0">
  760. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  761. <data key="d6"/>
  762. <data key="d7">
  763. <y:ShapeNode>
  764. <y:Geometry height="30.0" width="30.0" x="125.0" y="-255.4611111111111"/>
  765. <y:Fill color="#FFCC00" transparent="false"/>
  766. <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
  767. <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="11.634765625" x="9.1826171875" y="6.015625">2<y:LabelModel>
  768. <y:SmartNodeLabelModel distance="4.0"/>
  769. </y:LabelModel>
  770. <y:ModelParameter>
  771. <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
  772. </y:ModelParameter>
  773. </y:NodeLabel>
  774. <y:Shape type="rectangle"/>
  775. </y:ShapeNode>
  776. </data>
  777. </node>
  778. <node id="n1" yfiles.foldertype="group">
  779. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  780. <data key="d5"/>
  781. <data key="d6"/>
  782. <data key="d7">
  783. <y:ProxyAutoBoundsNode>
  784. <y:Realizers active="0">
  785. <y:GroupNode>
  786. <y:Geometry height="250.38333333333333" width="140.0" x="-30.0" y="-330.3833333333333"/>
  787. <y:Fill color="#F5F5F5" transparent="false"/>
  788. <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
  789. <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="140.0" x="0.0" y="0.0">Group 3</y:NodeLabel>
  790. <y:Shape type="roundrectangle"/>
  791. <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
  792. <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
  793. <y:BorderInsets bottom="1" bottomF="1.0" left="0" leftF="0.0" right="0" rightF="0.0" top="1" topF="1.0001736111111086"/>
  794. </y:GroupNode>
  795. <y:GroupNode>
  796. <y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
  797. <y:Fill color="#F5F5F5" transparent="false"/>
  798. <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
  799. <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.201171875" x="-7.6005859375" y="0.0">Folder 3</y:NodeLabel>
  800. <y:Shape type="roundrectangle"/>
  801. <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
  802. <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
  803. <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
  804. </y:GroupNode>
  805. </y:Realizers>
  806. </y:ProxyAutoBoundsNode>
  807. </data>
  808. <graph edgedefault="directed" id="n1:">
  809. <node id="n1::n0" yfiles.foldertype="group">
  810. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  811. <data key="d5"/>
  812. <data key="d6"/>
  813. <data key="d7">
  814. <y:ProxyAutoBoundsNode>
  815. <y:Realizers active="0">
  816. <y:GroupNode>
  817. <y:Geometry height="83.46111111111111" width="110.0" x="-15.0" y="-292.9222222222222"/>
  818. <y:Fill color="#F5F5F5" transparent="false"/>
  819. <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
  820. <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.0" x="0.0" y="0.0">Group 1</y:NodeLabel>
  821. <y:Shape type="roundrectangle"/>
  822. <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
  823. <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
  824. <y:BorderInsets bottom="1" bottomF="1.0" left="0" leftF="0.0" right="0" rightF="0.0" top="1" topF="1.0001736111111086"/>
  825. </y:GroupNode>
  826. <y:GroupNode>
  827. <y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
  828. <y:Fill color="#F5F5F5" transparent="false"/>
  829. <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
  830. <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.201171875" x="-7.6005859375" y="0.0">Folder 1</y:NodeLabel>
  831. <y:Shape type="roundrectangle"/>
  832. <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
  833. <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
  834. <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
  835. </y:GroupNode>
  836. </y:Realizers>
  837. </y:ProxyAutoBoundsNode>
  838. </data>
  839. <graph edgedefault="directed" id="n1::n0:">
  840. <node id="n1::n0::n0">
  841. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  842. <data key="d6"/>
  843. <data key="d7">
  844. <y:ShapeNode>
  845. <y:Geometry height="30.0" width="30.0" x="50.0" y="-255.4611111111111"/>
  846. <y:Fill color="#FFCC00" transparent="false"/>
  847. <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
  848. <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="11.634765625" x="9.1826171875" y="6.015625">1<y:LabelModel>
  849. <y:SmartNodeLabelModel distance="4.0"/>
  850. </y:LabelModel>
  851. <y:ModelParameter>
  852. <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
  853. </y:ModelParameter>
  854. </y:NodeLabel>
  855. <y:Shape type="rectangle"/>
  856. </y:ShapeNode>
  857. </data>
  858. </node>
  859. <node id="n1::n0::n1">
  860. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  861. <data key="d6"/>
  862. <data key="d7">
  863. <y:ShapeNode>
  864. <y:Geometry height="30.0" width="30.0" x="0.0" y="-255.4611111111111"/>
  865. <y:Fill color="#FFCC00" transparent="false"/>
  866. <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
  867. <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="11.634765625" x="9.1826171875" y="6.015625">3<y:LabelModel>
  868. <y:SmartNodeLabelModel distance="4.0"/>
  869. </y:LabelModel>
  870. <y:ModelParameter>
  871. <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
  872. </y:ModelParameter>
  873. </y:NodeLabel>
  874. <y:Shape type="rectangle"/>
  875. </y:ShapeNode>
  876. </data>
  877. </node>
  878. </graph>
  879. </node>
  880. <node id="n1::n1" yfiles.foldertype="group">
  881. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  882. <data key="d5"/>
  883. <data key="d6"/>
  884. <data key="d7">
  885. <y:ProxyAutoBoundsNode>
  886. <y:Realizers active="0">
  887. <y:GroupNode>
  888. <y:Geometry height="83.46111111111111" width="110.0" x="-15.0" y="-179.4611111111111"/>
  889. <y:Fill color="#F5F5F5" transparent="false"/>
  890. <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
  891. <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.0" x="0.0" y="0.0">Group 2</y:NodeLabel>
  892. <y:Shape type="roundrectangle"/>
  893. <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
  894. <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
  895. <y:BorderInsets bottom="1" bottomF="1.0" left="0" leftF="0.0" right="0" rightF="0.0" top="1" topF="1.0001736111111086"/>
  896. </y:GroupNode>
  897. <y:GroupNode>
  898. <y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
  899. <y:Fill color="#F5F5F5" transparent="false"/>
  900. <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
  901. <y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.201171875" x="-7.6005859375" y="0.0">Folder 2</y:NodeLabel>
  902. <y:Shape type="roundrectangle"/>
  903. <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
  904. <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
  905. <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
  906. </y:GroupNode>
  907. </y:Realizers>
  908. </y:ProxyAutoBoundsNode>
  909. </data>
  910. <graph edgedefault="directed" id="n1::n1:">
  911. <node id="n1::n1::n0">
  912. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  913. <data key="d6"/>
  914. <data key="d7">
  915. <y:ShapeNode>
  916. <y:Geometry height="30.0" width="30.0" x="0.0" y="-142.0"/>
  917. <y:Fill color="#FFCC00" transparent="false"/>
  918. <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
  919. <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="11.634765625" x="9.1826171875" y="6.015625">5<y:LabelModel>
  920. <y:SmartNodeLabelModel distance="4.0"/>
  921. </y:LabelModel>
  922. <y:ModelParameter>
  923. <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
  924. </y:ModelParameter>
  925. </y:NodeLabel>
  926. <y:Shape type="rectangle"/>
  927. </y:ShapeNode>
  928. </data>
  929. </node>
  930. <node id="n1::n1::n1">
  931. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  932. <data key="d6"/>
  933. <data key="d7">
  934. <y:ShapeNode>
  935. <y:Geometry height="30.0" width="30.0" x="50.0" y="-142.0"/>
  936. <y:Fill color="#FFCC00" transparent="false"/>
  937. <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
  938. <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="11.634765625" x="9.1826171875" y="6.015625">6<y:LabelModel>
  939. <y:SmartNodeLabelModel distance="4.0"/>
  940. </y:LabelModel>
  941. <y:ModelParameter>
  942. <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
  943. </y:ModelParameter>
  944. </y:NodeLabel>
  945. <y:Shape type="rectangle"/>
  946. </y:ShapeNode>
  947. </data>
  948. </node>
  949. </graph>
  950. </node>
  951. </graph>
  952. </node>
  953. <node id="n2">
  954. <data key="d4"><![CDATA[CustomPropertyValue]]></data>
  955. <data key="d6"/>
  956. <data key="d7">
  957. <y:ShapeNode>
  958. <y:Geometry height="30.0" width="30.0" x="125.0" y="-142.0"/>
  959. <y:Fill color="#FFCC00" transparent="false"/>
  960. <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
  961. <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="11.634765625" x="9.1826171875" y="6.015625">9<y:LabelModel>
  962. <y:SmartNodeLabelModel distance="4.0"/>
  963. </y:LabelModel>
  964. <y:ModelParameter>
  965. <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
  966. </y:ModelParameter>
  967. </y:NodeLabel>
  968. <y:Shape type="rectangle"/>
  969. </y:ShapeNode>
  970. </data>
  971. </node>
  972. <edge id="n1::n1::e0" source="n1::n1::n0" target="n1::n1::n1">
  973. <data key="d10"/>
  974. <data key="d11">
  975. <y:PolyLineEdge>
  976. <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
  977. <y:LineStyle color="#000000" type="line" width="1.0"/>
  978. <y:Arrows source="none" target="standard"/>
  979. <y:BendStyle smoothed="false"/>
  980. </y:PolyLineEdge>
  981. </data>
  982. </edge>
  983. <edge id="n1::n0::e0" source="n1::n0::n1" target="n1::n0::n0">
  984. <data key="d10"/>
  985. <data key="d11">
  986. <y:PolyLineEdge>
  987. <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
  988. <y:LineStyle color="#000000" type="line" width="1.0"/>
  989. <y:Arrows source="none" target="standard"/>
  990. <y:BendStyle smoothed="false"/>
  991. </y:PolyLineEdge>
  992. </data>
  993. </edge>
  994. <edge id="e0" source="n1::n0::n0" target="n0">
  995. <data key="d10"/>
  996. <data key="d11">
  997. <y:PolyLineEdge>
  998. <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
  999. <y:LineStyle color="#000000" type="line" width="1.0"/>
  1000. <y:Arrows source="none" target="standard"/>
  1001. <y:BendStyle smoothed="false"/>
  1002. </y:PolyLineEdge>
  1003. </data>
  1004. </edge>
  1005. <edge id="e1" source="n1::n1::n1" target="n2">
  1006. <data key="d10"/>
  1007. <data key="d11">
  1008. <y:PolyLineEdge>
  1009. <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
  1010. <y:LineStyle color="#000000" type="line" width="1.0"/>
  1011. <y:Arrows source="none" target="standard"/>
  1012. <y:BendStyle smoothed="false"/>
  1013. </y:PolyLineEdge>
  1014. </data>
  1015. </edge>
  1016. </graph>
  1017. <data key="d8">
  1018. <y:Resources/>
  1019. </data>
  1020. </graphml>
  1021. """
  1022. # verify that nodes / attributes are correctly read when part of a group
  1023. fh = io.BytesIO(data.encode("UTF-8"))
  1024. G = nx.read_graphml(fh)
  1025. data = [x for _, x in G.nodes(data=True)]
  1026. assert len(data) == 9
  1027. for node_data in data:
  1028. assert node_data["CustomProperty"] != ""
  1029. def test_long_attribute_type(self):
  1030. # test that graphs with attr.type="long" (as produced by botch and
  1031. # dose3) can be parsed
  1032. s = """<?xml version='1.0' encoding='utf-8'?>
  1033. <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
  1034. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  1035. xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
  1036. http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  1037. <key attr.name="cudfversion" attr.type="long" for="node" id="d6" />
  1038. <graph edgedefault="directed">
  1039. <node id="n1">
  1040. <data key="d6">4284</data>
  1041. </node>
  1042. </graph>
  1043. </graphml>"""
  1044. fh = io.BytesIO(s.encode("UTF-8"))
  1045. G = nx.read_graphml(fh)
  1046. expected = [("n1", {"cudfversion": 4284})]
  1047. assert sorted(G.nodes(data=True)) == expected
  1048. fh.seek(0)
  1049. H = nx.parse_graphml(s)
  1050. assert sorted(H.nodes(data=True)) == expected
  1051. class TestWriteGraphML(BaseGraphML):
  1052. writer = staticmethod(nx.write_graphml_lxml)
  1053. @classmethod
  1054. def setup_class(cls):
  1055. BaseGraphML.setup_class()
  1056. _ = pytest.importorskip("lxml.etree")
  1057. def test_write_interface(self):
  1058. try:
  1059. import lxml.etree
  1060. assert nx.write_graphml == nx.write_graphml_lxml
  1061. except ImportError:
  1062. assert nx.write_graphml == nx.write_graphml_xml
  1063. def test_write_read_simple_directed_graphml(self):
  1064. G = self.simple_directed_graph
  1065. G.graph["hi"] = "there"
  1066. fh = io.BytesIO()
  1067. self.writer(G, fh)
  1068. fh.seek(0)
  1069. H = nx.read_graphml(fh)
  1070. assert sorted(G.nodes()) == sorted(H.nodes())
  1071. assert sorted(G.edges()) == sorted(H.edges())
  1072. assert sorted(G.edges(data=True)) == sorted(H.edges(data=True))
  1073. self.simple_directed_fh.seek(0)
  1074. def test_GraphMLWriter_add_graphs(self):
  1075. gmlw = GraphMLWriter()
  1076. G = self.simple_directed_graph
  1077. H = G.copy()
  1078. gmlw.add_graphs([G, H])
  1079. def test_write_read_simple_no_prettyprint(self):
  1080. G = self.simple_directed_graph
  1081. G.graph["hi"] = "there"
  1082. G.graph["id"] = "1"
  1083. fh = io.BytesIO()
  1084. self.writer(G, fh, prettyprint=False)
  1085. fh.seek(0)
  1086. H = nx.read_graphml(fh)
  1087. assert sorted(G.nodes()) == sorted(H.nodes())
  1088. assert sorted(G.edges()) == sorted(H.edges())
  1089. assert sorted(G.edges(data=True)) == sorted(H.edges(data=True))
  1090. self.simple_directed_fh.seek(0)
  1091. def test_write_read_attribute_named_key_ids_graphml(self):
  1092. from xml.etree.ElementTree import parse
  1093. G = self.attribute_named_key_ids_graph
  1094. fh = io.BytesIO()
  1095. self.writer(G, fh, named_key_ids=True)
  1096. fh.seek(0)
  1097. H = nx.read_graphml(fh)
  1098. fh.seek(0)
  1099. assert nodes_equal(G.nodes(), H.nodes())
  1100. assert edges_equal(G.edges(), H.edges())
  1101. assert edges_equal(G.edges(data=True), H.edges(data=True))
  1102. self.attribute_named_key_ids_fh.seek(0)
  1103. xml = parse(fh)
  1104. # Children are the key elements, and the graph element
  1105. children = list(xml.getroot())
  1106. assert len(children) == 4
  1107. keys = [child.items() for child in children[:3]]
  1108. assert len(keys) == 3
  1109. assert ("id", "edge_prop") in keys[0]
  1110. assert ("attr.name", "edge_prop") in keys[0]
  1111. assert ("id", "prop2") in keys[1]
  1112. assert ("attr.name", "prop2") in keys[1]
  1113. assert ("id", "prop1") in keys[2]
  1114. assert ("attr.name", "prop1") in keys[2]
  1115. # Confirm the read graph nodes/edge are identical when compared to
  1116. # default writing behavior.
  1117. default_behavior_fh = io.BytesIO()
  1118. nx.write_graphml(G, default_behavior_fh)
  1119. default_behavior_fh.seek(0)
  1120. H = nx.read_graphml(default_behavior_fh)
  1121. named_key_ids_behavior_fh = io.BytesIO()
  1122. nx.write_graphml(G, named_key_ids_behavior_fh, named_key_ids=True)
  1123. named_key_ids_behavior_fh.seek(0)
  1124. J = nx.read_graphml(named_key_ids_behavior_fh)
  1125. assert all(n1 == n2 for (n1, n2) in zip(H.nodes, J.nodes))
  1126. assert all(e1 == e2 for (e1, e2) in zip(H.edges, J.edges))
  1127. def test_write_read_attribute_numeric_type_graphml(self):
  1128. from xml.etree.ElementTree import parse
  1129. G = self.attribute_numeric_type_graph
  1130. fh = io.BytesIO()
  1131. self.writer(G, fh, infer_numeric_types=True)
  1132. fh.seek(0)
  1133. H = nx.read_graphml(fh)
  1134. fh.seek(0)
  1135. assert nodes_equal(G.nodes(), H.nodes())
  1136. assert edges_equal(G.edges(), H.edges())
  1137. assert edges_equal(G.edges(data=True), H.edges(data=True))
  1138. self.attribute_numeric_type_fh.seek(0)
  1139. xml = parse(fh)
  1140. # Children are the key elements, and the graph element
  1141. children = list(xml.getroot())
  1142. assert len(children) == 3
  1143. keys = [child.items() for child in children[:2]]
  1144. assert len(keys) == 2
  1145. assert ("attr.type", "double") in keys[0]
  1146. assert ("attr.type", "double") in keys[1]
  1147. def test_more_multigraph_keys(self):
  1148. """Writing keys as edge id attributes means keys become strings.
  1149. The original keys are stored as data, so read them back in
  1150. if `str(key) == edge_id`
  1151. This allows the adjacency to remain the same.
  1152. """
  1153. G = nx.MultiGraph()
  1154. G.add_edges_from([("a", "b", 2), ("a", "b", 3)])
  1155. fd, fname = tempfile.mkstemp()
  1156. self.writer(G, fname)
  1157. H = nx.read_graphml(fname)
  1158. assert H.is_multigraph()
  1159. assert edges_equal(G.edges(keys=True), H.edges(keys=True))
  1160. assert G._adj == H._adj
  1161. os.close(fd)
  1162. os.unlink(fname)
  1163. def test_default_attribute(self):
  1164. G = nx.Graph(name="Fred")
  1165. G.add_node(1, label=1, color="green")
  1166. nx.add_path(G, [0, 1, 2, 3])
  1167. G.add_edge(1, 2, weight=3)
  1168. G.graph["node_default"] = {"color": "yellow"}
  1169. G.graph["edge_default"] = {"weight": 7}
  1170. fh = io.BytesIO()
  1171. self.writer(G, fh)
  1172. fh.seek(0)
  1173. H = nx.read_graphml(fh, node_type=int)
  1174. assert nodes_equal(G.nodes(), H.nodes())
  1175. assert edges_equal(G.edges(), H.edges())
  1176. assert G.graph == H.graph
  1177. def test_mixed_type_attributes(self):
  1178. G = nx.MultiGraph()
  1179. G.add_node("n0", special=False)
  1180. G.add_node("n1", special=0)
  1181. G.add_edge("n0", "n1", special=False)
  1182. G.add_edge("n0", "n1", special=0)
  1183. fh = io.BytesIO()
  1184. self.writer(G, fh)
  1185. fh.seek(0)
  1186. H = nx.read_graphml(fh)
  1187. assert not H.nodes["n0"]["special"]
  1188. assert H.nodes["n1"]["special"] == 0
  1189. assert not H.edges["n0", "n1", 0]["special"]
  1190. assert H.edges["n0", "n1", 1]["special"] == 0
  1191. def test_str_number_mixed_type_attributes(self):
  1192. G = nx.MultiGraph()
  1193. G.add_node("n0", special="hello")
  1194. G.add_node("n1", special=0)
  1195. G.add_edge("n0", "n1", special="hello")
  1196. G.add_edge("n0", "n1", special=0)
  1197. fh = io.BytesIO()
  1198. self.writer(G, fh)
  1199. fh.seek(0)
  1200. H = nx.read_graphml(fh)
  1201. assert H.nodes["n0"]["special"] == "hello"
  1202. assert H.nodes["n1"]["special"] == 0
  1203. assert H.edges["n0", "n1", 0]["special"] == "hello"
  1204. assert H.edges["n0", "n1", 1]["special"] == 0
  1205. def test_mixed_int_type_number_attributes(self):
  1206. np = pytest.importorskip("numpy")
  1207. G = nx.MultiGraph()
  1208. G.add_node("n0", special=np.int64(0))
  1209. G.add_node("n1", special=1)
  1210. G.add_edge("n0", "n1", special=np.int64(2))
  1211. G.add_edge("n0", "n1", special=3)
  1212. fh = io.BytesIO()
  1213. self.writer(G, fh)
  1214. fh.seek(0)
  1215. H = nx.read_graphml(fh)
  1216. assert H.nodes["n0"]["special"] == 0
  1217. assert H.nodes["n1"]["special"] == 1
  1218. assert H.edges["n0", "n1", 0]["special"] == 2
  1219. assert H.edges["n0", "n1", 1]["special"] == 3
  1220. def test_numpy_float(self):
  1221. np = pytest.importorskip("numpy")
  1222. wt = np.float_(3.4)
  1223. G = nx.Graph([(1, 2, {"weight": wt})])
  1224. fd, fname = tempfile.mkstemp()
  1225. self.writer(G, fname)
  1226. H = nx.read_graphml(fname, node_type=int)
  1227. assert G._adj == H._adj
  1228. os.close(fd)
  1229. os.unlink(fname)
  1230. def test_multigraph_to_graph(self):
  1231. # test converting multigraph to graph if no parallel edges found
  1232. G = nx.MultiGraph()
  1233. G.add_edges_from([("a", "b", 2), ("b", "c", 3)]) # no multiedges
  1234. fd, fname = tempfile.mkstemp()
  1235. self.writer(G, fname)
  1236. H = nx.read_graphml(fname)
  1237. assert not H.is_multigraph()
  1238. H = nx.read_graphml(fname, force_multigraph=True)
  1239. assert H.is_multigraph()
  1240. os.close(fd)
  1241. os.unlink(fname)
  1242. # add a multiedge
  1243. G.add_edge("a", "b", "e-id")
  1244. fd, fname = tempfile.mkstemp()
  1245. self.writer(G, fname)
  1246. H = nx.read_graphml(fname)
  1247. assert H.is_multigraph()
  1248. H = nx.read_graphml(fname, force_multigraph=True)
  1249. assert H.is_multigraph()
  1250. os.close(fd)
  1251. os.unlink(fname)
  1252. def test_write_generate_edge_id_from_attribute(self):
  1253. from xml.etree.ElementTree import parse
  1254. G = nx.Graph()
  1255. G.add_edges_from([("a", "b"), ("b", "c"), ("a", "c")])
  1256. edge_attributes = {e: str(e) for e in G.edges}
  1257. nx.set_edge_attributes(G, edge_attributes, "eid")
  1258. fd, fname = tempfile.mkstemp()
  1259. # set edge_id_from_attribute e.g. "eid" for write_graphml()
  1260. self.writer(G, fname, edge_id_from_attribute="eid")
  1261. # set edge_id_from_attribute e.g. "eid" for generate_graphml()
  1262. generator = nx.generate_graphml(G, edge_id_from_attribute="eid")
  1263. H = nx.read_graphml(fname)
  1264. assert nodes_equal(G.nodes(), H.nodes())
  1265. assert edges_equal(G.edges(), H.edges())
  1266. # NetworkX adds explicit edge "id" from file as attribute
  1267. nx.set_edge_attributes(G, edge_attributes, "id")
  1268. assert edges_equal(G.edges(data=True), H.edges(data=True))
  1269. tree = parse(fname)
  1270. children = list(tree.getroot())
  1271. assert len(children) == 2
  1272. edge_ids = [
  1273. edge.attrib["id"]
  1274. for edge in tree.getroot().findall(
  1275. ".//{http://graphml.graphdrawing.org/xmlns}edge"
  1276. )
  1277. ]
  1278. # verify edge id value is equal to specified attribute value
  1279. assert sorted(edge_ids) == sorted(edge_attributes.values())
  1280. # check graphml generated from generate_graphml()
  1281. data = "".join(generator)
  1282. J = nx.parse_graphml(data)
  1283. assert sorted(G.nodes()) == sorted(J.nodes())
  1284. assert sorted(G.edges()) == sorted(J.edges())
  1285. # NetworkX adds explicit edge "id" from file as attribute
  1286. nx.set_edge_attributes(G, edge_attributes, "id")
  1287. assert edges_equal(G.edges(data=True), J.edges(data=True))
  1288. os.close(fd)
  1289. os.unlink(fname)
  1290. def test_multigraph_write_generate_edge_id_from_attribute(self):
  1291. from xml.etree.ElementTree import parse
  1292. G = nx.MultiGraph()
  1293. G.add_edges_from([("a", "b"), ("b", "c"), ("a", "c"), ("a", "b")])
  1294. edge_attributes = {e: str(e) for e in G.edges}
  1295. nx.set_edge_attributes(G, edge_attributes, "eid")
  1296. fd, fname = tempfile.mkstemp()
  1297. # set edge_id_from_attribute e.g. "eid" for write_graphml()
  1298. self.writer(G, fname, edge_id_from_attribute="eid")
  1299. # set edge_id_from_attribute e.g. "eid" for generate_graphml()
  1300. generator = nx.generate_graphml(G, edge_id_from_attribute="eid")
  1301. H = nx.read_graphml(fname)
  1302. assert H.is_multigraph()
  1303. H = nx.read_graphml(fname, force_multigraph=True)
  1304. assert H.is_multigraph()
  1305. assert nodes_equal(G.nodes(), H.nodes())
  1306. assert edges_equal(G.edges(), H.edges())
  1307. assert sorted(data.get("eid") for u, v, data in H.edges(data=True)) == sorted(
  1308. edge_attributes.values()
  1309. )
  1310. # NetworkX uses edge_ids as keys in multigraphs if no key
  1311. assert sorted(key for u, v, key in H.edges(keys=True)) == sorted(
  1312. edge_attributes.values()
  1313. )
  1314. tree = parse(fname)
  1315. children = list(tree.getroot())
  1316. assert len(children) == 2
  1317. edge_ids = [
  1318. edge.attrib["id"]
  1319. for edge in tree.getroot().findall(
  1320. ".//{http://graphml.graphdrawing.org/xmlns}edge"
  1321. )
  1322. ]
  1323. # verify edge id value is equal to specified attribute value
  1324. assert sorted(edge_ids) == sorted(edge_attributes.values())
  1325. # check graphml generated from generate_graphml()
  1326. graphml_data = "".join(generator)
  1327. J = nx.parse_graphml(graphml_data)
  1328. assert J.is_multigraph()
  1329. assert nodes_equal(G.nodes(), J.nodes())
  1330. assert edges_equal(G.edges(), J.edges())
  1331. assert sorted(data.get("eid") for u, v, data in J.edges(data=True)) == sorted(
  1332. edge_attributes.values()
  1333. )
  1334. # NetworkX uses edge_ids as keys in multigraphs if no key
  1335. assert sorted(key for u, v, key in J.edges(keys=True)) == sorted(
  1336. edge_attributes.values()
  1337. )
  1338. os.close(fd)
  1339. os.unlink(fname)
  1340. def test_numpy_float64(self):
  1341. np = pytest.importorskip("numpy")
  1342. wt = np.float64(3.4)
  1343. G = nx.Graph([(1, 2, {"weight": wt})])
  1344. fd, fname = tempfile.mkstemp()
  1345. self.writer(G, fname)
  1346. H = nx.read_graphml(fname, node_type=int)
  1347. assert G.edges == H.edges
  1348. wtG = G[1][2]["weight"]
  1349. wtH = H[1][2]["weight"]
  1350. assert wtG == pytest.approx(wtH, abs=1e-6)
  1351. assert type(wtG) == np.float64
  1352. assert type(wtH) == float
  1353. os.close(fd)
  1354. os.unlink(fname)
  1355. def test_numpy_float32(self):
  1356. np = pytest.importorskip("numpy")
  1357. wt = np.float32(3.4)
  1358. G = nx.Graph([(1, 2, {"weight": wt})])
  1359. fd, fname = tempfile.mkstemp()
  1360. self.writer(G, fname)
  1361. H = nx.read_graphml(fname, node_type=int)
  1362. assert G.edges == H.edges
  1363. wtG = G[1][2]["weight"]
  1364. wtH = H[1][2]["weight"]
  1365. assert wtG == pytest.approx(wtH, abs=1e-6)
  1366. assert type(wtG) == np.float32
  1367. assert type(wtH) == float
  1368. os.close(fd)
  1369. os.unlink(fname)
  1370. def test_numpy_float64_inference(self):
  1371. np = pytest.importorskip("numpy")
  1372. G = self.attribute_numeric_type_graph
  1373. G.edges[("n1", "n1")]["weight"] = np.float64(1.1)
  1374. fd, fname = tempfile.mkstemp()
  1375. self.writer(G, fname, infer_numeric_types=True)
  1376. H = nx.read_graphml(fname)
  1377. assert G._adj == H._adj
  1378. os.close(fd)
  1379. os.unlink(fname)
  1380. def test_unicode_attributes(self):
  1381. G = nx.Graph()
  1382. name1 = chr(2344) + chr(123) + chr(6543)
  1383. name2 = chr(5543) + chr(1543) + chr(324)
  1384. node_type = str
  1385. G.add_edge(name1, "Radiohead", foo=name2)
  1386. fd, fname = tempfile.mkstemp()
  1387. self.writer(G, fname)
  1388. H = nx.read_graphml(fname, node_type=node_type)
  1389. assert G._adj == H._adj
  1390. os.close(fd)
  1391. os.unlink(fname)
  1392. def test_unicode_escape(self):
  1393. # test for handling json escaped strings in python 2 Issue #1880
  1394. import json
  1395. a = {"a": '{"a": "123"}'} # an object with many chars to escape
  1396. sa = json.dumps(a)
  1397. G = nx.Graph()
  1398. G.graph["test"] = sa
  1399. fh = io.BytesIO()
  1400. self.writer(G, fh)
  1401. fh.seek(0)
  1402. H = nx.read_graphml(fh)
  1403. assert G.graph["test"] == H.graph["test"]
  1404. class TestXMLGraphML(TestWriteGraphML):
  1405. writer = staticmethod(nx.write_graphml_xml)
  1406. @classmethod
  1407. def setup_class(cls):
  1408. TestWriteGraphML.setup_class()
  1409. def test_exception_for_unsupported_datatype_node_attr():
  1410. """Test that a detailed exception is raised when an attribute is of a type
  1411. not supported by GraphML, e.g. a list"""
  1412. pytest.importorskip("lxml.etree")
  1413. # node attribute
  1414. G = nx.Graph()
  1415. G.add_node(0, my_list_attribute=[0, 1, 2])
  1416. fh = io.BytesIO()
  1417. with pytest.raises(TypeError, match="GraphML does not support"):
  1418. nx.write_graphml(G, fh)
  1419. def test_exception_for_unsupported_datatype_edge_attr():
  1420. """Test that a detailed exception is raised when an attribute is of a type
  1421. not supported by GraphML, e.g. a list"""
  1422. pytest.importorskip("lxml.etree")
  1423. # edge attribute
  1424. G = nx.Graph()
  1425. G.add_edge(0, 1, my_list_attribute=[0, 1, 2])
  1426. fh = io.BytesIO()
  1427. with pytest.raises(TypeError, match="GraphML does not support"):
  1428. nx.write_graphml(G, fh)
  1429. def test_exception_for_unsupported_datatype_graph_attr():
  1430. """Test that a detailed exception is raised when an attribute is of a type
  1431. not supported by GraphML, e.g. a list"""
  1432. pytest.importorskip("lxml.etree")
  1433. # graph attribute
  1434. G = nx.Graph()
  1435. G.graph["my_list_attribute"] = [0, 1, 2]
  1436. fh = io.BytesIO()
  1437. with pytest.raises(TypeError, match="GraphML does not support"):
  1438. nx.write_graphml(G, fh)