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
This commit is contained in:
Wenzel Jakob 2015-10-01 16:42:15 +02:00
parent 5257330e6a
commit 96c10530aa
2 changed files with 40 additions and 0 deletions

View File

@ -41,6 +41,7 @@
#endif #endif
#endif #endif
#include <Python.h> #include <Python.h>
#include <frameobject.h>
#ifdef isalnum #ifdef isalnum
#undef isalnum #undef isalnum
#undef isalpha #undef isalpha
@ -122,6 +123,8 @@ struct cast_error : public std::runtime_error { public: cast_error(const
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
inline std::string error_string();
/// PyObject wrapper around generic types /// PyObject wrapper around generic types
template <typename type, typename holder_type = std::unique_ptr<type>> struct instance { template <typename type, typename holder_type = std::unique_ptr<type>> struct instance {
PyObject_HEAD PyObject_HEAD

View File

@ -32,6 +32,7 @@ public:
void inc_ref() const { Py_XINCREF(m_ptr); } void inc_ref() const { Py_XINCREF(m_ptr); }
void dec_ref() const { Py_XDECREF(m_ptr); } void dec_ref() const { Py_XDECREF(m_ptr); }
int ref_count() const { return (int) Py_REFCNT(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[](handle key);
inline detail::accessor operator[](const char *key); inline detail::accessor operator[](const char *key);
inline detail::accessor attr(handle key); inline detail::accessor attr(handle key);
@ -325,6 +326,17 @@ public:
class function : public object { class function : public object {
public: public:
PYBIND_OBJECT_DEFAULT(function, object, PyFunction_Check) 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 { class buffer : public object {
@ -365,5 +377,30 @@ inline internals &get_internals() {
} }
return *internals_ptr; 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(detail)
NAMESPACE_END(pybind) NAMESPACE_END(pybind)