2

In some places in exposing C++ code to python, I need to use a PyObject*. If I have an instance of a boost::python::class_ object, I can invoke ptr() on it. But what if I just have the type?

Basically, given the type list boost::python::bases<A, B, C>, I want to convert this to a boost::python::tuple of instances that I can pass into something like PyErr_NewExceptionWithDoc(). Is this possible?

1
  • In retrospect, even if this were possible, it's apparently impossible to create a python type that inherits from both a Python exception type and a Boost.Python class_. So I guess this is more curiosity than practicality. Commented Jul 6, 2016 at 14:30

1 Answer 1

1

Given a C++ type T, one can create a boost::python::type_id object, and then query into the Boost.Python registry for registration information. If an entry is found in the registry, then one can use it to obtain a handle to the Python class created for type T:

/// @brief Get the class object for a wrapped type that has been exposed
///        through Boost.Python.
template <typename T>
boost::python::object get_instance_class()
{
  // Query into the registry for type T.
  namespace python = boost::python;
  python::type_info type = python::type_id<T>();
  const python::converter::registration* registration =
    python::converter::registry::query(type);

  // If the class is not registered, return None.
  if (!registration) return python::object();

  python::handle<PyTypeObject> handle(python::borrowed(
    registration->get_class_object()));
  return python::object(handle);
}

Here is a complete example demonstrating locating a Python class object in the Boost.Python registry:

#include <boost/python.hpp>
#include <iostream>

/// @brief Get the class object for a wrapped type that has been exposed
///        through Boost.Python.
template <typename T>
boost::python::object get_instance_class()
{
  // Query into the registry for type T.
  namespace python = boost::python;
  python::type_info type = python::type_id<T>();
  const python::converter::registration* registration =
    python::converter::registry::query(type);

  // If the class is not registered, return None.
  if (!registration) return python::object();

  python::handle<PyTypeObject> handle(python::borrowed(
    registration->get_class_object()));
  return python::object(handle);
}

struct spam {};

int main()
{
  Py_Initialize();

  namespace python = boost::python;
  try
  {
    // Create the __main__ module.
    python::object main_module = python::import("__main__");
    python::object main_namespace = main_module.attr("__dict__");

    // Create `Spam` class.
    // >>> class Spam: pass
    auto spam_class_object = python::class_<spam>("Spam", python::no_init);
    // >>> print Spam
    main_module.attr("__builtins__").attr("print")(get_instance_class<spam>());
    // >>> assert(spam is spam)
    assert(spam_class_object.ptr() == get_instance_class<spam>().ptr());
  }
  catch (python::error_already_set&)
  {
    PyErr_Print();
    return 1;
  }
}

Output:

<class 'Spam'>

For more type related functionality, such as accepting type objects, is, and issubclass, see this answer.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.