Statistics
| Branch: | Revision:

iof-tools / networkxMiCe / networkx-master / networkx / readwrite / tests / test_graphml.py @ 5cef0f13

History | View | Annotate | Download (45.4 KB)

1
#!/usr/bin/env python
2
from nose.tools import *
3
from nose import SkipTest
4
import networkx as nx
5
from networkx.testing.utils import *
6
import io
7
import tempfile
8
import os
9

    
10

    
11
class BaseGraphML(object):
12
    def setUp(self):
13
        self.simple_directed_data = """<?xml version="1.0" encoding="UTF-8"?>
14
<!-- This file was written by the JAVA GraphML Library.-->
15
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
16
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
17
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
18
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
19
  <graph id="G" edgedefault="directed">
20
    <node id="n0"/>
21
    <node id="n1"/>
22
    <node id="n2"/>
23
    <node id="n3"/>
24
    <node id="n4"/>
25
    <node id="n5"/>
26
    <node id="n6"/>
27
    <node id="n7"/>
28
    <node id="n8"/>
29
    <node id="n9"/>
30
    <node id="n10"/>
31
    <edge id="foo" source="n0" target="n2"/>
32
    <edge source="n1" target="n2"/>
33
    <edge source="n2" target="n3"/>
34
    <edge source="n3" target="n5"/>
35
    <edge source="n3" target="n4"/>
36
    <edge source="n4" target="n6"/>
37
    <edge source="n6" target="n5"/>
38
    <edge source="n5" target="n7"/>
39
    <edge source="n6" target="n8"/>
40
    <edge source="n8" target="n7"/>
41
    <edge source="n8" target="n9"/>
42
  </graph>
43
</graphml>"""
44
        self.simple_directed_graph = nx.DiGraph()
45
        self.simple_directed_graph.add_node('n10')
46
        self.simple_directed_graph.add_edge('n0', 'n2', id='foo')
47
        self.simple_directed_graph.add_edges_from([('n1', 'n2'),
48
                                                   ('n2', 'n3'),
49
                                                   ('n3', 'n5'),
50
                                                   ('n3', 'n4'),
51
                                                   ('n4', 'n6'),
52
                                                   ('n6', 'n5'),
53
                                                   ('n5', 'n7'),
54
                                                   ('n6', 'n8'),
55
                                                   ('n8', 'n7'),
56
                                                   ('n8', 'n9'),
57
                                                   ])
58
        self.simple_directed_fh = \
59
            io.BytesIO(self.simple_directed_data.encode('UTF-8'))
60

    
61
        self.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
        self.attribute_graph = nx.DiGraph(id='G')
104
        self.attribute_graph.graph['node_default'] = {'color': 'yellow'}
105
        self.attribute_graph.add_node('n0', color='green')
106
        self.attribute_graph.add_node('n2', color='blue')
107
        self.attribute_graph.add_node('n3', color='red')
108
        self.attribute_graph.add_node('n4')
109
        self.attribute_graph.add_node('n5', color='turquoise')
110
        self.attribute_graph.add_edge('n0', 'n2', id='e0', weight=1.0)
111
        self.attribute_graph.add_edge('n0', 'n1', id='e1', weight=1.0)
112
        self.attribute_graph.add_edge('n1', 'n3', id='e2', weight=2.0)
113
        self.attribute_graph.add_edge('n3', 'n2', id='e3')
114
        self.attribute_graph.add_edge('n2', 'n4', id='e4')
115
        self.attribute_graph.add_edge('n3', 'n5', id='e5')
116
        self.attribute_graph.add_edge('n5', 'n4', id='e6', weight=1.1)
117
        self.attribute_fh = io.BytesIO(self.attribute_data.encode('UTF-8'))
118

    
119
        self.attribute_numeric_type_data = """<?xml version='1.0' encoding='utf-8'?>
120
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
121
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
122
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
123
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
124
  <key attr.name="weight" attr.type="double" for="node" id="d1" />
125
  <key attr.name="weight" attr.type="double" for="edge" id="d0" />
126
  <graph edgedefault="directed">
127
    <node id="n0">
128
      <data key="d1">1</data>
129
    </node>
130
    <node id="n1">
131
      <data key="d1">2.0</data>
132
    </node>
133
    <edge source="n0" target="n1">
134
      <data key="d0">1</data>
135
    </edge>
136
    <edge source="n1" target="n0">
137
      <data key="d0">k</data>
138
    </edge>
139
    <edge source="n1" target="n1">
140
      <data key="d0">1.0</data>
141
    </edge>
142
  </graph>
143
</graphml>
144
"""
145
        self.attribute_numeric_type_graph = nx.DiGraph()
146
        self.attribute_numeric_type_graph.add_node('n0', weight=1)
147
        self.attribute_numeric_type_graph.add_node('n1', weight=2.0)
148
        self.attribute_numeric_type_graph.add_edge('n0', 'n1', weight=1)
149
        self.attribute_numeric_type_graph.add_edge('n1', 'n1', weight=1.0)
150
        fh = io.BytesIO(self.attribute_numeric_type_data.encode('UTF-8'))
151
        self.attribute_numeric_type_fh = fh
152

    
153
        self.simple_undirected_data = """<?xml version="1.0" encoding="UTF-8"?>
154
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
155
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
156
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
157
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
158
  <graph id="G">
159
    <node id="n0"/>
160
    <node id="n1"/>
161
    <node id="n2"/>
162
    <node id="n10"/>
163
    <edge id="foo" source="n0" target="n2"/>
164
    <edge source="n1" target="n2"/>
165
    <edge source="n2" target="n3"/>
166
  </graph>
167
</graphml>"""
168
#    <edge source="n8" target="n10" directed="false"/>
169
        self.simple_undirected_graph = nx.Graph()
170
        self.simple_undirected_graph.add_node('n10')
171
        self.simple_undirected_graph.add_edge('n0', 'n2', id='foo')
172
        self.simple_undirected_graph.add_edges_from([('n1', 'n2'),
173
                                                     ('n2', 'n3'),
174
                                                     ])
175
        fh = io.BytesIO(self.simple_undirected_data.encode('UTF-8'))
176
        self.simple_undirected_fh = fh
177

    
178

    
179
class TestReadGraphML(BaseGraphML):
180
    def test_read_simple_directed_graphml(self):
181
        G = self.simple_directed_graph
182
        H = nx.read_graphml(self.simple_directed_fh)
183
        assert_equal(sorted(G.nodes()), sorted(H.nodes()))
184
        assert_equal(sorted(G.edges()), sorted(H.edges()))
185
        assert_equal(sorted(G.edges(data=True)),
186
                     sorted(H.edges(data=True)))
187
        self.simple_directed_fh.seek(0)
188

    
189
        I = nx.parse_graphml(self.simple_directed_data)
190
        assert_equal(sorted(G.nodes()), sorted(I.nodes()))
191
        assert_equal(sorted(G.edges()), sorted(I.edges()))
192
        assert_equal(sorted(G.edges(data=True)),
193
                     sorted(I.edges(data=True)))
194

    
195
    def test_read_simple_undirected_graphml(self):
196
        G = self.simple_undirected_graph
197
        H = nx.read_graphml(self.simple_undirected_fh)
198
        assert_nodes_equal(G.nodes(), H.nodes())
199
        assert_edges_equal(G.edges(), H.edges())
200
        self.simple_undirected_fh.seek(0)
201

    
202
        I = nx.parse_graphml(self.simple_undirected_data)
203
        assert_nodes_equal(G.nodes(), I.nodes())
204
        assert_edges_equal(G.edges(), I.edges())
205

    
206
    def test_read_attribute_graphml(self):
207
        G = self.attribute_graph
208
        H = nx.read_graphml(self.attribute_fh)
209
        assert_nodes_equal(G.nodes(True), sorted(H.nodes(data=True)))
210
        ge = sorted(G.edges(data=True))
211
        he = sorted(H.edges(data=True))
212
        for a, b in zip(ge, he):
213
            assert_equal(a, b)
214
        self.attribute_fh.seek(0)
215

    
216
        I = nx.parse_graphml(self.attribute_data)
217
        assert_equal(sorted(G.nodes(True)), sorted(I.nodes(data=True)))
218
        ge = sorted(G.edges(data=True))
219
        he = sorted(I.edges(data=True))
220
        for a, b in zip(ge, he):
221
            assert_equal(a, b)
222

    
223
    def test_directed_edge_in_undirected(self):
224
        s = """<?xml version="1.0" encoding="UTF-8"?>
225
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
226
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
227
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
228
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
229
  <graph id="G">
230
    <node id="n0"/>
231
    <node id="n1"/>
232
    <node id="n2"/>
233
    <edge source="n0" target="n1"/>
234
    <edge source="n1" target="n2" directed='true'/>
235
  </graph>
236
</graphml>"""
237
        fh = io.BytesIO(s.encode('UTF-8'))
238
        assert_raises(nx.NetworkXError, nx.read_graphml, fh)
239
        assert_raises(nx.NetworkXError, nx.parse_graphml, s)
240

    
241
    def test_undirected_edge_in_directed(self):
242
        s = """<?xml version="1.0" encoding="UTF-8"?>
243
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
244
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
245
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
246
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
247
  <graph id="G" edgedefault='directed'>
248
    <node id="n0"/>
249
    <node id="n1"/>
250
    <node id="n2"/>
251
    <edge source="n0" target="n1"/>
252
    <edge source="n1" target="n2" directed='false'/>
253
  </graph>
254
</graphml>"""
255
        fh = io.BytesIO(s.encode('UTF-8'))
256
        assert_raises(nx.NetworkXError, nx.read_graphml, fh)
257
        assert_raises(nx.NetworkXError, nx.parse_graphml, s)
258

    
259
    def test_key_raise(self):
260
        s = """<?xml version="1.0" encoding="UTF-8"?>
261
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
262
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
263
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
264
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
265
  <key id="d0" for="node" attr.name="color" attr.type="string">
266
    <default>yellow</default>
267
  </key>
268
  <key id="d1" for="edge" attr.name="weight" attr.type="double"/>
269
  <graph id="G" edgedefault="directed">
270
    <node id="n0">
271
      <data key="d0">green</data>
272
    </node>
273
    <node id="n1"/>
274
    <node id="n2">
275
      <data key="d0">blue</data>
276
    </node>
277
    <edge id="e0" source="n0" target="n2">
278
      <data key="d2">1.0</data>
279
    </edge>
280
  </graph>
281
</graphml>
282
"""
283
        fh = io.BytesIO(s.encode('UTF-8'))
