diff --git a/build/Jamfile b/build/Jamfile
index 77c12b23..3d38585a 100644
--- a/build/Jamfile
+++ b/build/Jamfile
@@ -54,6 +54,8 @@ if [ check-python-config ]
object_protocol.cpp
object_operators.cpp
wrapper.cpp
+ exec.cpp
+ import.cpp
;
dll boost_python
diff --git a/doc/v2/exec.html b/doc/v2/exec.html
new file mode 100644
index 00000000..d997dbe3
--- /dev/null
+++ b/doc/v2/exec.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+ Boost.Python - <boost/python/exec.hpp>
+
+
+
+
+
+
+ 
+ |
+
+
+
+
+ Header <boost/python/exec.hpp>
+ |
+
+
+
+
+ Contents
+
+
+ - Introduction
+
+ - Functions
+
+ -
+
+ exec
+ exec_file
+
+
+
+
+
+ Introduction
+
+ Exposes a mechanism for embedding the python interpreter into C++ code.
+
+ Functions
+
+ exec
+
+object exec(str code,
+ object globals = object(),
+ object locals = object());
+
+
+ - Effects:
+ Execute Python source code from
code in the context
+ specified by the dictionaries globals and locals.
+
+ - Returns:
+ An instance of object
+ which holds the result of executing the code.
+
+
+
+ exec_file
+
+object exec_file(str filename,
+ object globals = object(),
+ object locals = object());
+
+
+ - Effects:
+ Execute Python source code from the file named by
filename
+ in the context specified by the dictionaries globals and
+ locals.
+
+ - Returns:
+ An instance of object
+ which holds the result of executing the code.
+
+
+
+
+
+
diff --git a/doc/v2/import.html b/doc/v2/import.html
new file mode 100644
index 00000000..38a9e30d
--- /dev/null
+++ b/doc/v2/import.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+ Boost.Python - <boost/python/import.hpp>
+
+
+
+
+
+
+ 
+ |
+
+
+
+
+ Header <boost/python/import.hpp>
+ |
+
+
+
+
+ Contents
+
+
+ - Introduction
+
+ - Functions
+
+ -
+
+ import
+
+
+
+
+
+ Introduction
+
+ Exposes a mechanism for importing python modules.
+
+ Functions
+
+ import
+
+object import(str name);
+
+
+ - Effects: Imports the module named by
name.
+ - Returns: An instance of object
+ which holds a reference to the imported module.
+
+
+
+
+
diff --git a/doc/v2/reference.html b/doc/v2/reference.html
index 95097f67..69bb518d 100644
--- a/doc/v2/reference.html
+++ b/doc/v2/reference.html
@@ -60,6 +60,8 @@
To/From Python Type Conversion
+ Embedding
+
Utility and Infrastructure
Topics
@@ -939,6 +941,39 @@
+
+
+
+ - exec.hpp
+
+ -
+
+ - Functions
+
+ -
+
+ - exec
+ - exec_file
+
+
+
+
+
+ - import.hpp
+
+ -
+
+ - Functions
+
+ -
+
+ - import
+
+
+
+
+
+
diff --git a/include/boost/python.hpp b/include/boost/python.hpp
index 5205d40d..7a1a9084 100644
--- a/include/boost/python.hpp
+++ b/include/boost/python.hpp
@@ -25,11 +25,13 @@
# include
# include
# include
+# include
# include
# include
# include
# include
# include
+# include
# include
# include
# include
diff --git a/include/boost/python/exec.hpp b/include/boost/python/exec.hpp
new file mode 100644
index 00000000..fa4e324a
--- /dev/null
+++ b/include/boost/python/exec.hpp
@@ -0,0 +1,31 @@
+// 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)
+#ifndef EXEC_SS20050616_HPP
+# define EXEC_SS20050616_HPP
+
+# include
+# include
+
+namespace boost
+{
+namespace python
+{
+
+// Execute python source code from str.
+// global and local are the global and local scopes respectively,
+// used during execution.
+object
+exec(str string, object global = object(), object local = object());
+
+// Execute python source code from file filename.
+// global and local are the global and local scopes respectively,
+// used during execution.
+object
+exec_file(str filename, object global = object(), object local = object());
+
+}
+}
+
+#endif
diff --git a/include/boost/python/extract.hpp b/include/boost/python/extract.hpp
index f2269b1d..4e876f50 100644
--- a/include/boost/python/extract.hpp
+++ b/include/boost/python/extract.hpp
@@ -22,6 +22,13 @@
# include
# include
+#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(BOOST_INTEL_WIN, <= 900)
+// workaround for VC++ 6.x or 7.0
+# define BOOST_EXTRACT_WORKAROUND ()
+#else
+# define BOOST_EXTRACT_WORKAROUND
+#endif
+
namespace boost { namespace python {
namespace api
diff --git a/include/boost/python/import.hpp b/include/boost/python/import.hpp
new file mode 100644
index 00000000..85d1afc0
--- /dev/null
+++ b/include/boost/python/import.hpp
@@ -0,0 +1,22 @@
+// 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)
+#ifndef IMPORT_SS20050624_HPP
+# define IMPORT_SS20050624_HPP
+
+# include
+# include
+
+namespace boost
+{
+namespace python
+{
+
+// Import the named module and return a reference to it.
+object import(str name);
+
+}
+}
+
+#endif
diff --git a/src/exec.cpp b/src/exec.cpp
new file mode 100644
index 00000000..0981f8b1
--- /dev/null
+++ b/src/exec.cpp
@@ -0,0 +1,45 @@
+// 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
+#include
+#include
+#include
+
+namespace boost
+{
+namespace python
+{
+
+object exec(str string, object global, object local)
+{
+ // 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());
+ if (!result) throw_error_already_set();
+ return object(detail::new_reference(result));
+}
+
+// Execute python source code from file filename.
+// global and local are the global and local scopes respectively,
+// used during execution.
+object exec_file(str filename, object global, object local)
+{
+ // 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.
+ PyObject *pyfile = PyFile_FromString(f, "r");
+ if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file");
+ python::handle<> file(pyfile);
+ PyObject* result = PyRun_File(PyFile_AsFile(file.get()),
+ f,
+ Py_file_input,
+ global.ptr(), local.ptr());
+ if (!result) throw_error_already_set();
+ return object(detail::new_reference(result));
+}
+
+} // namespace boost::python
+} // namespace boost
diff --git a/src/import.cpp b/src/import.cpp
new file mode 100644
index 00000000..b0df9b23
--- /dev/null
+++ b/src/import.cpp
@@ -0,0 +1,25 @@
+// 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
+#include
+#include
+#include
+
+namespace boost
+{
+namespace python
+{
+
+object import(str name)
+{
+ // should be 'char const *' but older python versions don't use 'const' yet.
+ char *n = python::extract(name);
+ python::handle<> module(python::borrowed(PyImport_AddModule(n)));
+ return python::object(module);
+}
+
+} // namespace boost::python
+} // namespace boost
diff --git a/test/Jamfile b/test/Jamfile
index e993bf51..36bd0fa3 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -74,10 +74,10 @@ rule bpl-test ( name ? : files * : requirements * )
test-suite python
:
- [
- run ../test/embedding.cpp ../build/boost_python
+ [
+ run ../test/exec.cpp ../build/boost_python
: # program args
- : # input files
+ : ../test/exec.py
: # requirements
$(PYTHON_PROPERTIES)
BOOST_PYTHON_STATIC_LIB
diff --git a/test/embedding.cpp b/test/embedding.cpp
deleted file mode 100644
index acd1f180..00000000
--- a/test/embedding.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright David Abrahams 2002.
-// 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)
-
-// embedded_hello -- A simple Boost.Python embedding example -- by
-// Dirk Gerrits
-
-#include
-#include
-#include
-#include
-#include
-
-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() {}
-
- std::string hello()
- {
- return "Hello from C++!";
- }
-};
-
-// Familiar Boost.Python wrapper class for Base
-struct BaseWrap : public Base
-{
- BaseWrap(PyObject* self_)
- : self(self_) {}
-
- std::string hello() { return python::call_method(self, "hello"); }
-
- PyObject* self;
-};
-
-// Pack the Base class wrapper into a module
-BOOST_PYTHON_MODULE(embedded_hello)
-{
- python::class_("Base")
- ;
-
-}
-
-
-void test()
-{
-//- INITIALIZATION -----------------------------------------------------------//
-
- // 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");
- // Retrieve the main module
- python::object main_module((
- python::handle<>(python::borrowed(PyImport_AddModule("__main__")))));
-
- // Retrieve the main module's namespace
- python::object main_namespace((main_module.attr("__dict__")));
-
- // Define the derived class in Python.
- // (You'll normally want to put this in a .py file.)
- python::handle<> result(
- PyRun_String(
- "from embedded_hello import * \n"
- "class PythonDerived(Base): \n"
- " def hello(self): \n"
- " return 'Hello from Python!' \n",
- Py_file_input, main_namespace.ptr(), main_namespace.ptr())
- );
- // Result is not needed
- result.reset();
-
- // Extract the raw Python object representing the just defined derived class
- python::handle<> class_ptr(
- PyRun_String("PythonDerived\n", Py_eval_input,
- main_namespace.ptr(), main_namespace.ptr()) );
-
- // Wrap the raw Python object in a Boost.Python object
- python::object PythonDerived(class_ptr);
-
-//- MAIN PROGRAM -------------------------------------------------------------//
-
- // Creating and using instances of the C++ class is as easy as always.
- CppDerived cpp;
- std::cout << cpp.hello() << 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(py_base)
-#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(BOOST_INTEL_WIN, <= 900)
- ()
-#endif
- ;
- std::cout << py.hello() << std::endl;
-}
-
-void
-test_tutorial()
-{
- using namespace boost::python;
-
- object main_module((
- handle<>(borrowed(PyImport_AddModule("__main__")))));
-
- object main_namespace = main_module.attr("__dict__");
-
- handle<> ignored((PyRun_String(
-
- "hello = file('hello.txt', 'w')\n"
- "hello.write('Hello world!')\n"
- "hello.close()"
-
- , Py_file_input
- , main_namespace.ptr()
- , main_namespace.ptr())
- ));
-}
-
-void
-test_tutorial2()
-{
- using namespace boost::python;
-
- object main_module((
- handle<>(borrowed(PyImport_AddModule("__main__")))));
-
- object main_namespace = main_module.attr("__dict__");
-
- handle<> ignored((PyRun_String(
-
- "result = 5 ** 2"
-
- , Py_file_input
- , main_namespace.ptr()
- , main_namespace.ptr())
- ));
-
- int five_squared = extract(main_namespace["result"]);
- assert(five_squared == 25);
-
- object result((handle<>(
- PyRun_String("5 ** 2"
- , Py_eval_input
- , main_namespace.ptr()
- , main_namespace.ptr()))
- ));
-
- int five_squared2 = extract(result);
- assert(five_squared2 == 25);
-}
-
-int main()
-{
- // Initialize the interpreter
- Py_Initialize();
-
- if (python::handle_exception(test))
- {
- if (PyErr_Occurred())
- PyErr_Print();
- return 1;
- }
-
- if (python::handle_exception(test_tutorial))
- {
- if (PyErr_Occurred())
- PyErr_Print();
- return 1;
- }
-
- if (python::handle_exception(test_tutorial2))
- {
- if (PyErr_Occurred())
- PyErr_Print();
- return 1;
- }
-
- // Boost.Python doesn't support Py_Finalize yet.
- // Py_Finalize();
- return 0;
-}
-#include "module_tail.cpp"
diff --git a/test/exec.cpp b/test/exec.cpp
new file mode 100644
index 00000000..c0ce7fb6
--- /dev/null
+++ b/test/exec.cpp
@@ -0,0 +1,138 @@
+// 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
+#include
+
+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
+{
+ 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(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_ base("Base");
+}
+
+
+void exec_test()
+{
+ // 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");
+ // 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;
+ std::cout << cpp.hello() << 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(py_base) BOOST_EXTRACT_WORKAROUND;
+ std::cout << py.hello() << std::endl;
+}
+
+void exec_file_test()
+{
+ python::object main = python::import("__main__");
+ python::dict global(main.attr("__dict__"));
+ global.clear();
+ python::object result = python::exec_file("exec.py", global, global);
+ std::string global_as_string = python::extract(python::str(global))
+ BOOST_EXTRACT_WORKAROUND;
+ std::cout << global_as_string << std::endl;
+}
+
+void exec_test_error()
+{
+ python::object main = python::import("__main__");
+ python::dict global(main.attr("__dict__"));
+ python::object result = python::exec("print unknown \n", global, global);
+}
+
+int main()
+{
+ bool success = true;
+ // Initialize the interpreter
+ Py_Initialize();
+
+ if (python::handle_exception(exec_test) ||
+ python::handle_exception(exec_file_test))
+ {
+ if (PyErr_Occurred()) PyErr_Print();
+ else
+ {
+ std::cerr << "A C++ exception was thrown for which "
+ << "there was no exception handler registered." << std::endl;
+ }
+ success = false;
+ }
+ if (python::handle_exception(exec_test_error))
+ {
+ if (PyErr_Occurred()) PyErr_Print();
+ else
+ {
+ std::cerr << "A C++ exception was thrown for which "
+ << "there was no exception handler registered." << std::endl;
+ success = false;
+ }
+ }
+ else success = false;
+
+ // Boost.Python doesn't support Py_Finalize yet.
+ // Py_Finalize();
+ return success ? 0 : 1;
+}
+
+// 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"
diff --git a/test/exec.py b/test/exec.py
new file mode 100644
index 00000000..5c1ad592
--- /dev/null
+++ b/test/exec.py
@@ -0,0 +1,2 @@
+print 'Hello World !'
+number = 42