// 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 #include #include #include #include #include #include #include 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) #define CLASS_CB(c) class_, 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(m_self, #fn); } \ rtn base_##fn() { return __base__::fn(); } #define CALLBACK_MEMBER0C(fn, rtn) \ rtn fn() const { return call_method(m_self, #fn); } \ rtn base_##fn() const { return __base__::fn(); } // End of convenience macros // useful support classes template 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(ptr())(ptr()); } T* m_class_ptr; }; template struct item_object : public object { typedef object base; item_object() {} item_object(object const& o) : base(o), m_class(arg_from_python(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(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_INIT(python_main) { DEF(python_main); CLASS(main_args); } // sub module tests namespace sm { int test_func() { return 7; } BOOST_PYTHON_MODULE_INIT(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_INIT(sc_test) { class_("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 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; }