|
|
import codecs |
|
|
import io |
|
|
import math |
|
|
import os |
|
|
import tempfile |
|
|
from ast import literal_eval |
|
|
from contextlib import contextmanager |
|
|
from textwrap import dedent |
|
|
|
|
|
import pytest |
|
|
|
|
|
import networkx as nx |
|
|
from networkx.readwrite.gml import literal_destringizer, literal_stringizer |
|
|
|
|
|
|
|
|
class TestGraph: |
|
|
@classmethod |
|
|
def setup_class(cls): |
|
|
cls.simple_data = """Creator "me" |
|
|
Version "xx" |
|
|
graph [ |
|
|
comment "This is a sample graph" |
|
|
directed 1 |
|
|
IsPlanar 1 |
|
|
pos [ x 0 y 1 ] |
|
|
node [ |
|
|
id 1 |
|
|
label "Node 1" |
|
|
pos [ x 1 y 1 ] |
|
|
] |
|
|
node [ |
|
|
id 2 |
|
|
pos [ x 1 y 2 ] |
|
|
label "Node 2" |
|
|
] |
|
|
node [ |
|
|
id 3 |
|
|
label "Node 3" |
|
|
pos [ x 1 y 3 ] |
|
|
] |
|
|
edge [ |
|
|
source 1 |
|
|
target 2 |
|
|
label "Edge from node 1 to node 2" |
|
|
color [line "blue" thickness 3] |
|
|
|
|
|
] |
|
|
edge [ |
|
|
source 2 |
|
|
target 3 |
|
|
label "Edge from node 2 to node 3" |
|
|
] |
|
|
edge [ |
|
|
source 3 |
|
|
target 1 |
|
|
label "Edge from node 3 to node 1" |
|
|
] |
|
|
] |
|
|
""" |
|
|
|
|
|
def test_parse_gml_cytoscape_bug(self): |
|
|
|
|
|
cytoscape_example = """ |
|
|
Creator "Cytoscape" |
|
|
Version 1.0 |
|
|
graph [ |
|
|
node [ |
|
|
root_index -3 |
|
|
id -3 |
|
|
graphics [ |
|
|
x -96.0 |
|
|
y -67.0 |
|
|
w 40.0 |
|
|
h 40.0 |
|
|
fill "#ff9999" |
|
|
type "ellipse" |
|
|
outline "#666666" |
|
|
outline_width 1.5 |
|
|
] |
|
|
label "node2" |
|
|
] |
|
|
node [ |
|
|
root_index -2 |
|
|
id -2 |
|
|
graphics [ |
|
|
x 63.0 |
|
|
y 37.0 |
|
|
w 40.0 |
|
|
h 40.0 |
|
|
fill "#ff9999" |
|
|
type "ellipse" |
|
|
outline "#666666" |
|
|
outline_width 1.5 |
|
|
] |
|
|
label "node1" |
|
|
] |
|
|
node [ |
|
|
root_index -1 |
|
|
id -1 |
|
|
graphics [ |
|
|
x -31.0 |
|
|
y -17.0 |
|
|
w 40.0 |
|
|
h 40.0 |
|
|
fill "#ff9999" |
|
|
type "ellipse" |
|
|
outline "#666666" |
|
|
outline_width 1.5 |
|
|
] |
|
|
label "node0" |
|
|
] |
|
|
edge [ |
|
|
root_index -2 |
|
|
target -2 |
|
|
source -1 |
|
|
graphics [ |
|
|
width 1.5 |
|
|
fill "#0000ff" |
|
|
type "line" |
|
|
Line [ |
|
|
] |
|
|
source_arrow 0 |
|
|
target_arrow 3 |
|
|
] |
|
|
label "DirectedEdge" |
|
|
] |
|
|
edge [ |
|
|
root_index -1 |
|
|
target -1 |
|
|
source -3 |
|
|
graphics [ |
|
|
width 1.5 |
|
|
fill "#0000ff" |
|
|
type "line" |
|
|
Line [ |
|
|
] |
|
|
source_arrow 0 |
|
|
target_arrow 3 |
|
|
] |
|
|
label "DirectedEdge" |
|
|
] |
|
|
] |
|
|
""" |
|
|
nx.parse_gml(cytoscape_example) |
|
|
|
|
|
def test_parse_gml(self): |
|
|
G = nx.parse_gml(self.simple_data, label="label") |
|
|
assert sorted(G.nodes()) == ["Node 1", "Node 2", "Node 3"] |
|
|
assert sorted(G.edges()) == [ |
|
|
("Node 1", "Node 2"), |
|
|
("Node 2", "Node 3"), |
|
|
("Node 3", "Node 1"), |
|
|
] |
|
|
|
|
|
assert sorted(G.edges(data=True)) == [ |
|
|
( |
|
|
"Node 1", |
|
|
"Node 2", |
|
|
{ |
|
|
"color": {"line": "blue", "thickness": 3}, |
|
|
"label": "Edge from node 1 to node 2", |
|
|
}, |
|
|
), |
|
|
("Node 2", "Node 3", {"label": "Edge from node 2 to node 3"}), |
|
|
("Node 3", "Node 1", {"label": "Edge from node 3 to node 1"}), |
|
|
] |
|
|
|
|
|
def test_read_gml(self): |
|
|
(fd, fname) = tempfile.mkstemp() |
|
|
fh = open(fname, "w") |
|
|
fh.write(self.simple_data) |
|
|
fh.close() |
|
|
Gin = nx.read_gml(fname, label="label") |
|
|
G = nx.parse_gml(self.simple_data, label="label") |
|
|
assert sorted(G.nodes(data=True)) == sorted(Gin.nodes(data=True)) |
|
|
assert sorted(G.edges(data=True)) == sorted(Gin.edges(data=True)) |
|
|
os.close(fd) |
|
|
os.unlink(fname) |
|
|
|
|
|
def test_labels_are_strings(self): |
|
|
|
|
|
answer = """graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "1203" |
|
|
] |
|
|
]""" |
|
|
G = nx.Graph() |
|
|
G.add_node(1203) |
|
|
data = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) |
|
|
assert data == answer |
|
|
|
|
|
def test_relabel_duplicate(self): |
|
|
data = """ |
|
|
graph |
|
|
[ |
|
|
label "" |
|
|
directed 1 |
|
|
node |
|
|
[ |
|
|
id 0 |
|
|
label "same" |
|
|
] |
|
|
node |
|
|
[ |
|
|
id 1 |
|
|
label "same" |
|
|
] |
|
|
] |
|
|
""" |
|
|
fh = io.BytesIO(data.encode("UTF-8")) |
|
|
fh.seek(0) |
|
|
pytest.raises(nx.NetworkXError, nx.read_gml, fh, label="label") |
|
|
|
|
|
@pytest.mark.parametrize("stringizer", (None, literal_stringizer)) |
|
|
def test_tuplelabels(self, stringizer): |
|
|
|
|
|
|
|
|
G = nx.Graph() |
|
|
G.add_edge((0, 1), (1, 0)) |
|
|
data = "\n".join(nx.generate_gml(G, stringizer=stringizer)) |
|
|
answer = """graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "(0,1)" |
|
|
] |
|
|
node [ |
|
|
id 1 |
|
|
label "(1,0)" |
|
|
] |
|
|
edge [ |
|
|
source 0 |
|
|
target 1 |
|
|
] |
|
|
]""" |
|
|
assert data == answer |
|
|
|
|
|
def test_quotes(self): |
|
|
|
|
|
|
|
|
G = nx.path_graph(1) |
|
|
G.name = "path_graph(1)" |
|
|
attr = 'This is "quoted" and this is a copyright: ' + chr(169) |
|
|
G.nodes[0]["demo"] = attr |
|
|
fobj = tempfile.NamedTemporaryFile() |
|
|
nx.write_gml(G, fobj) |
|
|
fobj.seek(0) |
|
|
|
|
|
data = fobj.read().strip().decode("ascii") |
|
|
answer = """graph [ |
|
|
name "path_graph(1)" |
|
|
node [ |
|
|
id 0 |
|
|
label "0" |
|
|
demo "This is "quoted" and this is a copyright: ©" |
|
|
] |
|
|
]""" |
|
|
assert data == answer |
|
|
|
|
|
def test_unicode_node(self): |
|
|
node = "node" + chr(169) |
|
|
G = nx.Graph() |
|
|
G.add_node(node) |
|
|
fobj = tempfile.NamedTemporaryFile() |
|
|
nx.write_gml(G, fobj) |
|
|
fobj.seek(0) |
|
|
|
|
|
data = fobj.read().strip().decode("ascii") |
|
|
answer = """graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "node©" |
|
|
] |
|
|
]""" |
|
|
assert data == answer |
|
|
|
|
|
def test_float_label(self): |
|
|
node = 1.0 |
|
|
G = nx.Graph() |
|
|
G.add_node(node) |
|
|
fobj = tempfile.NamedTemporaryFile() |
|
|
nx.write_gml(G, fobj) |
|
|
fobj.seek(0) |
|
|
|
|
|
data = fobj.read().strip().decode("ascii") |
|
|
answer = """graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "1.0" |
|
|
] |
|
|
]""" |
|
|
assert data == answer |
|
|
|
|
|
def test_special_float_label(self): |
|
|
special_floats = [float("nan"), float("+inf"), float("-inf")] |
|
|
try: |
|
|
import numpy as np |
|
|
|
|
|
special_floats += [np.nan, np.inf, np.inf * -1] |
|
|
except ImportError: |
|
|
special_floats += special_floats |
|
|
|
|
|
G = nx.cycle_graph(len(special_floats)) |
|
|
attrs = dict(enumerate(special_floats)) |
|
|
nx.set_node_attributes(G, attrs, "nodefloat") |
|
|
edges = list(G.edges) |
|
|
attrs = {edges[i]: value for i, value in enumerate(special_floats)} |
|
|
nx.set_edge_attributes(G, attrs, "edgefloat") |
|
|
|
|
|
fobj = tempfile.NamedTemporaryFile() |
|
|
nx.write_gml(G, fobj) |
|
|
fobj.seek(0) |
|
|
|
|
|
data = fobj.read().strip().decode("ascii") |
|
|
answer = """graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "0" |
|
|
nodefloat NAN |
|
|
] |
|
|
node [ |
|
|
id 1 |
|
|
label "1" |
|
|
nodefloat +INF |
|
|
] |
|
|
node [ |
|
|
id 2 |
|
|
label "2" |
|
|
nodefloat -INF |
|
|
] |
|
|
node [ |
|
|
id 3 |
|
|
label "3" |
|
|
nodefloat NAN |
|
|
] |
|
|
node [ |
|
|
id 4 |
|
|
label "4" |
|
|
nodefloat +INF |
|
|
] |
|
|
node [ |
|
|
id 5 |
|
|
label "5" |
|
|
nodefloat -INF |
|
|
] |
|
|
edge [ |
|
|
source 0 |
|
|
target 1 |
|
|
edgefloat NAN |
|
|
] |
|
|
edge [ |
|
|
source 0 |
|
|
target 5 |
|
|
edgefloat +INF |
|
|
] |
|
|
edge [ |
|
|
source 1 |
|
|
target 2 |
|
|
edgefloat -INF |
|
|
] |
|
|
edge [ |
|
|
source 2 |
|
|
target 3 |
|
|
edgefloat NAN |
|
|
] |
|
|
edge [ |
|
|
source 3 |
|
|
target 4 |
|
|
edgefloat +INF |
|
|
] |
|
|
edge [ |
|
|
source 4 |
|
|
target 5 |
|
|
edgefloat -INF |
|
|
] |
|
|
]""" |
|
|
assert data == answer |
|
|
|
|
|
fobj.seek(0) |
|
|
graph = nx.read_gml(fobj) |
|
|
for indx, value in enumerate(special_floats): |
|
|
node_value = graph.nodes[str(indx)]["nodefloat"] |
|
|
if math.isnan(value): |
|
|
assert math.isnan(node_value) |
|
|
else: |
|
|
assert node_value == value |
|
|
|
|
|
edge = edges[indx] |
|
|
string_edge = (str(edge[0]), str(edge[1])) |
|
|
edge_value = graph.edges[string_edge]["edgefloat"] |
|
|
if math.isnan(value): |
|
|
assert math.isnan(edge_value) |
|
|
else: |
|
|
assert edge_value == value |
|
|
|
|
|
def test_name(self): |
|
|
G = nx.parse_gml('graph [ name "x" node [ id 0 label "x" ] ]') |
|
|
assert "x" == G.graph["name"] |
|
|
G = nx.parse_gml('graph [ node [ id 0 label "x" ] ]') |
|
|
assert "" == G.name |
|
|
assert "name" not in G.graph |
|
|
|
|
|
def test_graph_types(self): |
|
|
for directed in [None, False, True]: |
|
|
for multigraph in [None, False, True]: |
|
|
gml = "graph [" |
|
|
if directed is not None: |
|
|
gml += " directed " + str(int(directed)) |
|
|
if multigraph is not None: |
|
|
gml += " multigraph " + str(int(multigraph)) |
|
|
gml += ' node [ id 0 label "0" ]' |
|
|
gml += " edge [ source 0 target 0 ]" |
|
|
gml += " ]" |
|
|
G = nx.parse_gml(gml) |
|
|
assert bool(directed) == G.is_directed() |
|
|
assert bool(multigraph) == G.is_multigraph() |
|
|
gml = "graph [\n" |
|
|
if directed is True: |
|
|
gml += " directed 1\n" |
|
|
if multigraph is True: |
|
|
gml += " multigraph 1\n" |
|
|
gml += """ node [ |
|
|
id 0 |
|
|
label "0" |
|
|
] |
|
|
edge [ |
|
|
source 0 |
|
|
target 0 |
|
|
""" |
|
|
if multigraph: |
|
|
gml += " key 0\n" |
|
|
gml += " ]\n]" |
|
|
assert gml == "\n".join(nx.generate_gml(G)) |
|
|
|
|
|
def test_data_types(self): |
|
|
data = [ |
|
|
True, |
|
|
False, |
|
|
10**20, |
|
|
-2e33, |
|
|
"'", |
|
|
'"&&&""', |
|
|
[{(b"\xfd",): "\x7f", chr(0x4444): (1, 2)}, (2, "3")], |
|
|
] |
|
|
data.append(chr(0x14444)) |
|
|
data.append(literal_eval("{2.3j, 1 - 2.3j, ()}")) |
|
|
G = nx.Graph() |
|
|
G.name = data |
|
|
G.graph["data"] = data |
|
|
G.add_node(0, int=-1, data={"data": data}) |
|
|
G.add_edge(0, 0, float=-2.5, data=data) |
|
|
gml = "\n".join(nx.generate_gml(G, stringizer=literal_stringizer)) |
|
|
G = nx.parse_gml(gml, destringizer=literal_destringizer) |
|
|
assert data == G.name |
|
|
assert {"name": data, "data": data} == G.graph |
|
|
assert list(G.nodes(data=True)) == [(0, {"int": -1, "data": {"data": data}})] |
|
|
assert list(G.edges(data=True)) == [(0, 0, {"float": -2.5, "data": data})] |
|
|
G = nx.Graph() |
|
|
G.graph["data"] = "frozenset([1, 2, 3])" |
|
|
G = nx.parse_gml(nx.generate_gml(G), destringizer=literal_eval) |
|
|
assert G.graph["data"] == "frozenset([1, 2, 3])" |
|
|
|
|
|
def test_escape_unescape(self): |
|
|
gml = """graph [ |
|
|
name "&"䑄��&unknown;" |
|
|
]""" |
|
|
G = nx.parse_gml(gml) |
|
|
assert ( |
|
|
'&"\x0f' + chr(0x4444) + "��&unknown;" |
|
|
== G.name |
|
|
) |
|
|
gml = "\n".join(nx.generate_gml(G)) |
|
|
alnu = "#1234567890;&#x1234567890abcdef" |
|
|
answer = ( |
|
|
"""graph [ |
|
|
name "&"䑄&""" |
|
|
+ alnu |
|
|
+ """;&unknown;" |
|
|
]""" |
|
|
) |
|
|
assert answer == gml |
|
|
|
|
|
def test_exceptions(self): |
|
|
pytest.raises(ValueError, literal_destringizer, "(") |
|
|
pytest.raises(ValueError, literal_destringizer, "frozenset([1, 2, 3])") |
|
|
pytest.raises(ValueError, literal_destringizer, literal_destringizer) |
|
|
pytest.raises(ValueError, literal_stringizer, frozenset([1, 2, 3])) |
|
|
pytest.raises(ValueError, literal_stringizer, literal_stringizer) |
|
|
with tempfile.TemporaryFile() as f: |
|
|
f.write(codecs.BOM_UTF8 + b"graph[]") |
|
|
f.seek(0) |
|
|
pytest.raises(nx.NetworkXError, nx.read_gml, f) |
|
|
|
|
|
def assert_parse_error(gml): |
|
|
pytest.raises(nx.NetworkXError, nx.parse_gml, gml) |
|
|
|
|
|
assert_parse_error(["graph [\n\n", "]"]) |
|
|
assert_parse_error("") |
|
|
assert_parse_error('Creator ""') |
|
|
assert_parse_error("0") |
|
|
assert_parse_error("graph ]") |
|
|
assert_parse_error("graph [ 1 ]") |
|
|
assert_parse_error("graph [ 1.E+2 ]") |
|
|
assert_parse_error('graph [ "A" ]') |
|
|
assert_parse_error("graph [ ] graph ]") |
|
|
assert_parse_error("graph [ ] graph [ ]") |
|
|
assert_parse_error("graph [ data [1, 2, 3] ]") |
|
|
assert_parse_error("graph [ node [ ] ]") |
|
|
assert_parse_error("graph [ node [ id 0 ] ]") |
|
|
nx.parse_gml('graph [ node [ id "a" ] ]', label="id") |
|
|
assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 0 label 1 ] ]") |
|
|
assert_parse_error("graph [ node [ id 0 label 0 ] node [ id 1 label 0 ] ]") |
|
|
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ ] ]") |
|
|
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 ] ]") |
|
|
nx.parse_gml("graph [edge [ source 0 target 0 ] node [ id 0 label 0 ] ]") |
|
|
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 1 target 0 ] ]") |
|
|
assert_parse_error("graph [ node [ id 0 label 0 ] edge [ source 0 target 1 ] ]") |
|
|
assert_parse_error( |
|
|
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " |
|
|
"edge [ source 0 target 1 ] edge [ source 1 target 0 ] ]" |
|
|
) |
|
|
nx.parse_gml( |
|
|
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " |
|
|
"edge [ source 0 target 1 ] edge [ source 1 target 0 ] " |
|
|
"directed 1 ]" |
|
|
) |
|
|
nx.parse_gml( |
|
|
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " |
|
|
"edge [ source 0 target 1 ] edge [ source 0 target 1 ]" |
|
|
"multigraph 1 ]" |
|
|
) |
|
|
nx.parse_gml( |
|
|
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " |
|
|
"edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 ]" |
|
|
"multigraph 1 ]" |
|
|
) |
|
|
assert_parse_error( |
|
|
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " |
|
|
"edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 key 0 ]" |
|
|
"multigraph 1 ]" |
|
|
) |
|
|
nx.parse_gml( |
|
|
"graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] " |
|
|
"edge [ source 0 target 1 key 0 ] edge [ source 1 target 0 key 0 ]" |
|
|
"directed 1 multigraph 1 ]" |
|
|
) |
|
|
|
|
|
|
|
|
nx.parse_gml("graph [edge [ source a target a ] node [ id a label b ] ]") |
|
|
nx.parse_gml( |
|
|
"graph [ node [ id n42 label 0 ] node [ id x43 label 1 ]" |
|
|
"edge [ source n42 target x43 key 0 ]" |
|
|
"edge [ source x43 target n42 key 0 ]" |
|
|
"directed 1 multigraph 1 ]" |
|
|
) |
|
|
assert_parse_error( |
|
|
"graph [edge [ source u'u\4200' target u'u\4200' ] " |
|
|
+ "node [ id u'u\4200' label b ] ]" |
|
|
) |
|
|
|
|
|
def assert_generate_error(*args, **kwargs): |
|
|
pytest.raises( |
|
|
nx.NetworkXError, lambda: list(nx.generate_gml(*args, **kwargs)) |
|
|
) |
|
|
|
|
|
G = nx.Graph() |
|
|
G.graph[3] = 3 |
|
|
assert_generate_error(G) |
|
|
G = nx.Graph() |
|
|
G.graph["3"] = 3 |
|
|
assert_generate_error(G) |
|
|
G = nx.Graph() |
|
|
G.graph["data"] = frozenset([1, 2, 3]) |
|
|
assert_generate_error(G, stringizer=literal_stringizer) |
|
|
|
|
|
def test_label_kwarg(self): |
|
|
G = nx.parse_gml(self.simple_data, label="id") |
|
|
assert sorted(G.nodes) == [1, 2, 3] |
|
|
labels = [G.nodes[n]["label"] for n in sorted(G.nodes)] |
|
|
assert labels == ["Node 1", "Node 2", "Node 3"] |
|
|
|
|
|
G = nx.parse_gml(self.simple_data, label=None) |
|
|
assert sorted(G.nodes) == [1, 2, 3] |
|
|
labels = [G.nodes[n]["label"] for n in sorted(G.nodes)] |
|
|
assert labels == ["Node 1", "Node 2", "Node 3"] |
|
|
|
|
|
def test_outofrange_integers(self): |
|
|
|
|
|
|
|
|
G = nx.Graph() |
|
|
|
|
|
|
|
|
numbers = { |
|
|
"toosmall": (-(2**31)) - 1, |
|
|
"small": -(2**31), |
|
|
"med1": -4, |
|
|
"med2": 0, |
|
|
"med3": 17, |
|
|
"big": (2**31) - 1, |
|
|
"toobig": 2**31, |
|
|
} |
|
|
G.add_node("Node", **numbers) |
|
|
|
|
|
fd, fname = tempfile.mkstemp() |
|
|
try: |
|
|
nx.write_gml(G, fname) |
|
|
|
|
|
G2 = nx.read_gml(fname) |
|
|
for attr, value in G2.nodes["Node"].items(): |
|
|
if attr == "toosmall" or attr == "toobig": |
|
|
assert type(value) == str |
|
|
else: |
|
|
assert type(value) == int |
|
|
finally: |
|
|
os.close(fd) |
|
|
os.unlink(fname) |
|
|
|
|
|
def test_multiline(self): |
|
|
|
|
|
multiline_example = """ |
|
|
graph |
|
|
[ |
|
|
node |
|
|
[ |
|
|
id 0 |
|
|
label "multiline node" |
|
|
label2 "multiline1 |
|
|
multiline2 |
|
|
multiline3" |
|
|
alt_name "id 0" |
|
|
] |
|
|
] |
|
|
""" |
|
|
G = nx.parse_gml(multiline_example) |
|
|
assert G.nodes["multiline node"] == { |
|
|
"label2": "multiline1 multiline2 multiline3", |
|
|
"alt_name": "id 0", |
|
|
} |
|
|
|
|
|
|
|
|
@contextmanager |
|
|
def byte_file(): |
|
|
_file_handle = io.BytesIO() |
|
|
yield _file_handle |
|
|
_file_handle.seek(0) |
|
|
|
|
|
|
|
|
class TestPropertyLists: |
|
|
def test_writing_graph_with_multi_element_property_list(self): |
|
|
g = nx.Graph() |
|
|
g.add_node("n1", properties=["element", 0, 1, 2.5, True, False]) |
|
|
with byte_file() as f: |
|
|
nx.write_gml(g, f) |
|
|
result = f.read().decode() |
|
|
|
|
|
assert result == dedent( |
|
|
"""\ |
|
|
graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "n1" |
|
|
properties "element" |
|
|
properties 0 |
|
|
properties 1 |
|
|
properties 2.5 |
|
|
properties 1 |
|
|
properties 0 |
|
|
] |
|
|
] |
|
|
""" |
|
|
) |
|
|
|
|
|
def test_writing_graph_with_one_element_property_list(self): |
|
|
g = nx.Graph() |
|
|
g.add_node("n1", properties=["element"]) |
|
|
with byte_file() as f: |
|
|
nx.write_gml(g, f) |
|
|
result = f.read().decode() |
|
|
|
|
|
assert result == dedent( |
|
|
"""\ |
|
|
graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "n1" |
|
|
properties "_networkx_list_start" |
|
|
properties "element" |
|
|
] |
|
|
] |
|
|
""" |
|
|
) |
|
|
|
|
|
def test_reading_graph_with_list_property(self): |
|
|
with byte_file() as f: |
|
|
f.write( |
|
|
dedent( |
|
|
""" |
|
|
graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "n1" |
|
|
properties "element" |
|
|
properties 0 |
|
|
properties 1 |
|
|
properties 2.5 |
|
|
] |
|
|
] |
|
|
""" |
|
|
).encode("ascii") |
|
|
) |
|
|
f.seek(0) |
|
|
graph = nx.read_gml(f) |
|
|
assert graph.nodes(data=True)["n1"] == {"properties": ["element", 0, 1, 2.5]} |
|
|
|
|
|
def test_reading_graph_with_single_element_list_property(self): |
|
|
with byte_file() as f: |
|
|
f.write( |
|
|
dedent( |
|
|
""" |
|
|
graph [ |
|
|
node [ |
|
|
id 0 |
|
|
label "n1" |
|
|
properties "_networkx_list_start" |
|
|
properties "element" |
|
|
] |
|
|
] |
|
|
""" |
|
|
).encode("ascii") |
|
|
) |
|
|
f.seek(0) |
|
|
graph = nx.read_gml(f) |
|
|
assert graph.nodes(data=True)["n1"] == {"properties": ["element"]} |
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("coll", ([], ())) |
|
|
def test_stringize_empty_list_tuple(coll): |
|
|
G = nx.path_graph(2) |
|
|
G.nodes[0]["test"] = coll |
|
|
f = io.BytesIO() |
|
|
nx.write_gml(G, f) |
|
|
f.seek(0) |
|
|
H = nx.read_gml(f) |
|
|
assert H.nodes["0"]["test"] == coll |
|
|
|
|
|
|
|
|
H = nx.relabel_nodes(H, {"0": 0, "1": 1}) |
|
|
assert nx.utils.graphs_equal(G, H) |
|
|
|
|
|
|
|
|
f.seek(0) |
|
|
H = nx.read_gml(f, destringizer=int) |
|
|
assert nx.utils.graphs_equal(G, H) |
|
|
|