diff --git a/doc/tutorial/doc/basic_interface.html b/doc/tutorial/doc/basic_interface.html new file mode 100644 index 00000000..a9326c80 --- /dev/null +++ b/doc/tutorial/doc/basic_interface.html @@ -0,0 +1,77 @@ + + + +Basic Interface + + + + + + + + + + +
+ + Basic Interface +
+
+ + + + + + +
+

+Class object wraps PyObject*. All the intricacies of dealing with +PyObjects such as managing reference counting are handled by the +object class. C++ object interoperability is seamless. Boost.Python C++ +objects can in fact be explicitly constructed from any C++ object.

+

+To illustrate, this Python code snippet:

+
+    def f(x, y):
+         if (y == 'foo'):
+             x[3:7] = 'bar'
+         else:
+             x.items += y(3, x)
+         return x
+
+    def getfunc():
+       return f;
+
+

+Can be rewritten in C++ using Boost.Python facilities this way:

+
+    object f(object x, object y) {
+         if (y == "foo")
+             x.slice(3,7) = "bar";
+         else
+             x.attr("items") += y(3, x);
+         return x;
+    }
+    object getfunc() {
+        return object(f);
+    }
+
+

+Apart from cosmetic differences due to the fact that we are writing the +code in C++, the look and feel should be immediately apparent to the Python +coder.

+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/building_an_extension_module.html b/doc/tutorial/doc/building_an_extension_module.html new file mode 100644 index 00000000..ffa176b7 --- /dev/null +++ b/doc/tutorial/doc/building_an_extension_module.html @@ -0,0 +1,186 @@ + + + +Building an Extension Module + + + + + + + + + + +
+ Building + an Extension Module
+
+ + + + + + +
+

Building Boost.Python

+

Every Boost.Python extension module must be linked with the boost_python shared + library. To build boost_python, use Boost.Build + in the usual way from the libs/python/build subdirectory of your boost + installation (if you have already built boost from the top level this may have + no effect, since the work is already done).

+

Configuration

+

You may need to configure the following variables to point Boost.Build at your + Python installation:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Variable NameSemanticsDefaultNotes
PYTHON_ROOT The root directory of your Python installationWindows:
+ c:/tools/python
+ Unix: /usr/local
On Unix, this is the --with-prefix= directory used to configure + Python
PYTHON_VERSION The The 2-part python Major.Minor version numberWindows: 2.1 Unix: 1.5Be sure not to include a third number, e.g. not "2.2.1", even + if that's the version you have.
PYTHON_INCLUDES path to Python #include directoriesAutoconfigured from
+ PYTHON_ROOT
 
PYTHON_LIB_PATHpath to Python library object.Autoconfigured from
+ PYTHON_ROOT
 
PYTHON_STDLIB_PATHpath to Python standard library modulesAutoconfigured from
+ PYTHON_ROOT
 
CYGWIN_ROOT path to the user's Cygwin installationAutoconfigured from
+ PYTHON_ROOT
Cygwin only. This and the following + two settings are useful when building with multiple toolsets on Windows, + since Cygwin requires a different build of Python.
GCC_PYTHON_ROOTpath to the user's Cygwin Python installation$(CYGWIN_ROOT)
+ /usr/local
Cygwin only
GCC_DEBUG_PYTHON_ROOT path to the user's Cygwin pydebug + build$(CYGWIN_ROOT)
+ /usr/local/pydebug
Cygwin only
+

Results

+

The build process will create a libs/python/build/bin-stage subdirectory + of the boost root (or of $(ALL_LOCATE_TARGET), if you have set that + variable), containing the built libraries. The libraries are actually built + to unique directories for each toolset and variant elsewhere in the filesystem, + and copied to the bin-stage directory as a convenience, so if you build with + multiple toolsets at once, the product of later toolsets will overwrite that + of earlier toolsets in bin-stage.

+

Testing

+

To build and test Boost.Python from within the libs/python/build directory, + invoke

+
    bjam -sTOOLS=toolset test
+

This will update all of the Boost.Python v1 test and example targets. The tests + are relatively quiet by default. To get more-verbose output, you might try

+
    bjam -sTOOLS=toolset -sPYTHON_TEST_ARGS=-v test
+

which will print each test's Python code with the expected output as it passes.

+

Building your Extension Module

+

Though there are other approaches, the easiest way to build an extension module + using Boost.Python is with Boost.Build. Until Boost.Build v2 is released, cross-project + build dependencies are not supported, so it works most smoothly if you add a + new subproject to your boost installation. The libs/python/example + subdirectory of your boost installation contains a minimal example (along with + many extra sources). To copy the example subproject:

+
    +
  1. Create a new subdirectory in, libs/python, say libs/python/my_project.
  2. +
  3. Copy libs/python/example/Jamfile + to your new directory.
  4. +
  5. Edit the Jamfile as appropriate for your project. You'll want to change + the subproject rule invocation at the top, and the names of some + of the source files and/or targets.
  6. +
+

If you can't modify or copy your boost installation, the alternative is to + create your own Boost.Build project. A similar example you can use as a starting + point is available in this archive. You'll + need to edit the Jamfile and Jamrules files, depending on the relative location + of your Boost installation and the new project. Note that automatic testing + of extension modules is not available in this configuration.

+

Build Variants

+

Three variant configurations of all python-related targets are supported, and + can be selected by setting the BUILD variable:

+

* release (optimization, -DNDEBUG)
+ * debug (no optimization -D_DEBUG)
+ * debug-python (no optimization, -D_DEBUG -DBOOST_DEBUG_PYTHON)

+

