C++ Boost

Boost.Python

Header <boost/python/errors.hpp>


Contents

Introduction
Classes
Class error_already_set
Class error_already_set synopsis
Functions
handle_exception
expect_non_null
Examples

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.

Classes

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 PyErr_Occurred() returns a value convertible to true.

Class error_already_set synopsis

namespace boost { namespace python
{
    class error_already_set {};
}}

Functions

template <class T> bool handle_exception(T f) throw();

void handle_exception() throw();
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 whose catch clauses set an appropriate Python exception for the C++ exception caught, returning true if an exception was caught, 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 neccessary 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: make_function(), make_constructor(), module::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.
PyObject* expect_non_null(PyObject* x);

template <class T> T* expect_non_null(T* x);
Returns: x
Throws: error_already_set() iff x == 0.
Rationale: Simplifies error-handling when calling many functions in the Python/C API, which return 0 on error.

Examples

#include <string>
#include <boost/python/errors.hpp>
#include <boost/python/reference.hpp>

// Returns a std::string which has the same value as obj's "__name__"
// attribute.
std::string get_name(boost::python::ref obj)
{
   // throws if there's no __name__ attribute
   PyObject* p = boost::python::expect_non_null(
      PyObject_GetAttrString(obj.get(), "__name__"));

   // throws if it's not a Python string
   std::string result(
      boost::python::expect_non_null(
         PyString_AsString(p)));

   Py_XDECREF(p); // Done with p
   
   return result;
}

//
// Demonstrate form 1 of handle_exception
//

// Place a Python Int object whose value is 1 if a and b have
// identical "__name__" attributes, 0 otherwise.
void same_name_impl(PyObject*& result, PyObject* a, PyObject* b)
{
   result = PyInt_FromLong(
      get_name(boost::python::ref(a1)) == get_name(boost::python::ref(a2)));
}

// 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), a1, 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(boost::python::ref(a1)) == get_name(boost::python::ref(a2)));
   }
   catch(...)
   {
      // If an exception was thrown, translate it to Python
      boost::python::handle_exception();
      return 0;
   }
}

Revised 05 November, 2001

© Copyright Dave Abrahams 2002. All Rights Reserved.