diff --git a/src/exec.cpp b/src/exec.cpp index 5dfe033b..fb2a0350 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -17,14 +17,15 @@ namespace python object BOOST_PYTHON_DECL eval(str string, object global, object local) { // Set suitable default values for global and local dicts. - if (!global) + object none; + if (global.ptr() == none.ptr()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (!local) local = global; + if (local.ptr() == none.ptr()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *s = python::extract(string); PyObject* result = PyRun_String(s, Py_eval_input, global.ptr(), local.ptr()); @@ -35,14 +36,15 @@ object BOOST_PYTHON_DECL eval(str string, object global, object local) object BOOST_PYTHON_DECL exec(str string, object global, object local) { // Set suitable default values for global and local dicts. - if (!global) + object none; + if (global.ptr() == none.ptr()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (!local) local = global; + if (local.ptr() == none.ptr()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *s = python::extract(string); PyObject* result = PyRun_String(s, Py_file_input, global.ptr(), local.ptr()); @@ -53,14 +55,15 @@ object BOOST_PYTHON_DECL exec(str string, object global, object local) object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) { // Set suitable default values for global and local dicts. - if (!global) + object none; + if (global.ptr() == none.ptr()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (!local) local = global; + if (local.ptr() == none.ptr()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *s = python::extract(string); PyObject* result = PyRun_String(s, Py_single_input, global.ptr(), local.ptr()); @@ -74,14 +77,15 @@ object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) { // Set suitable default values for global and local dicts. - if (!global) + object none; + if (global.ptr() == none.ptr()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (!local) local = global; + if (local.ptr() == none.ptr()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *f = python::extract(filename); // Let python open the file to avoid potential binary incompatibilities. diff --git a/test/exec.cpp b/test/exec.cpp index 31883d89..d6874d6b 100644 --- a/test/exec.cpp +++ b/test/exec.cpp @@ -108,46 +108,73 @@ void exec_test_error() python::object result = python::exec("print unknown \n", global, global); } -int main(int argc, char **argv) +void exercise_embedding_html() { - BOOST_TEST(argc == 2); - std::string script = argv[1]; - // Initialize the interpreter - Py_Initialize(); + 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__"); - if (python::handle_exception(eval_test) || - python::handle_exception(exec_test) || - python::handle_exception(boost::bind(exec_file_test, script))) + 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_Occurred()) - { + if (!pyerr_expected) { BOOST_ERROR("Python Error detected"); PyErr_Print(); } - else - { - BOOST_ERROR("A C++ exception was thrown for which " - "there was no exception handler registered."); - } - } - - if (python::handle_exception(exec_test_error)) - { - if (PyErr_Occurred()) - { - PyErr_Print(); - } - else - { - BOOST_ERROR("A C++ exception was thrown for which " - "there was no exception handler registered."); + else { + PyErr_Clear(); } } else { - BOOST_ERROR("Python exception expected, but not seen."); + 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]; + // 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();