exec.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. #include <boost/python.hpp>
  6. #include <boost/detail/lightweight_test.hpp>
  7. #include <iostream>
  8. namespace python = boost::python;
  9. // An abstract base class
  10. class Base : public boost::noncopyable
  11. {
  12. public:
  13. virtual ~Base() {};
  14. virtual std::string hello() = 0;
  15. };
  16. // C++ derived class
  17. class CppDerived : public Base
  18. {
  19. public:
  20. virtual ~CppDerived() {}
  21. virtual std::string hello() { return "Hello from C++!";}
  22. };
  23. // Familiar Boost.Python wrapper class for Base
  24. struct BaseWrap : Base, python::wrapper<Base>
  25. {
  26. virtual std::string hello()
  27. {
  28. #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
  29. // workaround for VC++ 6.x or 7.0, see
  30. // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
  31. return python::call<std::string>(this->get_override("hello").ptr());
  32. #else
  33. return this->get_override("hello")();
  34. #endif
  35. }
  36. };
  37. // Pack the Base class wrapper into a module
  38. BOOST_PYTHON_MODULE(embedded_hello)
  39. {
  40. python::class_<BaseWrap, boost::noncopyable> base("Base");
  41. }
  42. void eval_test()
  43. {
  44. python::object result = python::eval("'abcdefg'.upper()");
  45. std::string value = python::extract<std::string>(result) BOOST_EXTRACT_WORKAROUND;
  46. BOOST_TEST(value == "ABCDEFG");
  47. }
  48. void exec_test()
  49. {
  50. // Retrieve the main module
  51. python::object main = python::import("__main__");
  52. // Retrieve the main module's namespace
  53. python::object global(main.attr("__dict__"));
  54. // Define the derived class in Python.
  55. python::object result = python::exec(
  56. "from embedded_hello import * \n"
  57. "class PythonDerived(Base): \n"
  58. " def hello(self): \n"
  59. " return 'Hello from Python!' \n",
  60. global, global);
  61. python::object PythonDerived = global["PythonDerived"];
  62. // Creating and using instances of the C++ class is as easy as always.
  63. CppDerived cpp;
  64. BOOST_TEST(cpp.hello() == "Hello from C++!");
  65. // But now creating and using instances of the Python class is almost
  66. // as easy!
  67. python::object py_base = PythonDerived();
  68. Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND;
  69. // Make sure the right 'hello' method is called.
  70. BOOST_TEST(py.hello() == "Hello from Python!");
  71. }
  72. void exec_file_test(std::string const &script)
  73. {
  74. // Run a python script in an empty environment.
  75. python::dict global;
  76. python::object result = python::exec_file(script.c_str(), global, global);
  77. // Extract an object the script stored in the global dictionary.
  78. BOOST_TEST(python::extract<int>(global["number"]) == 42);
  79. }
  80. void exec_test_error()
  81. {
  82. // Execute a statement that raises a python exception.
  83. python::dict global;
  84. python::object result = python::exec("print(unknown) \n", global, global);
  85. }
  86. void exercise_embedding_html()
  87. {
  88. using namespace boost::python;
  89. /* code from: libs/python/doc/tutorial/doc/tutorial.qbk
  90. (generates libs/python/doc/tutorial/doc/html/python/embedding.html)
  91. */
  92. object main_module = import("__main__");
  93. object main_namespace = main_module.attr("__dict__");
  94. object ignored = exec("hello = file('hello.txt', 'w')\n"
  95. "hello.write('Hello world!')\n"
  96. "hello.close()",
  97. main_namespace);
  98. }
  99. void check_pyerr(bool pyerr_expected=false)
  100. {
  101. if (PyErr_Occurred())
  102. {
  103. if (!pyerr_expected) {
  104. BOOST_ERROR("Python Error detected");
  105. PyErr_Print();
  106. }
  107. else {
  108. PyErr_Clear();
  109. }
  110. }
  111. else
  112. {
  113. BOOST_ERROR("A C++ exception was thrown for which "
  114. "there was no exception handler registered.");
  115. }
  116. }
  117. int main(int argc, char **argv)
  118. {
  119. BOOST_TEST(argc == 2 || argc == 3);
  120. std::string script = argv[1];
  121. // Register the module with the interpreter
  122. if (PyImport_AppendInittab(const_cast<char*>("embedded_hello"),
  123. #if PY_VERSION_HEX >= 0x03000000
  124. PyInit_embedded_hello
  125. #else
  126. initembedded_hello
  127. #endif
  128. ) == -1)
  129. {
  130. BOOST_ERROR("Failed to add embedded_hello to the interpreter's "
  131. "builtin modules");
  132. }
  133. // Initialize the interpreter
  134. Py_Initialize();
  135. if (python::handle_exception(eval_test)) {
  136. check_pyerr();
  137. }
  138. else if(python::handle_exception(exec_test)) {
  139. check_pyerr();
  140. }
  141. else if (python::handle_exception(boost::bind(exec_file_test, script))) {
  142. check_pyerr();
  143. }
  144. if (python::handle_exception(exec_test_error))
  145. {
  146. check_pyerr(/*pyerr_expected*/ true);
  147. }
  148. else
  149. {
  150. BOOST_ERROR("Python exception expected, but not seen.");
  151. }
  152. if (argc > 2) {
  153. // The main purpose is to test compilation. Since this test generates
  154. // a file and I (rwgk) am uncertain about the side-effects, run it only
  155. // if explicitly requested.
  156. exercise_embedding_html();
  157. }
  158. // Boost.Python doesn't support Py_Finalize yet.
  159. // Py_Finalize();
  160. return boost::report_errors();
  161. }
  162. // Including this file makes sure
  163. // that on Windows, any crashes (e.g. null pointer dereferences) invoke
  164. // the debugger immediately, rather than being translated into structured
  165. // exceptions that can interfere with debugging.
  166. #include "module_tail.cpp"