Skip to content

Commit a8896e4

Browse files
committed
Improve TypeError exceptions
- use pybind11 API instead of Python C API - provide more informative error messages
1 parent 74b1e5e commit a8896e4

File tree

3 files changed

+19
-19
lines changed

3 files changed

+19
-19
lines changed

core/python/bindings/src/core.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,8 @@ void setForwardedProperties(Stage& self, const py::object& names) {
8686
for (auto item : names)
8787
s.emplace(item.cast<std::string>());
8888
} catch (const py::cast_error& e) {
89-
// manually translate cast_error to type error
90-
PyErr_SetString(PyExc_TypeError, e.what());
91-
throw py::error_already_set();
89+
// translate cast_error to type_error with an informative message
90+
throw py::type_error("Expecting a string or a list of strings");
9291
}
9392
self.setForwardedProperties(s);
9493
}

core/python/bindings/src/properties.cpp

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ namespace moveit {
4343
namespace python {
4444
namespace {
4545

46+
/** In order to assign new property values in Python, we need to convert the Python object
47+
* to a boost::any instance of the correct type. As the C++ type cannot be inferred from
48+
* the Python type, we can support this assignment only for a few basic types (see fromPython())
49+
* as well as ROS message types. For other types, a generic assignment via
50+
* stage.properties["property"] = value
51+
* is not possible. Instead, use the .property<Type> declaration on the stage to allow for
52+
* direct assignment like this: stage.property = value
53+
**/
4654
class PropertyConverterRegistry
4755
{
4856
struct Entry
@@ -102,10 +110,8 @@ py::object PropertyConverterRegistry::toPython(const boost::any& value) {
102110

103111
auto it = REGISTRY_SINGLETON.types_.find(value.type());
104112
if (it == REGISTRY_SINGLETON.types_.end()) {
105-
std::string msg("No Python -> C++ conversion for: ");
106-
msg += boost::core::demangle(value.type().name());
107-
PyErr_SetString(PyExc_TypeError, msg.c_str());
108-
throw py::error_already_set();
113+
std::string name = boost::core::demangle(value.type().name());
114+
throw py::type_error("No Python -> C++ conversion for: " + name);
109115
}
110116

111117
return it->second.to_(value);
@@ -115,12 +121,9 @@ std::string rosMsgName(PyObject* object) {
115121
py::object o = py::reinterpret_borrow<py::object>(object);
116122
try {
117123
return o.attr("_type").cast<std::string>();
118-
} catch (const py::error_already_set&) {
119-
// change error to TypeError
120-
std::string msg = o.attr("__class__").attr("__name__").cast<std::string>();
121-
msg += " is not a ROS message type";
122-
PyErr_SetString(PyExc_TypeError, msg.c_str());
123-
throw py::error_already_set();
124+
} catch (const py::error_already_set& e) {
125+
// object is not a ROS message type, return it's class name instead
126+
return o.attr("__class__").attr("__name__").cast<std::string>();
124127
}
125128
}
126129

@@ -138,12 +141,8 @@ boost::any PropertyConverterRegistry::fromPython(const py::object& po) {
138141

139142
const std::string& ros_msg_name = rosMsgName(o);
140143
auto it = REGISTRY_SINGLETON.msg_names_.find(ros_msg_name);
141-
if (it == REGISTRY_SINGLETON.msg_names_.end()) {
142-
std::string msg("No Python -> C++ conversion for: ");
143-
msg += ros_msg_name;
144-
PyErr_SetString(PyExc_TypeError, msg.c_str());
145-
throw py::error_already_set();
146-
}
144+
if (it == REGISTRY_SINGLETON.msg_names_.end())
145+
throw py::type_error("No C++ conversion available for (property) type: " + ros_msg_name);
147146

148147
return it->second->second.from_(po);
149148
}

core/python/bindings/src/stages.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ void export_stages(pybind11::module& m) {
323323
324324
For an example, see :ref:`How-To-Guides <subsubsec-howto-connect>`.
325325
)")
326+
.property<stages::Connect::MergeMode>("merge_mode", "Defines the merge strategy to use")
327+
.property<double>("max_distance", "maximally accepted distance between end and goal sate")
326328
.def(py::init<const std::string&, const Connect::GroupPlannerVector&>(),
327329
"name"_a = std::string("connect"), "planners"_a);
328330

0 commit comments

Comments
 (0)