@@ -114,7 +114,7 @@ foo_class.def(&to_string, "__str__");
Numeric operators can be exposed manually, by defing C++
[member] functions that support the standard Python numeric
+ href="http://www.python.org/doc/current/ref/numeric-types.html">numeric
protocols. This is the same basic technique used to expose
to_string() as __str__() above, and is covered in detail below. BPL also supports
@@ -398,7 +398,7 @@ Note that "__rrpow__" is an extension not present in plain Python.
BPL can automatically wrap the following
+ "http://www.python.org/doc/current/ref/specialnames.html">
special methods:
@@ -672,12 +672,12 @@ for (iterator i = S.begin(), end = S.end(); i != end; ++i)
It is a better idea to support the standard Python
+ href="http://www.python.org/doc/current/ref/sequence-types.html">Python
sequence and mapping protocols for your wrapped containers. These
operators have to be wrapped manually because there are no corresponding
C++ operators that could be used for automatic wrapping. The Python
documentation lists the relevant
+ "http://www.python.org/doc/current/ref/sequence-types.html">
container operators. In particular, expose __getitem__, __setitem__
and remember to raise the appropriate Python exceptions
(PyExc_IndexError for sequences,
@@ -773,7 +773,7 @@ KeyError: 2
Just like built-in Python classes, BPL extension classes support special
+ href="http://www.python.org/doc/current/ref/attribute-access.html">special
the usual attribute access methods __getattr__,
__setattr__, and __delattr__.
Because writing these functions can
diff --git a/example/abstract.cpp b/example/abstract.cpp
new file mode 100644
index 00000000..41d34def
--- /dev/null
+++ b/example/abstract.cpp
@@ -0,0 +1,34 @@
+// Example by Ullrich Koethe
+#include "boost/python/class_builder.hpp"
+#include
+
+struct Abstract
+{
+ virtual std::string test() = 0;
+};
+
+struct Abstract_callback: Abstract
+{
+ Abstract_callback(PyObject * self)
+ : m_self(self)
+ {}
+
+ std::string test()
+ {
+ return boost::python::callback::call_method(m_self, "test");
+ }
+
+ PyObject * m_self;
+};
+
+extern "C"
+DL_EXPORT(void)
+initabstract()
+{
+ boost::python::module_builder a("abstract");
+
+ boost::python::class_builder
+ a_class(a, "Abstract");
+ a_class.def(boost::python::constructor<>()); // wrap a constructor
+ a_class.def(&Abstract::test, "test");
+}
diff --git a/example/dvect.cpp b/example/dvect.cpp
new file mode 100644
index 00000000..3228010c
--- /dev/null
+++ b/example/dvect.cpp
@@ -0,0 +1,69 @@
+#include "ivect.h"
+#include "dvect.h"
+#include
+#include
+namespace python = boost::python;
+
+namespace {
+
+ vects::ivect dvect_as_ivect(const vects::dvect& dv)
+ {
+ vects::ivect iv(dv.size());
+ vects::ivect::iterator iviter = iv.begin();
+ for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]);
+ return iv;
+ }
+
+ boost::python::tuple ivect_as_tuple(const vects::ivect& iv)
+ {
+ return iv.as_tuple();
+ }
+
+ std::auto_ptr auto_ptr_ivect(const vects::dvect& dv)
+ {
+ return std::auto_ptr(new vects::ivect(dvect_as_ivect(dv)));
+ }
+
+ boost::shared_ptr shared_ptr_ivect(const vects::dvect& dv)
+ {
+ return boost::shared_ptr(new vects::ivect(dvect_as_ivect(dv)));
+ }
+
+ boost::python::tuple auto_ptr_ivect_as_tuple(std::auto_ptr& iv)
+ {
+ return iv->as_tuple();
+ }
+
+ boost::python::tuple shared_ptr_ivect_as_tuple(boost::shared_ptr& iv)
+ {
+ return iv->as_tuple();
+ }
+}
+
+extern "C"
+DL_EXPORT(void)
+initdvect()
+{
+ try
+ {
+ python::module_builder this_module("dvect");
+
+ python::x_class_builder dvect_class(this_module, "dvect");
+
+ python::import_class_builder ivect_class("ivect", "ivect");
+
+ dvect_class.def(python::constructor());
+ dvect_class.def(&vects::dvect::as_tuple, "as_tuple");
+ dvect_class.def(dvect_as_ivect, "as_ivect");
+
+ this_module.def(ivect_as_tuple, "ivect_as_tuple");
+ dvect_class.def(auto_ptr_ivect, "auto_ptr_ivect");
+ dvect_class.def(shared_ptr_ivect, "shared_ptr_ivect");
+ this_module.def(auto_ptr_ivect_as_tuple, "auto_ptr_ivect_as_tuple");
+ this_module.def(shared_ptr_ivect_as_tuple, "shared_ptr_ivect_as_tuple");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/dvect.h b/example/dvect.h
new file mode 100644
index 00000000..8ffe7b50
--- /dev/null
+++ b/example/dvect.h
@@ -0,0 +1,32 @@
+#ifndef DVECT_H
+#define DVECT_H
+
+#include
+#include
+
+namespace vects {
+
+ struct dvect : public std::vector
+ {
+ dvect() : std::vector() {}
+ dvect(size_t n) : std::vector(n) {}
+ dvect(boost::python::tuple tuple) : std::vector(tuple.size())
+ {
+ std::vector::iterator v_it = begin();
+ for (int i = 0; i < tuple.size(); i++)
+ v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(),
+ boost::python::type());
+ }
+
+ boost::python::tuple as_tuple() const
+ {
+ boost::python::tuple t(size());
+ for (int i = 0; i < size(); i++)
+ t.set_item(i,
+ boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i])));
+ return t;
+ }
+ };
+}
+
+#endif // DVECT_H
diff --git a/example/example1.cpp b/example/example1.cpp
deleted file mode 100644
index 467ac0dc..00000000
--- a/example/example1.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#include
-
-namespace hello {
- class world
- {
- public:
- world(int) {}
- ~world() {}
- const char* get() const { return "hi, world"; }
- };
-
- size_t length(const world& x) { return strlen(x.get()); }
-}
-
-#include
-
-// Python requires an exported function called init in every
-// extension module. This is where we build the module contents.
-extern "C"
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-void inithello()
-{
- try
- {
- // create an object representing this extension module
- boost::python::module_builder hello("hello");
-
- // Create the Python type object for our extension class
- boost::python::class_builder world_class(hello, "world");
-
- // Add the __init__ function
- world_class.def(boost::python::constructor());
- // Add a regular member function
- world_class.def(&hello::world::get, "get");
-
- // Add a regular function to the module
- hello.def(hello::length, "length");
- }
- catch(...)
- {
- boost::python::handle_exception(); // Deal with the exception for Python
- }
-}
-
-// Win32 DLL boilerplate
-#if defined(_WIN32)
-#include
-extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
-{
- return 1;
-}
-#endif // _WIN32
diff --git a/example/rwgk1.cpp b/example/getting_started1.cpp
similarity index 74%
rename from example/rwgk1.cpp
rename to example/getting_started1.cpp
index b21ae4d1..9679a2a4 100644
--- a/example/rwgk1.cpp
+++ b/example/getting_started1.cpp
@@ -8,21 +8,18 @@ namespace { // Avoid cluttering the global namespace.
}
#include
-
namespace python = boost::python;
// Python requires an exported function called init in every
// extension module. This is where we build the module contents.
extern "C"
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-void initrwgk1()
+DL_EXPORT(void)
+initgetting_started1()
{
try
{
// Create an object representing this extension module.
- python::module_builder this_module("rwgk1");
+ python::module_builder this_module("getting_started1");
// Add regular functions to the module.
this_module.def(greet, "greet");
@@ -33,9 +30,3 @@ void initrwgk1()
python::handle_exception(); // Deal with the exception for Python
}
}
-
-// Win32 DLL boilerplate
-#if defined(_WIN32)
-#include
-extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; }
-#endif // _WIN32
diff --git a/example/getting_started2.cpp b/example/getting_started2.cpp
new file mode 100644
index 00000000..82b4a6df
--- /dev/null
+++ b/example/getting_started2.cpp
@@ -0,0 +1,51 @@
+#include
+#include
+#include
+namespace python = boost::python;
+
+namespace { // Avoid cluttering the global namespace.
+
+ // A friendly class.
+ class world
+ {
+ private:
+ std::string country;
+ public:
+ world(const std::string& country) { this->country = country; }
+ std::string greet() const { return "Hello from " + country + "!"; }
+ };
+
+ // A function taking a world object as an argument.
+ std::string invite(const world& w) {
+ return w.greet() + " Please come soon!";
+ }
+}
+
+extern "C"
+DL_EXPORT(void)
+initgetting_started2()
+{
+ try
+ {
+ // Create an object representing this extension module.
+ python::module_builder this_module("getting_started2");
+
+ // Create the Python type object for our extension class.
+ python::class_builder world_class(this_module, "world");
+
+ // Add the __init__ function.
+ world_class.def(python::constructor());
+ // Add a regular member function.
+ world_class.def(&world::greet, "greet");
+
+ // Add invite() as a regular function to the module.
+ this_module.def(invite, "invite");
+
+ // Even better, invite() can also be made a member of world_class!!!
+ world_class.def(invite, "invite");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/getting_started3.cpp b/example/getting_started3.cpp
new file mode 100644
index 00000000..7e827249
--- /dev/null
+++ b/example/getting_started3.cpp
@@ -0,0 +1,122 @@
+/*
+ This example shows how to make an Extension Class "pickleable".
+
+ Python's pickle module implements a basic but powerful algorithm
+ for "pickling" (a.k.a. serializing, marshalling or flattening)
+ nearly arbitrary Python objects.
+
+ The user can influence how an Extension Class instance is pickled
+ by defining three special methods: __getinitargs__(),
+ __getstate__(), and __setstate(). This interface is similar to
+ that for regular Python classes as described in detail in the
+ Python Library Reference for pickle:
+
+ http://www.python.org/doc/current/lib/module-pickle.html
+
+ When an Extension Class instance is pickled, __getinitargs__() is
+ called, if implemented. This method should return a tuple
+ containing the arguments to be passed to the class constructor when
+ the object is restored.
+
+ If there is no __getstate__() method, the instance's __dict__ is
+ pickled if it is not empty. If __getstate__() is defined, it should
+ return an object representing the state of the instance.
+
+ If there is no __setstate__() method, __getstate__() must return a
+ dictionary. When the instance is restored, the items in this dictionary
+ are added to the instance's __dict__.
+
+ If the Extension Class defines __setstate__(), the pickle loader
+ calls it with the result of __getstate__() as arguments. In this
+ case, the state object need not be a dictionary. The
+ __getstate__() and __setstate__() methods can do what they want.
+
+ If both __getinitargs__() and __getstate__() are defined, the
+ instance is restored by first calling the constructor with
+ the result of __getinitargs__() as argument. After the instance
+ is reconstructed, the __dict__ is updated or __setstate__() is
+ called if implemented.
+
+ The mechanism described here is an exact replication of that one
+ implemented by Jim Fulton's ExtensionClass (included in Zope 2.2.2).
+ */
+
+#include
+#include
+
+#include
+namespace python = boost::python;
+
+namespace { // Avoid cluttering the global namespace.
+
+ // A friendly class.
+ class world
+ {
+ private:
+ std::string country;
+ int secret_number;
+ public:
+ world(const std::string& country) : secret_number(0) {
+ this->country = country;
+ }
+ std::string greet() const { return "Hello from " + country + "!"; }
+ std::string get_country() const { return country; }
+ void set_secret_number(int number) { secret_number = number; }
+ int get_secret_number() const { return secret_number; }
+ };
+
+ // Support for pickle.
+ python::tuple world_getinitargs(const world& w) {
+ python::tuple result(1);
+ result.set_item(0, w.get_country());
+ return result;
+ }
+
+ python::tuple world_getstate(const world& w) {
+ python::tuple result(1);
+ result.set_item(0, w.get_secret_number());
+ return result;
+ }
+
+ void world_setstate(world& w, python::tuple state) {
+ if (state.size() != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "Unexpected argument in call to __setstate__.");
+ throw python::error_already_set();
+ }
+ int number = BOOST_PYTHON_CONVERSION::from_python(state[0].get(),
+ python::type());
+ if (number != 42)
+ w.set_secret_number(number);
+ }
+}
+
+extern "C"
+DL_EXPORT(void)
+initgetting_started3()
+{
+ try
+ {
+ // Create an object representing this extension module.
+ python::module_builder this_module("getting_started3");
+
+ // Create the Python type object for our extension class.
+ python::class_builder world_class(this_module, "world");
+
+ // Add the __init__ function.
+ world_class.def(python::constructor());
+ // Add a regular member function.
+ world_class.def(&world::greet, "greet");
+ world_class.def(&world::get_secret_number, "get_secret_number");
+ world_class.def(&world::set_secret_number, "set_secret_number");
+
+ // Support for pickle.
+ world_class.def(world_getinitargs, "__getinitargs__");
+ world_class.def(world_getstate, "__getstate__");
+ world_class.def(world_setstate, "__setstate__");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/getting_started4.cpp b/example/getting_started4.cpp
new file mode 100644
index 00000000..0c7bd7ee
--- /dev/null
+++ b/example/getting_started4.cpp
@@ -0,0 +1,104 @@
+#include
+namespace python = boost::python;
+
+namespace { // Avoid cluttering the global namespace.
+
+ // A wrapper is used to define additional constructors.
+ //
+ struct vector_double_wrapper: std::vector
+ {
+ // Tell the compiler how to convert a base class object to
+ // this wrapper object.
+ vector_double_wrapper(PyObject*, const std::vector& vd)
+ : std::vector(vd) {}
+
+ vector_double_wrapper(PyObject* self)
+ : std::vector() {}
+
+ vector_double_wrapper(PyObject* self, const int n)
+ : std::vector(n) {}
+
+ vector_double_wrapper(PyObject* self, python::tuple tuple)
+ : std::vector(tuple.size())
+ {
+ std::vector::iterator vd = begin();
+ for (int i = 0; i < tuple.size(); i++)
+ vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(),
+ python::type());
+ }
+ };
+
+ double getitem(const std::vector& vd, const std::size_t key) {
+ return vd[key];
+ }
+
+ void setitem(std::vector& vd, const std::size_t key,
+ const double &d) {
+ std::vector::iterator vditer = vd.begin();
+ vditer[key] = d;
+ }
+
+ void delitem(std::vector& vd, const std::size_t key) {
+ std::vector::iterator vditer = vd.begin();
+ vd.erase(&vditer[key]);
+ }
+
+ // Convert vector_double to a regular Python tuple.
+ //
+ python::tuple as_tuple(const std::vector& vd)
+ {
+ python::tuple t(vd.size());
+ for (int i = 0; i < vd.size(); i++) t.set_item(i,
+ python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i])));
+ return t;
+ }
+
+ // Function returning a vector_double object to Python.
+ //
+ std::vector foo(const int n)
+ {
+ std::vector vd(n);
+ std::vector::iterator vditer = vd.begin();
+ for (int i = 0; i < n; i++) vditer[i] = double(i);
+ return vd;
+ }
+
+ // Same as foo(), but avoid copying on return.
+ //
+ std::auto_ptr > bar(const int n)
+ {
+ std::auto_ptr > vdptr(new std::vector(n));
+ std::vector::iterator vditer = vdptr->begin();
+ for (int i = 0; i < n; i++) vditer[i] = double(10 * i);
+ return vdptr;
+ }
+}
+
+extern "C"
+DL_EXPORT(void)
+initgetting_started4()
+{
+ try
+ {
+ python::module_builder this_module("getting_started4");
+
+ python::class_builder, vector_double_wrapper>
+ vector_double(this_module, "vector_double");
+
+ vector_double.def(python::constructor<>());
+ vector_double.def(python::constructor());
+ vector_double.def(python::constructor());
+ vector_double.def(&std::vector::size, "__len__");
+ vector_double.def(getitem, "__getitem__");
+ vector_double.def(setitem, "__setitem__");
+ vector_double.def(delitem, "__delitem__");
+ vector_double.def(as_tuple, "as_tuple");
+
+ this_module.def(foo, "foo");
+ this_module.def(bar, "bar");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp
new file mode 100644
index 00000000..4b64e4b8
--- /dev/null
+++ b/example/getting_started5.cpp
@@ -0,0 +1,128 @@
+/*
+ This example shows how to convert a class from and to native
+ Python objects, such as tuples.
+
+ We do not want to expose the helper class MillerIndex as an
+ Extension Class. However, in order to simplify the wrapper code,
+ we want to define from_python() and to_python() functions for
+ class MillerIndex.
+
+ Consider the alternatives:
+
+ - Expose MillerIndex as an Extension Class.
+ We need a constructor MillerIndex(python::tuple).
+ Python function calls become more complex:
+ foo(MillerIndex((1,2,3)) instead of foo((1,2,3))
+ We need a method such as MillerIndex().as_tuple().
+
+ - Define a wrapper function for each function that we
+ want to expose, e.g.:
+ void add(const IndexingSet& ixset, const python::tuple PyMIx)
+
+ The first alternative introduces a new type that the user has to
+ deal with. Other modules using Miller indices might organize them in
+ different ways, for example to increase runtime efficiency for
+ important procedures. This means, the user has to know how to
+ convert between the different kinds of Miller index representations.
+ This can quickly become a nuisance. Relying on native Python data
+ structures minimizes the number of special types the user has to
+ learn and convert. Of course, this argument is only valid for
+ small and relatively simply classes.
+
+ If there are many member functions with MillerIndex arguments, the
+ second alternative is impractical, and concentrating the conversion
+ mechanism in one central place is essential for code
+ maintainability. An added benefit is that more convenient (smarter)
+ conversion functions can be provided without cluttering the rest of
+ the wrapper code.
+
+ */
+
+#include
+#include
+#include
+namespace python = boost::python;
+
+namespace { // Avoid cluttering the global namespace.
+
+ // The helper class.
+ //
+ class MillerIndex {
+ public:
+ int v[3];
+ };
+
+ // The main class. Imagine that there are MANY member functions
+ // like add() and get().
+ //
+ class IndexingSet {
+ private:
+ std::vector VMIx;
+ public:
+ void add(const MillerIndex& MIx) { VMIx.push_back(MIx); }
+ MillerIndex get(const std::size_t i) const { return VMIx[i]; }
+ };
+}
+
+BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
+
+ // Convert a Python tuple to a MillerIndex object.
+ //
+ MillerIndex from_python(PyObject* p, python::type)
+ {
+ python::tuple tup
+ = python::tuple(python::ref(p, python::ref::increment_count));
+ if (tup.size() != 3) {
+ PyErr_SetString(PyExc_ValueError,
+ "expecting exactly 3 values in tuple.");
+ throw python::error_already_set();
+ }
+ MillerIndex result;
+ for (int i = 0; i < 3; i++)
+ result.v[i] = from_python(tup[i].get(), python::type());
+ return result;
+ }
+
+ // Similar conversion for MillerIndex objects passed by value.
+ // Not actually used, but included to show the principle.
+ //
+ MillerIndex from_python(PyObject* p, python::type)
+ {
+ return from_python(p, python::type());
+ }
+
+ // Convert a MillerIndex object to a Python tuple.
+ //
+ PyObject* to_python(const MillerIndex& hkl)
+ {
+ python::tuple result(3);
+ for (int i = 0; i < 3; i++)
+ result.set_item(i, to_python(hkl.v[i]));
+ return result.reference().release();
+ }
+
+BOOST_PYTHON_END_CONVERSION_NAMESPACE
+
+extern "C"
+DL_EXPORT(void)
+initgetting_started5()
+{
+ try
+ {
+ // Create an object representing this extension module.
+ python::module_builder this_module("getting_started5");
+
+ // Create the Python type object for our extension class.
+ python::class_builder ixset_class(this_module, "IndexingSet");
+
+ // Add the __init__ function.
+ ixset_class.def(python::constructor<>());
+ // Add the member functions.
+ ixset_class.def(&IndexingSet::add, "add");
+ ixset_class.def(&IndexingSet::get, "get");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/ivect.cpp b/example/ivect.cpp
new file mode 100644
index 00000000..f8ca8707
--- /dev/null
+++ b/example/ivect.cpp
@@ -0,0 +1,69 @@
+#include "ivect.h"
+#include "dvect.h"
+#include
+#include
+namespace python = boost::python;
+
+namespace {
+
+ vects::dvect ivect_as_dvect(const vects::ivect& iv)
+ {
+ vects::dvect dv(iv.size());
+ vects::dvect::iterator dviter = dv.begin();
+ for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]);
+ return dv;
+ }
+
+ boost::python::tuple dvect_as_tuple(const vects::dvect& dv)
+ {
+ return dv.as_tuple();
+ }
+
+ std::auto_ptr auto_ptr_dvect(const vects::ivect& iv)
+ {
+ return std::auto_ptr(new vects::dvect(ivect_as_dvect(iv)));
+ }
+
+ boost::shared_ptr shared_ptr_dvect(const vects::ivect& iv)
+ {
+ return boost::shared_ptr(new vects::dvect(ivect_as_dvect(iv)));
+ }
+
+ boost::python::tuple auto_ptr_dvect_as_tuple(std::auto_ptr& dv)
+ {
+ return dv->as_tuple();
+ }
+
+ boost::python::tuple shared_ptr_dvect_as_tuple(boost::shared_ptr& dv)
+ {
+ return dv->as_tuple();
+ }
+}
+
+extern "C"
+DL_EXPORT(void)
+initivect()
+{
+ try
+ {
+ python::module_builder this_module("ivect");
+
+ python::x_class_builder ivect_class(this_module, "ivect");
+
+ python::import_class_builder dvect_class("dvect", "dvect");
+
+ ivect_class.def(python::constructor());
+ ivect_class.def(&vects::ivect::as_tuple, "as_tuple");
+ ivect_class.def(ivect_as_dvect, "as_dvect");
+
+ this_module.def(dvect_as_tuple, "dvect_as_tuple");
+ ivect_class.def(auto_ptr_dvect, "auto_ptr_dvect");
+ ivect_class.def(shared_ptr_dvect, "shared_ptr_dvect");
+ this_module.def(auto_ptr_dvect_as_tuple, "auto_ptr_dvect_as_tuple");
+ this_module.def(shared_ptr_dvect_as_tuple, "shared_ptr_dvect_as_tuple");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/ivect.h b/example/ivect.h
new file mode 100644
index 00000000..a0187307
--- /dev/null
+++ b/example/ivect.h
@@ -0,0 +1,32 @@
+#ifndef IVECT_H
+#define IVECT_H
+
+#include
+#include
+
+namespace vects {
+
+ struct ivect : public std::vector
+ {
+ ivect() : std::vector() {}
+ ivect(size_t n) : std::vector(n) {}
+ ivect(boost::python::tuple tuple) : std::vector(tuple.size())
+ {
+ std::vector::iterator v_it = begin();
+ for (int i = 0; i < tuple.size(); i++)
+ v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(),
+ boost::python::type());
+ }
+
+ boost::python::tuple as_tuple() const
+ {
+ boost::python::tuple t(size());
+ for (int i = 0; i < size(); i++)
+ t.set_item(i,
+ boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i])));
+ return t;
+ }
+ };
+}
+
+#endif // IVECT_H
diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp
new file mode 100644
index 00000000..82c3f049
--- /dev/null
+++ b/example/noncopyable_export.cpp
@@ -0,0 +1,24 @@
+#include
+#include
+namespace python = boost::python;
+
+#include "store.h"
+
+extern "C"
+DL_EXPORT(void)
+initnoncopyable_export()
+{
+ try
+ {
+ python::module_builder this_module("noncopyable_export");
+
+ python::xptr_class_builder store_class(this_module, "store");
+
+ store_class.def(python::constructor());
+ store_class.def(&store::recall, "recall");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp
new file mode 100644
index 00000000..529c9f42
--- /dev/null
+++ b/example/noncopyable_import.cpp
@@ -0,0 +1,42 @@
+#include
+#include
+namespace python = boost::python;
+
+#include "store.h"
+
+namespace { // Avoid cluttering the global namespace.
+
+ // A function with store objects as both input and output parameters.
+ // Because the copy constructor is disabled, we cannot pass a store
+ // object by value. Instead, we pass a smart pointer.
+ std::auto_ptr add_stores(const store& s1, const store& s2)
+ {
+ int sum = s1.recall() + s2.recall();
+ std::auto_ptr ss = std::auto_ptr(new store(sum));
+ return ss;
+ }
+}
+
+extern "C"
+DL_EXPORT(void)
+initnoncopyable_import()
+{
+ try
+ {
+ python::module_builder this_module("noncopyable_import");
+
+ python::import_class_builder
+ dvect_class("noncopyable_export", "store");
+
+ // Imagine all the additional classes with member functions
+ // that have store objects as input and output parameters.
+ // Lots and lots of them.
+ // However, to keep this example simple, we only define a
+ // module-level function.
+ this_module.def(add_stores, "add_stores");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/passing_char.cpp b/example/passing_char.cpp
new file mode 100644
index 00000000..0fc4640e
--- /dev/null
+++ b/example/passing_char.cpp
@@ -0,0 +1,52 @@
+#include
+
+namespace { // Avoid cluttering the global namespace.
+
+ // In C++, char, signed char and unsigned char are three distinct types.
+ // The Boost Python Library maps signed & unsigned char to
+ // Python integers. Plain char is mapped to a Python string with
+ // exactly one character.
+
+ // Plain char.
+ char get_char() { return 'ÿ'; }
+ void use_char(char c) {
+ std::cout << c << std::endl;
+ }
+
+ // signed char.
+ signed char get_signed_char() { return -128; }
+ void use_signed_char(signed char c) {
+ std::cout << c << " " << static_cast(c) << std::endl;
+ }
+
+ // unsigned char.
+ unsigned char get_unsigned_char() { return 128; }
+ void use_unsigned_char(unsigned char c) {
+ std::cout << c << " " << static_cast(c) << std::endl;
+ }
+}
+
+#include
+namespace python = boost::python;
+
+extern "C"
+DL_EXPORT(void)
+initpassing_char()
+{
+ try
+ {
+ // Create an object representing this extension module.
+ python::module_builder this_module("passing_char");
+
+ this_module.def(get_char, "get_char");
+ this_module.def(use_char, "use_char");
+ this_module.def(get_signed_char, "get_signed_char");
+ this_module.def(use_signed_char, "use_signed_char");
+ this_module.def(get_unsigned_char, "get_unsigned_char");
+ this_module.def(use_unsigned_char, "use_unsigned_char");
+ }
+ catch(...)
+ {
+ python::handle_exception(); // Deal with the exception for Python
+ }
+}
diff --git a/example/store.h b/example/store.h
new file mode 100644
index 00000000..74ef0477
--- /dev/null
+++ b/example/store.h
@@ -0,0 +1,14 @@
+#ifndef STORE_H
+#define STORE_H
+
+class store
+{
+ private:
+ store(const store&) { } // Disable the copy constructor.
+ int number;
+ public:
+ store(const int i) : number(i) { }
+ int recall() const { return number; }
+};
+
+#endif // STORE_H
diff --git a/example/test_abstract.py b/example/test_abstract.py
new file mode 100644
index 00000000..dda8aaa7
--- /dev/null
+++ b/example/test_abstract.py
@@ -0,0 +1,23 @@
+# Example by Ullrich Koethe
+r'''>>> from abstract import *
+ >>> class A(Abstract):
+ ... def __init__(self, text):
+ ... Abstract.__init__(self) # call the base class constructor
+ ... self.text = text
+ ... def test(self): # implement abstract function
+ ... return self.text
+ ...
+ >>> a = A("Hello")
+ >>> a.test()
+ 'Hello'
+'''
+
+def run(args = None):
+ if args is not None:
+ import sys
+ sys.argv = args
+ import doctest, test_abstract
+ doctest.testmod(test_abstract)
+
+if __name__ == '__main__':
+ run()
diff --git a/example/test_example1.py b/example/test_example1.py
deleted file mode 100644
index 0e3a9a18..00000000
--- a/example/test_example1.py
+++ /dev/null
@@ -1,50 +0,0 @@
-r'''
-// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
-// distribute this software is granted provided this copyright notice appears
-// in all copies. This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-// The author gratefully acknowleges the support of Dragon Systems, Inc., in
-// producing this work.
-
-That's it! If we build this shared library and put it on our PYTHONPATH we can
-now access our C++ class and function from Python.
-
- >>> import hello
- >>> hi_world = hello.world(3)
- >>> hi_world.get()
- 'hi, world'
- >>> hello.length(hi_world)
- 9
-
-We can even make a subclass of hello.world:
-
-
- >>> class my_subclass(hello.world):
- ... def get(self):
- ... return 'hello, world'
- ...
- >>> y = my_subclass(2)
- >>> y.get()
- 'hello, world'
-
-Pretty cool! You can't do that with an ordinary Python extension type!
-
- >>> hello.length(y)
- 9
-
-Of course, you may now have a slightly empty feeling in the pit of your little
-pythonic stomach. Perhaps you feel your subclass deserves to have a length() of
-12? If so, read on...
-'''
-from hello import *
-
-def run(args = None):
- if args is not None:
- import sys
- sys.argv = args
- import doctest, test_example1
- doctest.testmod(test_example1)
-
-if __name__ == '__main__':
- run()
diff --git a/example/test_getting_started1.py b/example/test_getting_started1.py
new file mode 100644
index 00000000..7daf65af
--- /dev/null
+++ b/example/test_getting_started1.py
@@ -0,0 +1,17 @@
+r'''>>> import getting_started1
+ >>> print getting_started1.greet()
+ hello, world
+ >>> number = 11
+ >>> print number, '*', number, '=', getting_started1.square(number)
+ 11 * 11 = 121
+'''
+
+def run(args = None):
+ if args is not None:
+ import sys
+ sys.argv = args
+ import doctest, test_getting_started1
+ doctest.testmod(test_getting_started1)
+
+if __name__ == '__main__':
+ run()
diff --git a/example/test_getting_started2.py b/example/test_getting_started2.py
new file mode 100644
index 00000000..09215816
--- /dev/null
+++ b/example/test_getting_started2.py
@@ -0,0 +1,19 @@
+r'''>>> import getting_started2
+ >>> w = getting_started2.world('California')
+ >>> print w.greet()
+ Hello from California!
+ >>> print getting_started2.invite(w)
+ Hello from California! Please come soon!
+ >>> print w.invite()
+ Hello from California! Please come soon!
+'''
+
+def run(args = None):
+ if args is not None:
+ import sys
+ sys.argv = args
+ import doctest, test_getting_started2
+ doctest.testmod(test_getting_started2)
+
+if __name__ == '__main__':
+ run()
diff --git a/example/test_getting_started3.py b/example/test_getting_started3.py
new file mode 100644
index 00000000..d62cf5a2
--- /dev/null
+++ b/example/test_getting_started3.py
@@ -0,0 +1,56 @@
+r'''>>> import getting_started3
+ >>> import re
+ >>> import pickle
+ >>> getting_started3.world.__module__
+ 'getting_started3'
+ >>> getting_started3.world.__safe_for_unpickling__
+ 1
+ >>> getting_started3.world.__reduce__()
+ 'world'
+ >>> assert re.match(
+ ... "\(, \('Hello',\), \(0,\)\)",
+ ... repr(getting_started3.world('Hello').__reduce__()))
+ >>>
+ >>> for number in (24, 42):
+ ... wd = getting_started3.world('California')
+ ... wd.set_secret_number(number)
+ ... pstr = pickle.dumps(wd)
+ ... print pstr
+ ... wl = pickle.loads(pstr)
+ ... print wd.greet(), wd.get_secret_number()
+ ... print wl.greet(), wl.get_secret_number()
+ cgetting_started3
+ world
+ p0
+ (S'California'
+ p1
+ tp2
+ R(I24
+ tp3
+ bp4
+ .
+ Hello from California! 24
+ Hello from California! 24
+ cgetting_started3
+ world
+ p0
+ (S'California'
+ p1
+ tp2
+ R(I42
+ tp3
+ bp4
+ .
+ Hello from California! 42
+ Hello from California! 0
+'''
+
+def run(args = None):
+ if args is not None:
+ import sys
+ sys.argv = args
+ import doctest, test_getting_started3
+ doctest.testmod(test_getting_started3)
+
+if __name__ == '__main__':
+ run()
diff --git a/example/test_getting_started4.py b/example/test_getting_started4.py
new file mode 100644
index 00000000..82b5c794
--- /dev/null
+++ b/example/test_getting_started4.py
@@ -0,0 +1,35 @@
+r'''>>> import getting_started4
+ >>> v=getting_started4.vector_double()
+ >>> print v.as_tuple()
+ ()
+ >>> v=getting_started4.vector_double(5)
+ >>> print v.as_tuple()
+ (0.0, 0.0, 0.0, 0.0, 0.0)
+ >>> print len(v)
+ 5
+ >>> v=getting_started4.vector_double((3,4,5))
+ >>> print v.as_tuple()
+ (3.0, 4.0, 5.0)
+ >>> print v[1]
+ 4.0
+ >>> v[1] = 40
+ >>> print v.as_tuple()
+ (3.0, 40.0, 5.0)
+ >>> del v[1]
+ >>> print v.as_tuple()
+ (3.0, 5.0)
+ >>> print getting_started4.foo(11).as_tuple()
+ (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
+ >>> print getting_started4.bar(12).as_tuple()
+ (0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0)
+'''
+
+def run(args = None):
+ if args is not None:
+ import sys
+ sys.argv = args
+ import doctest, test_getting_started4
+ doctest.testmod(test_getting_started4)
+
+if __name__ == '__main__':
+ run()
diff --git a/example/test_getting_started5.py b/example/test_getting_started5.py
new file mode 100644
index 00000000..8eeba1e2
--- /dev/null
+++ b/example/test_getting_started5.py
@@ -0,0 +1,22 @@
+r'''>>> import getting_started5
+ >>> ixset = getting_started5.IndexingSet()
+ >>> ixset.add((1,2,3))
+ >>> ixset.add((4,5,6))
+ >>> ixset.add((7,8,9))
+ >>> print ixset.get(0)
+ (1, 2, 3)
+ >>> print ixset.get(1)
+ (4, 5, 6)
+ >>> print ixset.get(2)
+ (7, 8, 9)
+'''
+
+def run(args = None):
+ if args is not None:
+ import sys
+ sys.argv = args
+ import doctest, test_getting_started5
+ doctest.testmod(test_getting_started5)
+
+if __name__ == '__main__':
+ run()
diff --git a/example/test_rwgk1.py b/example/test_rwgk1.py
deleted file mode 100644
index 87298875..00000000
--- a/example/test_rwgk1.py
+++ /dev/null
@@ -1,17 +0,0 @@
-r'''>>> import rwgk1
- >>> print rwgk1.greet()
- hello, world
- >>> number = 11
- >>> print number, '*', number, '=', rwgk1.square(number)
- 11 * 11 = 121
-'''
-
-def run(args = None):
- if args is not None:
- import sys
- sys.argv = args
- import doctest, test_rwgk1
- doctest.testmod(test_rwgk1)
-
-if __name__ == '__main__':
- run()
diff --git a/example/tst_dvect.py b/example/tst_dvect.py
new file mode 100644
index 00000000..563f0ad5
--- /dev/null
+++ b/example/tst_dvect.py
@@ -0,0 +1,16 @@
+import dvect
+print dvect.dvect.__converters__
+dv = dvect.dvect((1,2,3,4,5))
+print dv
+print dv.as_tuple()
+iv = dv.as_ivect()
+print iv
+print iv.as_tuple()
+print dvect.ivect_as_tuple(iv)
+aiv = dv.auto_ptr_ivect()
+print aiv
+siv = dv.shared_ptr_ivect()
+print dvect.auto_ptr_ivect_as_tuple(aiv)
+print dvect.ivect_as_tuple(aiv)
+print dvect.shared_ptr_ivect_as_tuple(siv)
+print dvect.ivect_as_tuple(siv)
diff --git a/example/tst_ivect.py b/example/tst_ivect.py
new file mode 100644
index 00000000..58bc323f
--- /dev/null
+++ b/example/tst_ivect.py
@@ -0,0 +1,16 @@
+import ivect
+print ivect.ivect.__converters__
+iv = ivect.ivect((1,2,3,4,5))
+print iv
+print iv.as_tuple()
+dv = iv.as_dvect()
+print dv
+print dv.as_tuple()
+print ivect.dvect_as_tuple(dv)
+adv = iv.auto_ptr_dvect()
+print adv
+sdv = iv.shared_ptr_dvect()
+print ivect.auto_ptr_dvect_as_tuple(adv)
+print ivect.dvect_as_tuple(adv)
+print ivect.shared_ptr_dvect_as_tuple(sdv)
+print ivect.dvect_as_tuple(sdv)
diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py
new file mode 100644
index 00000000..913df039
--- /dev/null
+++ b/example/tst_noncopyable.py
@@ -0,0 +1,8 @@
+import noncopyable_export
+import noncopyable_import
+s1 = noncopyable_export.store(1)
+print s1.recall()
+s2 = noncopyable_export.store(2)
+print s2.recall()
+s3 = noncopyable_import.add_stores(s1, s2)
+print s3.recall()
diff --git a/example/tst_passing_char.py b/example/tst_passing_char.py
new file mode 100644
index 00000000..d7aac264
--- /dev/null
+++ b/example/tst_passing_char.py
@@ -0,0 +1,20 @@
+import passing_char
+print passing_char.get_char()
+print passing_char.get_signed_char()
+print passing_char.get_unsigned_char()
+for arg in (-97, 97, -140, 140, "a", "ab"):
+ try:
+ print 'char', arg, ':'
+ passing_char.use_char(arg)
+ except (TypeError, ValueError), e:
+ print e.args[0]
+ try:
+ print 'signed char', arg, ':'
+ passing_char.use_signed_char(arg)
+ except (TypeError, ValueError), e:
+ print e.args[0]
+ try:
+ print 'unsigned char', arg, ':'
+ passing_char.use_unsigned_char(arg)
+ except (TypeError, ValueError), e:
+ print e.args[0]
diff --git a/include/boost/python/conversions.hpp b/include/boost/python/conversions.hpp
index d11f7f14..f7c07327 100644
--- a/include/boost/python/conversions.hpp
+++ b/include/boost/python/conversions.hpp
@@ -100,6 +100,10 @@ PyObject* to_python(unsigned short);
unsigned short from_python(PyObject*, boost::python::type);
unsigned short from_python(PyObject*, boost::python::type);
+PyObject* to_python(char);
+char from_python(PyObject*, boost::python::type);
+char from_python(PyObject*, boost::python::type);
+
PyObject* to_python(signed char);
signed char from_python(PyObject*, boost::python::type);
signed char from_python(PyObject*, boost::python::type);
@@ -304,6 +308,11 @@ inline unsigned short from_python(PyObject* p, boost::python::type());
}
+inline char from_python(PyObject* p, boost::python::type)
+{
+ return from_python(p, boost::python::type());
+}
+
inline signed char from_python(PyObject* p, boost::python::type)
{
return from_python(p, boost::python::type());
diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp
index 0e2e3427..6b3eb470 100644
--- a/include/boost/python/detail/extension_class.hpp
+++ b/include/boost/python/detail/extension_class.hpp
@@ -6,7 +6,7 @@
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
-// This file automatically generated for 5-argument constructors by
+// This file automatically generated for 10-argument constructors by
// gen_extclass.python
#ifndef EXTENSION_CLASS_DWA052000_H_
@@ -363,8 +363,8 @@ class extension_class
~extension_class();
// define constructors
- template
- inline void def(constructor)
+ template
+ inline void def(constructor)
// The following incantation builds a signature1, signature2,... object. It
// should _all_ get optimized away.
{ add_constructor(
@@ -373,7 +373,12 @@ class extension_class
prepend(type::id(),
prepend(type::id(),
prepend(type::id(),
- signature0()))))));
+ prepend(type::id(),
+ prepend(type::id(),
+ prepend(type::id(),
+ prepend(type::id(),
+ prepend(type::id(),
+ signature0())))))))))));
}
@@ -608,23 +613,33 @@ class extension_class
// A simple wrapper over a T which allows us to use extension_class with a
// single template parameter only. See extension_class, above.
-template
-class held_instance : public T
+template
+class held_instance : public Held
{
// There are no member functions: we want to avoid inadvertently overriding
// any virtual functions in T.
public:
- held_instance(PyObject*) : T() {}
+ held_instance(PyObject*) : Held() {}
template
- held_instance(PyObject*, A1 a1) : T(a1) {}
+ held_instance(PyObject*, A1 a1) : Held(a1) {}
template
- held_instance(PyObject*, A1 a1, A2 a2) : T(a1, a2) {}
+ held_instance(PyObject*, A1 a1, A2 a2) : Held(a1, a2) {}
template
- held_instance(PyObject*, A1 a1, A2 a2, A3 a3) : T(a1, a2, a3) {}
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3) : Held(a1, a2, a3) {}
template
- held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : T(a1, a2, a3, a4) {}
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : Held(a1, a2, a3, a4) {}
template
- held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : T(a1, a2, a3, a4, a5) {}
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : Held(a1, a2, a3, a4, a5) {}
+ template
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : Held(a1, a2, a3, a4, a5, a6) {}
+ template
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : Held(a1, a2, a3, a4, a5, a6, a7) {}
+ template
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : Held(a1, a2, a3, a4, a5, a6, a7, a8) {}
+ template
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : Held(a1, a2, a3, a4, a5, a6, a7, a8, a9) {}
+ template
+ held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : Held(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {}
};
// Abstract base class for all obj holders. Base for template class
@@ -676,6 +691,21 @@ public:
template
instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
m_held(p, a1, a2, a3, a4, a5) {}
+ template
+ instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
+ m_held(p, a1, a2, a3, a4, a5, a6) {}
+ template
+ instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
+ m_held(p, a1, a2, a3, a4, a5, a6, a7) {}
+ template
+ instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
+ m_held(p, a1, a2, a3, a4, a5, a6, a7, a8) {}
+ template
+ instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
+ m_held(p, a1, a2, a3, a4, a5, a6, a7, a8, a9) {}
+ template
+ instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
+ m_held(p, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {}
public: // implementation of instance_holder_base required interface
bool held_by_value() { return true; }
@@ -829,4 +859,3 @@ std::vector class_registry::static_derived_class_info;
}}} // namespace boost::python::detail
#endif // EXTENSION_CLASS_DWA052000_H_
-
diff --git a/include/boost/python/detail/import_extension_class.hpp b/include/boost/python/detail/import_extension_class.hpp
new file mode 100644
index 00000000..4d64a033
--- /dev/null
+++ b/include/boost/python/detail/import_extension_class.hpp
@@ -0,0 +1,361 @@
+#ifndef IMPORT_EXTENSION_CLASS_HPP_
+# define IMPORT_EXTENSION_CLASS_HPP_
+
+# include
+
+//QUESTIONMARK
+// Do we really need the special PyCvtsObject?
+// Is there a better way of creating the special PyCvtsObject?
+// My solution adds a lot of code including several reinterpret_cast.
+//#define SPECIAL_PYCVTSOBJECT
+
+namespace boost { namespace python {
+ struct import_error : error_already_set {};
+ struct export_error : error_already_set {};
+}}
+
+namespace boost { namespace python { namespace detail {
+
+// Concept: throw exception if api_major is changed
+// show warning on stderr if api_minor is changed
+const int EXPORT_CONVERTERS_API_MAJOR = 1;
+const int EXPORT_CONVERTERS_API_MINOR = 1;
+const std::string converters_attribute_name = "__converters__";
+#ifndef SPECIAL_PYCVTSOBJECT
+void *import_converters(const std::string& module_name,
+ const std::string& klass_name,
+ const std::string& attribute_name);
+#else
+PyObject *new_import_converters(const std::string& module_name,
+ const std::string& klass_name,
+ const std::string& attribute_name);
+#endif
+void check_export_converters_api(const int importing_major,
+ const int importing_minor,
+ const int imported_major,
+ const int imported_minor);
+
+}}}
+
+// forward declaration
+namespace boost { namespace python { namespace detail {
+template class import_extension_class;
+}}}
+
+BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
+
+//QUESTIONMARK
+// This class is a look-alike of class python_extension_class_converters.
+// Is there a way to ensure that the siblings stay in sync?
+template
+class python_import_extension_class_converters
+{
+ public:
+
+ friend python_import_extension_class_converters py_extension_class_converters(boost::python::type)
+ {
+ return python_import_extension_class_converters();
+ }
+
+ PyObject* to_python(const T& x) const
+ {
+ return boost::python::detail::import_extension_class::get_converters()->to_python(x);
+ }
+
+ friend T* from_python(PyObject* obj, boost::python::type)
+ {
+ return boost::python::detail::import_extension_class::get_converters()->Tptr_from_python(obj);
+ }
+
+ // Convert to const T*
+ friend const T* from_python(PyObject* p, boost::python::type)
+ { return from_python(p, boost::python::type()); }
+
+ // Convert to const T* const&
+ friend const T* from_python(PyObject* p, boost::python::type)
+ { return from_python(p, boost::python::type()); }
+
+ // Convert to T* const&
+ friend T* from_python(PyObject* p, boost::python::type)
+ { return from_python(p, boost::python::type()); }
+
+ // Convert to T&
+ friend T& from_python(PyObject* p, boost::python::type)
+ { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); }
+
+ // Convert to const T&
+ friend const T& from_python(PyObject* p, boost::python::type)
+ { return from_python(p, boost::python::type()); }
+
+ // Convert to T
+ friend const T& from_python(PyObject* p, boost::python::type)
+ { return from_python(p, boost::python::type()); }
+
+ friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) {
+ return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p);
+ }
+
+ friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) {
+ return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p);
+ }
+
+ friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) {
+ return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p);
+ }
+
+ friend PyObject* to_python(std::auto_ptr x) {
+ return boost::python::detail::import_extension_class::get_converters()->to_python(x);
+ }
+
+ friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) {
+ return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p);
+ }
+
+ friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) {
+ return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p);
+ }
+
+ friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) {
+ return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p);
+ }
+
+ friend PyObject* to_python(boost::shared_ptr x) {
+ return boost::python::detail::import_extension_class::get_converters()->to_python(x);
+ }
+};
+
+BOOST_PYTHON_END_CONVERSION_NAMESPACE
+
+namespace boost { namespace python {
+
+BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters);
+
+// A pointer to this class is exported/imported via the Python API.
+// All functions are virtual. This is, what we really export/import
+// is essentially just a pointer to a vtbl.
+template
+struct export_converters_base
+{
+ virtual const int get_api_major() const {
+ return detail::EXPORT_CONVERTERS_API_MAJOR; }
+ virtual const int get_api_minor() const {
+ return detail::EXPORT_CONVERTERS_API_MINOR; }
+ virtual PyObject *to_python(const T& x) = 0;
+ virtual PyObject *to_python(std::auto_ptr x) = 0;
+ virtual PyObject *to_python(boost::shared_ptr x) = 0;
+ virtual T* Tptr_from_python(PyObject* obj) = 0;
+ virtual std::auto_ptr& auto_ptr_from_python(PyObject *obj) = 0;
+ virtual boost::shared_ptr& shared_ptr_from_python(PyObject *obj) = 0;
+};
+
+// Converters to be used if T is not copyable.
+template
+struct export_ptr_converters : export_converters_base
+{
+ virtual PyObject *to_python(const T& x) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "to_python(const T&) converter not exported");
+ throw import_error();
+ }
+ virtual PyObject *to_python(std::auto_ptr x) {
+ return BOOST_PYTHON_CONVERSION::to_python(x);
+ }
+ virtual PyObject *to_python(boost::shared_ptr x) {
+ return BOOST_PYTHON_CONVERSION::to_python(x);
+ }
+ virtual T* Tptr_from_python(PyObject* obj) {
+ return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type());
+ }
+ virtual std::auto_ptr& auto_ptr_from_python(PyObject *obj) {
+ return BOOST_PYTHON_CONVERSION::python_extension_class_converters::ptr_from_python(obj, boost::python::type >());
+ }
+ virtual boost::shared_ptr& shared_ptr_from_python(PyObject *obj) {
+ return BOOST_PYTHON_CONVERSION::python_extension_class_converters::ptr_from_python(obj, boost::python::type >());
+ }
+};
+
+// The addditional to_python() converter that can be used if T is copyable.
+template
+struct export_converters : export_ptr_converters
+{
+ virtual PyObject *to_python(const T& x) {
+ BOOST_PYTHON_CONVERSION::python_extension_class_converters cv;
+ return cv.to_python(x);
+ }
+};
+
+namespace detail {
+
+//QUESTIONMARK
+// A stripped-down, modified version of class extension_class.
+// Would it make sense to establish a formal relationship
+// between the two classes?
+template
+class import_extension_class
+ : public python_import_extension_class_converters
+{
+ public:
+ inline import_extension_class(const char *module, const char* klass) {
+ m_module = module;
+ m_klass = klass;
+ }
+
+ static boost::python::export_converters_base* get_converters();
+
+ private:
+ static std::string m_module;
+ static std::string m_klass;
+ static boost::python::export_converters_base* imported_converters;
+};
+
+template std::string import_extension_class::m_module;
+template std::string import_extension_class::m_klass;
+template
+boost::python::export_converters_base*
+import_extension_class::imported_converters = 0;
+
+#ifdef SPECIAL_PYCVTSOBJECT
+
+// A special PyObject for passing pointers to export_converters_base
+template
+struct PyCvtsObject {
+ PyObject_HEAD
+ export_converters_base* cvts;
+};
+
+template
+void DEL_PyCvtsObject(PyCvtsObject* self) { PyMem_DEL(self); }
+
+template
+PyObject *create_PyCvtsObject(export_converters_base* cvts)
+{
+ static char PyCvtsObject_Type__doc__[] =
+ "Boost Python Library (BPL) converters objects to be exported from\n"
+ "one extension module to another.";
+
+ static PyTypeObject PyCvtsObject_Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /*ob_size*/
+ "PyCvtsObject", /*tp_name*/
+ sizeof(PyCvtsObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)(static_cast*)>
+ (DEL_PyCvtsObject)), /*tp_dealloc*/
+ (printfunc)0, /*tp_print*/
+ (getattrfunc)0, /*tp_getattr*/
+ (setattrfunc)0, /*tp_setattr*/
+ (cmpfunc)0, /*tp_compare*/
+ (reprfunc)0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ (hashfunc)0, /*tp_hash*/
+ (ternaryfunc)0, /*tp_call*/
+ (reprfunc)0, /*tp_str*/
+
+ /* Space for future expansion */
+ 0L,0L,0L,0L,
+ PyCvtsObject_Type__doc__ /* Documentation string */
+ };
+
+ PyCvtsObject* self = PyObject_NEW(PyCvtsObject, &PyCvtsObject_Type);
+ if (self == 0) throw export_error();
+ self->cvts = cvts;
+ return reinterpret_cast(self);
+}
+
+#endif // SPECIAL_PYCVTSOBJECT
+
+template
+boost::python::export_converters_base*
+import_extension_class::get_converters() {
+ if (imported_converters == 0) {
+#ifndef SPECIAL_PYCVTSOBJECT
+ void *cobject
+ = import_converters(m_module, m_klass, converters_attribute_name);
+ imported_converters
+ = static_cast*>(cobject);
+#else
+ ref cvts_obj(
+ new_import_converters(m_module, m_klass, converters_attribute_name));
+ PyCvtsObject* cvts = reinterpret_cast*>(cvts_obj.get());
+ imported_converters = cvts->cvts;
+#endif
+ check_export_converters_api(
+ EXPORT_CONVERTERS_API_MAJOR,
+ EXPORT_CONVERTERS_API_MINOR,
+ imported_converters->get_api_major(),
+ imported_converters->get_api_minor());
+ }
+ return imported_converters;
+}
+
+}}} // namespace boost::python::detail
+
+namespace boost { namespace python {
+
+//QUESTIONMARK
+// A stripped-down, modified version of class class_builder.
+// Would it make sense to establish a formal relationship
+// between the two classes?
+template
+class import_class_builder
+ : python_import_extension_class_converters