From 96c10530aa506341863c1acf9660a1e4551f340d Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 1 Oct 2015 16:42:15 +0200 Subject: [PATCH] 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 --- include/pybind/common.h | 3 +++ include/pybind/pytypes.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/pybind/common.h b/include/pybind/common.h index d327ab6af..3a95210b5 100644 --- a/include/pybind/common.h +++ b/include/pybind/common.h @@ -41,6 +41,7 @@ #endif #endif #include +#include #ifdef isalnum #undef isalnum #undef isalpha @@ -122,6 +123,8 @@ struct cast_error : public std::runtime_error { public: cast_error(const NAMESPACE_BEGIN(detail) +inline std::string error_string(); + /// PyObject wrapper around generic types template > struct instance { PyObject_HEAD diff --git a/include/pybind/pytypes.h b/include/pybind/pytypes.h index e9a60e9c6..4559ffbcb 100644 --- a/include/pybind/pytypes.h +++ b/include/pybind/pytypes.h @@ -32,6 +32,7 @@ public: 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 @@ public: 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 @@ inline internals &get_internals() { } 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)