Commit 897f454f authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Improve behaviour of property map type conversion

Now an explicit conversion to a compatible python type is attempted if
the value being set in a property map cannot be converted directly to a
C++ type.

This also fixes a bug with vector-valued property maps.
parent b3dd46c3
...@@ -98,7 +98,8 @@ public: ...@@ -98,7 +98,8 @@ public:
void CheckValid() const void CheckValid() const
{ {
if (!IsValid()) if (!IsValid())
throw ValueException("invalid vertex descriptor"); throw ValueException("invalid vertex descriptor: " +
lexical_cast<string>(_v));
} }
GraphInterface::vertex_t GetDescriptor() const GraphInterface::vertex_t GetDescriptor() const
...@@ -391,8 +392,10 @@ public: ...@@ -391,8 +392,10 @@ public:
return get(_pmap, key.GetDescriptor()); return get(_pmap, key.GetDescriptor());
} }
// in this case, val should be a copy, not a reference. This is to avoid a
// problem with vector-valued property maps
template <class PythonDescriptor> template <class PythonDescriptor>
void SetValue(const PythonDescriptor& key, const value_type& val) void SetValue(const PythonDescriptor& key, value_type val)
{ {
set_value(key, val, set_value(key, val,
is_convertible< is_convertible<
......
...@@ -95,6 +95,23 @@ def _type_alias(type_name): ...@@ -95,6 +95,23 @@ def _type_alias(type_name):
raise ValueError("invalid property value type: " + type_name) raise ValueError("invalid property value type: " + type_name)
def _python_type(type_name):
type_name = _type_alias(type_name)
if "vector" in type_name:
ma = re.compile(r"vector<(.*)>").match(type_name)
t = ma.group(1)
return list, _python_type(t)
if "int" in type_name:
return int
if type_name == "bool":
return bool
if "double" in type_name:
return float
if "string" in type_name:
return str
return object
def show_config(): def show_config():
"""Show ``graph_tool`` build configuration.""" """Show ``graph_tool`` build configuration."""
info = libcore.mod_info() info = libcore.mod_info()
...@@ -240,7 +257,7 @@ class PropertyMap(object): ...@@ -240,7 +257,7 @@ class PropertyMap(object):
self.__map = pmap self.__map = pmap
self.__g = weakref.ref(g) self.__g = weakref.ref(g)
self.__key_type = key_type self.__key_type = key_type
self.__key_trans = key_trans if key_trans != None else lambda k: k self.__key_trans = key_trans if key_trans is not None else lambda k: k
self.__register_map() self.__register_map()
def __register_map(self): def __register_map(self):
...@@ -263,7 +280,17 @@ class PropertyMap(object): ...@@ -263,7 +280,17 @@ class PropertyMap(object):
return self.__map[self.__key_trans(k)] return self.__map[self.__key_trans(k)]
def __setitem__(self, k, v): def __setitem__(self, k, v):
self.__map[self.__key_trans(k)] = v try:
self.__map[self.__key_trans(k)] = v
except TypeError:
# attempt to convert to a compatible python type. This is useful,
# for instance, when dealing with numpy scalar types.
valtype = self.python_value_type()
if isistance(valtype, tuple):
val = [valtype[1](x) for x in v]
else:
val = valtype(v)
self.__map[self.__key_trans(k)] = val
def __repr__(self): def __repr__(self):
# provide some more useful information # provide some more useful information
...@@ -293,6 +320,10 @@ class PropertyMap(object): ...@@ -293,6 +320,10 @@ class PropertyMap(object):
"""Return the value type of the map.""" """Return the value type of the map."""
return self.__map.value_type() return self.__map.value_type()
def python_value_type(self):
"""Return the python-compatible value type of the map."""
return _python_type(self.__map.value_type())
def get_array(self): def get_array(self):
"""Get a :class:`~graph_tool.PropertyArray` with the property values. """Get a :class:`~graph_tool.PropertyArray` with the property values.
...@@ -305,6 +336,8 @@ class PropertyMap(object): ...@@ -305,6 +336,8 @@ class PropertyMap(object):
the graph is to be modified; store a **copy** instead. the graph is to be modified; store a **copy** instead.
""" """
a = self._get_data() a = self._get_data()
if a is None:
return None
return PropertyArray(a, prop_map=self) return PropertyArray(a, prop_map=self)
def _get_data(self): def _get_data(self):
...@@ -322,7 +355,7 @@ class PropertyMap(object): ...@@ -322,7 +355,7 @@ class PropertyMap(object):
return a return a
def __get_array(self): def __get_array(self):
if self.get_array() != None: if self.get_array() is not None:
return self.get_array()[:] return self.get_array()[:]
else: else:
return None return None
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment