...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
error_already_set
error_already_set
synopsis<boost/python/errors.hpp>
provides types and
functions for managing and translating between Python and C++ exceptions.
This is relatively low-level functionality that is mostly used internally
by Boost.Python. Users should seldom need it.
error_already_set
error_already_set
is an exception type which can be
thrown to indicate that a Python error has occurred. If thrown, the
precondition is that PyErr_Occurred()
returns a value convertible to true
. Portable code shouldn't
throw this exception type directly, but should instead use throw_error_already_set()
,
below.
namespace boost { namespace python { class error_already_set {}; }}
template <class T> bool handle_exception(T f) throw(); void handle_exception() throw();
function0<void>(f)
is valid. The second form requires that a C++ exception is currently
being handled (see section 15.1 in the C++ standard).f()
inside a
try
block which first attempts to use all registered exception translators. If none of
those translates the exception, the catch
clauses then set
an appropriate Python exception for the C++ exception caught, returning
true
if an exception was thrown, false
otherwise. The second form passes a function which rethrows the
exception currently being handled to the first form.handle_exception
to manage exception
translation whenever your C++ code is called directly from the Python
API. This is done for you automatically by the usual function wrapping
facilities: make_function()
,
make_constructor()
,
def()
and class_::def()
. The second form can be
more convenient to use (see the example below),
but various compilers have problems when exceptions are rethrown from
within an enclosing try
block.template <class T> T* expect_non_null(T* x);
x
error_already_set()
iff x ==
0
.void throw_error_already_set();
throw error_already_set();
catch
block in handle_exception()
can catch the
exception.#include <string> #include <boost/python/errors.hpp> #include <boost/python/object.hpp> #include <boost/python/handle.hpp> // Returns a std::string which has the same value as obj's "__name__" // attribute. std::string get_name(boost::python::object obj) { // throws if there's no __name__ attribute PyObject* p = boost::python::expect_non_null( PyObject_GetAttrString(obj.ptr(), "__name__")); char const* s = PyString_AsString(p); if (s != 0) Py_DECREF(p); // throws if it's not a Python string std::string result( boost::python::expect_non_null( PyString_AsString(p))); Py_DECREF(p); // Done with p return result; } // // Demonstrate form 1 of handle_exception // // Place into result a Python Int object whose value is 1 if a and b have // identical "__name__" attributes, 0 otherwise. void same_name_impl(PyObject*& result, boost::python::object a, boost::python::object b) { result = PyInt_FromLong( get_name(a) == get_name(a2)); } object borrowed_object(PyObject* p) { return boost::python::object( boost::python::handle<>( boost::python::borrowed(a1))); } // This is an example Python 'C' API interface function extern "C" PyObject* same_name(PyObject* args, PyObject* keywords) { PyObject* a1; PyObject* a2; PyObject* result = 0; if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2)) return 0; // Use boost::bind to make an object compatible with // boost::Function0<void> if (boost::python::handle_exception( boost::bind<void>(same_name_impl, boost::ref(result), borrowed_object(a1), borrowed_object(a2)))) { // an exception was thrown; the Python error was set by // handle_exception() return 0; } return result; } // // Demonstrate form 2 of handle_exception. Not well-supported by all // compilers. // extern "C" PyObject* same_name2(PyObject* args, PyObject* keywords) { PyObject* a1; PyObject* a2; PyObject* result = 0; if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2)) return 0; try { return PyInt_FromLong( get_name(borrowed_object(a1)) == get_name(borrowed_object(a2))); } catch(...) { // If an exception was thrown, translate it to Python boost::python::handle_exception(); return 0; } }
Revised 13 November, 2002
© Copyright Dave Abrahams 2002.