test_graphml.py 66 KB

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