c253c5cc9c
[SVN r37585]
155 lines
4.3 KiB
C++
155 lines
4.3 KiB
C++
// 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 exec_test()
|
|
{
|
|
std::cout << "registering extension module embedded_hello..." << std::endl;
|
|
|
|
// Register the module with the interpreter
|
|
if (PyImport_AppendInittab("embedded_hello", initembedded_hello) == -1)
|
|
throw std::runtime_error("Failed to add embedded_hello to the interpreter's "
|
|
"builtin modules");
|
|
|
|
std::cout << "defining Python class derived from Base..." << std::endl;
|
|
|
|
// 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++!");
|
|
|
|
std::cout << "testing derived class from C++..." << std::endl;
|
|
|
|
// 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!");
|
|
|
|
std::cout << "success!" << std::endl;
|
|
}
|
|
|
|
void exec_file_test(std::string const &script)
|
|
{
|
|
std::cout << "running file " << script << "..." << std::endl;
|
|
|
|
// 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);
|
|
|
|
std::cout << "success!" << std::endl;
|
|
}
|
|
|
|
void exec_test_error()
|
|
{
|
|
std::cout << "intentionally causing a python exception..." << std::endl;
|
|
|
|
// Execute a statement that raises a python exception.
|
|
python::dict global;
|
|
python::object result = python::exec("print unknown \n", global, global);
|
|
|
|
std::cout << "Oops! This statement should be skipped due to an exception" << std::endl;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
BOOST_TEST(argc == 2);
|
|
std::string script = argv[1];
|
|
// Initialize the interpreter
|
|
Py_Initialize();
|
|
|
|
bool error_expected = false;
|
|
|
|
if (
|
|
python::handle_exception(exec_test)
|
|
|| python::handle_exception(boost::bind(exec_file_test, script))
|
|
|| (
|
|
(error_expected = true)
|
|
&& python::handle_exception(exec_test_error)
|
|
)
|
|
|
|
)
|
|
{
|
|
if (PyErr_Occurred())
|
|
{
|
|
if (!error_expected)
|
|
BOOST_ERROR("Python Error detected");
|
|
PyErr_Print();
|
|
}
|
|
else
|
|
{
|
|
BOOST_ERROR("A C++ exception was thrown for which "
|
|
"there was no exception translator registered.");
|
|
}
|
|
}
|
|
|
|
// Boost.Python doesn't support Py_Finalize yet, so don't call it!
|
|
return boost::report_errors();
|
|
}
|