Commit f257d426 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Reorganize exceptions thrown

No longer only thrown GraphError upon any error, but instead throw
specific exceptions which are more meaninful and are mapped to standard
python exceptions, such as IOError, ValueError and RuntimeError.
parent 54f5c469
......@@ -37,9 +37,9 @@ void absolute_trust(GraphInterface& g, int64_t source, boost::any c,
rng_t rng(static_cast<rng_t::result_type>(seed));
if (!belongs<edge_floating_properties>()(c))
throw GraphException("edge property must be of floating point value type");
throw ValueException("edge property must be of floating point value type");
if (!belongs<vertex_floating_vector_properties>()(t))
throw GraphException("vertex property must be of floating point vector value type");
throw ValueException("vertex property must be of floating point vector value type");
run_action<>()(g,
bind<void>(get_absolute_trust(), _1, g.GetVertexIndex(),
......
......@@ -129,11 +129,11 @@ void betweenness(GraphInterface& g, boost::any weight,
bool normalize)
{
if (!belongs<edge_floating_properties>()(edge_betweenness))
throw GraphException("edge property must be of floating point value"
throw ValueException("edge property must be of floating point value"
" type");
if (!belongs<vertex_floating_properties>()(vertex_betweenness))
throw GraphException("vertex property must be of floating point value"
throw ValueException("vertex property must be of floating point value"
" type");
if (!weight.empty())
......
......@@ -32,9 +32,9 @@ size_t eigentrust(GraphInterface& g, boost::any c, boost::any t,
double epslon, size_t max_iter)
{
if (!belongs<writable_edge_scalar_properties>()(c))
throw GraphException("edge property must be writable");
throw ValueException("edge property must be writable");
if (!belongs<vertex_floating_properties>()(t))
throw GraphException("vertex property must be of floating point"
throw ValueException("vertex property must be of floating point"
" value type");
size_t iter = 0;
......
......@@ -33,7 +33,7 @@ size_t pagerank(GraphInterface& g, boost::any rank, double d, double epslon,
size_t max_iter)
{
if (!belongs<writable_vertex_scalar_properties>()(rank))
throw GraphException("vertex property must be writable");
throw ValueException("vertex property must be writable");
size_t iter;
run_action<>()
......
......@@ -86,7 +86,7 @@ void extended_clustering(GraphInterface& g, python::list props)
prop_vector<writable_vertex_scalar_properties>()
(cmaps, num_vertices(g.GetGraph()));
if (vprop.empty())
throw GraphException("all vertex properties must be of the same"
throw ValueException("all vertex properties must be of the same"
" floating point type");
typedef mpl::transform<writable_vertex_scalar_properties,
......
......@@ -95,7 +95,7 @@ void get_motifs(GraphInterface& g, size_t k, python::list subgraph_list,
}
catch (bad_any_cast&)
{
throw GraphException("All motif graphs must be either directed or "
throw ValueException("All motif graphs must be either directed or "
"undirected!");
}
......
......@@ -50,7 +50,7 @@ void community_structure(GraphInterface& g, double gamma, string corr_name,
allowed_spin_properties;
if (!belongs<allowed_spin_properties>()(property))
throw GraphException("vertex property is not of integer type int32_t "
throw ValueException("vertex property is not of integer type int32_t "
"or int64_t");
typedef DynamicPropertyMapWrap<double,GraphInterface::edge_t> weight_map_t;
......@@ -70,7 +70,7 @@ void community_structure(GraphInterface& g, double gamma, string corr_name,
else if (corr_name == "correlated")
corr = CORRELATED;
else
throw GraphException("invalid correlation type: " + corr_name);
throw ValueException("invalid correlation type: " + corr_name);
bool directed = g.GetDirected();
g.SetDirected(false);
......
......@@ -70,8 +70,8 @@ struct get_communities
{
out_file.open(verbose.second.c_str());
if (!out_file.is_open())
throw GraphException("error opening file " + verbose.second +
" for writing");
throw IOException("error opening file " + verbose.second +
" for writing");
out_file.exceptions (ifstream::eofbit | ifstream::failbit |
ifstream::badbit);
}
......@@ -200,8 +200,8 @@ struct get_communities
}
catch (ifstream::failure e)
{
throw GraphException("error writing to file " +
verbose.second + ": " + e.what());
throw IOException("error writing to file " +
verbose.second + ": " + e.what());
}
}
}
......
......@@ -57,7 +57,7 @@ void community_network(GraphInterface& gi, GraphInterface& cgi,
}
catch (bad_any_cast&)
{
throw GraphException("invalid vertex count property");
throw ValueException("invalid vertex count property");
}
typedef property_map_types::apply<mpl::vector<int32_t,double>,
......@@ -66,7 +66,7 @@ void community_network(GraphInterface& gi, GraphInterface& cgi,
ecount_properties;
if (!belongs<ecount_properties>()(edge_count))
throw GraphException("invalid edge count property");
throw ValueException("invalid edge count property");
run_action<>()(gi, bind<void>(get_community_network(), _1,
ref(cgi.GetGraph()), cgi.GetVertexIndex(),
......
......@@ -47,5 +47,5 @@ void random_rewire(GraphInterface& gi, string strat, bool self_loops,
_1, edge_index, ref(rng), self_loops,
parallel_edges))();
else
throw GraphException("invalid random rewire stategy: " + strat);
throw ValueException("invalid random rewire strategy: " + strat);
}
......@@ -191,7 +191,7 @@ struct graph_rewire
has_self_loops = true;
}
if (has_self_loops)
throw GraphException("Self-loop detected. Can't rewire graph "
throw ValueException("Self-loop detected. Can't rewire graph "
"without self-loops if it already contains"
" self-loops!");
}
......@@ -221,7 +221,7 @@ struct graph_rewire
}
if (has_parallel_edges)
throw GraphException("Parallel edge detected. Can't rewire "
throw ValueException("Parallel edge detected. Can't rewire "
"graph without parallel edges if it "
"already contains parallel edges!");
}
......
......@@ -234,6 +234,19 @@ protected:
virtual void SetError(const string& error) {_error = error;}
};
class IOException : public GraphException
{
public:
IOException(const string& error): GraphException(error) {}
};
class ValueException : public GraphException
{
public:
ValueException(const string& error): GraphException(error) {}
};
} //namespace graph_tool
#endif
......
......@@ -136,21 +136,20 @@ struct export_vector_types
};
// exception translation
static PyObject* pyex =
PyErr_NewException((char *) "libgraph_tool_core.GraphError",
PyExc_Exception, NULL);
void graph_exception_translator(const GraphException& e)
{
PyObject* message = PyString_FromString(e.what());
PyObject_SetAttrString(pyex, "message", message);
PyErr_SetString(pyex, e.what());
}
template <class Exception>
void translate(const Exception& e)
void graph_exception_translator(const Exception& e)
{
PyErr_SetString(PyExc_RuntimeError, e.what());
PyObject* error;
if (is_same<Exception, GraphException>::value)
error = PyExc_RuntimeError;
if (is_same<Exception, IOException>::value)
error = PyExc_IOError;
if (is_same<Exception, ValueException>::value)
error = PyExc_ValueError;
PyObject* message = PyString_FromString(e.what());
PyObject_SetAttrString(error, "message", message);
PyErr_SetString(error, e.what());
}
void raise_error(const string& msg)
......@@ -310,8 +309,12 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
GraphInterface().ExportPythonInterface();
PyModule_AddObject(python::detail::current_scope, "GraphError", pyex);
register_exception_translator<GraphException>(graph_exception_translator);
register_exception_translator<GraphException>
(graph_exception_translator<GraphException>);
register_exception_translator<IOException>
(graph_exception_translator<IOException>);
register_exception_translator<ValueException>
(graph_exception_translator<ValueException>);
def("raise_error", &raise_error);
def("get_property_types", &get_property_types);
......
......@@ -216,7 +216,7 @@ struct copy_property
for (tie(vs, vs_end) = IteratorSel::range(src); vs != vs_end; ++vs)
{
if (vt == vt_end)
throw GraphException("Error copying properties: "
throw ValueException("Error copying properties: "
"graphs not identical");
dst_map[*vt] = c(src_map[*vs]);
++vt;
......@@ -224,7 +224,7 @@ struct copy_property
}
catch (bad_lexical_cast&)
{
throw GraphException("property values are not convertible");
throw ValueException("property values are not convertible");
}
}
};
......
......@@ -482,7 +482,7 @@ python::tuple GraphInterface::ReadFromFile(string file, python::object pfile,
if (format == "dot")
graphviz = true;
else if (format != "xml")
throw GraphException("error reading from file '" + file +
throw ValueException("error reading from file '" + file +
"': requested invalid format '" + format + "'");
try
{
......@@ -542,8 +542,7 @@ python::tuple GraphInterface::ReadFromFile(string file, python::object pfile,
}
catch (ios_base::failure &e)
{
throw GraphException("error reading from file '" + file + "':" +
e.what());
throw IOException("error reading from file '" + file + "':" + e.what());
}
};
......@@ -621,7 +620,7 @@ void GraphInterface::WriteToFile(string file, python::object pfile,
if (format == "dot")
graphviz = true;
else if (format != "xml")
throw GraphException("error writing to file '" + file +
throw ValueException("error writing to file '" + file +
"': requested invalid format '" + format + "'");
try
{
......@@ -711,7 +710,6 @@ void GraphInterface::WriteToFile(string file, python::object pfile,
}
catch (ios_base::failure &e)
{
throw GraphException("error writing to file '" + file + "':" +
e.what());
throw IOException("error writing to file '" + file + "':" + e.what());
}
}
......@@ -225,7 +225,7 @@ void GraphInterface::RemoveEdge(const python::object& e)
lambda::var(e), lambda::var(de),
lambda::var(found)))();
if (!found)
throw GraphException("invalid edge descriptor");
throw ValueException("invalid edge descriptor");
RemoveEdgeIndex(de);
}
......
......@@ -93,7 +93,7 @@ public:
void CheckValid() const
{
if (!IsValid())
throw GraphException("invalid vertex descriptor");
throw ValueException("invalid vertex descriptor");
}
GraphInterface::vertex_t GetDescriptor() const
......@@ -253,7 +253,7 @@ public:
void CheckValid() const
{
if (!_valid)
throw GraphException("invalid edge descriptor");
throw ValueException("invalid edge descriptor");
}
GraphInterface::edge_t GetDescriptor() const
......@@ -403,7 +403,7 @@ public:
void set_value(const PythonDescriptor& key, const value_type& val,
false_type)
{
throw GraphException("property is read-only");
throw ValueException("property is read-only");
}
size_t GetHash() const
......@@ -497,7 +497,7 @@ python::object new_property(const string& type, IndexMap index_map)
lambda::var(prop),
lambda::var(found)));
if (!found)
throw GraphException("Invalid property type " + type);
throw ValueException("Invalid property type: " + type);
return prop;
}
......
......@@ -43,7 +43,7 @@ boost::any graph_tool::degree_selector(GraphInterface::deg_t deg)
mpl::for_each<vertex_properties>
(bind<void>(get_scalar_selector(), _1, *d, var(sel), var(found)));
if (!found)
throw GraphException("invalid degree selector");
throw ValueException("invalid degree selector");
}
return sel;
}
......@@ -92,12 +92,11 @@ import numpy
import scipy
import scipy.stats
from . core import __version__, Graph, GraphError, Vector_bool, \
Vector_int32_t, Vector_int64_t, Vector_double, Vector_long_double,\
Vector_string, value_types, load_graph, PropertyMap, Vertex, Edge,\
show_config
__all__ = ["Graph", "Vertex", "Edge", "GraphError", "Vector_bool",
"Vector_int32_t", "Vector_int64_t", "Vector_double",
"Vector_long_double", "Vector_string", "value_types", "load_graph",
"PropertyMap", "show_config"]
from . core import __version__, Graph, Vector_bool, Vector_int32_t, \
Vector_int64_t, Vector_double, Vector_long_double, Vector_string, \
value_types, load_graph, PropertyMap, Vertex, Edge, show_config
__all__ = ["Graph", "Vertex", "Edge", "Vector_bool", "Vector_int32_t",
"Vector_int64_t", "Vector_double", "Vector_long_double",
"Vector_string", "value_types", "load_graph", "PropertyMap",
"show_config"]
......@@ -26,7 +26,7 @@ import sys, os, os.path, re, struct, fcntl, termios, gzip, bz2, string,\
textwrap, time, signal, traceback, shutil, time, math, inspect, \
functools, types, weakref, copy
from StringIO import StringIO
from decorators import _wraps, _require, _attrs, _handle_exceptions, _limit_args
from decorators import _wraps, _require, _attrs, _limit_args
################################################################################
# Utility functions
......@@ -39,9 +39,9 @@ def _prop(t, g, prop):
try:
pmap = g.properties[(t,prop)]
except KeyError:
raise GraphError("no internal %s property named: %s" %\
("vertex" if t == "v" else \
("edge" if t == "e" else "graph"),prop))
raise KeyError("no internal %s property named: %s" %\
("vertex" if t == "v" else \
("edge" if t == "e" else "graph"), prop))
else:
pmap = prop
if pmap == None:
......@@ -228,10 +228,9 @@ class PropertyDict(dict):
# The main graph interface
################################################################################
from libgraph_tool_core import Vertex, Edge, GraphError,\
Vector_bool, Vector_int32_t, Vector_int64_t, Vector_double,\
Vector_long_double, Vector_string, new_vertex_property, new_edge_property,\
new_graph_property
from libgraph_tool_core import Vertex, Edge, Vector_bool, Vector_int32_t, \
Vector_int64_t, Vector_double, Vector_long_double, Vector_string, \
new_vertex_property, new_edge_property, new_graph_property
class Graph(object):
"""This class encapsulates either a directed multigraph (default or if
......@@ -298,7 +297,6 @@ class Graph(object):
self.__edge_index = \
PropertyMap(libcore.get_edge_index(self.__graph), self, "e")
@_handle_exceptions
def copy(self):
"""Returns a deep copy of self. All internal property maps are also
copied."""
......@@ -307,7 +305,6 @@ class Graph(object):
# Graph access
# ============
@_handle_exceptions
def vertices(self):
"""Return an iterator over the vertices
......@@ -325,17 +322,14 @@ class Graph(object):
"""
return self.__graph.Vertices()
@_handle_exceptions
def vertex(self, i):
"""Return the i-th vertex from the graph."""
return self.__graph.Vertex(int(i))
@_handle_exceptions
def edges(self):
"""Return iterator over the edges."""
return self.__graph.Edges()
@_handle_exceptions
def add_vertex(self, n=1):
"""Add a vertices to the graph, and return it. If n > 1, n vertices are
inserted and a list is returned."""
......@@ -344,7 +338,6 @@ class Graph(object):
else:
return [self.__graph.AddVertex() for i in xrange(0,n)]
@_handle_exceptions
def remove_vertex(self, vertex):
"""Remove a vertex from the graph."""
k = vertex.in_degree() + vertex.out_degree()
......@@ -356,7 +349,6 @@ class Graph(object):
self.clear_vertex(vertex)
self.__graph.RemoveVertex(vertex)
@_handle_exceptions
def remove_vertex_if(self, predicate):
"""Remove all the vertices from the graph for which predicate(v)
evaluates to True."""
......@@ -366,7 +358,6 @@ class Graph(object):
if predicate(v):
self.remove_vertex(v)
@_handle_exceptions
def clear_vertex(self, vertex):
"""Removes all in and out-edges from the given vertex."""
del_es = []
......@@ -375,18 +366,15 @@ class Graph(object):
for e in del_es:
self.remove_edge(e)
@_handle_exceptions
def add_edge(self, source, target):
"""Add a new edge from 'source' to 'target' to the graph, and return
it."""
return self.__graph.AddEdge(source, target)
@_handle_exceptions
def remove_edge(self, edge):
"""Remove an edge from the graph."""
self.__graph.RemoveEdge(edge)
@_handle_exceptions
def remove_edge_if(self, predicate):
"""Remove all the edges from the graph for which predicate(e) evaluates
to True."""
......@@ -398,12 +386,10 @@ class Graph(object):
for e in del_es:
self.remove_edge(e)
@_handle_exceptions
def clear(self):
"""Remove all vertices and edges from the graph."""
self.__graph.Clear()
@_handle_exceptions
def clear_edges(self):
"""Remove all edges from the graph."""
self.__graph.ClearEdges()
......@@ -412,14 +398,12 @@ class Graph(object):
# ======================
# all properties
@_handle_exceptions
def __get_properties(self):
return PropertyDict(self, self.__properties,
lambda g,k: g.__properties[k],
lambda g,k,v: g.__set_property(k[0],k[1],v),
lambda g,k: g.__del_property(k[0],k[1]))
@_handle_exceptions
@_limit_args({"t":["v", "e", "g"]})
@_require("k", str)
@_require("v", PropertyMap)
......@@ -428,7 +412,6 @@ class Graph(object):
raise ValueError("wrong key type for property map")
self.__properties[(t,k)] = v
@_handle_exceptions
@_limit_args({"t":["v", "e", "g"]})
@_require("k", str)
def __del_property(self, t, k):
......@@ -454,7 +437,6 @@ class Graph(object):
return props
# vertex properties
@_handle_exceptions
def __get_vertex_properties(self):
return PropertyDict(self, self.__get_specific_properties("v"),
lambda g,k: g.__properties[("v",k)],
......@@ -463,7 +445,6 @@ class Graph(object):
vertex_properties = property(__get_vertex_properties,
doc="Dictionary of vertex properties")
# edge properties
@_handle_exceptions
def __get_edge_properties(self):
return PropertyDict(self, self.__get_specific_properties("e"),
lambda g,k: g.__properties[("e",k)],
......@@ -473,7 +454,6 @@ class Graph(object):
doc="Dictionary of edge properties")
# graph properties
@_handle_exceptions
def __get_graph_properties(self):
return PropertyDict(self, self.__get_specific_properties("g"),
lambda g,k: g.__properties[("g",k)],
......@@ -482,7 +462,6 @@ class Graph(object):
graph_properties = property(__get_graph_properties,
doc="Dictionary of graph properties")
@_handle_exceptions
def list_properties(self):
"""List all internal properties for convenience.
......@@ -532,7 +511,6 @@ class Graph(object):
# Property map creation
@_handle_exceptions
def new_property(self, key_type, type):
"""Create a new (uninitialized) vertex property map of key type
`key_type` (``v``, ``e`` or ``g``), value type ``type``, and return it.
......@@ -543,9 +521,8 @@ class Graph(object):
return self.new_edge_property(type)
if key_type == "g" or key_type == "graph":
return self.new_graph_property(type)
raise GraphError("unknown key type: " + key_type)
raise ValueError("unknown key type: " + key_type)
@_handle_exceptions
def new_vertex_property(self, type):
"""Create a new (uninitialized) vertex property map of type `type`, and
return it."""
......@@ -553,7 +530,6 @@ class Graph(object):
self.__graph.GetVertexIndex()),
self, "v")
@_handle_exceptions
def new_edge_property(self, type):
"""Create a new (uninitialized) edge property map of type `type`, and
return it."""
......@@ -561,7 +537,6 @@ class Graph(object):
self.__graph.GetEdgeIndex()),
self, "e")
@_handle_exceptions
def new_graph_property(self, type, val=None):
"""Create a new graph property map of type `type`, and return it. If
`val` is not None, the property is initialized to its value."""
......@@ -573,7 +548,6 @@ class Graph(object):
return prop
# property map copying
@_handle_exceptions
@_require("src", PropertyMap)
@_require("tgt", (PropertyMap, type(None)))
def copy_property(self, src, tgt=None, g=None):
......@@ -589,7 +563,7 @@ class Graph(object):
ret = None
if src.key_type() != tgt.key_type():
raise GraphError("source and target properties must have the same" +
raise ValueError("source and target properties must have the same" +
" key type")
if g == None:
g = self
......@@ -610,7 +584,6 @@ class Graph(object):
return ret
# degree property map
@_handle_exceptions
@_limit_args({"deg":["in","out","total"]})
def degree_property_map(self, deg):
"""Create and return a vertex property map containing the degree type
......@@ -621,7 +594,6 @@ class Graph(object):
# I/O operations
# ==============
@_handle_exceptions
def load(self, filename, format="auto"):
"""Load graph from 'filename' (which can also be a file-like
object). The format is guessed from the file name, or can be specified
......@@ -637,8 +609,7 @@ class Graph(object):
filename.endswith(".dot.bz2"):
format = "dot"
else:
libcore.raise_error\
("cannot determine file format of: " + filename )
raise ValueError("cannot determine file format of: " + filename)
elif format == "auto":
format = "xml"
if isinstance(filename, str):
......@@ -653,7 +624,6 @@ class Graph(object):
self.graph_properties[name] = PropertyMap(prop, self, "g",
lambda k: k.__graph)