284
        assert_raises(nx.NetworkXError, nx.read_graphml, fh)
285
        assert_raises(nx.NetworkXError, nx.parse_graphml, s)
286

    
287
    def test_hyperedge_raise(self):
288
        s = """<?xml version="1.0" encoding="UTF-8"?>
289
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
290
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
291
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
292
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
293
  <key id="d0" for="node" attr.name="color" attr.type="string">
294
    <default>yellow</default>
295
  </key>
296
  <key id="d1" for="edge" attr.name="weight" attr.type="double"/>
297
  <graph id="G" edgedefault="directed">
298
    <node id="n0">
299
      <data key="d0">green</data>
300
    </node>
301
    <node id="n1"/>
302
    <node id="n2">
303
      <data key="d0">blue</data>
304
    </node>
305
    <hyperedge id="e0" source="n0" target="n2">
306
       <endpoint node="n0"/>
307
       <endpoint node="n1"/>
308
       <endpoint node="n2"/>
309
    </hyperedge>
310
  </graph>
311
</graphml>
312
"""
313
        fh = io.BytesIO(s.encode('UTF-8'))
314
        assert_raises(nx.NetworkXError, nx.read_graphml, fh)
315
        assert_raises(nx.NetworkXError, nx.parse_graphml, s)
316

    
317
    def test_multigraph_keys(self):
318
        # Test that reading multigraphs uses edge id attributes as keys
319
        s = """<?xml version="1.0" encoding="UTF-8"?>
320
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
321
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
322
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
323
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
324
  <graph id="G" edgedefault="directed">
325
    <node id="n0"/>
326
    <node id="n1"/>
327
    <edge id="e0" source="n0" target="n1"/>
328
    <edge id="e1" source="n0" target="n1"/>
329
  </graph>
330
</graphml>
331
"""
332
        fh = io.BytesIO(s.encode('UTF-8'))
333
        G = nx.read_graphml(fh)
334
        expected = [("n0", "n1", "e0"), ("n0", "n1", "e1")]
335
        assert_equal(sorted(G.edges(keys=True)), expected)
336
        fh.seek(0)
337
        H = nx.parse_graphml(s)
338
        assert_equal(sorted(H.edges(keys=True)), expected)
339

    
340
    def test_preserve_multi_edge_data(self):
341
        """
342
        Test that data and keys of edges are preserved on consequent
343
        write and reads
344
        """
345
        G = nx.MultiGraph()
346
        G.add_node(1)
347
        G.add_node(2)
348
        G.add_edges_from([
349
            # edges with no data, no keys:
350
            (1, 2),
351
            # edges with only data:
352
            (1, 2, dict(key='data_key1')),
353
            (1, 2, dict(id='data_id2')),
354
            (1, 2, dict(key='data_key3', id='data_id3')),
355
            # edges with both data and keys:
356
            (1, 2, 103, dict(key='data_key4')),
357
            (1, 2, 104, dict(id='data_id5')),
358
            (1, 2, 105, dict(key='data_key6', id='data_id7')),
359
        ])
360
        fh = io.BytesIO()
361
        nx.write_graphml(G, fh)
362
        fh.seek(0)
363
        H = nx.read_graphml(fh, node_type=int)
364
        assert_edges_equal(
365
            G.edges(data=True, keys=True), H.edges(data=True, keys=True)
366
        )
367
        assert_equal(G._adj, H._adj)
368

    
369
    def test_yfiles_extension(self):
370
        data = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
371
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
372
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
373
         xmlns:y="http://www.yworks.com/xml/graphml"
374
         xmlns:yed="http://www.yworks.com/xml/yed/3"
375
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
376
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
377
  <!--Created by yFiles for Java 2.7-->
378
  <key for="graphml" id="d0" yfiles.type="resources"/>
379
  <key attr.name="url" attr.type="string" for="node" id="d1"/>
380
  <key attr.name="description" attr.type="string" for="node" id="d2"/>
381
  <key for="node" id="d3" yfiles.type="nodegraphics"/>
382
  <key attr.name="Description" attr.type="string" for="graph" id="d4">
383
    <default/>
384
  </key>
385
  <key attr.name="url" attr.type="string" for="edge" id="d5"/>
386
  <key attr.name="description" attr.type="string" for="edge" id="d6"/>
387
  <key for="edge" id="d7" yfiles.type="edgegraphics"/>
388
  <graph edgedefault="directed" id="G">
389
    <node id="n0">
390
      <data key="d3">
391
        <y:ShapeNode>
392
          <y:Geometry height="30.0" width="30.0" x="125.0" y="100.0"/>
393
          <y:Fill color="#FFCC00" transparent="false"/>
394
          <y:BorderStyle color="#000000" type="line" width="1.0"/>
395
          <y:NodeLabel alignment="center" autoSizePolicy="content"
