libs/python/test/submod_subclass_api.cpp
// Copyright David Hawkes 2002.
// Permission is hereby granted to copy, use and modify this software
// for any purpose, including commercial distribution, provided this
// copyright notice is not removed. No warranty WHATSOEVER is provided with this
// software. Any user(s) accepts this software "as is" and as such they will not
// bind the author(s) to any claim of suitabilty for any purpose.
// embed_test.cpp : substantial test of embedding python in c++ using boost
#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/call_method.hpp>
#include <boost/python/call.hpp>
#include <boost/python/object.hpp>
#include <boost/python/py_interface.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
using namespace boost;
using namespace boost::python;
// The following macros are for our convenience and coding expediency...
// There is no particular recomendation that they be used elsewhere
// as they are not feature complete and are just sufficient to suport
// the code here
#define DEF(fn) def(#fn, fn)
#define DEF_C(c, fn) def(#fn, &c::fn)
#define DEF_C_CB(c, fn) def(#fn, &c##_callback::base_##fn)
#define CLASS(c) class_<c, shared_ptr<c> >(#c)
#define CLASS_CB(c) class_<c, shared_ptr<c##_callback>, noncopyable >(#c)
#define START_CALLBACK_CLASS(c) \
class c##_callback : public c \
{ \
typedef c __base__; \
public: \
c##_callback(PyObject* self) : m_self(self) {} \
private: \
PyObject* m_self; \
public:
#define END_CALLBACK_CLASS };
#define CALLBACK_MEMBER0(fn, rtn) \
rtn fn() { return call_method<rtn>(m_self, #fn); } \
rtn base_##fn() { return __base__::fn(); }
#define CALLBACK_MEMBER0C(fn, rtn) \
rtn fn() const { return call_method<rtn>(m_self, #fn); } \
rtn base_##fn() const { return __base__::fn(); }
// End of convenience macros
// useful support classes
template<class T>
struct class_object : public object
{
typedef object base;
class_object() : m_class_ptr(NULL) {}
class_object(object const& o) : base(o) { init(); }
class_object& operator=(object const& o)
{
base::operator=(o);
init();
return *this;
}
T* operator->() const { return m_class_ptr; }
T& operator*() const { return *m_class_ptr; }
private:
void init()
{
m_class_ptr = arg_from_python<T*>(ptr())(ptr());
}
T* m_class_ptr;
};
template<class T>
struct item_object : public object
{
typedef object base;
item_object() {}
item_object(object const& o) : base(o), m_class(arg_from_python<T>(ptr())(ptr())) {}
item_object& operator=(object const& o)
{
base::operator=(o);
init();
return *this;
}
operator T() { return m_class; }
private:
void init()
{
m_class = arg_from_python<T>(ptr())(ptr());
}
T m_class;
};
// end of useful support classes
// pass our args in this struct
struct main_args {
main_args(int _argc, char* _argv[]) : argc(_argc), argv(_argv) {}
int argc;
char** argv;
};
int python_main(main_args const &ma);
// python module init
BOOST_PYTHON_MODULE(python_main)
{
DEF(python_main);
CLASS(main_args);
}
// sub module tests
namespace sm {
int test_func() { return 7; }
BOOST_PYTHON_MODULE(sm_test)
{
// define a submodule
boost::python::module(".sm");
// define a 2nd submodule
boost::python::module(".sm.sm2");
// define a test function to appear in 2nd submodule
DEF(test_func);
}
// sub-module tests
int test()
{
api::run_simple_string("import sm_test");
if(api::call_statement("_0 = bpl_test('sub modules', sm_test.sm.sm2.test_func, _1)", test_func()))
return 1;
return 0;
}
}
// sub class tests
namespace sc {
class c1 {
public:
c1() {}
class c2 {
public:
c2() : n(2) {}
int n;
};
c2 t;
};
c1::c2 test_func() {
return c1().t;
}
BOOST_PYTHON_MODULE(sc_test)
{
class_<c1::c2>("c1.c2")
.def_init()
.def_readwrite("n", &c1::c2::n);
CLASS(c1)
.def_init()
.def_readwrite("t", &c1::t);
DEF(test_func);
}
// sub-class tests
int test()
{
api::run_simple_string("import sc_test");
if(api::call_statement("_0 = bpl_test('sub classes', lambda : sc_test.c1.c2().n, _1.n)", test_func()))
return 1;
if(api::call_statement("_0 = bpl_test('sub classes', lambda : sc_test.c1().t.n, _1.n)", test_func()))
return 1;
return 0;
}
}
// new main that will have a python execution frame
int main(int argc, char* argv[])
{
// default return value;
int rtn = 0;
// define all the built-in modules used
PyImport_AppendInittab("python_main", initpython_main);
PyImport_AppendInittab("sm_test", sm::initsm_test);
PyImport_AppendInittab("sc_test", sc::initsc_test);
// initialize python
Py_Initialize();
// start a new block so that any objects are released prior to finalizing
{
// import our main module - this will also initialise boost
api::run_simple_string("import python_main");
// We call back here so we have a proper python execution frame to work with
item_object<int> o_rtn(api::call_statement("_0 = python_main.python_main(_1)", main_args(argc, argv)));
rtn = o_rtn;
}
// clean up
Py_Finalize();
return rtn;
}
char *bpl_test =
"def bpl_test(name, func, result):\n"
" print 'testing %s...' % name\n"
" if func() != result:\n"
" print 'failed'\n"
" return 1\n"
" else:\n"
" print 'OK'\n"
" return 0\n";
int python_main(main_args const &ma)
{
api::print("running...\n");
api::call_statement(bpl_test);
if(sm::test())
return 1;
if(sc::test())
return 1;
return 0;
}