Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More informative GraphML exceptions #5058

Merged
merged 4 commits into from Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 17 additions & 6 deletions networkx/readwrite/graphml.py
Expand Up @@ -447,6 +447,17 @@ def construct_types(self):
1: True,
}

def get_xml_type(self, key):
"""Wrapper around the xml_type dict that raises a more informative
exception message when a user attempts to use data of a type not
supported by GraphML."""
try:
return self.xml_type[key]
except KeyError as e:
raise TypeError(
f"GraphML does not support type {type(key)} as data values."
) from e


class GraphMLWriter(GraphML):
def __init__(
Expand Down Expand Up @@ -504,7 +515,7 @@ def attr_type(self, name, scope, value):
types = self.attribute_types[(name, scope)]

if len(types) > 1:
types = {self.xml_type[t] for t in types}
types = {self.get_xml_type(t) for t in types}
if "string" in types:
return str
elif "float" in types or "double" in types:
Expand Down Expand Up @@ -551,7 +562,7 @@ def add_data(self, name, element_type, value, scope="all", default=None):
raise nx.NetworkXError(
f"GraphML writer does not support {element_type} as data values."
)
keyid = self.get_key(name, self.xml_type[element_type], scope, default)
keyid = self.get_key(name, self.get_xml_type(element_type), scope, default)
data_element = self.myElement("data", key=keyid)
data_element.text = str(value)
return data_element
Expand Down Expand Up @@ -765,15 +776,15 @@ def add_graph_element(self, G):
for k, v in graphdata.items():
self.attribute_types[(str(k), "graph")].add(type(v))
for k, v in graphdata.items():
element_type = self.xml_type[self.attr_type(k, "graph", v)]
element_type = self.get_xml_type(self.attr_type(k, "graph", v))
self.get_key(str(k), element_type, "graph", None)
# Nodes and data
for node, d in G.nodes(data=True):
for k, v in d.items():
self.attribute_types[(str(k), "node")].add(type(v))
for node, d in G.nodes(data=True):
for k, v in d.items():
T = self.xml_type[self.attr_type(k, "node", v)]
T = self.get_xml_type(self.attr_type(k, "node", v))
self.get_key(str(k), T, "node", node_default.get(k))
# Edges and data
if G.is_multigraph():
Expand All @@ -782,15 +793,15 @@ def add_graph_element(self, G):
self.attribute_types[(str(k), "edge")].add(type(v))
for u, v, ekey, d in G.edges(keys=True, data=True):
for k, v in d.items():
T = self.xml_type[self.attr_type(k, "edge", v)]
T = self.get_xml_type(self.attr_type(k, "edge", v))
self.get_key(str(k), T, "edge", edge_default.get(k))
else:
for u, v, d in G.edges(data=True):
for k, v in d.items():
self.attribute_types[(str(k), "edge")].add(type(v))
for u, v, d in G.edges(data=True):
for k, v in d.items():
T = self.xml_type[self.attr_type(k, "edge", v)]
T = self.get_xml_type(self.attr_type(k, "edge", v))
self.get_key(str(k), T, "edge", edge_default.get(k))

# Now add attribute keys to the xml file
Expand Down
36 changes: 36 additions & 0 deletions networkx/readwrite/tests/test_graphml.py
Expand Up @@ -1500,3 +1500,39 @@ class TestXMLGraphML(TestWriteGraphML):
@classmethod
def setup_class(cls):
TestWriteGraphML.setup_class()


def test_exception_for_unsupported_datatype_node_attr():
"""Test that a detailed exception is raised when an attribute is of a type
not supported by GraphML, e.g. a list"""
pytest.importorskip("lxml.etree")
# node attribute
G = nx.Graph()
G.add_node(0, my_list_attribute=[0, 1, 2])
fh = io.BytesIO()
with pytest.raises(TypeError, match="GraphML does not support"):
nx.write_graphml(G, fh)


def test_exception_for_unsupported_datatype_edge_attr():
"""Test that a detailed exception is raised when an attribute is of a type
not supported by GraphML, e.g. a list"""
pytest.importorskip("lxml.etree")
# edge attribute
G = nx.Graph()
G.add_edge(0, 1, my_list_attribute=[0, 1, 2])
fh = io.BytesIO()
with pytest.raises(TypeError, match="GraphML does not support"):
nx.write_graphml(G, fh)


def test_exception_for_unsupported_datatype_graph_attr():
"""Test that a detailed exception is raised when an attribute is of a type
not supported by GraphML, e.g. a list"""
pytest.importorskip("lxml.etree")
# graph attribute
G = nx.Graph()
G.graph["my_list_attribute"] = [0, 1, 2]
fh = io.BytesIO()
with pytest.raises(TypeError, match="GraphML does not support"):
nx.write_graphml(G, fh)