396
           borderDistance="0.0" fontFamily="Dialog" fontSize="13"
397
           fontStyle="plain" hasBackgroundColor="false" hasLineColor="false"
398
           height="19.1328125" modelName="internal" modelPosition="c"
399
           textColor="#000000" visible="true" width="12.27099609375"
400
           x="8.864501953125" y="5.43359375">1</y:NodeLabel>
401
          <y:Shape type="rectangle"/>
402
        </y:ShapeNode>
403
      </data>
404
    </node>
405
    <node id="n1">
406
      <data key="d3">
407
        <y:ShapeNode>
408
          <y:Geometry height="30.0" width="30.0" x="183.0" y="205.0"/>
409
          <y:Fill color="#FFCC00" transparent="false"/>
410
          <y:BorderStyle color="#000000" type="line" width="1.0"/>
411
          <y:NodeLabel alignment="center" autoSizePolicy="content"
412
          borderDistance="0.0" fontFamily="Dialog" fontSize="13"
413
          fontStyle="plain" hasBackgroundColor="false" hasLineColor="false"
414
          height="19.1328125" modelName="internal" modelPosition="c"
415
          textColor="#000000" visible="true" width="12.27099609375"
416
          x="8.864501953125" y="5.43359375">2</y:NodeLabel>
417
          <y:Shape type="rectangle"/>
418
        </y:ShapeNode>
419
      </data>
420
    </node>
421
    <edge id="e0" source="n0" target="n1">
422
      <data key="d7">
423
        <y:PolyLineEdge>
424
          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
425
          <y:LineStyle color="#000000" type="line" width="1.0"/>
426
          <y:Arrows source="none" target="standard"/>
427
          <y:BendStyle smoothed="false"/>
428
        </y:PolyLineEdge>
429
      </data>
430
    </edge>
431
  </graph>
432
  <data key="d0">
433
    <y:Resources/>
434
  </data>
435
</graphml>
436
"""
437
        fh = io.BytesIO(data.encode('UTF-8'))
438
        G = nx.read_graphml(fh)
439
        assert_equal(list(G.edges()), [('n0', 'n1')])
440
        assert_equal(G['n0']['n1']['id'], 'e0')
441
        assert_equal(G.nodes['n0']['label'], '1')
442
        assert_equal(G.nodes['n1']['label'], '2')
443

    
444
        H = nx.parse_graphml(data)
445
        assert_equal(list(H.edges()), [('n0', 'n1')])
446
        assert_equal(H['n0']['n1']['id'], 'e0')
447
        assert_equal(H.nodes['n0']['label'], '1')
448
        assert_equal(H.nodes['n1']['label'], '2')
449

    
450
    def test_bool(self):
451
        s = """<?xml version="1.0" encoding="UTF-8"?>
452
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
453
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
454
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
455
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
456
  <key id="d0" for="node" attr.name="test" attr.type="boolean">
457
    <default>false</default>
458
  </key>
459
  <graph id="G" edgedefault="directed">
460
    <node id="n0">
461
      <data key="d0">true</data>
462
    </node>
463
    <node id="n1"/>
464
    <node id="n2">
465
      <data key="d0">false</data>
466
    </node>
467
    <node id="n3">
468
      <data key="d0">FaLsE</data>
469
    </node>
470
    <node id="n4">
471
      <data key="d0">True</data>
472
    </node>
473
    <node id="n5">
474
      <data key="d0">0</data>
475
    </node>
476
    <node id="n6">
477
      <data key="d0">1</data>
478
    </node>
479
  </graph>
480
</graphml>
481
"""
482
        fh = io.BytesIO(s.encode('UTF-8'))
483
        G = nx.read_graphml(fh)
484
        H = nx.parse_graphml(s)
485
        for graph in [G, H]:
486
            assert_equal(graph.nodes['n0']['test'], True)
487
            assert_equal(graph.nodes['n2']['test'], False)
488
            assert_equal(graph.nodes['n3']['test'], False)
489
            assert_equal(graph.nodes['n4']['test'], True)
490
            assert_equal(graph.nodes['n5']['test'], False)
491
            assert_equal(graph.nodes['n6']['test'], True)
492

    
493
    def test_graphml_header_line(self):
494
        good = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
495
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
496
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
497
         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
498
         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
499
  <key id="d0" for="node" attr.name="test" attr.type="boolean">
500
    <default>false</default>
501
  </key>
502
  <graph id="G">
503
    <node id="n0">
504
      <data key="d0">true</data>
505
    </node>
506
  </graph>
507
</graphml>
508
"""
509
        bad = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
510
<graphml>
511
  <key id="d0" for="node" attr.name="test" attr.type="boolean">
512
    <default>false</default>
513
  </key>
514
  <graph id="G">
515
    <node id="n0">
516
      <data key="d0">true</data>
517
    </node>
518
  </graph>
519
</graphml>
520
"""
521
        ugly = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
522
<graphml xmlns="https://ghghgh">
523
  <key id="d0" for="node" attr.name="test" attr.type="boolean">
524
    <default>false</default>
525
  </key>
526
  <graph id="G">
527
    <node id="n0">
528
      <data key="d0">true</data>
529
    </node>
530
  </graph>
531
</graphml>
532
"""
533
        for s in (good, bad):
