summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoss Barnowski <rossbar@berkeley.edu>2021-09-14 22:40:10 -0500
committerGitHub <noreply@github.com>2021-09-14 23:40:10 -0400
commit4e31e9ee035333d60e02cee4599d7de31ec097a9 (patch)
tree24be9ecf0b60157b52a7d95e623cd0f1e0b57554
parentbcc7a7e42b6e152ac57658e884f5184b33463b0b (diff)
downloadnetworkx-4e31e9ee035333d60e02cee4599d7de31ec097a9.tar.gz
More informative GraphML exceptions (#5058)
* Add tests that fail on uninformative exception. * Raise informative exception when non-supported type used. * Add importorskip to new tests. * Change naming scheme for backward compatibility.
-rw-r--r--networkx/readwrite/graphml.py23
-rw-r--r--networkx/readwrite/tests/test_graphml.py36
2 files changed, 53 insertions, 6 deletions
diff --git a/networkx/readwrite/graphml.py b/networkx/readwrite/graphml.py
index bb70a0d7..589173dc 100644
--- a/networkx/readwrite/graphml.py
+++ b/networkx/readwrite/graphml.py
@@ -447,6 +447,17 @@ class GraphML:
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__(
@@ -504,7 +515,7 @@ class GraphMLWriter(GraphML):
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:
@@ -551,7 +562,7 @@ class GraphMLWriter(GraphML):
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
@@ -765,7 +776,7 @@ class GraphMLWriterLxml(GraphMLWriter):
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):
@@ -773,7 +784,7 @@ class GraphMLWriterLxml(GraphMLWriter):
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():
@@ -782,7 +793,7 @@ class GraphMLWriterLxml(GraphMLWriter):
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):
@@ -790,7 +801,7 @@ class GraphMLWriterLxml(GraphMLWriter):
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
diff --git a/networkx/readwrite/tests/test_graphml.py b/networkx/readwrite/tests/test_graphml.py
index 4e6064a2..c97d07cc 100644
--- a/networkx/readwrite/tests/test_graphml.py
+++ b/networkx/readwrite/tests/test_graphml.py
@@ -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)