123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- // Copyright Stefan Seefeld 2005.
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #include <boost/python.hpp>
- #include <boost/detail/lightweight_test.hpp>
- #include <iostream>
- namespace python = boost::python;
- // An abstract base class
- class Base : public boost::noncopyable
- {
- public:
- virtual ~Base() {};
- virtual std::string hello() = 0;
- };
- // C++ derived class
- class CppDerived : public Base
- {
- public:
- virtual ~CppDerived() {}
- virtual std::string hello() { return "Hello from C++!";}
- };
- // Familiar Boost.Python wrapper class for Base
- struct BaseWrap : Base, python::wrapper<Base>
- {
- virtual std::string hello()
- {
- #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
- // workaround for VC++ 6.x or 7.0, see
- // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
- return python::call<std::string>(this->get_override("hello").ptr());
- #else
- return this->get_override("hello")();
- #endif
- }
- };
- // Pack the Base class wrapper into a module
- BOOST_PYTHON_MODULE(embedded_hello)
- {
- python::class_<BaseWrap, boost::noncopyable> base("Base");
- }
- void eval_test()
- {
- python::object result = python::eval("'abcdefg'.upper()");
- std::string value = python::extract<std::string>(result) BOOST_EXTRACT_WORKAROUND;
- BOOST_TEST(value == "ABCDEFG");
- }
- void exec_test()
- {
- // Retrieve the main module
- python::object main = python::import("__main__");
-
- // Retrieve the main module's namespace
- python::object global(main.attr("__dict__"));
- // Define the derived class in Python.
- python::object result = python::exec(
- "from embedded_hello import * \n"
- "class PythonDerived(Base): \n"
- " def hello(self): \n"
- " return 'Hello from Python!' \n",
- global, global);
- python::object PythonDerived = global["PythonDerived"];
- // Creating and using instances of the C++ class is as easy as always.
- CppDerived cpp;
- BOOST_TEST(cpp.hello() == "Hello from C++!");
- // But now creating and using instances of the Python class is almost
- // as easy!
- python::object py_base = PythonDerived();
- Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND;
- // Make sure the right 'hello' method is called.
- BOOST_TEST(py.hello() == "Hello from Python!");
- }
- void exec_file_test(std::string const &script)
- {
- // Run a python script in an empty environment.
- python::dict global;
- python::object result = python::exec_file(script.c_str(), global, global);
- // Extract an object the script stored in the global dictionary.
- BOOST_TEST(python::extract<int>(global["number"]) == 42);
- }
- void exec_test_error()
- {
- // Execute a statement that raises a python exception.
- python::dict global;
- python::object result = python::exec("print(unknown) \n", global, global);
- }
- void exercise_embedding_html()
- {
- using namespace boost::python;
- /* code from: libs/python/doc/tutorial/doc/tutorial.qbk
- (generates libs/python/doc/tutorial/doc/html/python/embedding.html)
- */
- object main_module = import("__main__");
- object main_namespace = main_module.attr("__dict__");
- object ignored = exec("hello = file('hello.txt', 'w')\n"
- "hello.write('Hello world!')\n"
- "hello.close()",
- main_namespace);
- }
- void check_pyerr(bool pyerr_expected=false)
- {
- if (PyErr_Occurred())
- {
- if (!pyerr_expected) {
- BOOST_ERROR("Python Error detected");
- PyErr_Print();
- }
- else {
- PyErr_Clear();
- }
- }
- else
- {
- BOOST_ERROR("A C++ exception was thrown for which "
- "there was no exception handler registered.");
- }
- }
- int main(int argc, char **argv)
- {
- BOOST_TEST(argc == 2 || argc == 3);
- std::string script = argv[1];
- // Register the module with the interpreter
- if (PyImport_AppendInittab(const_cast<char*>("embedded_hello"),
- #if PY_VERSION_HEX >= 0x03000000
- PyInit_embedded_hello
- #else
- initembedded_hello
- #endif
- ) == -1)
- {
- BOOST_ERROR("Failed to add embedded_hello to the interpreter's "
- "builtin modules");
- }
- // Initialize the interpreter
- Py_Initialize();
- if (python::handle_exception(eval_test)) {
- check_pyerr();
- }
- else if(python::handle_exception(exec_test)) {
- check_pyerr();
- }
- else if (python::handle_exception(boost::bind(exec_file_test, script))) {
- check_pyerr();
- }
-
- if (python::handle_exception(exec_test_error))
- {
- check_pyerr(/*pyerr_expected*/ true);
- }
- else
- {
- BOOST_ERROR("Python exception expected, but not seen.");
- }
- if (argc > 2) {
- // The main purpose is to test compilation. Since this test generates
- // a file and I (rwgk) am uncertain about the side-effects, run it only
- // if explicitly requested.
- exercise_embedding_html();
- }
- // Boost.Python doesn't support Py_Finalize yet.
- // Py_Finalize();
- return boost::report_errors();
- }
- // Including this file makes sure
- // that on Windows, any crashes (e.g. null pointer dereferences) invoke
- // the debugger immediately, rather than being translated into structured
- // exceptions that can interfere with debugging.
- #include "module_tail.cpp"
|