534
            fh = io.BytesIO(s.encode('UTF-8'))
535
            G = nx.read_graphml(fh)
536
            H = nx.parse_graphml(s)
537
            for graph in [G, H]:
538
                assert_equal(graph.nodes['n0']['test'], True)
539

    
540
        fh = io.BytesIO(ugly.encode('UTF-8'))
541
        assert_raises(nx.NetworkXError, nx.read_graphml, fh)
542
        assert_raises(nx.NetworkXError, nx.parse_graphml, ugly)
543

    
544
    def test_read_attributes_with_groups(self):
545
        data = """\
546
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
547
<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">
548
  <!--Created by yEd 3.17-->
549
  <key attr.name="Description" attr.type="string" for="graph" id="d0"/>
550
  <key for="port" id="d1" yfiles.type="portgraphics"/>
551
  <key for="port" id="d2" yfiles.type="portgeometry"/>
552
  <key for="port" id="d3" yfiles.type="portuserdata"/>
553
  <key attr.name="CustomProperty" attr.type="string" for="node" id="d4">
554
    <default/>
555
  </key>
556
  <key attr.name="url" attr.type="string" for="node" id="d5"/>
557
  <key attr.name="description" attr.type="string" for="node" id="d6"/>
558
  <key for="node" id="d7" yfiles.type="nodegraphics"/>
559
  <key for="graphml" id="d8" yfiles.type="resources"/>
560
  <key attr.name="url" attr.type="string" for="edge" id="d9"/>
561
  <key attr.name="description" attr.type="string" for="edge" id="d10"/>
562
  <key for="edge" id="d11" yfiles.type="edgegraphics"/>
563
  <graph edgedefault="directed" id="G">
564
    <data key="d0"/>
565
    <node id="n0">
566
      <data key="d4"><![CDATA[CustomPropertyValue]]></data>
567
      <data key="d6"/>
568
      <data key="d7">
569
        <y:ShapeNode>
570
          <y:Geometry height="30.0" width="30.0" x="125.0" y="-255.4611111111111"/>
571
          <y:Fill color="#FFCC00" transparent="false"/>
572
          <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
573
          <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>
574
              <y:SmartNodeLabelModel distance="4.0"/>
575
            </y:LabelModel>
576
            <y:ModelParameter>
577
              <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"/>
578
            </y:ModelParameter>
579
          </y:NodeLabel>
580
          <y:Shape type="rectangle"/>
581
        </y:ShapeNode>
582
      </data>
583
    </node>
584
    <node id="n1" yfiles.foldertype="group">
585
      <data key="d4"><![CDATA[CustomPropertyValue]]></data>
586
      <data key="d5"/>
587
      <data key="d6"/>
588
      <data key="d7">
589
        <y:ProxyAutoBoundsNode>
590
          <y:Realizers active="0">
591
            <y:GroupNode>
592
              <y:Geometry height="250.38333333333333" width="140.0" x="-30.0" y="-330.3833333333333"/>
593
              <y:Fill color="#F5F5F5" transparent="false"/>
594
              <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
595
              <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>
596
              <y:Shape type="roundrectangle"/>
597
              <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
598
              <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
599
              <y:BorderInsets bottom="1" bottomF="1.0" left="0" leftF="0.0" right="0" rightF="0.0" top="1" topF="1.0001736111111086"/>
600
            </y:GroupNode>
601
            <y:GroupNode>
602
              <y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
603
              <y:Fill color="#F5F5F5" transparent="false"/>
604
              <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
605
              <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>
606
              <y:Shape type="roundrectangle"/>
607
              <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
608
              <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
609
              <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
610
            </y:GroupNode>
611
          </y:Realizers>
612
        </y:ProxyAutoBoundsNode>
613
      </data>
614
      <graph edgedefault="directed" id="n1:">
615
        <node id="n1::n0" yfiles.foldertype="group">
616
          <data key="d4"><![CDATA[CustomPropertyValue]]></data>
617
          <data key="d5"/>
618
          <data key="d6"/>
619
          <data key="d7">
620
            <y:ProxyAutoBoundsNode>
621
              <y:Realizers active="0">
622
                <y:GroupNode>
623
                  <y:Geometry height="83.46111111111111" width="110.0" x="-15.0" y="-292.9222222222222"/>
624
                  <y:Fill color="#F5F5F5" transparent="false"/>
625
                  <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
626
                  <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>
627
                  <y:Shape type="roundrectangle"/>
628
                  <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
629
                  <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
630
                  <y:BorderInsets bottom="1" bottomF="1.0" left="0" leftF="0.0" right="0" rightF="0.0" top="1" topF="1.0001736111111086"/>
631
                </y:GroupNode>
632
                <y:GroupNode>
633
                  <y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
634
                  <y:Fill color="#F5F5F5" transparent="false"/>
635
                  <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
636
                  <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>
637
                  <y:Shape type="roundrectangle"/>
638
                  <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
639
                  <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
640
                  <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
641
                </y:GroupNode>
642
              </y:Realizers>
643
            </y:ProxyAutoBoundsNode>
644
          </data>
645
          <graph edgedefault="directed" id="n1::n0:">
646
            <node id="n1::n0::n0">
647
              <data key="d4"><![CDATA[CustomPropertyValue]]></data>
648
              <data key="d6"/>
649
              <data key="d7">
650
                <y:ShapeNode>
651
                  <y:Geometry height="30.0" width="30.0" x="50.0" y="-255.4611111111111"/>
652
                  <y:Fill color="#FFCC00" transparent="false"/>
653
                  <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
654
                  <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>
655
                      <y:SmartNodeLabelModel distance="4.0"/>
656
                    </y:LabelModel>
657
                    <y:ModelParameter>
658
                      <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"/>
659
                    </y:ModelParameter>
660
                  </y:NodeLabel>
661
                  <y:Shape type="rectangle"/>
662
                </y:ShapeNode>
663
              </data>
664
            </node>
665
            <node id="n1::n0::n1">
666
              <data key="d4"><![CDATA[CustomPropertyValue]]></data>
667
              <data key="d6"/>
668
              <data key="d7">
669
                <y:ShapeNode>
670
                  <y:Geometry height="30.0" width="30.0" x="0.0" y="-255.4611111111111"/>
671
                  <y:Fill color="#FFCC00" transparent="false"/>
672
                  <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
673
                  <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>
674
                      <y:SmartNodeLabelModel distance="4.0"/>
675
                    </y:LabelModel>
676
                    <y:ModelParameter>
677
                      <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"/>
678
                    </y:ModelParameter>
679
                  </y:NodeLabel>
680
                  <y:Shape type="rectangle"/>
681
                </y:ShapeNode>
682
              </data>
683
            </node>
684
          </graph>
685
        </node>
686
        <node id="n1::n1" yfiles.foldertype="group">
687
          <data key="d4"><![CDATA[CustomPropertyValue]]></data>
688
          <data key="d5"/>
689
          <data key="d6"/>
690
          <data key="d7">
691
            <y:ProxyAutoBoundsNode>
692
              <y:Realizers active="0">
693
                <y:GroupNode>
694
                  <y:Geometry height="83.46111111111111" width="110.0" x="-15.0" y="-179.4611111111111"/>
695
                  <y:Fill color="#F5F5F5" transparent="false"/>
696
                  <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
697
                  <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>
698
                  <y:Shape type="roundrectangle"/>
699
                  <y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
700
                  <y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
701
                  <y:BorderInsets bottom="1" bottomF="1.0" left="0" leftF="0.0" right="0" rightF="0.0" top="1" topF="1.0001736111111086"/>
702
                </y:GroupNode>
703
                <y:GroupNode>
704
                  <y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
705
                  <y:Fill color="#F5F5F5" transparent="false"/>
706
                  <y:BorderStyle color="#000000" type="dashed" width="1.0"/>
707
                  <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>
708
                  <y:Shape type="roundrectangle"/>
709
                  <y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
710
                  <y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
711
                  <y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
712
                </y:GroupNode>
713
              </y:Realizers>
714
            </y:ProxyAutoBoundsNode>
715
          </data>
716
          <graph edgedefault="directed" id="n1::n1:">
717
            <node id="n1::n1::n0">
718
              <data key="d4"><![CDATA[CustomPropertyValue]]></data>
719
              <data key="d6"/>
720
              <data key="d7">
721
                <y:ShapeNode>
722
                  <y:Geometry height="30.0" width="30.0" x="0.0" y="-142.0"/>
723
                  <y:Fill color="#FFCC00" transparent="false"/>
724
                  <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
725
                  <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>
726
                      <y:SmartNodeLabelModel distance="4.0"/>
727
                    </y:LabelModel>
728
                    <y:ModelParameter>
729
                      <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"/>
730
                    </y:ModelParameter>
731
                  </y:NodeLabel>
732
                  <y:Shape type="rectangle"/>
733
                </y:ShapeNode>
734
              </data>
735
            </node>
736
            <node id="n1::n1::n1">
737
              <data key="d4"><![CDATA[CustomPropertyValue]]></data>
738
              <data key="d6"/>
739
              <data key="d7">
740
                <y:ShapeNode>
741
                  <y:Geometry height="30.0" width="30.0" x="50.0" y="-142.0"/>
742
                  <y:Fill color="#FFCC00" transparent="false"/>
743
                  <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
744
                  <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>
745
                      <y:SmartNodeLabelModel distance="4.0"/>
746
                    </y:LabelModel>
747
                    <y:ModelParameter>
748
                      <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"/>
749
                    </y:ModelParameter>
750
                  </y:NodeLabel>
751
                  <y:Shape type="rectangle"/>
752
                </y:ShapeNode>
753
              </data>
754
            </node>
755
          </graph>
756
        </node>
757
      </graph>
758
    </node>
759
    <node id="n2">
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="-142.0"/>
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">9<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
    <edge id="n1::n1::e0" source="n1::n1::n0" target="n1::n1::n1">
779
      <data key="d10"/>
780
      <data key="d11">
781
        <y:PolyLineEdge>
782
          <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
783
          <y:LineStyle color="#000000" type="line" width="1.0"/>
784
          <y:Arrows source="none" target="standard"/>
785
          <y:BendStyle smoothed="false"/>
786
        </y:PolyLineEdge>
787
      </data>
788
    </edge>
789
    <edge id="n1::n0::e0" source="n1::n0::n1" target="n1::n0::n0">
790
      <data key="d10"/>
791
      <data key="d11">
792
        <y:PolyLineEdge>
793
          <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
794
          <y:LineStyle color="#000000" type="line" width="1.0"/>
795
          <y:Arrows source="none" target="standard"/>
796
          <y:BendStyle smoothed="false"/>
797
        </y:PolyLineEdge>
798
      </data>
799
    </edge>
800
    <edge id="e0" source="n1::n0::n0" target="n0">
801
      <data key="d10"/>
802
      <data key="d11">
803
        <y:PolyLineEdge>
804
          <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
805
          <y:LineStyle color="#000000" type="line" width="1.0"/>
806
          <y:Arrows source="none" target="standard"/>
807
          <y:BendStyle smoothed="false"/>
808
        </y:PolyLineEdge>
809
      </data>
810
    </edge>
811
    <edge id="e1" source="n1::n1::n1" target="n2">
812
      <data key="d10"/>
813
      <data key="d11">
814
        <y:PolyLineEdge>
815
          <y:Path sx="15.0" sy="-0.0" tx="-15.0" ty="-0.0"/>
816
          <y:LineStyle color="#000000" type="line" width="1.0"/>
817
          <y:Arrows source="none" target="standard"/>
818
          <y:BendStyle smoothed="false"/>
819
        </y:PolyLineEdge>
820
      </data>
821
    </edge>
822
  </graph>
823
  <data key="d8">
824
    <y:Resources/>
825
  </data>
826
</graphml>
827
"""
828
        # verify that nodes / attributes are correctly read when part of a group
829
        fh = io.BytesIO(data.encode('UTF-8'))
830
        G = nx.read_graphml(fh)
831
        data = [x for _, x in G.nodes(data=True)]
832
        assert_equal(len(data), 9)
833
        for node_data in data:
834
            assert_not_equal(node_data['CustomProperty'], '')
835

    
836

    
837
class TestWriteGraphML(BaseGraphML):
838
    writer = staticmethod(nx.write_graphml_lxml)
839

    
840
    @classmethod
841
    def setupClass(cls):
842
        try:
843
            import lxml.etree
844
        except ImportError:
845
            raise SkipTest('lxml.etree not available.')
846

    
847
    def test_write_interface(self):
848
        try:
849
            import lxml.etree
850
            assert_equal(nx.write_graphml, nx.write_graphml_lxml)
851
        except ImportError:
852
            assert_equal(nx.write_graphml, nx.write_graphml_xml)
853

    
854
    def test_write_read_simple_directed_graphml(self):
855
        G = self.simple_directed_graph
856
        G.graph['hi'] = 'there'
857
        fh = io.BytesIO()
858
        self.writer(G, fh)
859
        fh.seek(0)
860
        H = nx.read_graphml(fh)
861
        assert_equal(sorted(G.nodes()), sorted(H.nodes()))
