2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-26 18:52:26 +00:00

Add basic embedding support.

[SVN r30601]
This commit is contained in:
Stefan Seefeld
2005-08-17 13:04:42 +00:00
parent 9205f507b0
commit 126a3efb92
14 changed files with 462 additions and 199 deletions

View File

@@ -54,6 +54,8 @@ if [ check-python-config ]
object_protocol.cpp
object_operators.cpp
wrapper.cpp
exec.cpp
import.cpp
;
dll boost_python

88
doc/v2/exec.html Normal file
View File

@@ -0,0 +1,88 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>Boost.Python - &lt;boost/python/exec.hpp&gt;</title>
</head>
<body>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header &lt;boost/python/exec.hpp&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#functions">Functions</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#exec-spec"><code>exec</code></a></dt>
<dt><a href="#exec_file-spec"><code>exec_file</code></a></dt>
</dl>
</dd>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>Exposes a mechanism for embedding the python interpreter into C++ code.</p>
<h2><a name="functions"></a>Functions</h2>
<h3><a name="exec-spec"></a><code>exec</code></h3>
<pre>
object exec(str code,
object globals = object(),
object locals = object());
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Execute Python source code from <code>code</code> in the context
specified by the dictionaries <code>globals</code> and <code>locals</code>.
</dt>
<dt><b>Returns:</b>
An instance of <a href="object.html#object-spec">object</a>
which holds the result of executing the code.
</dt>
</dl>
<h3><a name="exec_file-spec"></a><code>exec_file</code></h3>
<pre>
object exec_file(str filename,
object globals = object(),
object locals = object());
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Execute Python source code from the file named by <code>filename</code>
in the context specified by the dictionaries <code>globals</code> and
<code>locals</code>.
</dt>
<dt><b>Returns:</b>
An instance of <a href="object.html#object-spec">object</a>
which holds the result of executing the code.
</dt>
</dl>
</body>
</html>

62
doc/v2/import.html Normal file
View File

@@ -0,0 +1,62 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>Boost.Python - &lt;boost/python/import.hpp&gt;</title>
</head>
<body>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header &lt;boost/python/import.hpp&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#functions">Functions</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#import-spec"><code>import</code></a></dt>
</dl>
</dd>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>Exposes a mechanism for importing python modules.</p>
<h2><a name="functions"></a>Functions</h2>
<h3><a name="import-spec"></a><code>import</code></h3>
<pre>
object import(str name);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Imports the module named by <code>name</code>.</dt>
<dt><b>Returns:</b> An instance of <a href="object.html#object-spec">object</a>
which holds a reference to the imported module.</dt>
</dl>
</body>
</html>

View File

@@ -60,6 +60,8 @@
<dt><a href="#type_conversion">To/From Python Type Conversion</a></dt>
<dt><a href="#embedding">Embedding</a></dt>
<dt><a href="#utility">Utility and Infrastructure</a></dt>
<dt><a href="#topics">Topics</a></dt>
@@ -939,6 +941,39 @@
</dd>
</dl>
<h2><a name="embedding">Embedding</a></h2>
<dl class="index">
<dt><a href="exec.html">exec.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="exec.html#functions">Functions</a></dt>
<dd>
<dl class="index">
<dt><a href="exec.html#exec-spec">exec</a></dt>
<dt><a href="exec.html#exec_file-spec">exec_file</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="import.html">import.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="import.html#functions">Functions</a></dt>
<dd>
<dl class="index">
<dt><a href="import.html#import-spec">import</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
<h2><a name="utility">Utility and Infrastructure</a></h2>
<dl>

View File

@@ -25,11 +25,13 @@
# include <boost/python/enum.hpp>
# include <boost/python/errors.hpp>
# include <boost/python/exception_translator.hpp>
# include <boost/python/exec.hpp>
# include <boost/python/extract.hpp>
# include <boost/python/handle.hpp>
# include <boost/python/has_back_reference.hpp>
# include <boost/python/implicit.hpp>
# include <boost/python/init.hpp>
# include <boost/python/import.hpp>
# include <boost/python/instance_holder.hpp>
# include <boost/python/iterator.hpp>
# include <boost/python/list.hpp>

View File

@@ -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 <boost/python/object.hpp>
# include <boost/python/str.hpp>
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

View File

@@ -22,6 +22,13 @@
# include <boost/utility.hpp>
# include <boost/call_traits.hpp>
#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

View File

@@ -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 <boost/python/object.hpp>
# include <boost/python/str.hpp>
namespace boost
{
namespace python
{
// Import the named module and return a reference to it.
object import(str name);
}
}
#endif

45
src/exec.cpp Normal file
View File

@@ -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 <boost/python/exec.hpp>
#include <boost/python/borrowed.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/handle.hpp>
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<char *>(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<char *>(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

25
src/import.cpp Normal file
View File

@@ -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 <boost/python/import.hpp>
#include <boost/python/borrowed.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/handle.hpp>
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<char *>(name);
python::handle<> module(python::borrowed(PyImport_AddModule(n)));
return python::object(module);
}
} // namespace boost::python
} // namespace boost

View File

@@ -74,10 +74,10 @@ rule bpl-test ( name ? : files * : requirements * )
test-suite python
:
[
run ../test/embedding.cpp <lib>../build/boost_python
[
run ../test/exec.cpp <lib>../build/boost_python
: # program args
: # input files
: ../test/exec.py
: # requirements
$(PYTHON_PROPERTIES)
<define>BOOST_PYTHON_STATIC_LIB

View File

@@ -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 <boost/python.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <stdexcept>
#include <cassert>
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<std::string>(self, "hello"); }
PyObject* self;
};
// Pack the Base class wrapper into a module
BOOST_PYTHON_MODULE(embedded_hello)
{
python::class_<Base, BaseWrap, boost::noncopyable>("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<Base&>(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<int>(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<int>(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"

138
test/exec.cpp Normal file
View File

@@ -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 <boost/python.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()
{
// 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<Base&>(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<std::string>(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"

2
test/exec.py Normal file
View File

@@ -0,0 +1,2 @@
print 'Hello World !'
number = 42