[section boost/python/errors.hpp]
[section Introduction]
<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.
[endsect]
[section Class `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 [@http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71 PyErr_Occurred()] returns a value convertible to `true`. Portable code shouldn't throw this exception type directly, but should instead use [link high_level_components.boost_python_errors_hpp.functions throw_error_already_set()], below.
``
namespace boost { namespace python
{
    class error_already_set {};
}}
``
[endsect]
[section Functions]
``
template <class T> bool handle_exception(T f) throw();
void handle_exception() throw();
``
[variablelist
[[Requires][The first form requires that the expression 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).]]
[[Effects][The first form calls f() inside a try block which first attempts to use all registered [link high_level_components.boost_python_exception_translato 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.]]
[[Postconditions][No exception is being handled]]
[[Throws][nothing]]
[[Rationale][At inter-language boundaries it is important to ensure that no C++ exceptions escape, since the calling language usually doesn't have the equipment necessary to properly unwind the stack. Use 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: [link function_invocation_and_creation.boost_python_make_function_hpp.functions make_function()], [link function_invocation_and_creation.boost_python_make_function_hpp.functions make_constructor()], [link high_level_components.boost_python_def_hpp.functions def()] and [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu 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);``
[variablelist
[[Returns][x]]
[[Throws][error_already_set() iff x == 0.]]
[[Rationale][Simplifies error-handling when calling functions in the Python/C API which return 0 on error.]]
]
``void throw_error_already_set();``
[variablelist
[[Effects][throw error_already_set();]]
[[Rationale][Simplifies error-handling when calling functions in the Python/C API which return 0 on error.]]
]
``void throw_error_already_set();``
[variablelist
[[Effects][throw error_already_set();]]
[[Rationale][Many platforms and compilers are not able to consistently catch exceptions thrown across shared library boundaries. Using this function from the Boost.Python library ensures that the appropriate catch block in handle_exception() can catch the exception.]]
]
[endsect]
[section Example]
``
#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;
   }
}
``
[endsect]
[endsect]