The first two variants of the boost_python library are built by default, and + are compatible with the default Python distribution. The debug-python variant + corresponds to a specially-built debugging version of Python. On Unix platforms, + this python is built by adding --with-pydebug when configuring the + Python build. On Windows, the debugging version of Python is generated by the + "Win32 Debug" target of the PCBuild.dsw Visual C++ 6.0 project in + the PCBuild subdirectory of your Python distribution. Extension modules built + with Python debugging enabled are not link-compatible with a non-debug build + of Python. Since few people actually have a debug build of Python (it doesn't + come with the standard distribution), the normal debug variant builds modules + which are compatible with ordinary Python.

+

On many windows compilers, when extension modules are built with -D_DEBUG, + Python defaults to force linking with a special debugging version of the Python + DLL. Since this debug DLL isn't supplied with the default Python installation + for Windows, Boost.Python uses boost/python/detail/wrap_python.hpp + to temporarily undefine _DEBUG when Python.h is #included + - unless BOOST_DEBUG_PYTHON is defined.

+

If you want the extra runtime checks available with the debugging version of + the library, #define BOOST_DEBUG_PYTHON + to re-enable python debuggin, and link with the debug-python variant of boost_python.

+

If you do not #define BOOST_DEBUG_PYTHON, + be sure that any source files in your extension module #include + <boost/python/detail/wrap_python.hpp> instead of the usual Python.h, + or you will have link incompatibilities.

+ + + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/building_hello_world.html b/doc/tutorial/doc/building_hello_world.html new file mode 100644 index 00000000..297757ea --- /dev/null +++ b/doc/tutorial/doc/building_hello_world.html @@ -0,0 +1,191 @@ + + + +Building Hello World + + + + + + + + + + +
+ + Building Hello World +
+
+ + + + + + +
+

From Start To Finish

+Now the first thing you'd want to do is to build the Hello World module and +try it for yourself in Python. In this section, we shall outline the steps +necessary to achieve that. We shall use the build tool that comes bundled +with every boost distribution: bjam.

+ + + + +
+ Building without bjam

+ +Besides bjam, there are of course other ways to get your module built. +What's written here should not be taken as "the one and only way". +There are of course other build tools apart from bjam. +
+

+We shall skip over the details. Our objective will be to simply create the +hello world module and run it in Python. For a complete reference to +building Boost.Python, check out: +building.html. +After this brief bjam tutorial, we should have built two DLLs:

+

+if you are on Windows, and

+

+if you are on Unix.

+

+The tutorial example can be found in the directory: +libs/python/example/tutorial. There, you can find:

+

+The hello.cpp file is our C++ hello world example. The Jamfile is a +minimalist bjam script that builds the DLLs for us.

+

+Before anything else, you should have the bjam executable in your boost +directory or somewhere in your path such that bjam can be executed in +the command line. Pre-built Boost.Jam executables are available for most +platforms. For example, a pre-built Microsoft Windows bjam executable can +be downloaded +here. +The complete list of bjam pre-built +executables can be found +here.

+

Lets Jam!

+

+

+Here is our minimalist Jamfile:

+
+    subproject libs/python/example/tutorial ;
+
+    SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
+    include python.jam ;
+
+    extension hello                     # Declare a Python extension called hello
+    :   hello.cpp                       # source
+        <dll>../../build/boost_python   # dependencies
+        ;
+

+First, we need to specify our location in the boost project hierarchy. +It so happens that the tutorial example is located in /libs/python/example/tutorial. +Thus:

+
+    subproject libs/python/example/tutorial ;
+

+Then we will include the definitions needed by Python modules:

+
+    SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
+    include python.jam ;
+

+Finally we declare our hello extension:

+
+    extension hello                     # Declare a Python extension called hello
+    :   hello.cpp                       # source
+        <dll>../../build/boost_python   # dependencies
+        ;
+

Running bjam

+bjam is run using your operating system's command line interpreter.

+

Start it up.

+Make sure that the environment is set so that we can invoke the C++ +compiler. With MSVC, that would mean running the Vcvars32.bat batch +file. For instance:

+
+    C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat
+
+

+Some environment variables will have to be setup for proper building of our +Python modules. Example:

+
+    set PYTHON_ROOT=c:/dev/tools/python
+    set PYTHON_VERSION=2.2
+
+

+The above assumes that the Python installation is in c:/dev/tools/python +and that we are using Python version 2.2. You'll have to tweak this path +appropriately. Be sure not to include a third number, e.g. not "2.2.1", +even if that's the version you have.

+

+Now we are ready... Be sure to cd to libs/python/example/tutorial +where the tutorial "hello.cpp" and the "Jamfile" is situated.

+

+Finally:

+
+    bjam -sTOOLS=msvc
+
+

+We are again assuming that we are using Microsoft Visual C++ version 6. If +not, then you will have to specify the appropriate tool. See + +Building Boost Libraries for +further details.

+

+It should be building now:

+
+    cd C:\dev\boost\libs\python\example\tutorial
+    bjam -sTOOLS=msvc
+    ...patience...
+    ...found 1703 targets...
+    ...updating 40 targets...
+

+And so on... Finally:

+
+    vc-C++ ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\
+    runtime-link-dynamic\hello.obj
+    hello.cpp
+    vc-Link ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\
+    runtime-link-dynamic\hello.pyd ..\..\..\..\libs\python\example\tutorial\bin\
+    hello.pyd\msvc\debug\runtime-link-dynamic\hello.lib
+       Creating library ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\
+       msvc\debug\runtime-link-dynamic\hello.lib and object ..\..\..\..\libs\python\
+       example\tutorial\bin\hello.pyd\msvc\debug\runtime-link-dynamic\hello.exp
+    ...updated 40 targets...
+

+If all is well, you should now have:

+

+if you are on Windows, and

+

+if you are on Unix.

+

+boost_python.dll can be found somewhere in libs\python\build\bin +while hello.pyd can be found somewhere in +libs\python\example\tutorial\bin. After a successful build, you can just +link in these DLLs with the Python interpreter. In Windows for example, you +can simply put these libraries inside the directory where the Python +executable is.

+

+You may now fire up Python and run our hello module:

+
+    >>> import hello
+    >>> print hello.greet()
+    hello, world
+
+

There you go... Have fun!

+ + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/call_policies.html b/doc/tutorial/doc/call_policies.html new file mode 100644 index 00000000..4f836700 --- /dev/null +++ b/doc/tutorial/doc/call_policies.html @@ -0,0 +1,169 @@ + + + +Call Policies + + + + + + + + + + +
+ + Call Policies +
+
+ + + + + + +
+

+In C++, we often deal with arguments and return types such as pointers +and references. Such primitive types are rather, ummmm, low level and +they really don't tell us much. At the very least, we don't know the +owner of the pointer or the referenced object. No wonder languages +such as Java and Python never deal with such low level entities. In +C++, it's usually considered a good practice to use smart pointers +which exactly describe ownership semantics. Still, even good C++ +interfaces use raw references and pointers sometimes, so Boost.Python +must deal with them. To do this, it may need your help. Consider the +following C++ function:

+
+    X& f(Y& y, Z* z);
+
+

+How should the library wrap this function? A naive approach builds a +Python X object around result reference. This strategy might or might +not work out. Here's an example where it didn't

+
+    >>> x = f(y, z) #x refers to some C++ X
+    >>> del y
+    >>> x.some_method() #CRASH!
+
+

+What's the problem?

+

+Well, what if f() was implemented as shown below:

+
+    X& f(Y& y, Z* z)
+    {
+        y.z = z;
+        return y.x;
+    }
+
+

+The problem is that the lifetime of result X& is tied to the lifetime +of y, because the f() returns a reference to a member of the y +object. This idiom is is not uncommon and perfectly acceptable in the +context of C++. However, Python users should not be able to crash the +system just by using our C++ interface. In this case deleting y will +invalidate the reference to X. We have a dangling reference.

+

+Here's what's happening:

+
  1. f is called passing in a reference to y and a pointer to z
  2. A reference to y.x is returned
  3. y is deleted. x is a dangling reference
  4. x.some_method() is called
  5. BOOM!

+We could copy result into a new object:

+
+    >>> f(y, z).set(42) #Result disappears
+    >>> y.x.get()       #No crash, but still bad
+    3.14
+
+

+This is not really our intent of our C++ interface. We've broken our +promise that the Python interface should reflect the C++ interface as +closely as possible.

+

+Our problems do not end there. Suppose Y is implemented as follows:

+
+    struct Y
+    {
+        X x; Z* z;
+        int z_value() { return z->value(); }
+    };
+
+

+Notice that the data member z is held by class Y using a raw +pointer. Now we have a potential dangling pointer problem inside Y:

+
+    >>> x = f(y, z) #y refers to z
+    >>> del z       #Kill the z object
+    >>> y.z_value() #CRASH!
+
+

+For reference, here's the implementation of f again:

+
+    X& f(Y& y, Z* z)
+    {
+        y.z = z;
+        return y.x;
+    }
+
+

+Here's what's happening:

+
  1. f is called passing in a reference to y and a pointer to z
  2. A pointer to z is held by y
  3. A reference to y.x is returned
  4. z is deleted. y.z is a dangling pointer
  5. y.z_value() is called
  6. z->value() is called
  7. BOOM!

Call Policies

+Call Policies may be used in situations such as the example detailed above. +In our example, return_internal_reference and with_custodian_and_ward +are our friends:

+
+    def("f", f,
+        return_internal_reference<1,
+            with_custodian_and_ward<1, 2> >());
+
+

+What are the 1 and 2 parameters, you ask?

+
+    return_internal_reference<1
+
+

+Informs Boost.Python that the first argument, in our case Y& y, is the +owner of the returned reference: X&. The "1" simply specifies the +first argument. In short: "return an internal reference X& owned by the +1st argument Y& y".

+
+    with_custodian_and_ward<1, 2>
+
+

+Informs Boost.Python that the lifetime of the argument indicated by ward +(i.e. the 2nd argument: Z* z) is dependent on the lifetime of the +argument indicated by custodian (i.e. the 1st argument: Y& y).

+

+It is also important to note that we have defined two policies above. Two +or more policies can be composed by chaining. Here's the general syntax:

+
+    policy1<args...,
+        policy2<args...,
+            policy3<args...> > >
+
+

+Here is the list of predefined call policies. A complete reference detailing +these can be found +here.

+ + + + +
+ Remember the Zen, Luke:

+"Explicit is better than implicit"
+"In the face of ambiguity, refuse the temptation to guess"
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/class_data_members.html b/doc/tutorial/doc/class_data_members.html new file mode 100644 index 00000000..39847ba8 --- /dev/null +++ b/doc/tutorial/doc/class_data_members.html @@ -0,0 +1,77 @@ + + + +Class Data Members + + + + + + + + + + +
+ + Class Data Members +
+
+ + + + + + +
+

+Data members may also be exposed to Python so that they can be +accessed as attributes of the corresponding Python class. Each data +member that we wish to be exposed may be regarded as read-only or +read-write. Consider this class Var:

+
+    struct Var
+    {
+        Var(std::string name) : name(name), value() {}
+        std::string const name;
+        float value;
+    };
+
+

+Our C++ Var class and its data members can be exposed to Python:

+
+    class_<Var>("Var", init<std::string>())
+        .def_readonly("name", &Var::name)
+        .def_readwrite("value", &Var::value);
+
+

+Then, in Python:

+
+    >>> x = Var('pi')
+    >>> x.value = 3.14
+    >>> print x.name, 'is around', x.value
+    pi is around 3.14
+
+

+Note that name is exposed as read-only while value is exposed +as read-write.

+
+    >>> x.name = 'e' # can't change name
+    Traceback (most recent call last):
+      File "<stdin>", line 1, in ?
+    AttributeError: can't set attribute
+
+ + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/class_operators_special_functions.html b/doc/tutorial/doc/class_operators_special_functions.html new file mode 100644 index 00000000..ca7f6c0b --- /dev/null +++ b/doc/tutorial/doc/class_operators_special_functions.html @@ -0,0 +1,109 @@ + + + +Class Operators/Special Functions + + + + + + + + + + +
+ + Class Operators/Special Functions +
+
+ + + + + + +
+

Python Operators

+C is well known for the abundance of operators. C++ extends this to the +extremes by allowing operator overloading. Boost.Python takes advantage of +this and makes it easy to wrap C++ operator-powered classes.

+

+Consider a file position class FilePos and a set of operators that take +on FilePos instances:

+
+    class FilePos { /*...*/ };
+
+    FilePos     operator+(FilePos, int);
+    FilePos     operator+(int, FilePos);
+    int         operator-(FilePos, FilePos);
+    FilePos     operator-(FilePos, int);
+    FilePos&    operator+=(FilePos&, int);
+    FilePos&    operator-=(FilePos&, int);
+    bool        operator<(FilePos, FilePos);
+
+

+The class and the various operators can be mapped to Python rather easily +and intuitively:

+
+    class_<FilePos>("FilePos")
+        .def(self + int())          // __add__
+        .def(int() + self)          // __radd__
+        .def(self - self)           // __sub__
+        .def(self - int())          // __rsub__
+        .def(self += int())         // __iadd__
+        .def(self -= other<int>())
+        .def(self < self);          // __lt__
+
+

+The code snippet above is very clear and needs almost no explanation at +all. It is virtually the same as the operators' signatures. Just take +note that self refers to FilePos object. Also, not every class T that +you might need to interact with in an operator expression is (cheaply) +default-constructible. You can use other<T>() in place of an actual +T instance when writing "self expressions".

+

Special Methods

+Python has a few more Special Methods. Boost.Python supports all of the +standard special method names supported by real Python class instances. A +similar set of intuitive interfaces can also be used to wrap C++ functions +that correspond to these Python special functions. Example:

+
+    class Rational
+    { operator double() const; };
+
+    Rational pow(Rational, Rational);
+    Rational abs(Rational);
+    ostream& operator<<(ostream&,Rational);
+
+    class_<Rational>()
+        .def(float_(self))                  // __float__
+        .def(pow(self, other<Rational>))    // __pow__
+        .def(abs(self))                     // __abs__
+        .def(str(self))                     // __str__
+        ;
+
+

+Need we say more?

+ + + + +
+ What is the business of operator<< .def(str(self))? +Well, the method str requires the operator<< to do its work (i.e. +operator<< is used by the method defined by def(str(self)).
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/class_properties.html b/doc/tutorial/doc/class_properties.html new file mode 100644 index 00000000..cd2267d5 --- /dev/null +++ b/doc/tutorial/doc/class_properties.html @@ -0,0 +1,81 @@ + + + +Class Properties + + + + + + + + + + +
+ + Class Properties +
+
+ + + + + + +
+

+In C++, classes with public data members are usually frowned +upon. Well designed classes that take advantage of encapsulation hide +the class' data members. The only way to access the class' data is +through access (getter/setter) functions. Access functions expose class +properties. Here's an example:

+
+    struct Num
+    {
+        Num();
+        float get() const;
+        void set(float value);
+        ...
+    };
+
+

+However, in Python attribute access is fine; it doesn't neccessarily break +encapsulation to let users handle attributes directly, because the +attributes can just be a different syntax for a method call. Wrapping our +Num class using Boost.Python:

+
+    class_<Num>("Num")
+        .add_property("rovalue", &Var::get)
+        .add_property("value", &Var::get, &Var::set);
+
+

+And at last, in Python:

+
+    >>> x = Num()
+    >>> x.value = 3.14
+    >>> x.value, x.rovalue
+    (3.14, 3.14)
+    >>> x.rovalue = 2.17 #error!
+
+

+Take note that the class property rovalue is exposed as read-only +since the rovalue setter member function is not passed in:

+
+    .add_property("rovalue", &Var::get)
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/class_virtual_functions.html b/doc/tutorial/doc/class_virtual_functions.html new file mode 100644 index 00000000..6116678a --- /dev/null +++ b/doc/tutorial/doc/class_virtual_functions.html @@ -0,0 +1,227 @@ + + + +Class Virtual Functions + + + + + + + + + + +
+ + Class Virtual Functions +
+
+ + + + + + +
+

+In this section, we shall learn how to make functions behave +polymorphically through virtual functions. Continuing our example, let us +add a virtual function to our Base class:

+
+    struct Base
+    {
+        virtual int f() = 0;
+    };
+
+

+Since f is a pure virtual function, Base is now an abstract +class. Given an instance of our class, the free function call_f +calls some implementation of this virtual function in a concrete +derived class:

+
+    int call_f(Base& b) { return b.f(); }
+
+

+To allow this function to be implemented in a Python derived class, we +need to create a class wrapper:

+
+    struct BaseWrap : Base
+    {
+        BaseWrap(PyObject* self_)
+            : self(self_) {}
+        int f() { return call_method<int>(self, "f"); }
+        PyObject* self;
+    };
+
+ + + + +
+ member function and methods

Python, like +many object oriented languages uses the term methods. Methods +correspond roughly to C++'s member functions
+

+Our class wrapper BaseWrap is derived from Base. Its overridden +virtual member function f in effect calls the corresponding method +of the Python object self, which is a pointer back to the Python +Base object holding our BaseWrap instance.

+ + + + +
+ Why do we need BaseWrap?

+ +You may ask, "Why do we need the BaseWrap derived class? This could +have been designed so that everything gets done right inside of +Base."

+ +One of the goals of Boost.Python is to be minimally intrusive on an +existing C++ design. In principle, it should be possible to expose the +interface for a 3rd party library without changing it. To unintrusively +hook into the virtual functions so that a Python override may be called, we +must use a derived class.

+ +Note however that you don't need to do this to get methods overridden +in Python to behave virtually when called from Python. The only +time you need to do the BaseWrap dance is when you have a virtual +function that's going to be overridden in Python and called +polymorphically from C++.
+

+Wrapping Base and the free function call_f:

+
+    class_<Base, BaseWrap, boost::noncopyable>("Base", no_init)
+        ;
+    def("call_f", call_f);
+
+

+Notice that we parameterized the class_ template with BaseWrap as the +second parameter. What is noncopyable? Without it, the library will try +to create code for converting Base return values of wrapped functions to +Python. To do that, it needs Base's copy constructor... which isn't +available, since Base is an abstract class.

+

+In Python, let us try to instantiate our Base class:

+
+    >>> base = Base()
+    AttributeError: ...
+
+

+Why is it an error? Base is an abstract class. As such it is advisable +to define the Python wrapper with no_init as we have done above. Doing +so will disallow abstract base classes such as Base to be instantiated.

+

Deriving a Python class

+Now, at last, we can even derive from our base class Base in Python:

+
+    >>> class Derived(Base):
+    ...     def f(self):
+    ...         return 42
+    ...
+
+

+Cool eh? A Python class deriving from a C++ class!

+

+Let's now make an instance of our Python class Derived:

+
+    >>> derived = Derived()
+
+

+Calling derived.f():

+
+    >>> derived.f()
+    42
+
+

+Will yield the expected result. Finally, calling calling the free function +call_f with derived as argument:

+
+    >>> call_f(derived)
+    42
+
+

+Will also yield the expected result.

+

+Here's what's happening:

+
  1. call_f(derived) is called in Python
  2. This corresponds to def("call_f", call_f);. Boost.Python dispatches this call.
  3. int call_f(Base& b) { return b.f(); } accepts the call.
  4. The overridden virtual function f of BaseWrap is called.
  5. call_method<int>(self, "f"); dispatches the call back to Python.
  6. def f(self): return 42 is finally called.

+Rewind back to our Base class, if its member function f was not +declared as pure virtual:

+
+    struct Base
+    {
+        virtual int f() { return 0; }
+    };
+
+

+And instead is implemented to return 0, as shown above.

+
+    struct BaseWrap : Base
+    {
+        BaseWrap(PyObject* self_)
+            : self(self_) {}
+        int f() { return call_method<int>(self, "f"); }
+        static int default_f(Base* b) { return b->Base::f(); } // <<=== added
+        PyObject* self;
+    };
+
+

+then, our Boost.Python wrapper:

+
+    class_<Base, BaseWrap>("Base")
+        .def("f", &BaseWrap::default_f)
+        ;
+
+

+Note that we are allowing Base objects to be instantiated this time, +unlike before where we specifically defined the class_<Base> with +no_init.

+

+In Python, the results would be as expected:

+
+    >>> base = Base()
+    >>> class Derived(Base):
+    ...     def f(self):
+    ...         return 42
+    ...
+    >>> derived = Derived()
+
+

+Calling base.f():

+
+    >>> base.f()
+    0
+
+

+Calling derived.f():

+
+    >>> derived.f()
+    42
+
+

+Calling call_f, passing in a base object:

+
+    >>> call_f(base)
+    0
+
+

+Calling call_f, passing in a derived object:

+
+    >>> call_f(derived)
+    42
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/constructors.html b/doc/tutorial/doc/constructors.html new file mode 100644 index 00000000..79237526 --- /dev/null +++ b/doc/tutorial/doc/constructors.html @@ -0,0 +1,102 @@ + + + +Constructors + + + + + + + + + + +
+ + Constructors +
+
+ + + + + + +
+

+Our previous example didn't have any explicit constructors. +Since World is declared as a plain struct, it has an implicit default +constructor. Boost.Python exposes the default constructor by default, +which is why we were able to write

+
+    >>> planet = hello.World()
+
+

+We may wish to wrap a class with a non-default constructor. Let us +build on our previous example:

+
+    struct World
+    {
+        World(std::string msg): msg(msg) {} // added constructor
+        void set(std::string msg) { this->msg = msg; }
+        std::string greet() { return msg; }
+        std::string msg;
+    };
+
+

+This time World has no default constructor; our previous +wrapping code would fail to compile when the library tried to expose +it. We have to tell class_<World> about the constructor we want to +expose instead.

+
+    #include <boost/python.hpp>
+    using namespace boost::python;
+
+    BOOST_PYTHON_MODULE(hello)
+    {
+        class_<World>("World", init<std::string>())
+            .def("greet", &World::greet)
+            .def("set", &World::set)
+        ;
+    }
+
+

+init<std::string>() exposes the constructor taking in a +std::string (in Python, constructors are spelled +""__init__"").

+

+We can expose additional constructors by passing more init<...>s to +the def() member function. Say for example we have another World +constructor taking in two doubles:

+
+    class_<World>("World", init<std::string>())
+        .def(init<double, double>())
+        .def("greet", &World::greet)
+        .def("set", &World::set)
+    ;
+
+

+On the other hand, if we do not wish to expose any constructors at +all, we may use no_init instead:

+
+    class_<Abstract>("Abstract", no_init)
+
+

+This actually adds an __init__ method which always raises a +Python RuntimeError exception.

+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/default_arguments.html b/doc/tutorial/doc/default_arguments.html new file mode 100644 index 00000000..bfb3ce3b --- /dev/null +++ b/doc/tutorial/doc/default_arguments.html @@ -0,0 +1,118 @@ + + + +Default Arguments + + + + + + + + + + +
+ + Default Arguments +
+
+ + + + + + +
+

+Boost.Python wraps (member) function pointers. Unfortunately, C++ function +pointers carry no default argument info. Take a function f with default +arguments:

+
+    int f(int, double = 3.14, char const* = "hello");
+
+

+But the type of a pointer to the function f has no information +about its default arguments:

+
+    int(*g)(int,double,char const*) = f;    // defaults lost!
+
+

+When we pass this function pointer to the def function, there is no way +to retrieve the default arguments:

+
+    def("f", f);                            // defaults lost!
+
+

+Because of this, when wrapping C++ code in earlier versions of +Boost.Python, we had to resort to writing thin wrappers:

+
+    // write "thin wrappers"
+    int f1(int x) { f(x); }
+    int f2(int x, double y) { f(x,y); }
+
+    /*...*/
+
+        // in module init
+        def("f", f);  // all arguments
+        def("f", f2); // two arguments
+        def("f", f1); // one argument
+
+

+When you want to wrap functions (or member functions) that either:

+

+Boost.Python now has a way to make it easier.

+

+For instance, given a function:

+
+    int foo(int a, char b = 1, unsigned c = 2, double d = 3);
+
+

+The macro invocation:

+
+    BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4)
+
+

+Will automatically create the thin wrappers for us. This macro will create +a class foo_overloads that can be passed on to def(...). The third +and fourth macro argument are the minimum arguments and maximum arguments, +respectively. In our foo function the minimum number of arguments is 1 +and the maximum number of arguments is 4. The def(...) function will +automatically add all the foo variants for us:

+
+    .def("foo", foo, foo_overloads());
+
+

+A similar facility is provided for class constructors, again, with +default arguments or a sequence of overloads. Remember init<...>? For example, +given a class X with a constructor:

+
+    struct X
+    {
+        X(int a, char b = 'D', std::string c = "constructor", double d = 0.0);
+        /*...*/
+    }
+
+

+You can easily add this constructor to Boost.Python in one shot:

+
+    .def(init<int, optional<char, std::string, double> >())
+
+

+Notice the use of init<...> and optional<...> to signify the default +(optional arguments).

+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/derived_object_types.html b/doc/tutorial/doc/derived_object_types.html new file mode 100644 index 00000000..54ffccb3 --- /dev/null +++ b/doc/tutorial/doc/derived_object_types.html @@ -0,0 +1,117 @@ + + + +Derived Object types + + + + + + + + + + +
+ + Derived Object types +
+
+ + + + + + +
+

+Boost.Python comes with a set of derived object types corresponding to +that of Python's:

+

+These derived object types act like real Python types. For instance:

+
+    str(1) ==> "1"
+
+

+Wherever appropriate, a particular derived object has corresponding +Python type's methods. For instance, dict has a keys() method:

+
+    d.keys()
+
+

+make_tuple is provided for declaring tuple literals. Example:

+
+    make_tuple(123, 'D', "Hello, World", 0.0);
+
+

+In C++, when Boost.Python objects are used as arguments to functions, +subtype matching is required. For example, when a function f, as +declared below, is wrapped, it will only accept instances of Python's +str type and subtypes.

+
+    void f(str name)
+    {
+        object n2 = name.attr("upper")();   // NAME = name.upper()
+        str NAME = name.upper();            // better
+        object msg = "%s is bigger than %s" % make_tuple(NAME,name);
+    }
+
+

+In finer detail:

+
+    str NAME = name.upper();
+
+

+Illustrates that we provide versions of the str type's methods as C++ +member functions.

+
+    object msg = "%s is bigger than %s" % make_tuple(NAME,name);
+
+

+Demonstrates that you can write the C++ equivalent of "format" % x,y,z +in Python, which is useful since there's no easy way to do that in std C++.

+

+ Beware the common pitfall of forgetting that the constructors +of most of Python's mutable types make copies, just as in Python.

+

+Python:

+
+    >>> d = dict(x.__dict__)     #copies x.__dict__
+    >>> d['whatever']            #modifies the copy
+
+

+C++:

+
+    dict d(x.attr("__dict__"));  #copies x.__dict__
+    d['whatever'] = 3;           #modifies the copy
+
+

class_<T> as objects

+Due to the dynamic nature of Boost.Python objects, any class_<T> may +also be one of these types! The following code snippet wraps the class +(type) object.

+

+We can use this to create wrapped instances. Example:

+
+    object vec345 = (
+        class_<Vec2>("Vec2", init<double, double>())
+            .def_readonly("length", &Point::length)
+            .def_readonly("angle", &Point::angle)
+        )(3.0, 4.0);
+
+    assert(vec345.attr("length") == 5.0);
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/enums.html b/doc/tutorial/doc/enums.html new file mode 100644 index 00000000..0cee713c --- /dev/null +++ b/doc/tutorial/doc/enums.html @@ -0,0 +1,95 @@ + + + +Enums + + + + + + + + + + +
+ + Enums +
+
+ + + + + + +
+

+Boost.Python has a nifty facility to capture and wrap C++ enums. While +Python has no enum type, we'll often want to expose our C++ enums to +Python as an int. Boost.Python's enum facility makes this easy while +taking care of the proper conversions from Python's dynamic typing to C++'s +strong static typing (in C++, ints cannot be implicitly converted to +enums). To illustrate, given a C++ enum:

+
+    enum choice { red, blue };
+
+

+the construct:

+
+    enum_<choice>("choice")
+        .value("red", red)
+        .value("blue", blue)
+        ;
+
+

+can be used to expose to Python. The new enum type is created in the +current scope(), which is usually the current module. The snippet above +creates a Python class derived from Python's int type which is +associated with the C++ type passed as its first parameter.

+ + + + +
+ what is a scope?

The scope is a class that has an +associated global Python object which controls the Python namespace in +which new extension classes and wrapped functions will be defined as +attributes. Details can be found +here.
+

+You can access those values in Python as

+
+    >>> my_module.choice.red
+    my_module.choice.red
+
+

+where my_module is the module where the enum is declared. You can also +create a new scope around a class:

+
+    scope in_X(class_<X>("X")
+                    .def( ... )
+                    .def( ... )
+                );
+
+    // Expose X::nested as X.nested
+    enum_<X::nested>("nested")
+        .value("red", red)
+        .value("blue", blue)
+        ;
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/exception_translation.html b/doc/tutorial/doc/exception_translation.html new file mode 100644 index 00000000..9ec6bc86 --- /dev/null +++ b/doc/tutorial/doc/exception_translation.html @@ -0,0 +1,60 @@ + + + +Exception Translation + + + + + + + + + +
+ + Exception Translation +
+
+ + + + + + +
+

+All C++ exceptions must be caught at the boundary with Python code. This +boundary is the point where C++ meets Python. Boost.Python provides a +default exception handler that translates selected standard exceptions, +then gives up:

+
+    raise RuntimeError, 'unidentifiable C++ Exception'
+
+

+Users may provide custom translation. Here's an example:

+
+    struct PodBayDoorException;
+    void translator(PodBayDoorException& x) {
+        PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave...");
+    }
+    BOOST_PYTHON_MODULE(kubrick) {
+         register_exception_translator<
+              PodBayDoorException>(translator);
+         ...
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/exposing_classes.html b/doc/tutorial/doc/exposing_classes.html new file mode 100644 index 00000000..7a989346 --- /dev/null +++ b/doc/tutorial/doc/exposing_classes.html @@ -0,0 +1,79 @@ + + + +Exposing Classes + + + + + + + + + + +
+ + Exposing Classes +
+
+ + + + + + +
+

+Now let's expose a C++ class to Python.

+

+Consider a C++ class/struct that we want to expose to Python:

+
+    struct World
+    {
+        void set(std::string msg) { this->msg = msg; }
+        std::string greet() { return msg; }
+        std::string msg;
+    };
+
+

+We can expose this to Python by writing a corresponding Boost.Python +C++ Wrapper:

+
+    #include <boost/python.hpp>
+    using namespace boost::python;
+
+    BOOST_PYTHON_MODULE(hello)
+    {
+        class_<World>("World")
+            .def("greet", &World::greet)
+            .def("set", &World::set)
+        ;
+    }
+
+

+Here, we wrote a C++ class wrapper that exposes the member functions +greet and set. Now, after building our module as a shared library, we +may use our class World in Python. Here's a sample Python session:

+
+    >>> import hello
+    >>> planet = hello.World()
+    >>> planet.set('howdy')
+    >>> planet.greet()
+    'howdy'
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/extracting_c___objects.html b/doc/tutorial/doc/extracting_c___objects.html new file mode 100644 index 00000000..36b8bf85 --- /dev/null +++ b/doc/tutorial/doc/extracting_c___objects.html @@ -0,0 +1,79 @@ + + + +Extracting C++ objects + + + + + + + + + + +
+ + Extracting C++ objects +
+
+ + + + + + +
+

+At some point, we will need to get C++ values out of object instances. This +can be achieved with the extract<T> function. Consider the following:

+
+    double x = o.attr("length"); // compile error
+
+

+In the code above, we got a compiler error because Boost.Python +object can't be implicitly converted to doubles. Instead, what +we wanted to do above can be achieved by writing:

+
+    double l = extract<double>(o.attr("length"));
+    Vec2& v = extract<Vec2&>(o);
+    assert(l == v.length());
+
+

+The first line attempts to extract the "length" attribute of the +Boost.Python object o. The second line attempts to extract the +Vec2 object from held by the Boost.Python object o.

+

+Take note that we said "attempt to" above. What if the Boost.Python +object o does not really hold a Vec2 type? This is certainly +a possibility considering the dynamic nature of Python objects. To +be on the safe side, if the C++ type can't be extracted, an +appropriate exception is thrown. To avoid an exception, we need to +test for extractibility:

+
+    extract<Vec2&> x(o);
+    if (x.check()) {
+        Vec2& v = x(); ...
+
+

+ The astute reader might have noticed that the extract<T> +facility in fact solves the mutable copying problem:

+
+    dict d = extract<dict>(x.attr("__dict__"));
+    d['whatever'] = 3;          #modifies x.__dict__ !
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/functions.html b/doc/tutorial/doc/functions.html new file mode 100644 index 00000000..036242e2 --- /dev/null +++ b/doc/tutorial/doc/functions.html @@ -0,0 +1,73 @@ + + + +Functions + + + + + + + + + + +
+ + Functions +
+
+ + + + + + +
+

+In this chapter, we'll look at Boost.Python powered functions in closer +detail. We shall see some facilities to make exposing C++ functions to +Python safe from potential pifalls such as dangling pointers and +references. We shall also see facilities that will make it even easier for +us to expose C++ functions that take advantage of C++ features such as +overloading and default arguments.

+

Read on...

+But before you do, you might want to fire up Python 2.2 or later and type +>>> import this.

+
+    >>> import this
+    The Zen of Python, by Tim Peters
+    Beautiful is better than ugly.
+    Explicit is better than implicit.
+    Simple is better than complex.
+    Complex is better than complicated.
+    Flat is better than nested.
+    Sparse is better than dense.
+    Readability counts.
+    Special cases aren't special enough to break the rules.
+    Although practicality beats purity.
+    Errors should never pass silently.
+    Unless explicitly silenced.
+    In the face of ambiguity, refuse the temptation to guess.
+    There should be one-- and preferably only one --obvious way to do it
+    Although that way may not be obvious at first unless you're Dutch.
+    Now is better than never.
+    Although never is often better than *right* now.
+    If the implementation is hard to explain, it's a bad idea.
+    If the implementation is easy to explain, it may be a good idea.
+    Namespaces are one honking great idea -- let's do more of those!
+
+ + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/inheritance.html b/doc/tutorial/doc/inheritance.html new file mode 100644 index 00000000..0f9fe33f --- /dev/null +++ b/doc/tutorial/doc/inheritance.html @@ -0,0 +1,98 @@ + + + +Inheritance + + + + + + + + + + +
+ + Inheritance +
+
+ + + + + + +
+

+In the previous examples, we dealt with classes that are not polymorphic. +This is not often the case. Much of the time, we will be wrapping +polymorphic classes and class hierarchies related by inheritance. We will +often have to write Boost.Python wrappers for classes that are derived from +abstract base classes.

+

+Consider this trivial inheritance structure:

+
+    struct Base { virtual ~Base(); };
+    struct Derived : Base {};
+
+

+And a set of C++ functions operating on Base and Derived object +instances:

+
+    void b(Base*);
+    void d(Derived*);
+    Base* factory() { return new Derived; }
+
+

+We've seen how we can wrap the base class Base:

+
+    class_<Base>("Base")
+        /*...*/
+        ;
+
+

+Now we can inform Boost.Python of the inheritance relationship between +Derived and its base class Base. Thus:

+
+    class_<Derived, bases<Base> >("Derived")
+        /*...*/
+        ;
+
+

+Doing so, we get some things for free:

+
  1. Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)
  2. If Base is polymorphic, Derived objects which have been passed to Python via a pointer or reference to Base can be passed where a pointer or reference to Derived is expected.

+Now, we shall expose the C++ free functions b and d and factory:

+
+    def("b", b);
+    def("d", d);
+    def("factory", factory);
+
+

+Note that free function factory is being used to generate new +instances of class Derived. In such cases, we use +return_value_policy<manage_new_object> to instruct Python to adopt +the pointer to Base and hold the instance in a new Python Base +object until the the Python object is destroyed. We shall see more of +Boost.Python +call policies later.

+
+    // Tell Python to take ownership of factory's result
+    def("factory", factory,
+        return_value_policy<manage_new_object>());
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/iterators.html b/doc/tutorial/doc/iterators.html new file mode 100644 index 00000000..00e8dc44 --- /dev/null +++ b/doc/tutorial/doc/iterators.html @@ -0,0 +1,101 @@ + + + +Iterators + + + + + + + + + + +
+ + Iterators +
+
+ + + + + + +
+

+In C++, and STL in particular, we see iterators everywhere. Python also has +iterators, but these are two very different beasts.

+

+C++ iterators:

+

+Python Iterators:

+

+The typical Python iteration protocol: for y in x... is as follows:

+
+    iter = x.__iter__()         #get iterator
+    try:
+        while 1:
+        y = iter.next()         #get each item
+        ...                     #process y
+    except StopIteration: pass  #iterator exhausted
+
+

+Boost.Python provides some mechanisms to make C++ iterators play along +nicely as Python iterators. What we need to do is to produce +appropriate __iter__ function from C++ iterators that is compatible +with the Python iteration protocol. For example:

+
+    object get_iterator = iterator<vector<int> >();
+    object iter = get_iterator(v);
+    object first = iter.next();
+
+

+Or for use in class_<>:

+
+    .def("__iter__", iterator<vector<int> >())
+
+

+range

+

+We can create a Python savvy iterator using the range function:

+

+Here, start/finish may be one of:

+

+iterator

+

+Given a container T, iterator is a shortcut that simply calls range +with &T::begin, &T::end.

+

+Let's put this into action... Here's an example from some hypothetical +bogon Particle accelerator code:

+
+    f = Field()
+    for x in f.pions:
+        smash(x)
+    for y in f.bogons:
+        count(y)
+
+

+Now, our C++ Wrapper:

+
+    class_<F>("Field")
+        .property("pions", range(&F::p_begin, &F::p_end))
+        .property("bogons", range(&F::b_begin, &F::b_end));
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/object_interface.html b/doc/tutorial/doc/object_interface.html new file mode 100644 index 00000000..d18a40bb --- /dev/null +++ b/doc/tutorial/doc/object_interface.html @@ -0,0 +1,54 @@ + + + +Object Interface + + + + + + + + + + +
+ + Object Interface +
+
+ + + + + + +
+

+Python is dynamically typed, unlike C++ which is statically typed. Python +variables may hold an integer, a float, list, dict, tuple, str, long etc., +among other things. In the viewpoint of Boost.Python and C++, these +Pythonic variables are just instances of class object. We shall see in +this chapter how to deal with Python objects.

+

+As mentioned, one of the goals of Boost.Python is to provide a +bidirectional mapping between C++ and Python while maintaining the Python +feel. Boost.Python C++ objects are as close as possible to Python. This +should minimize the learning curve significantly.

+

+

+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/quickstart.html b/doc/tutorial/doc/quickstart.html new file mode 100644 index 00000000..ec1a89ac --- /dev/null +++ b/doc/tutorial/doc/quickstart.html @@ -0,0 +1,79 @@ + + + +QuickStart + + + + + + + + + +
+ + QuickStart +
+
+ + + + + + +
+

+The Boost Python Library is a framework for interfacing Python and +C++. It allows you to quickly and seamlessly expose C++ classes +functions and objects to Python, and vice-versa, using no special +tools -- just your C++ compiler. It is designed to wrap C++ interfaces +non-intrusively, so that you should not have to change the C++ code at +all in order to wrap it, making Boost.Python ideal for exposing +3rd-party libraries to Python. The library's use of advanced +metaprogramming techniques simplifies its syntax for users, so that +wrapping code takes on the look of a kind of declarative interface +definition language (IDL).

+

Hello World

+Following C/C++ tradition, let's start with the "hello, world". A C++ +Function:

+
+    char const* greet()
+    {
+       return "hello, world";
+    }
+
+

+can be exposed to Python by writing a Boost.Python wrapper:

+
+    #include <boost/python.hpp>
+    using namespace boost::python;
+
+    BOOST_PYTHON_MODULE(hello)
+    {
+        def("greet", greet);
+    }
+
+

+That's it. We're done. We can now build this as a shared library. The +resulting DLL is now visible to Python. Here's a sample Python session:

+
+    >>> import hello
+    >>> print hello.greet()
+    hello, world
+
+

Next stop... Building your Hello World module from start to finish...

+ + + + + +
+
+
+ +