Advertisement
patlecat

embedding.cpp from Boost.Python

Nov 6th, 2014
620
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.40 KB | None | 0 0
  1. // Copyright Stefan Seefeld 2005.
  2. // Distributed under the Boost Software License, Version 1.0. (See
  3. // accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5.  
  6. #include <boost/python.hpp>
  7.  
  8. #include <boost/detail/lightweight_test.hpp>
  9. #include <iostream>
  10.  
  11. namespace python = boost::python;
  12.  
  13. // An abstract base class
  14. class Base : public boost::noncopyable
  15. {
  16. public:
  17.   virtual ~Base() {};
  18.   virtual std::string hello() = 0;
  19. };
  20.  
  21. // C++ derived class
  22. class CppDerived : public Base
  23. {
  24. public:
  25.   virtual ~CppDerived() {}
  26.   virtual std::string hello() { return "Hello from C++!";}
  27. };
  28.  
  29. // Familiar Boost.Python wrapper class for Base
  30. struct BaseWrap : Base, python::wrapper<Base>
  31. {
  32.   virtual std::string hello()
  33.   {
  34. #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
  35.     // workaround for VC++ 6.x or 7.0, see
  36.     // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
  37.     return python::call<std::string>(this->get_override("hello").ptr());
  38. #else
  39.     return this->get_override("hello")();
  40. #endif
  41.   }
  42. };
  43.  
  44. // Pack the Base class wrapper into a module
  45. BOOST_PYTHON_MODULE(embedded_hello)
  46. {
  47.   python::class_<BaseWrap, boost::noncopyable> base("Base");
  48. }
  49.  
  50.  
  51. void exec_test()
  52. {
  53.     std::cout << "registering extension module embedded_hello..." << std::endl;
  54.    
  55.   // Register the module with the interpreter
  56.   if (PyImport_AppendInittab("embedded_hello", PyInit_embedded_hello) == -1)
  57.     throw std::runtime_error("Failed to add embedded_hello to the interpreter's "
  58.                  "builtin modules");
  59.  
  60.   std::cout << "defining Python class derived from Base..." << std::endl;
  61.  
  62.   // Retrieve the main module
  63.   python::object main = python::import("__main__");
  64.  
  65.   // Retrieve the main module's namespace
  66.   python::object global(main.attr("__dict__"));
  67.  
  68.   // Define the derived class in Python.
  69.   python::object result = python::exec(
  70.     "from embedded_hello import *        \n"
  71.     "class PythonDerived(Base):          \n"
  72.     "    def hello(self):                \n"
  73.     "        return 'Hello from Python!' \n",
  74.     global, global);
  75.  
  76.   python::object PythonDerived = global["PythonDerived"];
  77.  
  78.   // Creating and using instances of the C++ class is as easy as always.
  79.   CppDerived cpp;
  80.   BOOST_TEST(cpp.hello() == "Hello from C++!");
  81.  
  82.   std::cout << "testing derived class from C++..." << std::endl;
  83.  
  84.   // But now creating and using instances of the Python class is almost
  85.   // as easy!
  86.   python::object py_base = PythonDerived();
  87.   Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND;
  88.  
  89.   // Make sure the right 'hello' method is called.
  90.   BOOST_TEST(py.hello() == "Hello from Python!");
  91.  
  92.   std::cout << "success!" << std::endl;
  93. }
  94.  
  95. void exec_file_test(std::string const &script)
  96. {
  97.     std::cout << "running file " << script << "..." << std::endl;
  98.    
  99.     // Run a python script in an empty environment.
  100.     python::dict global;
  101.     python::object result = python::exec_file(script.c_str(), global, global);
  102.  
  103.     // Extract an object the script stored in the global dictionary.
  104.     BOOST_TEST(python::extract<int>(global["number"]) ==  42);
  105.    
  106.     std::cout << "success!" << std::endl;
  107. }
  108.  
  109. void exec_test_error()
  110. {
  111.     std::cout << "intentionally causing a python exception..." << std::endl;
  112.    
  113.     // Execute a statement that raises a python exception.
  114.     python::dict global;
  115.     python::object result = python::exec("print unknown \n", global, global);
  116.  
  117.     std::cout << "Oops! This statement should be skipped due to an exception" << std::endl;
  118. }
  119.  
  120. int main(int argc, char **argv)
  121. {
  122.   BOOST_TEST(argc == 2);
  123.   std::string script = argv[1];
  124.   // Initialize the interpreter
  125.   Py_Initialize();
  126.  
  127.   bool error_expected = false;
  128.  
  129.   if (
  130.       python::handle_exception(exec_test)
  131.       || python::handle_exception(boost::bind(exec_file_test, script))
  132.       || (
  133.           (error_expected = true)
  134.           && python::handle_exception(exec_test_error)
  135.       )
  136.  
  137.   )
  138.   {
  139.     if (PyErr_Occurred())
  140.     {
  141.         if (!error_expected)
  142.             BOOST_ERROR("Python Error detected");
  143.         PyErr_Print();
  144.     }
  145.     else
  146.     {
  147.         BOOST_ERROR("A C++ exception was thrown  for which "
  148.                     "there was no exception translator registered.");
  149.     }
  150.   }
  151.  
  152.   // Boost.Python doesn't support Py_Finalize yet, so don't call it!
  153.   return boost::report_errors();
  154. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement