[C++-sig] Check number of arguments of a function object ?
Joseph Lisee
jlisee at gmail.com
Tue Feb 26 22:42:24 CET 2008
And responding to my self,
So I wanted to get this done for my project and I am sharing the code. This is
a functor class with checks the argument count. Its for an event system and it
has been tested.
The following is public domain:
/// ------------------------ EventFunctor.h ----------------------------- ///
/** Wraps a called python object, so it can handle events
*
* Then given python object is checked to make sure its calledable and has
* the proper number of arguments on functor creation.
*/
class EventFunctor
{
public:
EventFunctor(boost::python::object pyObject);
void operator()(EventPtr event);
/** The callable python object which is called to handle the event */
boost::python::object pyFunction;
};
/// ----------------------- EventFunctor.cpp ---------------------------- ///
#include <boost/python.hpp>
#include "EventFunctor.h"
namespace bp = boost::python;
EventFunctor::EventFunctor(bp::object pyObject) :
pyFunction(pyObject)
{
bool bad = false;
// Check to make sure its a callable object
if (0 == PyObject_HasAttrString(pyObject.ptr(), "__call__"))
{
// If not, lets throw an exception to warn the user
PyErr_SetString(PyExc_TypeError, "Handler must be a callable object");
bad = true;
}
else
{
int expectedArgs = 1;
// Handle function objects vs. functions
// * Free python functions have a 'func_code' attributes
// * For python function objects, their __call__ method has func_code
bp::object func_code;
if (0 == PyObject_HasAttrString(pyObject.ptr(), "func_code"))
{
// Function object, need to increment count for 'self'
expectedArgs += 1;
func_code = pyObject.attr("__call__").attr("func_code");
}
else
{
func_code = pyObject.attr("func_code");
// Handle instancemethod type callable
if (0 != PyObject_HasAttrString(pyObject.ptr(), "im_self"))
expectedArgs += 1;
}
int argCount = bp::extract<int>(func_code.attr("co_argcount"));
// 0x4 in the flags means we have a function signature with *args
int flags = bp::extract<int>(func_code.attr("co_flags"));
// To many arguments
if (argCount > expectedArgs)
{
PyErr_SetString(PyExc_TypeError,
"Handler has to many args, expected 1");
bad = true;
}
// To few arguments and no "*args" in signature
else if ((argCount < expectedArgs) && !(flags & 4))
{
PyErr_SetString(PyExc_TypeError,
"Handler has too few args, expected 1");
bad = true;
}
}
if (bad)
bp::throw_error_already_set();
}
void EventFunctor::operator()(EventPtr event)
{
pyFunction(event);
}
-Joseph Lisee
More information about the Cplusplus-sig
mailing list