1

I simply have a function object:

boost::function<int(int)> func = /** ... **/;

And want to expose it to Python with a docstring.
But the obvious:

def("func", func, "Some boring documentation goes here.");

Fails with an amusing ~2500 lines message.

Any ideas?


Edit: I made other tests:

def("func", func); // doesn't compile

def("func",
   make_function(
     func,
     default_call_policies(),
     vector<int,int>()
   )
); // compiles

def("func",
   make_function(
     func,
     default_call_policies(),
     vector<int,int>()
   ),
   "Some boring documentation goes here"
); // doesn't compile
7
  • 1
    Does it work without the docstring? I would imagine the docstring is not your problem here. Commented Mar 25, 2013 at 21:28
  • Any reason why you can't expose the function you're wrapping directly to Python without the boost::function intermediary? Commented Mar 25, 2013 at 21:30
  • @KyleC no, you're right. but see my edit (the docstring could be the problem). Commented Mar 25, 2013 at 21:32
  • @Praetorian The boost::function comes from doing a bind(...). Commented Mar 25, 2013 at 21:34
  • So, I can expose it via make_function, but if I add the docstring it fails. Commented Mar 25, 2013 at 21:46

1 Answer 1

2

The boost::python::def() documentation mentions being able to provide a docstring only when provided a non-null function or member function pointer. One solution is to wrap the function object call in a function:

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

int times_two(int x) { return x * 2; }

boost::function<int(int)> func = &times_two;

int times_two_wrap(int x) { return func(x); }

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("times_two", &times_two_wrap,
              "returns two times the supplied value");
}

Interactive usage:

>>> import example
>>> assert(6 == example.times_two(3))
>>> print help(example.times_two)

times_two( (int)arg1) -> int :
    returns two times the supplied value

    C++ signature :
        int times_two(int)
>>>

Boost.Python has multiple API layers. The highest layer is mostly documented, but it makes use of a less-documented lower-level API. In this particular case, it looks as though the higher-level API is poorly forwarding to the lower-level API. One could instead create a python function using boost::python::make_function(), then use the lower-level boost::python::objects::add_to_namespace() function, as demonstrated below:

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

int times_two(int x) { return x * 2; }

boost::function<int(int)> func = &times_two;

BOOST_PYTHON_MODULE(example)
{
   namespace python = boost::python;
   // Wrap the functor in a Python object.
   python::object py_func = python::make_function(
     func,
     python::default_call_policies(),
     boost::mpl::vector<int, int>());
   // Add the function directly to the namespace.
   python::objects::add_to_namespace(
     python::scope(), // current namespace,
     "times_two",     // function name,
     py_func,         // function,
     "returns two times the supplied value");
}

This produces the same output with the interactive usage. The only notable behavioral difference between the two approaches is that the first example enables one to change the underlying implementation at runtime by assigning a new value to func.

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

3 Comments

Thank you. Keep in mind you can probably patch the docstring from C++: object func = make_function(...) and then func["__doc__"] = "patched docstring".
@jmendeth: I tried this on a function object created with raw_function(). The code compiles, but running gives me an error message: TypeError: 'Boost.Python.function' object does not support item assignment
@jmendeth -- setattr() works: object f = raw_function(&func, 1); setattr(f, "__doc__", str("doc")); def("func", f);

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.