862
        assert_equal(sorted(G.edges()), sorted(H.edges()))
863
        assert_equal(sorted(G.edges(data=True)), sorted(H.edges(data=True)))
864
        self.simple_directed_fh.seek(0)
865

    
866
    def test_write_read_attribute_numeric_type_graphml(self):
867
        from xml.etree.ElementTree import parse
868

    
869
        G = self.attribute_numeric_type_graph
870
        fh = io.BytesIO()
871
        self.writer(G, fh, infer_numeric_types=True)
872
        fh.seek(0)
873
        H = nx.read_graphml(fh)
874
        fh.seek(0)
875

    
876
        assert_nodes_equal(G.nodes(), H.nodes())
877
        assert_edges_equal(G.edges(), H.edges())
878
        assert_edges_equal(G.edges(data=True), H.edges(data=True))
879
        self.attribute_numeric_type_fh.seek(0)
880

    
881
        xml = parse(fh)
882
        # Children are the key elements, and the graph element
883
        children = xml.getroot().getchildren()
884
        assert_equal(len(children), 3)
885

    
886
        keys = [child.items() for child in children[:2]]
887

    
888
        assert_equal(len(keys), 2)
889
        assert_in(('attr.type', 'double'), keys[0])
890
        assert_in(('attr.type', 'double'), keys[1])
891

    
892
    def test_more_multigraph_keys(self):
893
        """Writing keys as edge id attributes means keys become strings.
894
        The original keys are stored as data, so read them back in
895
        if `make_str(key) == edge_id`
896
        This allows the adjacency to remain the same.
897
        """
898
        G = nx.MultiGraph()
899
        G.add_edges_from([('a', 'b', 2), ('a', 'b', 3)])
900
        fd, fname = tempfile.mkstemp()
901
        self.writer(G, fname)
902
        H = nx.read_graphml(fname)
903
        assert_true(H.is_multigraph())
904
        assert_edges_equal(G.edges(keys=True), H.edges(keys=True))
905
        assert_equal(G._adj, H._adj)
906
        os.close(fd)
