A few convenience functions for working with Python types
- Get a descriptive string after a Python exception (without changing the exception status)
- Convenience function to map from a C++ object to a Python handle
- Convenience to check if a pybind::function is defined by an underlying
C++ implementation
- Get the type object of a pybind::handle
diff --git a/include/pybind/common.h b/include/pybind/common.h
index d327ab6..3a95210 100644
--- a/include/pybind/common.h
+++ b/include/pybind/common.h
@@ -41,6 +41,7 @@
#endif
#endif
#include <Python.h>
+#include <frameobject.h>
#ifdef isalnum
#undef isalnum
#undef isalpha
@@ -122,6 +123,8 @@
NAMESPACE_BEGIN(detail)
+inline std::string error_string();
+
/// PyObject wrapper around generic types
template <typename type, typename holder_type = std::unique_ptr<type>> struct instance {
PyObject_HEAD
diff --git a/include/pybind/pytypes.h b/include/pybind/pytypes.h
index e9a60e9..4559ffb 100644
--- a/include/pybind/pytypes.h
+++ b/include/pybind/pytypes.h
@@ -32,6 +32,7 @@
void inc_ref() const { Py_XINCREF(m_ptr); }
void dec_ref() const { Py_XDECREF(m_ptr); }
int ref_count() const { return (int) Py_REFCNT(m_ptr); }
+ handle get_type() { return (PyObject *) Py_TYPE(m_ptr); }
inline detail::accessor operator[](handle key);
inline detail::accessor operator[](const char *key);
inline detail::accessor attr(handle key);
@@ -325,6 +326,17 @@
class function : public object {
public:
PYBIND_OBJECT_DEFAULT(function, object, PyFunction_Check)
+
+ bool is_cpp_function() {
+ PyObject *ptr = m_ptr;
+ if (ptr == nullptr)
+ return false;
+#if PY_MAJOR_VERSION < 3
+ if (PyMethod_Check(ptr))
+ ptr = PyMethod_GET_FUNCTION(ptr);
+#endif
+ return PyCFunction_Check(ptr);
+ }
};
class buffer : public object {
@@ -365,5 +377,30 @@
}
return *internals_ptr;
}
+
+inline std::string error_string() {
+ std::string errorString;
+ PyThreadState *tstate = PyThreadState_GET();
+ if (tstate == nullptr)
+ return "";
+
+ if (tstate->curexc_type) {
+ errorString += (const char *) handle(tstate->curexc_type).str();
+ errorString += ": ";
+ }
+ if (tstate->curexc_value)
+ errorString += (const char *) handle(tstate->curexc_value).str();
+
+ return errorString;
+}
+
+inline handle get_object_handle(const void *ptr) {
+ auto instances = get_internals().registered_instances;
+ auto it = instances.find(ptr);
+ if (it == instances.end())
+ throw std::runtime_error("Internal error: could not acquire Python handle of a C++ object");
+ return it->second;
+}
+
NAMESPACE_END(detail)
NAMESPACE_END(pybind)