907
        os.unlink(fname)
908

    
909
    def test_default_attribute(self):
910
        G = nx.Graph(name="Fred")
911
        G.add_node(1, label=1, color='green')
912
        nx.add_path(G, [0, 1, 2, 3])
913
        G.add_edge(1, 2, weight=3)
914
        G.graph['node_default'] = {'color': 'yellow'}
915
        G.graph['edge_default'] = {'weight': 7}
916
        fh = io.BytesIO()
917
        self.writer(G, fh)
918
        fh.seek(0)
919
        H = nx.read_graphml(fh, node_type=int)
920
        assert_nodes_equal(G.nodes(), H.nodes())
921
        assert_edges_equal(G.edges(), H.edges())
922
        assert_equal(G.graph, H.graph)
923

    
924
    def test_multigraph_to_graph(self):
925
        # test converting multigraph to graph if no parallel edges found
926
        G = nx.MultiGraph()
927
        G.add_edges_from([('a', 'b', 2), ('b', 'c', 3)])  # no multiedges
928
        fd, fname = tempfile.mkstemp()
929
        self.writer(G, fname)
930
        H = nx.read_graphml(fname)
931
        assert_false(H.is_multigraph())
932
        os.close(fd)
933
        os.unlink(fname)
934

    
935
    def test_numpy_float(self):
936
        try:
937
            import numpy as np
938
        except:
939
            return
940
        wt = np.float(3.4)
941
        G = nx.Graph([(1, 2, {'weight': wt})])
942
        fd, fname = tempfile.mkstemp()
943
        self.writer(G, fname)
944
        H = nx.read_graphml(fname, node_type=int)
945
        assert_equal(G._adj, H._adj)
946
        os.close(fd)
947
        os.unlink(fname)
948

    
949
    def test_numpy_float64(self):
950
        try:
951
            import numpy as np
952
        except:
953
            return
954
        wt = np.float64(3.4)
955
        G = nx.Graph([(1, 2, {'weight': wt})])
956
        fd, fname = tempfile.mkstemp()
957
        self.writer(G, fname)
958
        H = nx.read_graphml(fname, node_type=int)
959
        assert_equal(G.edges, H.edges)
960
        wtG = G[1][2]['weight']
961
        wtH = H[1][2]['weight']
962
        assert_almost_equal(wtG, wtH, places=6)
963
        assert_equal(type(wtG), np.float64)
964
        assert_equal(type(wtH), float)
965
        os.close(fd)
966
        os.unlink(fname)
967

    
968
    def test_numpy_float32(self):
969
        try:
970
            import numpy as np
971
        except:
972
            return
973
        wt = np.float32(3.4)
974
        G = nx.Graph([(1, 2, {'weight': wt})])
975
        fd, fname = tempfile.mkstemp()
976
        self.writer(G, fname)
977
        H = nx.read_graphml(fname, node_type=int)
978
        assert_equal(G.edges, H.edges)
979
        wtG = G[1][2]['weight']
980
        wtH = H[1][2]['weight']
981
        assert_almost_equal(wtG, wtH, places=6)
982
        assert_equal(type(wtG), np.float32)
983
        assert_equal(type(wtH), float)
984
        os.close(fd)
985
        os.unlink(fname)
986

    
987
    def test_unicode_attributes(self):
988
        G = nx.Graph()
989
        try:  # Python 3.x
990
            name1 = chr(2344) + chr(123) + chr(6543)
991
            name2 = chr(5543) + chr(1543) + chr(324)
992
            node_type = str
993
        except ValueError:  # Python 2.6+
994
            name1 = unichr(2344) + unichr(123) + unichr(6543)
995
            name2 = unichr(5543) + unichr(1543) + unichr(324)
996
            node_type = unicode
997
        G.add_edge(name1, 'Radiohead', foo=name2)
998
        fd, fname = tempfile.mkstemp()
999
        self.writer(G, fname)
1000
        H = nx.read_graphml(fname, node_type=node_type)
1001
        assert_equal(G._adj, H._adj)
1002
        os.close(fd)
1003
        os.unlink(fname)
1004

    
1005
    def test_unicode_escape(self):
1006
        # test for handling json escaped stings in python 2 Issue #1880
1007
        import json
1008
        a = dict(a='{"a": "123"}')  # an object with many chars to escape
1009
        try:  # Python 3.x
1010
            chr(2344)
1011
            sa = json.dumps(a)
1012
        except ValueError:  # Python 2.6+
1013
            sa = unicode(json.dumps(a))
1014
        G = nx.Graph()
1015
        G.graph['test'] = sa
1016
        fh = io.BytesIO()
1017
        self.writer(G, fh)
1018
        fh.seek(0)
1019
        H = nx.read_graphml(fh)
1020
        assert_equal(G.graph['test'], H.graph['test'])
1021

    
1022

    
1023
class TestXMLGraphML(TestWriteGraphML):
1024
    writer = staticmethod(nx.write_graphml_xml)
1025

    
1026
    @classmethod
1027
    def setupClass(cls):
1028
        try:
1029
            import xml.etree.ElementTree
1030
        except ImportError:
1031
            raise SkipTest('xml.etree.ElementTree not available.')