diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-06-25 22:59:01 +0000 |
---|---|---|
committer | <> | 2013-09-27 11:49:28 +0000 |
commit | 8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch) | |
tree | c09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/python | |
download | boost-tarball-baserock/morph.tar.gz |
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/python')
476 files changed, 58967 insertions, 0 deletions
diff --git a/libs/python/build/Jamfile.v2 b/libs/python/build/Jamfile.v2 new file mode 100644 index 000000000..32bffb0f7 --- /dev/null +++ b/libs/python/build/Jamfile.v2 @@ -0,0 +1,151 @@ +# Copyright David Abrahams 2001-2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import os ; +import indirect ; +import modules ; +import feature ; + +import python ; + +if ! [ python.configured ] && ! ( --without-python in [ modules.peek : ARGV ] ) +{ + # Attempt default configuration of python + import toolset : using ; + using python ; +} + +if [ python.configured ] || ( --without-python in [ modules.peek : ARGV ] ) +{ + alias config-warning ; +} +else +{ + message config-warning + : "warning: No python installation configured and autoconfiguration" + : "note: failed. See http://www.boost.org/libs/python/doc/building.html" + : "note: for configuration instructions or pass --without-python to" + : "note: suppress this message and silently skip all Boost.Python targets" + ; +} + +rule find-py3-version +{ + local versions = [ feature.values python ] ; + local py3ver ; + for local v in $(versions) + { + if $(v) >= 3.0 + { + py3ver = $(v) ; + } + } + return $(py3ver) ; +} + +py3-version = [ find-py3-version ] ; + +project boost/python + : source-location ../src + : requirements + -<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + <tag>@$(__name__).tag + ; + +rule tag ( name : type ? : property-set ) +{ + local result = $(name) ; + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + if $(name) = boost_python && $(PYTHON_ID) + { + result = $(result)-$(PYTHON_ID) ; + } + } + + # forward to the boost tagging rule + return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + $(result) : $(type) : $(property-set) ] ; +} + +rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } +rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } + +rule lib_boost_python ( is-py3 ? ) +{ + + lib [ cond $(is-py3) : boost_python3 : boost_python ] + : # sources + numeric.cpp + list.cpp + long.cpp + dict.cpp + tuple.cpp + str.cpp + slice.cpp + + converter/from_python.cpp + converter/registry.cpp + converter/type_id.cpp + object/enum.cpp + object/class.cpp + object/function.cpp + object/inheritance.cpp + object/life_support.cpp + object/pickle_support.cpp + errors.cpp + module.cpp + converter/builtin_converters.cpp + converter/arg_to_python_base.cpp + object/iterator.cpp + object/stl_iterator.cpp + object_protocol.cpp + object_operators.cpp + wrapper.cpp + import.cpp + exec.cpp + object/function_doc_signature.cpp + : # requirements + <link>static:<define>BOOST_PYTHON_STATIC_LIB + <define>BOOST_PYTHON_SOURCE + + # On Windows, all code using Python has to link to the Python + # import library. + # + # On *nix we never link libboost_python to libpython. When + # extending Python, all Python symbols are provided by the + # Python interpreter executable. When embedding Python, the + # client executable is expected to explicitly link to + # /python//python (the target representing libpython) itself. + # + # python_for_extensions is a target defined by Boost.Build to + # provide the Python include paths, and on Windows, the Python + # import library, as usage requirements. + [ cond [ python.configured ] : <library>/python//python_for_extensions ] + + # we prevent building when there is no python available + # as it's not possible anyway, and to cause dependents to + # fail to build + [ unless [ python.configured ] : <build>no ] + <dependency>config-warning + + <python-debugging>on:<define>BOOST_DEBUG_PYTHON + [ cond $(is-py3) : <python>$(py3-version) ] + : # default build + <link>shared + : # usage requirements + <link>static:<define>BOOST_PYTHON_STATIC_LIB + <python-debugging>on:<define>BOOST_DEBUG_PYTHON + ; + +} + +lib_boost_python ; +boost-install boost_python ; + +if $(py3-version) +{ + lib_boost_python yes ; + boost-install boost_python3 ; +} diff --git a/libs/python/build/python_v1.zip b/libs/python/build/python_v1.zip Binary files differnew file mode 100644 index 000000000..0377a07bb --- /dev/null +++ b/libs/python/build/python_v1.zip diff --git a/libs/python/class.cpp b/libs/python/class.cpp new file mode 100644 index 000000000..078bebdf6 --- /dev/null +++ b/libs/python/class.cpp @@ -0,0 +1,28 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/object.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +struct X +{ + int x; + X(int n) : x(n) { } +}; + +int x_function(X& x) +{ return x.x; +} + + +BOOST_PYTHON_MODULE(class_ext) +{ + class_<X>("X", init<int>()); + def("x_function", x_function); +} + +#include "module_tail.cpp" diff --git a/libs/python/doc/Jamfile b/libs/python/doc/Jamfile new file mode 100644 index 000000000..9b7c8841a --- /dev/null +++ b/libs/python/doc/Jamfile @@ -0,0 +1,23 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import docutils ; + +import path ; +sources = building.rst ; +bases = $(sources:S=) ; + +# This is a path relative to the html/ subdirectory where the +# generated output will eventually be moved. +stylesheet = "--stylesheet=../../../rst.css" ; + +for local b in $(bases) +{ + html $(b) : $(b).rst : + + <docutils-html>"-gdt --source-url="./$(b).rst" --link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript "$(stylesheet) + ; +} + +alias htmls : $(bases) ; +stage . : $(bases) ; diff --git a/libs/python/doc/PyConDC_2003/bpl.html b/libs/python/doc/PyConDC_2003/bpl.html new file mode 100644 index 000000000..32b655bd9 --- /dev/null +++ b/libs/python/doc/PyConDC_2003/bpl.html @@ -0,0 +1,22 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="refresh" content="0; URL=http://www.boost-consulting.com/writing/bpl.html"> + + <title>Loading: “Building Hybrid Systems With Boost.Python”</title> + </head> + + <body> + Loading...; if nothing happens, please go to <a href= "http://www.boost-consulting.com/writing/bpl.html">http://www.boost-consulting.com/writing/bpl.html</a>. + </body> +</html> + diff --git a/libs/python/doc/PyConDC_2003/bpl.pdf b/libs/python/doc/PyConDC_2003/bpl.pdf Binary files differnew file mode 100644 index 000000000..09827aff0 --- /dev/null +++ b/libs/python/doc/PyConDC_2003/bpl.pdf diff --git a/libs/python/doc/PyConDC_2003/bpl.txt b/libs/python/doc/PyConDC_2003/bpl.txt new file mode 100644 index 000000000..d6921b124 --- /dev/null +++ b/libs/python/doc/PyConDC_2003/bpl.txt @@ -0,0 +1,5 @@ +.. Copyright David Abrahams 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +This file has been moved to http://www.boost-consulting.com/writing/bpl.txt. diff --git a/libs/python/doc/PyConDC_2003/bpl_mods.txt b/libs/python/doc/PyConDC_2003/bpl_mods.txt new file mode 100644 index 000000000..d42f00f8b --- /dev/null +++ b/libs/python/doc/PyConDC_2003/bpl_mods.txt @@ -0,0 +1,911 @@ +Copyright David Abrahams 2006. Distributed under the Boost +Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +.. This is a comment. Note how any initial comments are moved by + transforms to after the document title, subtitle, and docinfo. + +.. Need intro and conclusion +.. Exposing classes + .. Constructors + .. Overloading + .. Properties and data members + .. Inheritance + .. Operators and Special Functions + .. Virtual Functions +.. Call Policies + +++++++++++++++++++++++++++++++++++++++++++++++ + Introducing Boost.Python (Extended Abstract) +++++++++++++++++++++++++++++++++++++++++++++++ + + +.. bibliographic fields (which also require a transform): + +:Author: David Abrahams +:Address: 45 Walnut Street + Somerville, MA 02143 +:Contact: dave@boost-consulting.com +:organization: `Boost Consulting`_ +:status: This is a "work in progress" +:version: 1 +:copyright: Copyright David Abrahams 2002. All rights reserved + +:Dedication: + + For my girlfriend, wife, and partner Luann + +:abstract: + + This paper describes the Boost.Python library, a system for + C++/Python interoperability. + +.. meta:: + :keywords: Boost,python,Boost.Python,C++ + :description lang=en: C++/Python interoperability with Boost.Python + +.. contents:: Table of Contents +.. section-numbering:: + + +.. _`Boost Consulting`: http://www.boost-consulting.com + +============== + Introduction +============== + +Python and C++ are in many ways as different as two languages could +be: while C++ is usually compiled to machine-code, Python is +interpreted. Python's dynamic type system is often cited as the +foundation of its flexibility, while in C++ static typing is the +cornerstone of its efficiency. C++ has an intricate and difficult +meta-language to support compile-time polymorphism, while Python is +a uniform language with convenient runtime polymorphism. + +Yet for many programmers, these very differences mean that Python and +C++ complement one another perfectly. Performance bottlenecks in +Python programs can be rewritten in C++ for maximal speed, and +authors of powerful C++ libraries choose Python as a middleware +language for its flexible system integration capabilities. +Furthermore, the surface differences mask some strong similarities: + +* 'C'-family control structures (if, while, for...) + +* Support for object-orientation, functional programming, and generic + programming (these are both *multi-paradigm* programming languages.) + +* Comprehensive operator overloading facilities, recognizing the + importance of syntactic variability for readability and + expressivity. + +* High-level concepts such as collections and iterators. + +* High-level encapsulation facilities (C++: namespaces, Python: modules) + to support the design of re-usable libraries. + +* Exception-handling for effective management of error conditions. + +* C++ idioms in common use, such as handle/body classes and + reference-counted smart pointers mirror Python reference semantics. + +Python provides a rich 'C' API for writers of 'C' extension modules. +Unfortunately, using this API directly for exposing C++ type and +function interfaces to Python is much more tedious than it should be. +This is mainly due to the limitations of the 'C' language. Compared to +C++ and Python, 'C' has only very rudimentary abstraction facilities. +Support for exception-handling is completely missing. One important +undesirable consequence is that 'C' extension module writers are +required to manually manage Python reference counts. Another unpleasant +consequence is a very high degree of repetition of similar code in 'C' +extension modules. Of course highly redundant code does not only cause +frustration for the module writer, but is also very difficult to +maintain. + +The limitations of the 'C' API have lead to the development of a +variety of wrapping systems. SWIG_ is probably the most popular package +for the integration of C/C++ and Python. A more recent development is +the SIP_ package, which is specifically designed for interfacing Python +with the Qt_ graphical user interface library. Both SWIG and SIP +introduce a new specialized language for defining the inter-language +bindings. Of course being able to use a specialized language has +advantages, but having to deal with three different languages (Python, +C/C++ and the interface language) also introduces practical and mental +difficulties. The CXX_ package demonstrates an interesting alternative. +It shows that at least some parts of Python's 'C' API can be wrapped +and presented through a much more user-friendly C++ interface. However, +unlike SWIG and SIP, CXX does not include support for wrapping C++ +classes as new Python types. CXX is also no longer actively developed. + +In some respects Boost.Python combines ideas from SWIG and SIP with +ideas from CXX. Like SWIG and SIP, Boost.Python is a system for +wrapping C++ classes as new Python "built-in" types, and C/C++ +functions as Python functions. Like CXX, Boost.Python presents Python's +'C' API through a C++ interface. Boost.Python goes beyond the scope of +other systems with the unique support for C++ virtual functions that +are overrideable in Python, support for organizing extensions as Python +packages with a central registry for inter-language type conversions, +and a convenient mechanism for tying into Python's serialization engine +(pickle). Importantly, all this is achieved without introducing a new +syntax. Boost.Python leverages the power of C++ meta-programming +techniques to introspect about the C++ type system, and presents a +simple, IDL-like C++ interface for exposing C/C++ code in extension +modules. Boost.Python is a pure C++ library, the inter-language +bindings are defined in pure C++, and other than a C++ compiler only +Python itself is required to get started with Boost.Python. Last but +not least, Boost.Python is an unrestricted open source library. There +are no strings attached even for commercial applications. + +.. _SWIG: http://www.swig.org/ +.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php +.. _Qt: http://www.trolltech.com/ +.. _CXX: http://cxx.sourceforge.net/ + +=========================== + Boost.Python Design Goals +=========================== + +The primary goal of Boost.Python is to allow users to expose C++ +classes and functions to Python using nothing more than a C++ +compiler. In broad strokes, the user experience should be one of +directly manipulating C++ objects from Python. + +However, it's also important not to translate all interfaces *too* +literally: the idioms of each language must be respected. For +example, though C++ and Python both have an iterator concept, they are +expressed very differently. Boost.Python has to be able to bridge the +interface gap. + +It must be possible to insulate Python users from crashes resulting +from trivial misuses of C++ interfaces, such as accessing +already-deleted objects. By the same token the library should +insulate C++ users from low-level Python 'C' API, replacing +error-prone 'C' interfaces like manual reference-count management and +raw ``PyObject`` pointers with more-robust alternatives. + +Support for component-based development is crucial, so that C++ types +exposed in one extension module can be passed to functions exposed in +another without loss of crucial information like C++ inheritance +relationships. + +Finally, all wrapping must be *non-intrusive*, without modifying or +even seeing the original C++ source code. Existing C++ libraries have +to be wrappable by third parties who only have access to header files +and binaries. + +========================== + Hello Boost.Python World +========================== + +And now for a preview of Boost.Python, and how it improves on the raw +facilities offered by Python. Here's a function we might want to +expose:: + + char const* greet(unsigned x) + { + static char const* const msgs[] = { "hello", "Boost.Python", "world!" }; + + if (x > 2) + throw std::range_error("greet: index out of range"); + + return msgs[x]; + } + +To wrap this function in standard C++ using the Python 'C' API, we'd +need something like this:: + + extern "C" // all Python interactions use 'C' linkage and calling convention + { + // Wrapper to handle argument/result conversion and checking + PyObject* greet_wrap(PyObject* args, PyObject * keywords) + { + int x; + if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments + { + char const* result = greet(x); // invoke wrapped function + return PyString_FromString(result); // convert result to Python + } + return 0; // error occurred + } + + // Table of wrapped functions to be exposed by the module + static PyMethodDef methods[] = { + { "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" } + , { NULL, NULL, 0, NULL } // sentinel + }; + + // module initialization function + DL_EXPORT init_hello() + { + (void) Py_InitModule("hello", methods); // add the methods to the module + } + } + +Now here's the wrapping code we'd use to expose it with Boost.Python:: + + #include <boost/python.hpp> + using namespace boost::python; + BOOST_PYTHON_MODULE(hello) + { + def("greet", greet, "return one of 3 parts of a greeting"); + } + +and here it is in action:: + + >>> import hello + >>> for x in range(3): + ... print hello.greet(x) + ... + hello + Boost.Python + world! + +Aside from the fact that the 'C' API version is much more verbose than +the BPL one, it's worth noting that it doesn't handle a few things +correctly: + +* The original function accepts an unsigned integer, and the Python + 'C' API only gives us a way of extracting signed integers. The + Boost.Python version will raise a Python exception if we try to pass + a negative number to ``hello.greet``, but the other one will proceed + to do whatever the C++ implementation does when converting an + negative integer to unsigned (usually wrapping to some very large + number), and pass the incorrect translation on to the wrapped + function. + +* That brings us to the second problem: if the C++ ``greet()`` + function is called with a number greater than 2, it will throw an + exception. Typically, if a C++ exception propagates across the + boundary with code generated by a 'C' compiler, it will cause a + crash. As you can see in the first version, there's no C++ + scaffolding there to prevent this from happening. Functions wrapped + by Boost.Python automatically include an exception-handling layer + which protects Python users by translating unhandled C++ exceptions + into a corresponding Python exception. + +* A slightly more-subtle limitation is that the argument conversion + used in the Python 'C' API case can only get that integer ``x`` in + *one way*. PyArg_ParseTuple can't convert Python ``long`` objects + (arbitrary-precision integers) which happen to fit in an ``unsigned + int`` but not in a ``signed long``, nor will it ever handle a + wrapped C++ class with a user-defined implicit ``operator unsigned + int()`` conversion. The BPL's dynamic type conversion registry + allows users to add arbitrary conversion methods. + +================== + Library Overview +================== + +This section outlines some of the library's major features. Except as +necessary to avoid confusion, details of library implementation are +omitted. + +------------------------------------------- + The fundamental type-conversion mechanism +------------------------------------------- + +XXX This needs to be rewritten. + +Every argument of every wrapped function requires some kind of +extraction code to convert it from Python to C++. Likewise, the +function return value has to be converted from C++ to Python. +Appropriate Python exceptions must be raised if the conversion fails. +Argument and return types are part of the function's type, and much of +this tedium can be relieved if the wrapping system can extract that +information through introspection. + +Passing a wrapped C++ derived class instance to a C++ function +accepting a pointer or reference to a base class requires knowledge of +the inheritance relationship and how to translate the address of a base +class into that of a derived class. + +------------------ + Exposing Classes +------------------ + +C++ classes and structs are exposed with a similarly-terse interface. +Given:: + + struct World + { + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +The following code will expose it in our extension module:: + + #include <boost/python.hpp> + BOOST_PYTHON_MODULE(hello) + { + class_<World>("World") + .def("greet", &World::greet) + .def("set", &World::set) + ; + } + +Although this code has a certain pythonic familiarity, people +sometimes find the syntax bit confusing because it doesn't look like +most of the C++ code they're used to. All the same, this is just +standard C++. Because of their flexible syntax and operator +overloading, C++ and Python are great for defining domain-specific +(sub)languages +(DSLs), and that's what we've done in BPL. To break it down:: + + class_<World>("World") + +constructs an unnamed object of type ``class_<World>`` and passes +``"World"`` to its constructor. This creates a new-style Python class +called ``World`` in the extension module, and associates it with the +C++ type ``World`` in the BPL type conversion registry. We might have +also written:: + + class_<World> w("World"); + +but that would've been more verbose, since we'd have to name ``w`` +again to invoke its ``def()`` member function:: + + w.def("greet", &World::greet) + +There's nothing special about the location of the dot for member +access in the original example: C++ allows any amount of whitespace on +either side of a token, and placing the dot at the beginning of each +line allows us to chain as many successive calls to member functions +as we like with a uniform syntax. The other key fact that allows +chaining is that ``class_<>`` member functions all return a reference +to ``*this``. + +So the example is equivalent to:: + + class_<World> w("World"); + w.def("greet", &World::greet); + w.def("set", &World::set); + +It's occasionally useful to be able to break down the components of a +Boost.Python class wrapper in this way, but the rest of this paper +will tend to stick to the terse syntax. + +For completeness, here's the wrapped class in use: + +>>> import hello +>>> planet = hello.World() +>>> planet.set('howdy') +>>> planet.greet() +'howdy' + +Constructors +============ + +Since our ``World`` class is just a plain ``struct``, it has an +implicit no-argument (nullary) constructor. Boost.Python exposes the +nullary constructor by default, which is why we were able to write: + +>>> planet = hello.World() + +However, well-designed classes in any language may require constructor +arguments in order to establish their invariants. Unlike Python, +where ``__init__`` is just a specially-named method, In C++ +constructors cannot be handled like ordinary member functions. In +particular, we can't take their address: ``&World::World`` is an +error. The library provides a different interface for specifying +constructors. Given:: + + struct World + { + World(std::string msg); // added constructor + ... + +we can modify our wrapping code as follows:: + + class_<World>("World", init<std::string>()) + ... + +of course, a C++ class may have additional constructors, and we can +expose those as well by passing more instances of ``init<...>`` to +``def()``:: + + class_<World>("World", init<std::string>()) + .def(init<double, double>()) + ... + +Boost.Python allows wrapped functions, member functions, and +constructors to be overloaded to mirror C++ overloading. + +Data Members and Properties +=========================== + +Any publicly-accessible data members in a C++ class can be easily +exposed as either ``readonly`` or ``readwrite`` attributes:: + + class_<World>("World", init<std::string>()) + .def_readonly("msg", &World::msg) + ... + +and can be used directly in Python: + +>>> planet = hello.World('howdy') +>>> planet.msg +'howdy' + +This does *not* result in adding attributes to the ``World`` instance +``__dict__``, which can result in substantial memory savings when +wrapping large data structures. In fact, no instance ``__dict__`` +will be created at all unless attributes are explicitly added from +Python. BPL owes this capability to the new Python 2.2 type system, +in particular the descriptor interface and ``property`` type. + +In C++, publicly-accessible data members are considered a sign of poor +design because they break encapsulation, and style guides usually +dictate the use of "getter" and "setter" functions instead. In +Python, however, ``__getattr__``, ``__setattr__``, and since 2.2, +``property`` mean that attribute access is just one more +well-encapsulated syntactic tool at the programmer's disposal. BPL +bridges this idiomatic gap by making Python ``property`` creation +directly available to users. So if ``msg`` were private, we could +still expose it as attribute in Python as follows:: + + class_<World>("World", init<std::string>()) + .add_property("msg", &World::greet, &World::set) + ... + +The example above mirrors the familiar usage of properties in Python +2.2+: + +>>> class World(object): +... __init__(self, msg): +... self.__msg = msg +... def greet(self): +... return self.__msg +... def set(self, msg): +... self.__msg = msg +... msg = property(greet, set) + +Operators and Special Functions +=============================== + +The ability to write arithmetic operators for user-defined types that +C++ and Python both allow the definition of has been a major factor in +the popularity of both languages for scientific computing. The +success of packages like NumPy attests to the power of exposing +operators in extension modules. In this example we'll wrap a class +representing a position in a large file:: + + class FilePos { /*...*/ }; + + // Linear offset + FilePos operator+(FilePos, int); + FilePos operator+(int, FilePos); + FilePos operator-(FilePos, int); + + // Distance between two FilePos objects + int operator-(FilePos, FilePos); + + // Offset with assignment + FilePos& operator+=(FilePos&, int); + FilePos& operator-=(FilePos&, int); + + // Comparison + bool operator<(FilePos, FilePos); + +The wrapping code looks like this:: + + class_<FilePos>("FilePos") + .def(self + int()) // __add__ + .def(int() + self) // __radd__ + .def(self - int()) // __sub__ + + .def(self - self) // __sub__ + + .def(self += int()) // __iadd__ + .def(self -= int()) // __isub__ + + .def(self < self); // __lt__ + ; + +The magic is performed using a simplified application of "expression +templates" [VELD1995]_, a technique originally developed by for +optimization of high-performance matrix algebra expressions. The +essence is that instead of performing the computation immediately, +operators are overloaded to construct a type *representing* the +computation. In matrix algebra, dramatic optimizations are often +available when the structure of an entire expression can be taken into +account, rather than processing each operation "greedily". +Boost.Python uses the same technique to build an appropriate Python +callable object based on an expression involving ``self``, which is +then added to the class. + +Inheritance +=========== + +C++ inheritance relationships can be represented to Boost.Python by adding +an optional ``bases<...>`` argument to the ``class_<...>`` template +parameter list as follows:: + + class_<Derived, bases<Base1,Base2> >("Derived") + ... + +This has two effects: + +1. When the ``class_<...>`` is created, Python type objects + corresponding to ``Base1`` and ``Base2`` are looked up in the BPL + registry, and are used as bases for the new Python ``Derived`` type + object [#mi]_, so methods exposed for the Python ``Base1`` and + ``Base2`` types are automatically members of the ``Derived`` type. + Because the registry is global, this works correctly even if + ``Derived`` is exposed in a different module from either of its + bases. + +2. C++ conversions from ``Derived`` to its bases are added to the + Boost.Python registry. Thus wrapped C++ methods expecting (a + pointer or reference to) an object of either base type can be + called with an object wrapping a ``Derived`` instance. Wrapped + member functions of class ``T`` are treated as though they have an + implicit first argument of ``T&``, so these conversions are + necessary to allow the base class methods to be called for derived + objects. + +Of course it's possible to derive new Python classes from wrapped C++ +class instances. Because Boost.Python uses the new-style class +system, that works very much as for the Python built-in types. There +is one significant detail in which it differs: the built-in types +generally establish their invariants in their ``__new__`` function, so +that derived classes do not need to call ``__init__`` on the base +class before invoking its methods : + +>>> class L(list): +... def __init__(self): +... pass +... +>>> L().reverse() +>>> + +Because C++ object construction is a one-step operation, C++ instance +data cannot be constructed until the arguments are available, in the +``__init__`` function: + +>>> class D(SomeBPLClass): +... def __init__(self): +... pass +... +>>> D().some_bpl_method() +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: bad argument type for built-in operation + +This happened because Boost.Python couldn't find instance data of type +``SomeBPLClass`` within the ``D`` instance; ``D``'s ``__init__`` +function masked construction of the base class. It could be corrected +by either removing ``D``'s ``__init__`` function or having it call +``SomeBPLClass.__init__(...)`` explicitly. + +Virtual Functions +================= + +Deriving new types in Python from extension classes is not very +interesting unless they can be used polymorphically from C++. In +other words, Python method implementations should appear to override +the implementation of C++ virtual functions when called *through base +class pointers/references from C++*. Since the only way to alter the +behavior of a virtual function is to override it in a derived class, +the user must build a special derived class to dispatch a polymorphic +class' virtual functions:: + + // + // interface to wrap: + // + class Base + { + public: + virtual int f(std::string x) { return 42; } + virtual ~Base(); + }; + + int calls_f(Base const& b, std::string x) { return b.f(x); } + + // + // Wrapping Code + // + + // Dispatcher class + struct BaseWrap : Base + { + // Store a pointer to the Python object + BaseWrap(PyObject* self_) : self(self_) {} + PyObject* self; + + // Default implementation, for when f is not overridden + int f_default(std::string x) { return this->Base::f(x); } + // Dispatch implementation + int f(std::string x) { return call_method<int>(self, "f", x); } + }; + + ... + def("calls_f", calls_f); + class_<Base, BaseWrap>("Base") + .def("f", &Base::f, &BaseWrap::f_default) + ; + +Now here's some Python code which demonstrates: + +>>> class Derived(Base): +... def f(self, s): +... return len(s) +... +>>> calls_f(Base(), 'foo') +42 +>>> calls_f(Derived(), 'forty-two') +9 + +Things to notice about the dispatcher class: + +* The key element which allows overriding in Python is the + ``call_method`` invocation, which uses the same global type + conversion registry as the C++ function wrapping does to convert its + arguments from C++ to Python and its return type from Python to C++. + +* Any constructor signatures you wish to wrap must be replicated with + an initial ``PyObject*`` argument + +* The dispatcher must store this argument so that it can be used to + invoke ``call_method`` + +* The ``f_default`` member function is needed when the function being + exposed is not pure virtual; there's no other way ``Base::f`` can be + called on an object of type ``BaseWrap``, since it overrides ``f``. + +Admittedly, this formula is tedious to repeat, especially on a project +with many polymorphic classes; that it is necessary reflects +limitations in C++'s compile-time reflection capabilities. Several +efforts are underway to write front-ends for Boost.Python which can +generate these dispatchers (and other wrapping code) automatically. +If these are successful it will mark a move away from wrapping +everything directly in pure C++ for many of our users. + +--------------- + Serialization +--------------- + +*Serialization* is the process of converting objects in memory to a +form that can be stored on disk or sent over a network connection. The +serialized object (most often a plain string) can be retrieved and +converted back to the original object. A good serialization system will +automatically convert entire object hierarchies. Python's standard +``pickle`` module is such a system. It leverages the language's strong +runtime introspection facilities for serializing practically arbitrary +user-defined objects. With a few simple and unintrusive provisions this +powerful machinery can be extended to also work for wrapped C++ objects. +Here is an example:: + + #include <string> + + struct World + { + World(std::string a_msg) : msg(a_msg) {} + std::string greet() const { return msg; } + std::string msg; + }; + + #include <boost/python.hpp> + using namespace boost::python; + + struct World_picklers : pickle_suite + { + static tuple + getinitargs(World const& w) { return make_tuple(w.greet()); } + }; + + BOOST_PYTHON_MODULE(hello) + { + class_<World>("World", init<std::string>()) + .def("greet", &World::greet) + .def_pickle(World_picklers()) + ; + } + +Now let's create a ``World`` object and put it to rest on disk:: + + >>> import hello + >>> import pickle + >>> a_world = hello.World("howdy") + >>> pickle.dump(a_world, open("my_world", "w")) + +In a potentially *different script* on a potentially *different +computer* with a potentially *different operating system*:: + + >>> import pickle + >>> resurrected_world = pickle.load(open("my_world", "r")) + >>> resurrected_world.greet() + 'howdy' + +Of course the ``cPickle`` module can also be used for faster +processing. + +Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol +defined in the standard Python documentation. There is a one-to-one +correspondence between the standard pickling methods (``__getinitargs__``, +``__getstate__``, ``__setstate__``) and the functions defined by the +user in the class derived from ``pickle_suite`` (``getinitargs``, +``getstate``, ``setstate``). The ``class_::def_pickle()`` member function +is used to establish the Python bindings for all user-defined functions +simultaneously. Correct signatures for these functions are enforced at +compile time. Non-sensical combinations of the three pickle functions +are also rejected at compile time. These measures are designed to +help the user in avoiding obvious errors. + +Enabling serialization of more complex C++ objects requires a little +more work than is shown in the example above. Fortunately the +``object`` interface (see next section) greatly helps in keeping the +code manageable. + +------------------ + Object interface +------------------ + +Experienced extension module authors will be familiar with the 'C' view +of Python objects, the ubiquitous ``PyObject*``. Most if not all Python +'C' API functions involve ``PyObject*`` as arguments or return type. A +major complication is the raw reference counting interface presented to +the 'C' programmer. E.g. some API functions return *new references* and +others return *borrowed references*. It is up to the extension module +writer to properly increment and decrement reference counts. This +quickly becomes cumbersome and error prone, especially if there are +multiple execution paths. + +Boost.Python provides a type ``object`` which is essentially a high +level wrapper around ``PyObject*``. ``object`` automates reference +counting as much as possible. It also provides the facilities for +converting arbitrary C++ types to Python objects and vice versa. +This significantly reduces the learning effort for prospective +extension module writers. + +Creating an ``object`` from any other type is extremely simple:: + + object o(3); + +``object`` has templated interactions with all other types, with +automatic to-python conversions. It happens so naturally that it's +easily overlooked. + +The ``extract<T>`` class template can be used to convert Python objects +to C++ types:: + + double x = extract<double>(o); + +All registered user-defined conversions are automatically accessible +through the ``object`` interface. With reference to the ``World`` class +defined in previous examples:: + + object as_python_object(World("howdy")); + World back_as_c_plus_plus_object = extract<World>(as_python_object); + +If a C++ type cannot be converted to a Python object an appropriate +exception is thrown at runtime. Similarly, an appropriate exception is +thrown if a C++ type cannot be extracted from a Python object. +``extract<T>`` provides facilities for avoiding exceptions if this is +desired. + +The ``object::attr()`` member function is available for accessing +and manipulating attributes of Python objects. For example:: + + object planet(World()); + planet.attr("set")("howdy"); + +``planet.attr("set")`` returns a callable ``object``. ``"howdy"`` is +converted to a Python string object which is then passed as an argument +to the ``set`` method. + +The ``object`` type is accompanied by a set of derived types +that mirror the Python built-in types such as ``list``, ``dict``, +``tuple``, etc. as much as possible. This enables convenient +manipulation of these high-level types from C++:: + + dict d; + d["some"] = "thing"; + d["lucky_number"] = 13; + list l = d.keys(); + +This almost looks and works like regular Python code, but it is pure C++. + +================= + Thinking hybrid +================= + +For many applications runtime performance considerations are very +important. This is particularly true for most scientific applications. +Often the performance considerations dictate the use of a compiled +language for the core algorithms. Traditionally the decision to use a +particular programming language is an exclusive one. Because of the +practical and mental difficulties of combining different languages many +systems are written in just one language. This is quite unfortunate +because the price payed for runtime performance is typically a +significant overhead due to static typing. For example, our experience +shows that developing maintainable C++ code is typically much more +time-consuming and requires much more hard-earned working experience +than developing useful Python code. A related observation is that many +compiled packages are augmented by some type of rudimentary scripting +layer. These ad hoc solutions clearly show that many times a compiled +language alone does not get the job done. On the other hand it is also +clear that a pure Python implementation is too slow for numerically +intensive production code. + +Boost.Python enables us to *think hybrid* when developing new +applications. Python can be used for rapidly prototyping a +new application. Python's ease of use and the large pool of standard +libraries give us a head start on the way to a first working system. If +necessary, the working procedure can be used to discover the +rate-limiting algorithms. To maximize performance these can be +reimplemented in C++, together with the Boost.Python bindings needed to +tie them back into the existing higher-level procedure. + +Of course, this *top-down* approach is less attractive if it is clear +from the start that many algorithms will eventually have to be +implemented in a compiled language. Fortunately Boost.Python also +enables us to pursue a *bottom-up* approach. We have used this approach +very successfully in the development of a toolbox for scientific +applications (scitbx) that we will describe elsewhere. The toolbox +started out mainly as a library of C++ classes with Boost.Python +bindings, and for a while the growth was mainly concentrated on the C++ +parts. However, as the toolbox is becoming more complete, more and more +newly added functionality can be implemented in Python. We expect this +trend to continue, as illustrated qualitatively in this figure: + +.. image:: python_cpp_mix.png + +This figure shows the ratio of newly added C++ and Python code over +time as new algorithms are implemented. We expect this ratio to level +out near 70% Python. The increasing ability to solve new problems +mostly with the easy-to-use Python language rather than a necessarily +more arcane statically typed language is the return on the investment +of learning how to use Boost.Python. The ability to solve some problems +entirely using only Python will enable a larger group of people to +participate in the rapid development of new applications. + +============= + Conclusions +============= + +The examples in this paper illustrate that Boost.Python enables +seamless interoperability between C++ and Python. Importantly, this is +achieved without introducing a third syntax: the Python/C++ interface +definitions are written in pure C++. This avoids any problems with +parsing the C++ code to be interfaced to Python, yet the interface +definitions are concise and maintainable. Freed from most of the +development-time penalties of crossing a language boundary, software +designers can take full advantage of two rich and complimentary +language environments. In practice it turns out that some things are +very difficult to do with pure Python/C (e.g. an efficient array +library with an intuitive interface in the compiled language) and +others are very difficult to do with pure C++ (e.g. serialization). +If one has the luxury of being able to design a software system as a +hybrid system from the ground up there are many new ways of avoiding +road blocks in one language or the other. + +.. I'm not ready to give up on all of this quite yet + +.. Perhaps one day we'll have a language with the simplicity and + expressive power of Python and the compile-time muscle of C++. Being + able to take advantage of all of these facilities without paying the + mental and development-time penalties of crossing a language barrier + would bring enormous benefits. Until then, interoperability tools + like Boost.Python can help lower the barrier and make the benefits of + both languages more accessible to both communities. + +=========== + Footnotes +=========== + +.. [#mi] For hard-core new-style class/extension module writers it is + worth noting that the normal requirement that all extension classes + with data form a layout-compatible single-inheritance chain is + lifted for Boost.Python extension classes. Clearly, either + ``Base1`` or ``Base2`` has to occupy a different offset in the + ``Derived`` class instance. This is possible because the wrapped + part of BPL extension class instances is never assumed to have a + fixed offset within the wrapper. + +=========== + Citations +=========== + +.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report, + Vol. 7 No. 5 June 1995, pp. 26-31. + http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html diff --git a/libs/python/doc/PyConDC_2003/default.css b/libs/python/doc/PyConDC_2003/default.css new file mode 100644 index 000000000..f8109bbd3 --- /dev/null +++ b/libs/python/doc/PyConDC_2003/default.css @@ -0,0 +1,188 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:copyright: This stylesheet has been placed in the public domain. + +boostinspect:nolicense + +Default cascading style sheet for the HTML output of Docutils. +*/ + +.first { + margin-top: 0 } + +.last { + margin-bottom: 0 } + +a.toc-backref { + text-decoration: none ; + color: black } + +dd { + margin-bottom: 0.5em } + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.attention, div.caution, div.danger, div.error, div.hint, +div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +div.hint p.admonition-title, div.important p.admonition-title, +div.note p.admonition-title, div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + font-size: smaller } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr { + width: 75% } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.line-block { + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option-argument { + font-style: italic } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +table { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.citation { + border-left: solid thin gray ; + padding-left: 0.5ex } + +table.docinfo { + margin: 2em 4em } + +table.footnote { + border-left: solid thin black ; + padding-left: 0.5ex } + +td, th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +th.docinfo-name, th.field-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap } + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + font-size: 100% } + +tt { + background-color: #eeeeee } + +ul.auto-toc { + list-style-type: none } diff --git a/libs/python/doc/PyConDC_2003/python_cpp_mix.jpg b/libs/python/doc/PyConDC_2003/python_cpp_mix.jpg Binary files differnew file mode 100644 index 000000000..755a9605b --- /dev/null +++ b/libs/python/doc/PyConDC_2003/python_cpp_mix.jpg diff --git a/libs/python/doc/PyConDC_2003/python_cpp_mix.png b/libs/python/doc/PyConDC_2003/python_cpp_mix.png Binary files differnew file mode 100644 index 000000000..fd74cbb22 --- /dev/null +++ b/libs/python/doc/PyConDC_2003/python_cpp_mix.png diff --git a/libs/python/doc/boost.css b/libs/python/doc/boost.css new file mode 100644 index 000000000..6c3e9808e --- /dev/null +++ b/libs/python/doc/boost.css @@ -0,0 +1,63 @@ +/* Copyright David Abrahams 2006. Distributed under the Boost + Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ +H1 +{ + FONT-SIZE: 200% + COLOR: #00007f +} +H2 +{ + FONT-SIZE: 150%; +} +H3 +{ + FONT-SIZE: 125%; +} +H4 +{ + FONT-SIZE: 108%; +} +BODY +{ + FONT-SIZE: 100%; + BACKGROUND-COLOR: #ffffff +} +PRE +{ + MARGIN-LEFT: 2pc; + FONT-SIZE: 80%; + BACKGROUND-COLOR: #dfffff +} +CODE +{ + FONT-SIZE: 95%; + white-space: pre +} +.index +{ + TEXT-ALIGN: left +} +.page-index +{ + TEXT-ALIGN: left +} +.definition +{ + TEXT-ALIGN: left +} +.footnote +{ + FONT-SIZE: 66%; + VERTICAL-ALIGN: super; + TEXT-DECORATION: none +} +.function-semantics +{ + CLEAR: left +} +.metafunction-semantics +{ + CLEAR: left +} diff --git a/libs/python/doc/building.html b/libs/python/doc/building.html new file mode 100644 index 000000000..e2c48847f --- /dev/null +++ b/libs/python/doc/building.html @@ -0,0 +1,636 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> +<title>Boost C++ Libraries: Boost.Python Build and Test HOWTO</title> +<link rel="stylesheet" href="../../../rst.css" type="text/css" /> +</head> +<body> +<div class="document" id="logo-boost-python-build-and-test-howto"> +<h1 class="title"><a class="reference external" href="../index.html"><img alt="Boost C++ Libraries:" class="boost-logo" src="../../../boost.png" /></a> Boost.Python Build and Test HOWTO</h1> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at --> +<!-- http://www.boost.org/LICENSE_1_0.txt) --> +<div class="contents sidebar small topic" id="contents"> +<p class="topic-title first">Contents</p> +<ul class="auto-toc simple"> +<li><a class="reference internal" href="#requirements" id="id25">1 Requirements</a></li> +<li><a class="reference internal" href="#background" id="id26">2 Background</a></li> +<li><a class="reference internal" href="#no-install-quickstart" id="id27">3 No-Install Quickstart</a><ul class="auto-toc"> +<li><a class="reference internal" href="#basic-procedure" id="id28">3.1 Basic Procedure</a></li> +<li><a class="reference internal" href="#in-case-of-trouble" id="id29">3.2 In Case of Trouble</a></li> +<li><a class="reference internal" href="#in-case-everything-seemed-to-work" id="id30">3.3 In Case Everything Seemed to Work</a></li> +<li><a class="reference internal" href="#modifying-the-example-project" id="id31">3.4 Modifying the Example Project</a></li> +</ul> +</li> +<li><a class="reference internal" href="#installing-boost-python-on-your-system" id="id32">4 Installing Boost.Python on your System</a></li> +<li><a class="reference internal" href="#configuring-boost-build" id="id33">5 Configuring Boost.Build</a><ul class="auto-toc"> +<li><a class="reference internal" href="#python-configuration-parameters" id="id34">5.1 Python Configuration Parameters</a></li> +<li><a class="reference internal" href="#examples" id="id35">5.2 Examples</a></li> +</ul> +</li> +<li><a class="reference internal" href="#choosing-a-boost-python-library-binary" id="id36">6 Choosing a Boost.Python Library Binary</a><ul class="auto-toc"> +<li><a class="reference internal" href="#the-dynamic-binary" id="id37">6.1 The Dynamic Binary</a></li> +<li><a class="reference internal" href="#the-static-binary" id="id38">6.2 The Static Binary</a></li> +</ul> +</li> +<li><a class="reference internal" href="#include-issues" id="id39">7 <tt class="docutils literal"><span class="pre">#include</span></tt> Issues</a></li> +<li><a class="reference internal" href="#python-debugging-builds" id="id40">8 Python Debugging Builds</a></li> +<li><a class="reference internal" href="#testing-boost-python" id="id41">9 Testing Boost.Python</a></li> +<li><a class="reference internal" href="#notes-for-mingw-and-cygwin-with-mno-cygwin-gcc-users" id="id42">10 Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users</a></li> +</ul> +</div> +<div class="section" id="requirements"> +<h1><a class="toc-backref" href="#id25">1 Requirements</a></h1> +<p>Boost.Python requires <a class="reference external" href="http://www.python.org/2.2">Python 2.2</a><a class="footnote-reference" href="#id22" id="id2"><sup>1</sup></a> <em>or</em> <a class="reference external" href="http://www.python.org"><em>newer</em></a>.</p> +</div> +<div class="section" id="background"> +<h1><a class="toc-backref" href="#id26">2 Background</a></h1> +<p>There are two basic models for combining C++ and Python:</p> +<ul class="simple"> +<li><a class="reference external" href="http://www.python.org/doc/current/ext/intro.html">extending</a>, in which the end-user launches the Python interpreter +executable and imports Python “extension modules†written in C++. +Think of taking a library written in C++ and giving it a Python +interface so Python programmers can use it. From Python, these +modules look just like regular Python modules.</li> +<li><a class="reference external" href="http://www.python.org/doc/current/ext/embedding.html">embedding</a>, in which the end-user launches a program written +in C++ that in turn invokes the Python interpreter as a library +subroutine. Think of adding scriptability to an existing +application.</li> +</ul> +<p>The key distinction between extending and embedding is the location +of the C++ <tt class="docutils literal"><span class="pre">main()</span></tt> function: in the Python interpreter executable, +or in some other program, respectively. Note that even when +embedding Python in another program, <a class="reference external" href="http://www.python.org/doc/current/ext/extending-with-embedding.html">extension modules are often +the best way to make C/C++ functionality accessible to Python +code</a>, so the use of extension modules is really at the heart of +both models.</p> +<p>Except in rare cases, extension modules are built as +dynamically-loaded libraries with a single entry point, which means +you can change them without rebuilding either the other extension +modules or the executable containing <tt class="docutils literal"><span class="pre">main()</span></tt>.</p> +</div> +<div class="section" id="no-install-quickstart"> +<span id="quickstart"></span><h1><a class="toc-backref" href="#id27">3 No-Install Quickstart</a></h1> +<p>There is no need to “install Boost†in order to get started using +Boost.Python. These instructions use <a class="reference external" href="../../../tools/build/index.html">Boost.Build</a> projects, +which will build those binaries as soon as they're needed. Your +first tests may take a little longer while you wait for +Boost.Python to build, but doing things this way will save you from +worrying about build intricacies like which library binaries to use +for a specific compiler configuration and figuring out the right +compiler options to use yourself.</p> +<!-- .. raw:: html + +<div style="width:50%"> --> +<div class="note"> +<p class="first admonition-title">Note</p> +<p>Of course it's possible to use other build systems to +build Boost.Python and its extensions, but they are not +officially supported by Boost. Moreover <strong>99% of all “I can't +build Boost.Python†problems come from trying to use another +build system</strong> without first following these instructions.</p> +<p>If you want to use another system anyway, we suggest that you +follow these instructions, and then invoke <tt class="docutils literal"><span class="pre">bjam</span></tt> with the</p> +<pre class="literal-block"> +<tt class="docutils literal"><span class="pre">-a</span> <span class="pre">-o</span></tt><em>filename</em> +</pre> +<p class="last">options to dump the build commands it executes to a file, so +you can see what your alternate build system needs to do.</p> +</div> +<!-- .. raw:: html + +</div> --> +<div class="section" id="basic-procedure"> +<h2><a class="toc-backref" href="#id28">3.1 Basic Procedure</a></h2> +<ol class="arabic"> +<li><p class="first">Get Boost; see sections 1 and 2 [<a class="reference external" href="../../../more/getting_started/unix-variants.html#get-boost">Unix/Linux</a>, <a class="reference external" href="../../../more/getting_started/windows.html#get-boost">Windows</a>] of the +Boost <a class="reference external" href="../../../more/getting_started/index.html">Getting Started Guide</a>.</p> +</li> +<li><p class="first">Get the <tt class="docutils literal"><span class="pre">bjam</span></tt> build driver. See section 5 [<a class="reference external" href="../../../more/getting_started/unix-variants.html#prepare-to-use-a-boost-library-binary">Unix/Linux</a>, +<a class="reference external" href="../../../more/getting_started/windows.html#prepare-to-use-a-boost-library-binary">Windows</a>] of the Boost <a class="reference external" href="../../../more/getting_started/index.html">Getting Started Guide</a>.</p> +</li> +<li><p class="first">cd into the <tt class="docutils literal"><span class="pre">libs/python/example/quickstart/</span></tt> directory of your +Boost installation, which contains a small example project.</p> +</li> +<li><p class="first">Invoke <tt class="docutils literal"><span class="pre">bjam</span></tt>. Replace the “<tt class="docutils literal"><span class="pre">stage</span></tt>“ argument from the +example invocation from section 5 of the <a class="reference external" href="../../../more/getting_started/index.html">Getting Started +Guide</a> with “<tt class="docutils literal"><span class="pre">test</span></tt>,“ to build all the test targets. Also add +the argument “<tt class="docutils literal"><span class="pre">--verbose-test</span></tt>†to see the output generated by +the tests when they are run.</p> +<p>On Windows, your <tt class="docutils literal"><span class="pre">bjam</span></tt> invocation might look something like:</p> +<pre class="literal-block"> +C:\boost_1_34_0\…\quickstart> <strong>bjam toolset=msvc --verbose-test test</strong> +</pre> +<p>and on Unix variants, perhaps,</p> +<pre class="literal-block"> +~/boost_1_34_0/…/quickstart$ <strong>bjam toolset=gcc --verbose-test test</strong> +</pre> +</li> +</ol> +<div class="admonition-note-to-windows-users admonition"> +<p class="first admonition-title">Note to Windows Users</p> +<p class="last">For the sake of concision, the rest of this guide will use +unix-style forward slashes in pathnames instead of the +backslashes with which you may be more familiar. The forward +slashes should work everywhere except in <a class="reference external" href="../../../more/getting_started/windows.html#command-prompt">Command Prompt</a> +windows, where you should use backslashes.</p> +</div> +<p>If you followed this procedure successfully, you will have built an +extension module called <tt class="docutils literal"><span class="pre">extending</span></tt> and tested it by running a +Python script called <tt class="docutils literal"><span class="pre">test_extending.py</span></tt>. You will also have +built and run a simple application called <tt class="docutils literal"><span class="pre">embedding</span></tt> that embeds +python.</p> +</div> +<div class="section" id="in-case-of-trouble"> +<h2><a class="toc-backref" href="#id29">3.2 In Case of Trouble</a></h2> +<p>If you're seeing lots of compiler and/or linker error messages, +it's probably because Boost.Build is having trouble finding your +Python installation. You might want to pass the +<tt class="docutils literal"><span class="pre">--debug-configuration</span></tt> option to <tt class="docutils literal"><span class="pre">bjam</span></tt> the first few times +you invoke it, to make sure that Boost.Build is correctly locating +all the parts of your Python installation. If it isn't, consider +<a class="reference internal" href="#configuring-boost-build">Configuring Boost.Build</a> as detailed below.</p> +<p>If you're still having trouble, Someone on one of the following +mailing lists may be able to help:</p> +<ul class="simple"> +<li>The <a class="reference external" href="http://www.boost.org/more/mailing_lists.htm#jamboost">Boost.Build mailing list</a> for issues related to Boost.Build</li> +<li>The Python <a class="reference external" href="http://www.boost.org/more/mailing_lists.htm#cplussig">C++ Sig</a> for issues specifically related to Boost.Python</li> +</ul> +</div> +<div class="section" id="in-case-everything-seemed-to-work"> +<h2><a class="toc-backref" href="#id30">3.3 In Case Everything Seemed to Work</a></h2> +<p>Rejoice! If you're new to Boost.Python, at this point it might be +a good idea to ignore build issues for a while and concentrate on +learning the library by going through the <a class="reference external" href="tutorial/index.html">tutorial</a> and perhaps +some of the <a class="reference external" href="v2/reference.html">reference documentation</a>, trying out what you've +learned about the API by modifying the quickstart project.</p> +</div> +<div class="section" id="modifying-the-example-project"> +<h2><a class="toc-backref" href="#id31">3.4 Modifying the Example Project</a></h2> +<p>If you're content to keep your extension module forever in one +source file called <a class="reference external" href="../example/quickstart/extending.cpp"><tt class="docutils literal"><span class="pre">extending.cpp</span></tt></a>, inside your Boost +distribution, and import it forever as <tt class="docutils literal"><span class="pre">extending</span></tt>, then you can +stop here. However, it's likely that you will want to make a few +changes. There are a few things you can do without having to learn +<a class="reference external" href="../../../tools/build/index.html">Boost.Build</a> in depth.</p> +<p>The project you just built is specified in two files in the current +directory: <a class="reference external" href="../example/quickstart/boost-build.jam"><tt class="docutils literal"><span class="pre">boost-build.jam</span></tt></a>, which tells <tt class="docutils literal"><span class="pre">bjam</span></tt> where it can +find the interpreted code of the Boost build system, and +<a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a>, which describes the targets you just built. These +files are heavily commented, so they should be easy to modify. +Take care, however, to preserve whitespace. Punctuation such as +<tt class="docutils literal"><span class="pre">;</span></tt> will not be recognized as intended by <tt class="docutils literal"><span class="pre">bjam</span></tt> if it is not +surrounded by whitespace.</p> +<div class="section" id="relocate-the-project"> +<h3>Relocate the Project</h3> +<p>You'll probably want to copy this project elsewhere so you can +change it without modifying your Boost distribution. To do that, +simply</p> +<ol class="loweralpha simple"> +<li>copy the entire <tt class="docutils literal"><span class="pre">libs/python/example/quickstart/</span></tt> directory +into a new directory.</li> +<li>In the new copies of <a class="reference external" href="../example/quickstart/boost-build.jam"><tt class="docutils literal"><span class="pre">boost-build.jam</span></tt></a> and <a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a>, locate +the relative path near the top of the file that is clearly +marked by a comment, and edit that path so that it refers to the +same directory your Boost distribution as it referred to when +the file was in its original location in the +<tt class="docutils literal"><span class="pre">libs/python/example/quickstart/</span></tt> directory.</li> +</ol> +<p>For example, if you moved the project from +<tt class="docutils literal"><span class="pre">/home/dave/boost_1_34_0/libs/python/example/quickstart</span></tt> to +<tt class="docutils literal"><span class="pre">/home/dave/my-project</span></tt>, you could change the first path in +<a class="reference external" href="../example/quickstart/boost-build.jam"><tt class="docutils literal"><span class="pre">boost-build.jam</span></tt></a> from</p> +<pre class="literal-block"> +<strong>../../../..</strong>/tools/build/v2 +</pre> +<p>to</p> +<pre class="literal-block"> +<strong>/home/dave/boost_1_34_0</strong>/tools/build/v2 +</pre> +<p>and change the first path in <a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a> from</p> +<pre class="literal-block"> +<strong>../../../..</strong> +</pre> +<p>to</p> +<pre class="literal-block"> +<strong>/home/dave/boost_1_34_0</strong> +</pre> +</div> +<div class="section" id="add-new-or-change-names-of-existing-source-files"> +<h3>Add New or Change Names of Existing Source Files</h3> +<p>The names of additional source files involved in building your +extension module or embedding application can be listed in +<a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a> right alongside <tt class="docutils literal"><span class="pre">extending.cpp</span></tt> or <tt class="docutils literal"><span class="pre">embedding.cpp</span></tt> +respectively. Just be sure to leave whitespace around each +filename:</p> +<pre class="literal-block"> +… file1.cpp file2.cpp file3.cpp … +</pre> +<p>Naturally, if you want to change the name of a source file you can +tell Boost.Build about it by editing the name in <a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a>.</p> +</div> +<div class="section" id="change-the-name-of-your-extension-module"> +<h3>Change the Name of your Extension Module</h3> +<p>The name of the extension module is determined by two things:</p> +<ol class="arabic simple"> +<li>the name in <a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a> immediately following <tt class="docutils literal"><span class="pre">python-extension</span></tt>, and</li> +<li>the name passed to <tt class="docutils literal"><span class="pre">BOOST_PYTHON_MODULE</span></tt> in <a class="reference external" href="../example/quickstart/extending.cpp"><tt class="docutils literal"><span class="pre">extending.cpp</span></tt></a>.</li> +</ol> +<p>To change the name of the extension module from <tt class="docutils literal"><span class="pre">extending</span></tt> to +<tt class="docutils literal"><span class="pre">hello</span></tt>, you'd edit <a class="reference external" href="../example/quickstart/Jamroot"><tt class="docutils literal"><span class="pre">Jamroot</span></tt></a>, changing</p> +<pre class="literal-block"> +python-extension <strong>extending</strong> : extending.cpp ; +</pre> +<p>to</p> +<pre class="literal-block"> +python-extension <strong>hello</strong> : extending.cpp ; +</pre> +<p>and you'd edit extending.cpp, changing</p> +<pre class="literal-block"> +BOOST_PYTHON_MODULE(<strong>extending</strong>) +</pre> +<p>to</p> +<pre class="literal-block"> +BOOST_PYTHON_MODULE(<strong>hello</strong>) +</pre> +</div> +</div> +</div> +<div class="section" id="installing-boost-python-on-your-system"> +<h1><a class="toc-backref" href="#id32">4 Installing Boost.Python on your System</a></h1> +<p>Since Boost.Python is a separately-compiled (as opposed to +<a class="reference external" href="../../../more/getting_started/windows.html#header-only-libraries">header-only</a>) library, its user relies on the services of a +Boost.Python library binary.</p> +<p>If you need a regular installation of the Boost.Python library +binaries on your system, the Boost <a class="reference external" href="../../../more/getting_started/index.html">Getting Started Guide</a> will +walk you through the steps of creating one. If building binaries +from source, you might want to supply the <tt class="docutils literal"><span class="pre">--with-python</span></tt> +argument to <tt class="docutils literal"><span class="pre">bjam</span></tt> (or the <tt class="docutils literal"><span class="pre">--with-libraries=python</span></tt> argument +to <tt class="docutils literal"><span class="pre">configure</span></tt>), so only the Boost.Python binary will be built, +rather than all the Boost binaries.</p> +</div> +<div class="section" id="configuring-boost-build"> +<h1><a class="toc-backref" href="#id33">5 Configuring Boost.Build</a></h1> +<p>As described in the <a class="reference external" href="http://www.boost.orgdoc/html/bbv2/advanced.html#bbv2.advanced.configuration">Boost.Build reference manual</a>, a file called +<tt class="docutils literal"><span class="pre">user-config.jam</span></tt> in your home directory<a class="footnote-reference" href="#home-dir" id="id11"><sup>6</sup></a> is used to +specify the tools and libraries available to the build system. You +may need to create or edit <tt class="docutils literal"><span class="pre">user-config.jam</span></tt> to tell Boost.Build +how to invoke Python, <tt class="docutils literal"><span class="pre">#include</span></tt> its headers, and link with its +libraries.</p> +<div class="admonition-users-of-unix-variant-oses admonition"> +<p class="first admonition-title">Users of Unix-Variant OSes</p> +<p class="last">If you are using a unix-variant OS and you ran Boost's +<tt class="docutils literal"><span class="pre">configure</span></tt> script, it may have generated a +<tt class="docutils literal"><span class="pre">user-config.jam</span></tt> for you.<a class="footnote-reference" href="#overwrite" id="id13"><sup>4</sup></a> If your <tt class="docutils literal"><span class="pre">configure</span></tt>/<tt class="docutils literal"><span class="pre">make</span></tt> sequence was successful and Boost.Python binaries +were built, your <tt class="docutils literal"><span class="pre">user-config.jam</span></tt> file is probably already +correct.</p> +</div> +<p>If you have one fairly “standard†python installation for your +platform, you might not need to do anything special to describe it. If +you haven't configured python in <tt class="docutils literal"><span class="pre">user-config.jam</span></tt> (and you don't +specify <tt class="docutils literal"><span class="pre">--without-python</span></tt> on the Boost.Build command line), +Boost.Build will automatically execute the equivalent of</p> +<pre class="literal-block"> +import toolset : using ; +using python ; +</pre> +<p>which automatically looks for Python in the most likely places. +However, that only happens when using the Boost.Python project file +(e.g. when referred to by another project as in the <a class="reference internal" href="#quickstart">quickstart</a> +method). If instead you are linking against separately-compiled +Boost.Python binaries, you should set up a <tt class="docutils literal"><span class="pre">user-config.jam</span></tt> file +with at least the minimal incantation above.</p> +<div class="section" id="python-configuration-parameters"> +<h2><a class="toc-backref" href="#id34">5.1 Python Configuration Parameters</a></h2> +<p>If you have several versions of Python installed, or Python is +installed in an unusual way, you may want to supply any or all of +the following optional parameters to <tt class="docutils literal"><span class="pre">using</span> <span class="pre">python</span></tt>.</p> +<dl class="docutils"> +<dt>version</dt> +<dd>the version of Python to use. Should be in Major.Minor +format, for example, <tt class="docutils literal"><span class="pre">2.3</span></tt>. Do not include the subminor +version (i.e. <em>not</em> <tt class="docutils literal"><span class="pre">2.5.1</span></tt>). If you have multiple Python +versions installed, the version will usually be the only +configuration argument required.</dd> +<dt>cmd-or-prefix</dt> +<dd>preferably, a command that invokes a Python interpreter. +Alternatively, the installation prefix for Python libraries and +header files. Only use the alternative formulation if there is +no appropriate Python executable available.</dd> +<dt>includes</dt> +<dd>the <tt class="docutils literal"><span class="pre">#include</span></tt> paths for Python headers. Normally the correct +path(s) will be automatically deduced from <tt class="docutils literal"><span class="pre">version</span></tt> and/or +<tt class="docutils literal"><span class="pre">cmd-or-prefix</span></tt>.</dd> +<dt>libraries</dt> +<dd>the path to Python library binaries. On MacOS/Darwin, +you can also pass the path of the Python framework. Normally the +correct path(s) will be automatically deduced from <tt class="docutils literal"><span class="pre">version</span></tt> +and/or <tt class="docutils literal"><span class="pre">cmd-or-prefix</span></tt>.</dd> +<dt>condition</dt> +<dd>if specified, should be a set of Boost.Build +properties that are matched against the build configuration when +Boost.Build selects a Python configuration to use. See examples +below for details.</dd> +<dt>extension-suffix</dt> +<dd>A string to append to the name of extension +modules before the true filename extension. You almost certainly +don't need to use this. Usually this suffix is only used when +targeting a Windows debug build of Python, and will be set +automatically for you based on the value of the +<a class="reference internal" href="#python-debugging"><tt class="docutils literal"><span class="pre"><python-debugging></span></tt></a> feature. However, at least one Linux +distribution (Ubuntu Feisty Fawn) has a specially configured +<a class="reference external" href="https://wiki.ubuntu.com/PyDbgBuilds">python-dbg</a> package that claims to use such a suffix.</dd> +</dl> +</div> +<div class="section" id="examples"> +<h2><a class="toc-backref" href="#id35">5.2 Examples</a></h2> +<p>Note that in the examples below, case and <em>especially whitespace</em> are +significant.</p> +<ul> +<li><p class="first">If you have both python 2.5 and python 2.4 installed, +<tt class="docutils literal"><span class="pre">user-config.jam</span></tt> might contain:</p> +<pre class="literal-block"> +using python : 2.5 ; # Make both versions of Python available + +using python : 2.4 ; # To build with python 2.4, add python=2.4 + # to your command line. +</pre> +<p>The first version configured (2.5) becomes the default. To build +against python 2.4, add <tt class="docutils literal"><span class="pre">python=2.4</span></tt> to the <tt class="docutils literal"><span class="pre">bjam</span></tt> command line.</p> +</li> +<li><p class="first">If you have python installed in an unusual location, you might +supply the path to the interpreter in the <tt class="docutils literal"><span class="pre">cmd-or-prefix</span></tt> +parameter:</p> +<pre class="literal-block"> +using python : : /usr/local/python-2.6-beta/bin/python ; +</pre> +</li> +<li><p class="first">If you have a separate build of Python for use with a particular +toolset, you might supply that toolset in the <tt class="docutils literal"><span class="pre">condition</span></tt> +parameter:</p> +<pre class="literal-block"> +using python ; # use for most toolsets + +# Use with Intel C++ toolset +using python + : # version + : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix + : # includes + : # libraries + : <toolset>intel # condition + ; +</pre> +</li> +<li><p class="first">If you have downloaded the Python sources and built both the +normal and the “<a class="reference internal" href="#id19">python debugging</a>†builds from source on +Windows, you might see:</p> +<pre class="literal-block"> +using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; +using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d + : # includes + : # libs + : <python-debugging>on ; +</pre> +</li> +<li><p class="first">You can set up your user-config.jam so a bjam built under Windows +can build/test both Windows and <a class="reference external" href="http://cygwin.com">Cygwin</a> python extensions. Just pass +<tt class="docutils literal"><span class="pre"><target-os>cygwin</span></tt> in the <tt class="docutils literal"><span class="pre">condition</span></tt> parameter +for the cygwin python installation:</p> +<pre class="literal-block"> +# windows installation +using python ; + +# cygwin installation +using python : : c:\\cygwin\\bin\\python2.5 : : : <target-os>cygwin ; +</pre> +<p>when you put target-os=cygwin in your build request, it should build +with the cygwin version of python:<a class="footnote-reference" href="#flavor" id="id15"><sup>5</sup></a></p> +<blockquote> +<p>bjam target-os=cygwin toolset=gcc</p> +</blockquote> +<p>This is supposed to work the other way, too (targeting windows +python with a <a class="reference external" href="http://cygwin.com">Cygwin</a> bjam) but it seems as though the support in +Boost.Build's toolsets for building that way is broken at the +time of this writing.</p> +</li> +<li><p class="first">Note that because of <a class="reference external" href="http://zigzag.cs.msu.su/boost.build/wiki/AlternativeSelection">the way Boost.Build currently selects target +alternatives</a>, you might have be very explicit in your build +requests. For example, given:</p> +<pre class="literal-block"> +using python : 2.5 ; # a regular windows build +using python : 2.4 : : : : <target-os>cygwin ; +</pre> +<p>building with</p> +<pre class="literal-block"> +bjam target-os=cygwin +</pre> +<p>will yield an error. Instead, you'll need to write:</p> +<pre class="literal-block"> +bjam target-os=cygwin/python=2.4 +</pre> +</li> +</ul> +</div> +</div> +<div class="section" id="choosing-a-boost-python-library-binary"> +<h1><a class="toc-backref" href="#id36">6 Choosing a Boost.Python Library Binary</a></h1> +<p>If—instead of letting Boost.Build construct and link with the right +libraries automatically—you choose to use a pre-built Boost.Python +library, you'll need to think about which one to link with. The +Boost.Python binary comes in both static and dynamic flavors. Take +care to choose the right flavor for your application.<a class="footnote-reference" href="#naming" id="id17"><sup>2</sup></a></p> +<div class="section" id="the-dynamic-binary"> +<h2><a class="toc-backref" href="#id37">6.1 The Dynamic Binary</a></h2> +<p>The dynamic library is the safest and most-versatile choice:</p> +<ul class="simple"> +<li>A single copy of the library code is used by all extension +modules built with a given toolset.<a class="footnote-reference" href="#toolset-specific" id="id18"><sup>3</sup></a></li> +<li>The library contains a type conversion registry. Because one +registry is shared among all extension modules, instances of a +class exposed to Python in one dynamically-loaded extension +module can be passed to functions exposed in another such module.</li> +</ul> +</div> +<div class="section" id="the-static-binary"> +<h2><a class="toc-backref" href="#id38">6.2 The Static Binary</a></h2> +<p>It might be appropriate to use the static Boost.Python library in +any of the following cases:</p> +<ul class="simple"> +<li>You are <a class="reference external" href="http://www.python.org/doc/current/ext/intro.html">extending</a> python and the types exposed in your +dynamically-loaded extension module don't need to be used by any +other Boost.Python extension modules, and you don't care if the +core library code is duplicated among them.</li> +<li>You are <a class="reference external" href="http://www.python.org/doc/current/ext/embedding.html">embedding</a> python in your application and either:<ul> +<li>You are targeting a Unix variant OS other than MacOS or AIX, +where the dynamically-loaded extension modules can “see†the +Boost.Python library symbols that are part of the executable.</li> +<li>Or, you have statically linked some Boost.Python extension +modules into your application and you don't care if any +dynamically-loaded Boost.Python extension modules are able to +use the types exposed by your statically-linked extension +modules (and vice-versa).</li> +</ul> +</li> +</ul> +</div> +</div> +<div class="section" id="include-issues"> +<h1><a class="toc-backref" href="#id39">7 <tt class="docutils literal"><span class="pre">#include</span></tt> Issues</a></h1> +<ol class="arabic simple"> +<li>If you should ever have occasion to <tt class="docutils literal"><span class="pre">#include</span> <span class="pre">"python.h"</span></tt> +directly in a translation unit of a program using Boost.Python, +use <tt class="docutils literal"><span class="pre">#include</span> <span class="pre">"boost/python/detail/wrap_python.hpp"</span></tt> instead. +It handles several issues necessary for use with Boost.Python, +one of which is mentioned in the next section.</li> +<li>Be sure not to <tt class="docutils literal"><span class="pre">#include</span></tt> any system headers before +<tt class="docutils literal"><span class="pre">wrap_python.hpp</span></tt>. This restriction is actually imposed by +Python, or more properly, by Python's interaction with your +operating system. See +<a class="reference external" href="http://docs.python.org/ext/simpleExample.html">http://docs.python.org/ext/simpleExample.html</a> for details.</li> +</ol> +</div> +<div class="section" id="python-debugging-builds"> +<span id="id19"></span><span id="python-debugging"></span><h1><a class="toc-backref" href="#id40">8 Python Debugging Builds</a></h1> +<p>Python can be built in a special “python debugging†configuration +that adds extra checks and instrumentation that can be very useful +for developers of extension modules. The data structures used by +the debugging configuration contain additional members, so <strong>a +Python executable built with python debugging enabled cannot be +used with an extension module or library compiled without it, and +vice-versa.</strong></p> +<p>Since pre-built “python debugging†versions of the Python +executable and libraries are not supplied with most distributions +of Python,<a class="footnote-reference" href="#get-debug-build" id="id20"><sup>7</sup></a> and we didn't want to force our users +to build them, Boost.Build does not automatically enable python +debugging in its <tt class="docutils literal"><span class="pre">debug</span></tt> build variant (which is the default). +Instead there is a special build property called +<tt class="docutils literal"><span class="pre">python-debugging</span></tt> that, when used as a build property, will +define the right preprocessor symbols and select the right +libraries to link with.</p> +<p>On unix-variant platforms, the debugging versions of Python's data +structures will only be used if the symbol <tt class="docutils literal"><span class="pre">Py_DEBUG</span></tt> is defined. +On many windows compilers, when extension modules are built with +the preprocessor symbol <tt class="docutils literal"><span class="pre">_DEBUG</span></tt>, Python defaults to force +linking with a special debugging version of the Python DLL. Since +that symbol is very commonly used even when Python is not present, +Boost.Python temporarily undefines _DEBUG when Python.h +is #included from <tt class="docutils literal"><span class="pre">boost/python/detail/wrap_python.hpp</span></tt> - unless +<tt class="docutils literal"><span class="pre">BOOST_DEBUG_PYTHON</span></tt> is defined. The upshot is that if you want +“python debuggingâ€and you aren't using Boost.Build, you should make +sure <tt class="docutils literal"><span class="pre">BOOST_DEBUG_PYTHON</span></tt> is defined, or python debugging will be +suppressed.</p> +</div> +<div class="section" id="testing-boost-python"> +<h1><a class="toc-backref" href="#id41">9 Testing Boost.Python</a></h1> +<p>To run the full test suite for Boost.Python, invoke <tt class="docutils literal"><span class="pre">bjam</span></tt> in the +<tt class="docutils literal"><span class="pre">libs/python/test</span></tt> subdirectory of your Boost distribution.</p> +</div> +<div class="section" id="notes-for-mingw-and-cygwin-with-mno-cygwin-gcc-users"> +<h1><a class="toc-backref" href="#id42">10 Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users</a></h1> +<p>If you are using a version of Python prior to 2.4.1 with a MinGW +prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to +create a MinGW-compatible version of the Python library; the one +shipped with Python will only work with a Microsoft-compatible +linker. Follow the instructions in the “Non-Microsoft†section of +the “Building Extensions: Tips And Tricks†chapter in <a class="reference external" href="http://www.python.org/doc/current/inst/index.html">Installing +Python Modules</a> to create <tt class="docutils literal"><span class="pre">libpythonXX.a</span></tt>, where <tt class="docutils literal"><span class="pre">XX</span></tt> +corresponds to the major and minor version numbers of your Python +installation.</p> +<hr class="docutils" /> +<table class="docutils footnote" frame="void" id="id22" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id2">[1]</a></td><td>Note that although we tested earlier versions of +Boost.Python with Python 2.2, and we don't <em>think</em> we've done +anything to break compatibility, this release of Boost.Python +may not have been tested with versions of Python earlier than +2.4, so we're not 100% sure that python 2.2 and 2.3 are +supported.</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="naming" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id17">[2]</a></td><td><p class="first">Information about how to identify the +static and dynamic builds of Boost.Python:</p> +<ul class="simple"> +<li><a class="reference external" href="../../../more/getting_started/windows.html#library-naming">on Windows</a></li> +<li><a class="reference external" href="../../../more/getting_started/unix-variants.html#library-naming">on Unix variants</a></li> +</ul> +</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="toolset-specific" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id18">[3]</a></td><td>Because of the way most *nix platforms +share symbols among dynamically-loaded objects, I'm not certain +that extension modules built with different compiler toolsets +will always use different copies of the Boost.Python library +when loaded into the same Python instance. Not using different +libraries could be a good thing if the compilers have compatible +ABIs, because extension modules built with the two libraries +would be interoperable. Otherwise, it could spell disaster, +since an extension module and the Boost.Python library would +have different ideas of such things as class layout. I would +appreciate someone doing the experiment to find out what +happens.</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="overwrite" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id13">[4]</a></td><td><tt class="docutils literal"><span class="pre">configure</span></tt> overwrites the existing +<tt class="docutils literal"><span class="pre">user-config.jam</span></tt> in your home directory +(if any) after making a backup of the old version.</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="flavor" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id15">[5]</a></td><td>Note that the <tt class="docutils literal"><span class="pre"><target-os>cygwin</span></tt> feature is +different from the <tt class="docutils literal"><span class="pre"><flavor>cygwin</span></tt> subfeature of the <tt class="docutils literal"><span class="pre">gcc</span></tt> +toolset, and you might need handle both explicitly if you also +have a MinGW GCC installed.</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="home-dir" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id11">[6]</a></td><td><p class="first">Windows users, your home directory can be +found by typing:</p> +<pre class="literal-block"> +ECHO %HOMEDRIVE%%HOMEPATH% +</pre> +<p class="last">into a <a class="reference external" href="../../../more/getting_started/windows.html#command-prompt">command prompt</a> window.</p> +</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="get-debug-build" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id20">[7]</a></td><td>On Unix and similar platforms, a debugging +python and associated libraries are built by adding +<tt class="docutils literal"><span class="pre">--with-pydebug</span></tt> when configuring the Python build. On +Windows, the debugging version of Python is generated by +the "Win32 Debug" target of the Visual Studio project in the +PCBuild subdirectory of a full Python source code distribution. +</td></tr> +</tbody> +</table> +</div> +</div> +<div class="footer"> +<hr class="footer" /> +<a class="reference external" href="./building.rst">View document source</a>. +Generated on: 2007-07-02 13:46 UTC. +Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. + +</div> +</body> +</html> diff --git a/libs/python/doc/building.rst b/libs/python/doc/building.rst new file mode 100644 index 000000000..1e2c7d42f --- /dev/null +++ b/libs/python/doc/building.rst @@ -0,0 +1,680 @@ +.. Copyright David Abrahams 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at +.. http://www.boost.org/LICENSE_1_0.txt) + +============================================== + |(logo)|__ Boost.Python Build and Test HOWTO +============================================== + +.. |(logo)| image:: ../../../boost.png + :alt: Boost C++ Libraries: + :class: boost-logo + +__ ../index.html + + +.. section-numbering:: + :depth: 2 + +.. contents:: Contents + :depth: 2 + :class: sidebar small + +.. |newer| replace:: *newer* + +Requirements +============ + +Boost.Python requires `Python 2.2`_ [#2.2]_ *or* |newer|__. + +.. _Python 2.2: http://www.python.org/2.2 +__ http://www.python.org + +Background +========== + +There are two basic models for combining C++ and Python: + +- extending_, in which the end-user launches the Python interpreter + executable and imports Python “extension modules†written in C++. + Think of taking a library written in C++ and giving it a Python + interface so Python programmers can use it. From Python, these + modules look just like regular Python modules. + +- embedding_, in which the end-user launches a program written + in C++ that in turn invokes the Python interpreter as a library + subroutine. Think of adding scriptability to an existing + application. + +.. _extending: http://www.python.org/doc/current/ext/intro.html +.. _embedding: http://www.python.org/doc/current/ext/embedding.html + +The key distinction between extending and embedding is the location +of the C++ ``main()`` function: in the Python interpreter executable, +or in some other program, respectively. Note that even when +embedding Python in another program, `extension modules are often +the best way to make C/C++ functionality accessible to Python +code`__, so the use of extension modules is really at the heart of +both models. + +__ http://www.python.org/doc/current/ext/extending-with-embedding.html + +Except in rare cases, extension modules are built as +dynamically-loaded libraries with a single entry point, which means +you can change them without rebuilding either the other extension +modules or the executable containing ``main()``. + +.. _quickstart: + +No-Install Quickstart +===================== + +There is no need to “install Boost†in order to get started using +Boost.Python. These instructions use Boost.Build_ projects, +which will build those binaries as soon as they're needed. Your +first tests may take a little longer while you wait for +Boost.Python to build, but doing things this way will save you from +worrying about build intricacies like which library binaries to use +for a specific compiler configuration and figuring out the right +compiler options to use yourself. + +.. .. raw:: html + + <div style="width:50%"> + +.. Note:: Of course it's possible to use other build systems to + build Boost.Python and its extensions, but they are not + officially supported by Boost. Moreover **99% of all “I can't + build Boost.Python†problems come from trying to use another + build system** without first following these instructions. + + If you want to use another system anyway, we suggest that you + follow these instructions, and then invoke ``bjam`` with the + + .. parsed-literal:: + + ``-a -o``\ *filename* + + options to dump the build commands it executes to a file, so + you can see what your alternate build system needs to do. + +.. .. raw:: html + + </div> + +.. _Boost.Build: ../../../tools/build/index.html + +Basic Procedure +--------------- + +1. Get Boost; see sections 1 and 2 [`Unix/Linux`__, `Windows`__\ ] of the + Boost `Getting Started Guide`_. + + __ ../../../more/getting_started/unix-variants.html#get-boost + __ ../../../more/getting_started/windows.html#get-boost + +2. Get the ``bjam`` build driver. See section 5 [`Unix/Linux`__, + `Windows`__\ ] of the Boost `Getting Started Guide`_. + + __ ../../../more/getting_started/unix-variants.html#prepare-to-use-a-boost-library-binary + __ ../../../more/getting_started/windows.html#prepare-to-use-a-boost-library-binary + + +3. cd into the ``libs/python/example/quickstart/`` directory of your + Boost installation, which contains a small example project. + +4. Invoke ``bjam``. Replace the “\ ``stage``\ “ argument from the + example invocation from section 5 of the `Getting Started + Guide`_ with “\ ``test``\ ,“ to build all the test targets. Also add + the argument “\ ``--verbose-test``\ †to see the output generated by + the tests when they are run. + + On Windows, your ``bjam`` invocation might look something like: + + .. parsed-literal:: + + C:\\boost_1_34_0\\…\\quickstart> **bjam toolset=msvc --verbose-test test** + + and on Unix variants, perhaps, + + .. parsed-literal:: + + ~/boost_1_34_0/…/quickstart$ **bjam toolset=gcc --verbose-test test** + +.. Admonition:: Note to Windows Users + + For the sake of concision, the rest of this guide will use + unix-style forward slashes in pathnames instead of the + backslashes with which you may be more familiar. The forward + slashes should work everywhere except in `Command Prompt`_ + windows, where you should use backslashes. + + .. _Command Prompt: ../../../more/getting_started/windows.html#command-prompt + +If you followed this procedure successfully, you will have built an +extension module called ``extending`` and tested it by running a +Python script called ``test_extending.py``. You will also have +built and run a simple application called ``embedding`` that embeds +python. + +.. _Getting Started Guide: ../../../more/getting_started/index.html + +In Case of Trouble +------------------ + +If you're seeing lots of compiler and/or linker error messages, +it's probably because Boost.Build is having trouble finding your +Python installation. You might want to pass the +``--debug-configuration`` option to ``bjam`` the first few times +you invoke it, to make sure that Boost.Build is correctly locating +all the parts of your Python installation. If it isn't, consider +`Configuring Boost.Build`_ as detailed below. + +If you're still having trouble, Someone on one of the following +mailing lists may be able to help: + +* The `Boost.Build mailing list`__ for issues related to Boost.Build +* The Python `C++ Sig`__ for issues specifically related to Boost.Python + +__ http://www.boost.org/more/mailing_lists.htm#jamboost +__ http://www.boost.org/more/mailing_lists.htm#cplussig + +In Case Everything Seemed to Work +--------------------------------- + +Rejoice! If you're new to Boost.Python, at this point it might be +a good idea to ignore build issues for a while and concentrate on +learning the library by going through the tutorial_ and perhaps +some of the `reference documentation`_, trying out what you've +learned about the API by modifying the quickstart project. + +.. _reference documentation: v2/reference.html +.. _tutorial: tutorial/index.html + +Modifying the Example Project +----------------------------- + +If you're content to keep your extension module forever in one +source file called |extending.cpp|_, inside your Boost +distribution, and import it forever as ``extending``, then you can +stop here. However, it's likely that you will want to make a few +changes. There are a few things you can do without having to learn +Boost.Build_ in depth. + +The project you just built is specified in two files in the current +directory: |boost-build.jam|_, which tells ``bjam`` where it can +find the interpreted code of the Boost build system, and +|Jamroot|_, which describes the targets you just built. These +files are heavily commented, so they should be easy to modify. +Take care, however, to preserve whitespace. Punctuation such as +``;`` will not be recognized as intended by ``bjam`` if it is not +surrounded by whitespace. + +.. |boost-build.jam| replace:: ``boost-build.jam`` +.. _boost-build.jam: ../example/quickstart/boost-build.jam + +.. |Jamroot| replace:: ``Jamroot`` +.. _Jamroot: ../example/quickstart/Jamroot + +.. |extending.cpp| replace:: ``extending.cpp`` +.. _extending.cpp: ../example/quickstart/extending.cpp + +Relocate the Project +.................... + +You'll probably want to copy this project elsewhere so you can +change it without modifying your Boost distribution. To do that, +simply + +a. copy the entire ``libs/python/example/quickstart/`` directory + into a new directory. + +b. In the new copies of |boost-build.jam|_ and |Jamroot|_, locate + the relative path near the top of the file that is clearly + marked by a comment, and edit that path so that it refers to the + same directory your Boost distribution as it referred to when + the file was in its original location in the + ``libs/python/example/quickstart/`` directory. + +For example, if you moved the project from +``/home/dave/boost_1_34_0/libs/python/example/quickstart`` to +``/home/dave/my-project``, you could change the first path in +|boost-build.jam|_ from + +.. parsed-literal:: + + **../../../..**\ /tools/build/v2 + +to + +.. parsed-literal:: + + **/home/dave/boost_1_34_0**\ /tools/build/v2 + +and change the first path in |Jamroot|_ from + +.. parsed-literal:: + + **../../../..** + +to + +.. parsed-literal:: + + **/home/dave/boost_1_34_0** + +Add New or Change Names of Existing Source Files +................................................ + +The names of additional source files involved in building your +extension module or embedding application can be listed in +|Jamroot|_ right alongside ``extending.cpp`` or ``embedding.cpp`` +respectively. Just be sure to leave whitespace around each +filename:: + + … file1.cpp file2.cpp file3.cpp … + +Naturally, if you want to change the name of a source file you can +tell Boost.Build about it by editing the name in |Jamroot|_. + +Change the Name of your Extension Module +........................................ + +The name of the extension module is determined by two things: + +1. the name in |Jamroot|_ immediately following ``python-extension``, and +2. the name passed to ``BOOST_PYTHON_MODULE`` in |extending.cpp|_. + +To change the name of the extension module from ``extending`` to +``hello``, you'd edit |Jamroot|_, changing + +.. parsed-literal:: + + python-extension **extending** : extending.cpp ; + +to + +.. parsed-literal:: + + python-extension **hello** : extending.cpp ; + +and you'd edit extending.cpp, changing + +.. parsed-literal:: + + BOOST_PYTHON_MODULE(\ **extending**\ ) + +to + +.. parsed-literal:: + + BOOST_PYTHON_MODULE(\ **hello**\ ) + +Installing Boost.Python on your System +====================================== + +Since Boost.Python is a separately-compiled (as opposed to +`header-only`_) library, its user relies on the services of a +Boost.Python library binary. + +.. _header-only: ../../../more/getting_started/windows.html#header-only-libraries + +If you need a regular installation of the Boost.Python library +binaries on your system, the Boost `Getting Started Guide`_ will +walk you through the steps of creating one. If building binaries +from source, you might want to supply the ``--with-python`` +argument to ``bjam`` (or the ``--with-libraries=python`` argument +to ``configure``), so only the Boost.Python binary will be built, +rather than all the Boost binaries. + + +Configuring Boost.Build +======================= + +As described in the `Boost.Build reference manual`__, a file called +``user-config.jam`` in your home directory [#home-dir]_ is used to +specify the tools and libraries available to the build system. You +may need to create or edit ``user-config.jam`` to tell Boost.Build +how to invoke Python, ``#include`` its headers, and link with its +libraries. + +__ http://www.boost.orgdoc/html/bbv2/advanced.html#bbv2.advanced.configuration + +.. Admonition:: Users of Unix-Variant OSes + + If you are using a unix-variant OS and you ran Boost's + ``configure`` script, it may have generated a + ``user-config.jam`` for you. [#overwrite]_ If your ``configure``\ + /\ ``make`` sequence was successful and Boost.Python binaries + were built, your ``user-config.jam`` file is probably already + correct. + +If you have one fairly “standard†python installation for your +platform, you might not need to do anything special to describe it. If +you haven't configured python in ``user-config.jam`` (and you don't +specify ``--without-python`` on the Boost.Build command line), +Boost.Build will automatically execute the equivalent of :: + + import toolset : using ; + using python ; + +which automatically looks for Python in the most likely places. +However, that only happens when using the Boost.Python project file +(e.g. when referred to by another project as in the quickstart_ +method). If instead you are linking against separately-compiled +Boost.Python binaries, you should set up a ``user-config.jam`` file +with at least the minimal incantation above. + +Python Configuration Parameters +------------------------------- + +If you have several versions of Python installed, or Python is +installed in an unusual way, you may want to supply any or all of +the following optional parameters to ``using python``. + +version + the version of Python to use. Should be in Major.Minor + format, for example, ``2.3``. Do not include the subminor + version (i.e. *not* ``2.5.1``). If you have multiple Python + versions installed, the version will usually be the only + configuration argument required. + +cmd-or-prefix + preferably, a command that invokes a Python interpreter. + Alternatively, the installation prefix for Python libraries and + header files. Only use the alternative formulation if there is + no appropriate Python executable available. + +includes + the ``#include`` paths for Python headers. Normally the correct + path(s) will be automatically deduced from ``version`` and/or + ``cmd-or-prefix``. + +libraries + the path to Python library binaries. On MacOS/Darwin, + you can also pass the path of the Python framework. Normally the + correct path(s) will be automatically deduced from ``version`` + and/or ``cmd-or-prefix``. + +condition + if specified, should be a set of Boost.Build + properties that are matched against the build configuration when + Boost.Build selects a Python configuration to use. See examples + below for details. + +extension-suffix + A string to append to the name of extension + modules before the true filename extension. You almost certainly + don't need to use this. Usually this suffix is only used when + targeting a Windows debug build of Python, and will be set + automatically for you based on the value of the + |python-debugging|_ feature. However, at least one Linux + distribution (Ubuntu Feisty Fawn) has a specially configured + `python-dbg`__ package that claims to use such a suffix. + +.. |python-debugging| replace:: ``<python-debugging>`` + +__ https://wiki.ubuntu.com/PyDbgBuilds + + +Examples +-------- + +Note that in the examples below, case and *especially whitespace* are +significant. + +- If you have both python 2.5 and python 2.4 installed, + ``user-config.jam`` might contain:: + + using python : 2.5 ; # Make both versions of Python available + + using python : 2.4 ; # To build with python 2.4, add python=2.4 + # to your command line. + + The first version configured (2.5) becomes the default. To build + against python 2.4, add ``python=2.4`` to the ``bjam`` command line. + +- If you have python installed in an unusual location, you might + supply the path to the interpreter in the ``cmd-or-prefix`` + parameter:: + + using python : : /usr/local/python-2.6-beta/bin/python ; + +- If you have a separate build of Python for use with a particular + toolset, you might supply that toolset in the ``condition`` + parameter:: + + using python ; # use for most toolsets + + # Use with Intel C++ toolset + using python + : # version + : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix + : # includes + : # libraries + : <toolset>intel # condition + ; + + +- If you have downloaded the Python sources and built both the + normal and the “\ `python debugging`_\ †builds from source on + Windows, you might see:: + + using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; + using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d + : # includes + : # libs + : <python-debugging>on ; + +- You can set up your user-config.jam so a bjam built under Windows + can build/test both Windows and Cygwin_ python extensions. Just pass + ``<target-os>cygwin`` in the ``condition`` parameter + for the cygwin python installation:: + + # windows installation + using python ; + + # cygwin installation + using python : : c:\\cygwin\\bin\\python2.5 : : : <target-os>cygwin ; + + when you put target-os=cygwin in your build request, it should build + with the cygwin version of python: [#flavor]_ + + bjam target-os=cygwin toolset=gcc + + This is supposed to work the other way, too (targeting windows + python with a Cygwin_ bjam) but it seems as though the support in + Boost.Build's toolsets for building that way is broken at the + time of this writing. + +- Note that because of `the way Boost.Build currently selects target + alternatives`__, you might have be very explicit in your build + requests. For example, given:: + + using python : 2.5 ; # a regular windows build + using python : 2.4 : : : : <target-os>cygwin ; + + building with :: + + bjam target-os=cygwin + + will yield an error. Instead, you'll need to write:: + + bjam target-os=cygwin/python=2.4 + +.. _Cygwin: http://cygwin.com + +__ http://zigzag.cs.msu.su/boost.build/wiki/AlternativeSelection + +Choosing a Boost.Python Library Binary +====================================== + +If—instead of letting Boost.Build construct and link with the right +libraries automatically—you choose to use a pre-built Boost.Python +library, you'll need to think about which one to link with. The +Boost.Python binary comes in both static and dynamic flavors. Take +care to choose the right flavor for your application. [#naming]_ + +The Dynamic Binary +------------------ + +The dynamic library is the safest and most-versatile choice: + +- A single copy of the library code is used by all extension + modules built with a given toolset. [#toolset-specific]_ + +- The library contains a type conversion registry. Because one + registry is shared among all extension modules, instances of a + class exposed to Python in one dynamically-loaded extension + module can be passed to functions exposed in another such module. + +The Static Binary +----------------- + +It might be appropriate to use the static Boost.Python library in +any of the following cases: + +- You are extending_ python and the types exposed in your + dynamically-loaded extension module don't need to be used by any + other Boost.Python extension modules, and you don't care if the + core library code is duplicated among them. + +- You are embedding_ python in your application and either: + + - You are targeting a Unix variant OS other than MacOS or AIX, + where the dynamically-loaded extension modules can “see†the + Boost.Python library symbols that are part of the executable. + + - Or, you have statically linked some Boost.Python extension + modules into your application and you don't care if any + dynamically-loaded Boost.Python extension modules are able to + use the types exposed by your statically-linked extension + modules (and vice-versa). + +``#include`` Issues +=================== + +1. If you should ever have occasion to ``#include "python.h"`` + directly in a translation unit of a program using Boost.Python, + use ``#include "boost/python/detail/wrap_python.hpp"`` instead. + It handles several issues necessary for use with Boost.Python, + one of which is mentioned in the next section. + +2. Be sure not to ``#include`` any system headers before + ``wrap_python.hpp``. This restriction is actually imposed by + Python, or more properly, by Python's interaction with your + operating system. See + http://docs.python.org/ext/simpleExample.html for details. + +.. _python-debugging: +.. _python debugging: + +Python Debugging Builds +======================= + +Python can be built in a special “python debugging†configuration +that adds extra checks and instrumentation that can be very useful +for developers of extension modules. The data structures used by +the debugging configuration contain additional members, so **a +Python executable built with python debugging enabled cannot be +used with an extension module or library compiled without it, and +vice-versa.** + +Since pre-built “python debugging†versions of the Python +executable and libraries are not supplied with most distributions +of Python, [#get-debug-build]_ and we didn't want to force our users +to build them, Boost.Build does not automatically enable python +debugging in its ``debug`` build variant (which is the default). +Instead there is a special build property called +``python-debugging`` that, when used as a build property, will +define the right preprocessor symbols and select the right +libraries to link with. + +On unix-variant platforms, the debugging versions of Python's data +structures will only be used if the symbol ``Py_DEBUG`` is defined. +On many windows compilers, when extension modules are built with +the preprocessor symbol ``_DEBUG``, Python defaults to force +linking with a special debugging version of the Python DLL. Since +that symbol is very commonly used even when Python is not present, +Boost.Python temporarily undefines _DEBUG when Python.h +is #included from ``boost/python/detail/wrap_python.hpp`` - unless +``BOOST_DEBUG_PYTHON`` is defined. The upshot is that if you want +“python debuggingâ€and you aren't using Boost.Build, you should make +sure ``BOOST_DEBUG_PYTHON`` is defined, or python debugging will be +suppressed. + +Testing Boost.Python +==================== + +To run the full test suite for Boost.Python, invoke ``bjam`` in the +``libs/python/test`` subdirectory of your Boost distribution. + +Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users +======================================================= + +If you are using a version of Python prior to 2.4.1 with a MinGW +prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to +create a MinGW-compatible version of the Python library; the one +shipped with Python will only work with a Microsoft-compatible +linker. Follow the instructions in the “Non-Microsoft†section of +the “Building Extensions: Tips And Tricks†chapter in `Installing +Python Modules`__ to create ``libpythonXX.a``, where ``XX`` +corresponds to the major and minor version numbers of your Python +installation. + +__ http://www.python.org/doc/current/inst/index.html + +----------------------------- + +.. [#2.2] Note that although we tested earlier versions of + Boost.Python with Python 2.2, and we don't *think* we've done + anything to break compatibility, this release of Boost.Python + may not have been tested with versions of Python earlier than + 2.4, so we're not 100% sure that python 2.2 and 2.3 are + supported. + +.. [#naming] Information about how to identify the + static and dynamic builds of Boost.Python: + + * `on Windows`__ + * `on Unix variants`__ + + __ ../../../more/getting_started/windows.html#library-naming + __ ../../../more/getting_started/unix-variants.html#library-naming + +.. [#toolset-specific] Because of the way most \*nix platforms + share symbols among dynamically-loaded objects, I'm not certain + that extension modules built with different compiler toolsets + will always use different copies of the Boost.Python library + when loaded into the same Python instance. Not using different + libraries could be a good thing if the compilers have compatible + ABIs, because extension modules built with the two libraries + would be interoperable. Otherwise, it could spell disaster, + since an extension module and the Boost.Python library would + have different ideas of such things as class layout. I would + appreciate someone doing the experiment to find out what + happens. + +.. [#overwrite] ``configure`` overwrites the existing + ``user-config.jam`` in your home directory + (if any) after making a backup of the old version. + +.. [#flavor] Note that the ``<target-os>cygwin`` feature is + different from the ``<flavor>cygwin`` subfeature of the ``gcc`` + toolset, and you might need handle both explicitly if you also + have a MinGW GCC installed. + +.. [#home-dir] Windows users, your home directory can be + found by typing:: + + ECHO %HOMEDRIVE%%HOMEPATH% + + into a `command prompt`_ window. + +.. [#get-debug-build] On Unix and similar platforms, a debugging + python and associated libraries are 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 Visual Studio project in the + PCBuild subdirectory of a full Python source code distribution. diff --git a/libs/python/doc/index.html b/libs/python/doc/index.html new file mode 100644 index 000000000..e600366fe --- /dev/null +++ b/libs/python/doc/index.html @@ -0,0 +1,184 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../../../boost.css"> + + <title>Boost.Python</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center">Boost.Python</h1> + + <h2 align="center">Index</h2> + </td> + + + <td align="right"> + + <form method="get" action="http://www.google.com/custom"> + <p> + <span id= "search-choice"> + Search + <select name="hq" id="hq"> + <option label="All Documentation" value= + "site:www.boost.org inurl:www.boost.org/libs/python/doc"> + All Documentation + </option> + <option label="Tutorial" value= + "site:www.boost.org inurl:www.boost.org/libs/python/doc/tutorial"> + Tutorial + </option> + <option label="Reference" value= + "site:www.boost.org inurl:www.boost.org/libs/python/doc/v2"> + Reference + </option> + </select> + <br> + </span> + + <span id="search-text"> + <input type="text" name="q" id="q" size="31" maxlength="255" alt="Search Text" /> + </span> + + <br> + <span id= "google"> + <a href= "http://www.google.com/search"> + <img src="../../../more/google_logo_25wht.gif" alt="Google" border="0" /></a>Powered + </span> + + <span id="go"> + <input type="image" name="search" src="../../../more/space.gif" alt="Search" id="search-button" /> + </span> + + <br> + <input type="hidden" name="cof" value= "LW:277;L:http://www.boost.org/boost.png;LH:86;AH:center;GL:0;S:http://www.boost.org;AWFID:9b83d16ce652ed5a;" /> + <input type="hidden" name="sa" value= "Google Search" /> + <input type="hidden" name= "domains" value= "www.boost.org;mail.python.org" /></p> + </form> + + </td> + </tr> +<tr> + + </tr> + </table> + <hr> + + + <h2>Synopsis</h2> + Welcome to version 2 of <b>Boost.Python</b>, a C++ library which enables + seamless interoperability between C++ and the <a href= + "http://www.python.org">Python</a> programming language. The new version + has been rewritten from the ground up, with a more convenient and + flexible interface, and many new capabilities, including support for: + + <ul> + <li>References and Pointers</li> + + <li>Globally Registered Type Coercions</li> + + <li>Automatic Cross-Module Type Conversions</li> + + <li>Efficient Function Overloading</li> + + <li>C++ to Python Exception Translation</li> + + <li>Default Arguments</li> + + <li>Keyword Arguments</li> + + <li>Manipulating Python objects in C++</li> + + <li>Exporting C++ Iterators as Python Iterators</li> + + <li>Documentation Strings</li> + </ul> + The development of these features was funded in part by grants to <a + href="http://www.boost-consulting.com">Boost Consulting</a> from the <a + href="http://www.llnl.gov/">Lawrence Livermore National Laboratories</a> + and by the <a href="http://cci.lbl.gov/">Computational Crystallography + Initiative</a> at Lawrence Berkeley National Laboratories. + + <hr> + + <h2>Contents</h2> + + <dl class="index"> + <dt><a href="tutorial/index.html">Tutorial Introduction</a></dt> + + <dt><a href="building.html">Building and Testing</a></dt> + + <dt><a href="v2/reference.html">Reference Manual</a></dt> + + <dt>Suites:</dt> + <dd> + <ul> + <li><a href="v2/pickle.html">Pickle</a></li> + <li><a href="v2/indexing.html">Indexing</a></li> + </ul> + </dd> + + <dt><a href="v2/configuration.html">Configuration Information</a></dt> + + <dt><a href="v2/platforms.html">Known Working Platforms and + Compilers</a></dt> + + <dt><a href="v2/definitions.html">Definitions</a></dt> + + <dt><a href="projects.html">Projects using Boost.Python</a></dt> + + <dt><a href="support.html">Support Resources</a></dt> + + <dt><a href="v2/faq.html">Frequently Asked Questions (FAQs)</a></dt> + + <dt><a href="http://www.language-binding.net/pyplusplus/pyplusplus.html">Py++ Boost.Python code generator</a></dt> + + <dt><a href="../pyste/index.html">Pyste Boost.Python code generator (no longer maintained)</a></dt> + + <dt><a href="internals.html">Internals Documentation</a></dt> + + <dt><a href="news.html">News/Change Log</a></dt> + + <dt><a href="../todo.html">TODO list</a></dt> + + <dt><a href="v2/progress_reports.html">LLNL Progress Reports</a></dt> + + <dt><a href="v2/acknowledgments.html">Acknowledgments</a></dt> + </dl> + <hr> + + <h2>Articles</h2> + + "<a href="PyConDC_2003/bpl.html">Building Hybrid + Systems With Boost Python</a>", by Dave Abrahams and Ralf + W. Grosse-Kunstleve (<a href="PyConDC_2003/bpl.pdf">PDF</a>) + + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 26 August, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002-2003.</i></p> + </body> +</html> + diff --git a/libs/python/doc/internals.html b/libs/python/doc/internals.html new file mode 100644 index 000000000..2f7d76070 --- /dev/null +++ b/libs/python/doc/internals.html @@ -0,0 +1,186 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.3.0: http://docutils.sourceforge.net/" /> +<title>Boost.Python Internals Boost</title> +<link rel="stylesheet" href="../../../rst.css" type="text/css" /> +</head> +<body> +<div class="document" id="boost-python-internals-logo"> +<h1 class="title"><a class="reference" href="index.html">Boost.Python</a> Internals <a class="reference" href="../../../index.htm"><img alt="Boost" src="../../../boost.png" /></a></h1> +<div class="section" id="a-conversation-between-brett-calcott-and-david-abrahams"> +<h1><a name="a-conversation-between-brett-calcott-and-david-abrahams">A conversation between Brett Calcott and David Abrahams</a></h1> +<table class="field-list" frame="void" rules="none"> +<col class="field-name" /> +<col class="field-body" /> +<tbody valign="top"> +<tr class="field"><th class="field-name">copyright:</th><td class="field-body">Copyright David Abrahams and Brett Calcott 2003. See +accompanying <a class="reference" href="../../../LICENSE_1_0.txt">license</a> for terms of use.</td> +</tr> +</tbody> +</table> +<p>In both of these cases, I'm quite capable of reading code - but the +thing I don't get from scanning the source is a sense of the +architecture, both structurally, and temporally (er, I mean in what +order things go on).</p> +<ol class="arabic"> +<li><p class="first">What happens when you do the following:</p> +<pre class="literal-block"> +struct boring {}; +...etc... +class_<boring>("boring") + ; +</pre> +</li> +</ol> +<p>There seems to be a fair bit going on.</p> +<blockquote> +<ul class="simple"> +<li>Python needs a new ClassType to be registered.</li> +<li>We need to construct a new type that can hold our boring struct.</li> +<li>Inward and outward converters need to be registered for the type.</li> +</ul> +</blockquote> +<p>Can you gesture in the general direction where these things are done?</p> +<blockquote> +<p>I only have time for a "off-the-top-of-my-head" answer at the moment; +I suggest you step through the code with a debugger after reading this +to see how it works, fill in details, and make sure I didn't forget +anything.</p> +<blockquote> +<p>A new (Python) subclass of Boost.Python.Instance (see +libs/python/src/object/class.cpp) is created by invoking +Boost.Python.class, the metatype:</p> +<pre class="literal-block"> +>>> boring = Boost.Python.class( +... 'boring' +... , bases_tuple # in this case, just () +... , { +... '__module__' : module_name +... , '__doc__' : doc_string # optional +... } +... ) +</pre> +<p>A handle to this object is stuck in the m_class_object field +of the registration associated with <tt class="literal"><span class="pre">typeid(boring)</span></tt>. The +registry will keep that object alive forever, even if you +wipe out the 'boring' attribute of the extension module +(probably not a good thing).</p> +<p>Because you didn't specify <tt class="literal"><span class="pre">class<boring,</span> <span class="pre">non_copyable,</span> +<span class="pre">...></span></tt>, a to-python converter for boring is registered which +copies its argument into a value_holder held by the the +Python boring object.</p> +<p>Because you didn't specify <tt class="literal"><span class="pre">class<boring</span> <span class="pre">...>(no_init)</span></tt>, +an <tt class="literal"><span class="pre">__init__</span></tt> function object is added to the class +dictionary which default-constructs a boring in a +value_holder (because you didn't specify some smart pointer +or derived wrapper class as a holder) held by the Python +boring object.</p> +<p><tt class="literal"><span class="pre">register_class_from_python</span></tt> is used to register a +from-python converter for <tt class="literal"><span class="pre">shared_ptr<boring></span></tt>. +<tt class="literal"><span class="pre">boost::shared_ptr</span></tt>s are special among smart pointers +because their Deleter argument can be made to manage the +whole Python object, not just the C++ object it contains, no +matter how the C++ object is held.</p> +<p>If there were any <tt class="literal"><span class="pre">bases<></span></tt>, we'd also be registering the +relationship between these base classes and boring in the +up/down cast graph (<tt class="literal"><span class="pre">inheritance.[hpp/cpp]</span></tt>).</p> +<p>In earlier versions of the code, we'd be registering lvalue +from-python converters for the class here, but now +from-python conversion for wrapped classes is handled as a +special case, before consulting the registry, if the source +Python object's metaclass is the Boost.Python metaclass.</p> +<p>Hmm, that from-python converter probably ought to be handled +the way class converters are, with no explicit conversions +registered.</p> +</blockquote> +</blockquote> +<ol class="arabic" start="2"> +<li><p class="first">Can you give a brief overview of the data structures that are +present in the registry</p> +<blockquote> +<p>The registry is simple: it's just a map from typeid -> +registration (see boost/python/converter/registrations.hpp). +<tt class="literal"><span class="pre">lvalue_chain</span></tt> and <tt class="literal"><span class="pre">rvalue_chain</span></tt> are simple endogenous +linked lists.</p> +<p>If you want to know more, just ask.</p> +<p>If you want to know about the cast graph, ask me something specific in +a separate message.</p> +</blockquote> +<p>and an overview of the process that happens as a type makes its +way from c++ to python and back again.</p> +</li> +</ol> +<blockquote> +<p>Big subject. I suggest some background reading: look for relevant +info in the LLNL progress reports and the messages they link to. +Also,</p> +<blockquote> +<p><a class="reference" href="http://mail.python.org/pipermail/c++-sig/2002-May/001023.html">http://mail.python.org/pipermail/c++-sig/2002-May/001023.html</a></p> +<p><a class="reference" href="http://mail.python.org/pipermail/c++-sig/2002-December/003115.html">http://mail.python.org/pipermail/c++-sig/2002-December/003115.html</a></p> +<p><a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/1280898">http://aspn.activestate.com/ASPN/Mail/Message/1280898</a></p> +<p><a class="reference" href="http://mail.python.org/pipermail/c++-sig/2002-July/001755.html">http://mail.python.org/pipermail/c++-sig/2002-July/001755.html</a></p> +</blockquote> +<p>from c++ to python:</p> +<blockquote> +<p>It depends on the type and the call policies in use or, for +<tt class="literal"><span class="pre">call<>(...)</span></tt>, <tt class="literal"><span class="pre">call_method<>(...)</span></tt>, or <tt class="literal"><span class="pre">object(...)</span></tt>, if +<tt class="literal"><span class="pre">ref</span></tt> or <tt class="literal"><span class="pre">ptr</span></tt> is used. There are also two basic +categories to to-python conversion, "return value" conversion +(for Python->C++ calls) and "argument" conversion (for +C++->Python calls and explicit <tt class="literal"><span class="pre">object()</span></tt> conversions). The +behavior of these two categories differs subtly in various ways +whose details I forget at the moment. You can probably find +the answers in the above references, and certainly in the code.</p> +<p>The "default" case is by-value (copying) conversion, which uses +to_python_value as a to-python converter.</p> +<blockquote> +<p>Since there can sensibly be only one way to convert any type +to python (disregarding the idea of scoped registries for the +moment), it makes sense that to-python conversions can be +handled by specializing a template. If the type is one of +the types handled by a built-in conversion +(builtin_converters.hpp), the corresponding template +specialization of to_python_value gets used.</p> +<p>Otherwise, to_python_value uses the <tt class="literal"><span class="pre">m_to_python</span></tt> +function in the registration for the C++ type.</p> +</blockquote> +<p>Other conversions, like by-reference conversions, are only +available for wrapped classes, and are requested explicitly by +using <tt class="literal"><span class="pre">ref(...)</span></tt>, <tt class="literal"><span class="pre">ptr(...)</span></tt>, or by specifying different +CallPolicies for a call, which can cause a different to-python +converter to be used. These conversions are never registered +anywhere, though they do need to use the registration to find +the Python class corresponding to the C++ type being referred +to. They just build a new Python instance and stick the +appropriate Holder instance in it.</p> +</blockquote> +<p>from python to C++:</p> +<blockquote> +<p>Once again I think there is a distinction between "return value" +and "argument" conversions, and I forget exactly what that is.</p> +<p>What happens depends on whether an lvalue conversion is needed +(see <a class="reference" href="http://mail.python.org/pipermail/c++-sig/2002-May/001023.html">http://mail.python.org/pipermail/c++-sig/2002-May/001023.html</a>) +All lvalue conversions are also registered in a type's rvalue +conversion chain, since when an rvalue will do, an lvalue is +certainly good enough.</p> +<p>An lvalue conversion can be done in one step (just get me the +pointer to the object - it can be <tt class="literal"><span class="pre">NULL</span></tt> if no conversion is +possible) while an rvalue conversion requires two steps to +support wrapped function overloading and multiple converters for +a given C++ target type: first tell me if a conversion is +possible, then construct the converted object as a second step.</p> +</blockquote> +</blockquote> +</div> +</div> +<hr class="footer"/> +<div class="footer"> +<a class="reference" href="internals.rst">View document source</a>. +Generated on: 2003-09-12 14:51 UTC. +Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. +</div> +</body> +</html> diff --git a/libs/python/doc/internals.rst b/libs/python/doc/internals.rst new file mode 100644 index 000000000..2438d5ffb --- /dev/null +++ b/libs/python/doc/internals.rst @@ -0,0 +1,182 @@ +=================================== + Boost.Python_ Internals |(logo)|__ +=================================== + +.. |(logo)| image:: ../../../boost.png + :alt: Boost + :class: boost-logo + +__ ../../../index.htm + +.. _`Boost.Python`: index.html + +.. _license: ../../../LICENSE_1_0.txt + + +------------------------------------------------------- +A conversation between Brett Calcott and David Abrahams +------------------------------------------------------- + +:copyright: Copyright David Abrahams and Brett Calcott 2003. See + accompanying license_ for terms of use. + +In both of these cases, I'm quite capable of reading code - but the +thing I don't get from scanning the source is a sense of the +architecture, both structurally, and temporally (er, I mean in what +order things go on). + +1) What happens when you do the following:: + + struct boring {}; + ...etc... + class_<boring>("boring") + ; + +There seems to be a fair bit going on. + + - Python needs a new ClassType to be registered. + - We need to construct a new type that can hold our boring struct. + - Inward and outward converters need to be registered for the type. + +Can you gesture in the general direction where these things are done? + + I only have time for a "off-the-top-of-my-head" answer at the moment; + I suggest you step through the code with a debugger after reading this + to see how it works, fill in details, and make sure I didn't forget + anything. + + A new (Python) subclass of Boost.Python.Instance (see + libs/python/src/object/class.cpp) is created by invoking + Boost.Python.class, the metatype:: + + >>> boring = Boost.Python.class( + ... 'boring' + ... , bases_tuple # in this case, just () + ... , { + ... '__module__' : module_name + ... , '__doc__' : doc_string # optional + ... } + ... ) + + A handle to this object is stuck in the m_class_object field + of the registration associated with ``typeid(boring)``. The + registry will keep that object alive forever, even if you + wipe out the 'boring' attribute of the extension module + (probably not a good thing). + + Because you didn't specify ``class<boring, non_copyable, + ...>``, a to-python converter for boring is registered which + copies its argument into a value_holder held by the the + Python boring object. + + Because you didn't specify ``class<boring ...>(no_init)``, + an ``__init__`` function object is added to the class + dictionary which default-constructs a boring in a + value_holder (because you didn't specify some smart pointer + or derived wrapper class as a holder) held by the Python + boring object. + + ``register_class_from_python`` is used to register a + from-python converter for ``shared_ptr<boring>``. + ``boost::shared_ptr``\ s are special among smart pointers + because their Deleter argument can be made to manage the + whole Python object, not just the C++ object it contains, no + matter how the C++ object is held. + + If there were any ``bases<>``, we'd also be registering the + relationship between these base classes and boring in the + up/down cast graph (``inheritance.[hpp/cpp]``). + + In earlier versions of the code, we'd be registering lvalue + from-python converters for the class here, but now + from-python conversion for wrapped classes is handled as a + special case, before consulting the registry, if the source + Python object's metaclass is the Boost.Python metaclass. + + Hmm, that from-python converter probably ought to be handled + the way class converters are, with no explicit conversions + registered. + +2) Can you give a brief overview of the data structures that are + present in the registry + + The registry is simple: it's just a map from typeid -> + registration (see boost/python/converter/registrations.hpp). + ``lvalue_chain`` and ``rvalue_chain`` are simple endogenous + linked lists. + + If you want to know more, just ask. + + If you want to know about the cast graph, ask me something specific in + a separate message. + + and an overview of the process that happens as a type makes its + way from c++ to python and back again. + + Big subject. I suggest some background reading: look for relevant + info in the LLNL progress reports and the messages they link to. + Also, + + http://mail.python.org/pipermail/c++-sig/2002-May/001023.html + + http://mail.python.org/pipermail/c++-sig/2002-December/003115.html + + http://aspn.activestate.com/ASPN/Mail/Message/1280898 + + http://mail.python.org/pipermail/c++-sig/2002-July/001755.html + + from c++ to python: + + It depends on the type and the call policies in use or, for + ``call<>(...)``, ``call_method<>(...)``, or ``object(...)``, if + ``ref`` or ``ptr`` is used. There are also two basic + categories to to-python conversion, "return value" conversion + (for Python->C++ calls) and "argument" conversion (for + C++->Python calls and explicit ``object()`` conversions). The + behavior of these two categories differs subtly in various ways + whose details I forget at the moment. You can probably find + the answers in the above references, and certainly in the code. + + The "default" case is by-value (copying) conversion, which uses + to_python_value as a to-python converter. + + Since there can sensibly be only one way to convert any type + to python (disregarding the idea of scoped registries for the + moment), it makes sense that to-python conversions can be + handled by specializing a template. If the type is one of + the types handled by a built-in conversion + (builtin_converters.hpp), the corresponding template + specialization of to_python_value gets used. + + Otherwise, to_python_value uses the ``m_to_python`` + function in the registration for the C++ type. + + Other conversions, like by-reference conversions, are only + available for wrapped classes, and are requested explicitly by + using ``ref(...)``, ``ptr(...)``, or by specifying different + CallPolicies for a call, which can cause a different to-python + converter to be used. These conversions are never registered + anywhere, though they do need to use the registration to find + the Python class corresponding to the C++ type being referred + to. They just build a new Python instance and stick the + appropriate Holder instance in it. + + + from python to C++: + + Once again I think there is a distinction between "return value" + and "argument" conversions, and I forget exactly what that is. + + What happens depends on whether an lvalue conversion is needed + (see http://mail.python.org/pipermail/c++-sig/2002-May/001023.html) + All lvalue conversions are also registered in a type's rvalue + conversion chain, since when an rvalue will do, an lvalue is + certainly good enough. + + An lvalue conversion can be done in one step (just get me the + pointer to the object - it can be ``NULL`` if no conversion is + possible) while an rvalue conversion requires two steps to + support wrapped function overloading and multiple converters for + a given C++ target type: first tell me if a conversion is + possible, then construct the converted object as a second step. + diff --git a/libs/python/doc/news.html b/libs/python/doc/news.html new file mode 100644 index 000000000..da57caeb3 --- /dev/null +++ b/libs/python/doc/news.html @@ -0,0 +1,371 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st September 2004), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="boost.css"> + + <title>Boost.Python - News/Change Log</title> +</head> + +<body link="#0000FF" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="index.html">Boost.Python</a></h1> + + <h2 align="center">News/Change Log</h2> + </td> + </tr> + </table> + <hr> + + <dl class="page-index"> + + <dt>Current SVN</dt> + <dd> + <ul> + <li>Python 3 support:</li> + <ul> + <li>All the current Boost.Python test cases passed. Extension modules using + Boost.Python expected to support Python 3 smoothly.</li> + <li>Introduced <code>object.contains</code> where <code>x.contains(y)</code> + is equivalent to Python code <code>y in x</code>. + Now <code>dict.has_key</code> is just a wrapper of <code>object.contains</code>. + </li> + <li>When building against Python 3, <code>str.decode</code> will be removed.</li> + <li>When building against Python 3, the original signature of <code>list.sort</code>, which is: + <pre>void sort(object_cref cmpfunc);</pre> + will change to: + <pre>void sort(args_proxy const &args, kwds_proxy const &kwds);</pre> + + This is because in Python 3 <code>list.sort</code> requires all its arguments be keyword arguments. + So you should call it like this: + <pre>x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true))));</pre> + + </li> + <li>According to <a href="http://www.python.org/dev/peps/pep-3123/">PEP 3123</a>, + when building Boost.Python against Python older than 2.6, the following macros will + be defined in Boost.Python header: + <pre> +# define Py_TYPE(o) (((PyObject*)(o))->ob_type) +# define Py_REFCNT(o) (((PyObject*)(o))->ob_refcnt) +# define Py_SIZE(o) (((PyVarObject*)(o))->ob_size)</pre> + So extension writers can use these macro directly, to make code clean and compatible with Python 3. + </li> + </ul> + </ul> + </dd> + + <dt>1.39.0 Release</dt> + + <dd> + <ul> + <li>Pythonic signatures are now automatically appended to the + docstrings. + + <li>Use <a href="v2/docstring_options.html" + ><code>docstring_options.hpp</code></a> header + control the content of docstrings. + + <li>This new feature increases the size of the modules by about 14%. + If this is not acceptable it can be turned off by defining the macro + BOOST_PYTHON_NO_PY_SIGNATURES. Modules compiled with and without the macro + defined are compatible. + </li> + <li> If BOOST_PYTHON_NO_PY_SIGNATURES is undefined, this version defines the + macro BOOST_PYTHON_SUPPORTS_PY_SIGNATURES. This allows writing code that will compile + with older version of Boost.Python (see <a href="v2/pytype_function.html#examples">here</a>). + </li> + <li>By defining BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE, and at a cost + of another 14% size increase, proper pythonic type is generated for the "self" + parameter of the __init__ methods. + </li> + + <li> To support this new feature changes were made to the + <a href="v2/to_python_converter.html"><code>to_python_converter.hpp</code></a>, + <a href="v2/default_call_policies.html"><code>default_call_policies</code></a>, + <a href="v2/ResultConverter.html"><code>ResultConverter</code></a>, + <a href="v2/CallPolicies.html"><code>CallPolicies</code></a> and some others. + Efforts were made not to have interface breaking changes. + </li> + + </ul> + </dd> + + <dt>12 May 2007 - 1.34.0 release</dt> + + <dd> + <ul> + <li>C++ signatures are now automatically appended to the + docstrings. + + <li>New <a href="v2/docstring_options.html" + ><code>docstring_options.hpp</code></a> header to + control the content of docstrings. + + <li>Support for converting <code>void*</code> to/from python, + with <code><a + href="v2/opaque.html">opaque_pointer_converter</a></code> + as the return value policy. Thanks to Niall Douglas for the + initial patch. + </ul> + </dd> + + <dt>19 October 2005 - 1.33.1 release</dt> + + <dd> + <ul> + <li><code>wrapper<T></code> can now be used as expected with a + held type of <i>some-smart-pointer</i><code><T></code></li> + + <li>The build now assumes Python 2.4 by default, rather than 2.2</li> + + <li>Support Python that's built without Unicode support</li> + + <li>Support for wrapping classes with overloaded address-of + (<code>&</code>) operators</li> + </ul> + </dd> + + <dt>14 August 2005 - 1.33 release</dt> + + <dd> + <ul> + <li>Support for docstrings on nonstatic properties.</li> + + <li>We now export the client-provided docstrings for + <code>init<optional<> ></code> and + <i>XXX</i><code>_FUNCTION_OVERLOADS()</code> for only the last + overload.</li> + + <li>Fixed some support for Embedded VC++ 4</li> + + <li>Better support for rvalue from-python conversions of shared_ptr: + always return a pointer that holds the owning python object *unless* + the python object contains a NULL shared_ptr holder of the right + type.</li> + + <li>Support for exposing <code>vector<T*></code> with the + indexing suite.</li> + + <li>Support for GCC-3.3 on MacOS.</li> + + <li>updated visual studio project build file to include two new files + (slice.cpp and wrapper.cpp)</li> + + <li>Added search feature to the index page.</li> + + <li>Numerous fixes to the tutorial</li> + + <li>Numerous workarounds for MSVC 6 and 7, GCC 2.96, and EDG + 2.45</li> + </ul> + </dd> + + <dt>11 March 2005</dt> + + <dd> + <ul> + <li>Added a hack that will fool PyDoc into working with Boost.Python, + thanks to Nick Rasmussen</li> + </ul> + </dd> + + <dt>19 November 2004 - 1.32 release</dt> + + <dd> + <ul> + <li>Updated to use the Boost Software License.</li> + + <li>A new, <a href= + "tutorial/doc/html/python/exposing.html#python.class_virtual_functions"> + better method of wrapping classes with virtual functions</a> has been + implemented.</li> + + <li>Support for upcoming GCC symbol export control features have been + folded in, thanks to Niall Douglas.</li> + + <li>Improved support for <code>std::auto_ptr</code>-like types.</li> + + <li>The Visual C++ bug that makes top-level <i>cv-qualification</i> + of function parameter types part of the function type has been worked + around.</li> + + <li>Components used by other libraries have been moved out of + <code>python/detail</code> and into <code>boost/detail</code> to + improve dependency relationships.</li> + + <li>Miscellaneous bug fixes and compiler workarounds.</li> + </ul> + </dd> + + <dt>8 Sept 2004</dt> + + <dd>Support for Python's Bool type, thanks to <a href= + "mailto:dholth-at-fastmail.fm">Daniel Holth</a>.</dd> + + <dt>11 Sept 2003</dt> + + <dd> + <ul> + <li>Changed the response to multiple to-python converters being + registered for the same type from a hard error into warning; + Boost.Python now reports the offending type in the message.</li> + + <li>Added builtin <code>std::wstring</code> conversions</li> + + <li>Added <code>std::out_of_range</code> => Python + <code>IndexError</code> exception conversion, thanks to <a href= + "mailto:RaoulGough-at-yahoo.co.uk">Raoul Gough</a></li> + </ul> + </dd> + + <dt>9 Sept 2003</dt> + + <dd>Added new <code><a href="v2/str.html#str-spec">str</a></code></dd> + + <dt>constructors which take a range of characters, allowing strings + containing nul (<code>'\0'</code>) characters.</dt> + + <dt>8 Sept 2003</dt> + + <dd>Added the ability to create methods from function objects (with an + <code>operator()</code>); see the <a href= + "v2/make_function.html#make_function-spec">make_function</a> docs for + more info.</dd> + + <dt>10 August 2003</dt> + + <dd>Added the new <code>properties</code> unit tests contributed by + <a href="mailto:romany-at-actimize.com">Roman Yakovenko</a> and + documented <code>add_static_property</code> at his urging.</dd> + + <dt>1 August 2003</dt> + + <dd> + Added the new <code>arg</code> class contributed by <a href= + "mailto:nickm-at-sitius.com">Nikolay Mladenov</a> which supplies the + ability to wrap functions that can be called with ommitted arguments in + the middle: + <pre> +void f(int x = 0, double y = 3.14, std::string z = std::string("foo")); + +BOOST_PYTHON_MODULE(test) +{ + def("f", f + , (arg("x", 0), arg("y", 3.14), arg("z", "foo"))); +} + +</pre>And in Python: + <pre> +>>> import test +>>> f(0, z = "bar") +>>> f(z = "bar", y = 0.0) +</pre>Thanks, Nikolay! + </dd> + + <dt>22 July 2003</dt> + + <dd>Killed the dreaded "bad argument type for builtin operation" error. + Argument errors now show the actual and expected argument types!</dd> + + <dt>19 July 2003</dt> + + <dd>Added the new <code><a href= + "v2/return_arg.html">return_arg</a></code> policy from <a href= + "mailto:nickm-at-sitius.com">Nikolay Mladenov</a>. Thanks, Nikolay!</dd> + + <dt>18 March, 2003</dt> + + <dd><a href="mailto:Gottfried.Ganssauge-at-haufe.de">Gottfried + Ganßauge</a> has contributed <a href= + "v2/opaque.html">opaque pointer support</a>.<br> + <a href="mailto:nicodemus-at-globalite.com.br">Bruno da Silva de + Oliveira</a> has contributed the exciting <a href= + "../pyste/index.html">Pyste</a> ("Pie-steh") package.</dd> + + <dt>24 February 2003</dt> + + <dd>Finished improved support for <code>boost::shared_ptr</code>. Now any + wrapped object of C++ class <code>X</code> can be converted automatically + to <code>shared_ptr<X></code>, regardless of how it was wrapped. + The <code>shared_ptr</code> will manage the lifetime of the Python object + which supplied the <code>X</code>, rather than just the <code>X</code> + object itself, and when such a <code>shared_ptr</code> is converted back + to Python, the original Python object will be returned.</dd> + + <dt>19 January 2003</dt> + + <dd>Integrated <code>staticmethod</code> support from <a href= + "mailto:nickm-at-sitius.com">Nikolay Mladenov</a>. Thanks, Nikolay!</dd> + + <dt>29 December 2002</dt> + + <dd>Added Visual Studio project file and instructions from Brett Calcott. + Thanks, Brett!</dd> + + <dt>20 December 2002</dt> + + <dd>Added automatic downcasting for pointers, references, and smart + pointers to polymorphic class types upon conversion to python</dd> + + <dt>18 December 2002</dt> + + <dd>Optimized from_python conversions for wrapped classes by putting the + conversion logic in the shared library instead of registering separate + converters for each class in each extension module</dd> + + <dt>19 November 2002</dt> + + <dd>Removed the need for users to cast base class member function + pointers when used as arguments to <a href= + "v2/class.html#class_-spec-modifiers">add_property</a></dd> + + <dt>13 December 2002</dt> + + <dd>Allow exporting of <a href= + "v2/enum.html#enum_-spec"><code>enum_</code></a> values into enclosing + <a href="v2/scope.html#scope-spec"><code>scope</code></a>.<br> + Fixed unsigned integer conversions to deal correctly with numbers that + are out-of-range of <code>signed long</code>.</dd> + + <dt>14 November 2002</dt> + + <dd>Auto-detection of class data members wrapped with <a href= + "v2/data_members.html#make_getter-spec"><code>make_getter</code></a></dd> + + <dt>13 November 2002</dt> + + <dd>Full Support for <code>std::auto_ptr<></code> added.</dd> + + <dt>October 2002</dt> + + <dd>Ongoing updates and improvements to tutorial documentation</dd> + + <dt>10 October 2002</dt> + + <dd>Boost.Python V2 is released!</dd> + </dl> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 19 November 2004 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --></p> + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002-2003.</i></p> +</body> +</html> diff --git a/libs/python/doc/polymorphism.txt b/libs/python/doc/polymorphism.txt new file mode 100644 index 000000000..38e2f6914 --- /dev/null +++ b/libs/python/doc/polymorphism.txt @@ -0,0 +1,222 @@ +.. Copyright David Abrahams 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at +.. http://www.boost.org/LICENSE_1_0.txt) + +How Runtime Polymorphism is expressed in Boost.Python: +----------------------------------------------------- + + struct A { virtual std::string f(); virtual ~A(); }; + + std::string call_f(A& x) { return x.f(); } + + struct B { virtual std::string f() { return "B"; } }; + + struct Bcb : B + { + Bcb(PyObject* self) : m_self(self) {} + + virtual std::string f() { return call_method<std::string>(m_sef, "f"); } + static std::string f_default(B& b) { return b.B::f(); } + + PyObject* m_self; + }; + + struct C : B + { + virtual std::string f() { return "C"; } + }; + + >>> class D(B): + ... def f(): + ... return 'D' + ... + >>> class E(B): pass + ... + + +When we write, "invokes B::f non-virtually", we mean: + + void g(B& x) { x.B::f(); } + +This will call B::f() regardless of the dynamic type of x. Any other +way of invoking B::f, including through a function pointer, is a +"virtual invocation", and will call the most-derived override of f(). + +Case studies + + C++\Python class + \___A_____B_____C_____D____E___ + | + A | 1 + | + B | 2 3 + | + Bcb | 4 5 6 + | + C | 7 8 + | + + +1. Simple case + +2. Python A holds a B*. Probably won't happen once we have forced + downcasting. + + Requires: + x.f() -> 'B' + call_f(x) -> 'B' + + Implies: A.f invokes A::f() (virtually or otherwise) + +3. Python B holds a B*. + + Requires: + x.f() -> 'B' + call_f(x) -> 'B' + + Implies: B.f invokes B::f (virtually or otherwise) + + +4. B constructed from Python + + Requires: + + x.f() -> 'B' + call_f(x) -> 'B' + + Implies: B.f invokes B::f non-virtually. Bcb::f invokes B::f + non-virtually. + + Question: Does it help if we arrange for Python B construction to + build a true B object? Then this case doesn't arise. + + +5. D is a Python class derived from B + + Requires: + + x.f() -> 'D' + call_f(x) -> 'D' + + Implies: Bcb::f must invoke call_method to look up the Python + method override, otherwise call_f wouldn't work. + +6. E is like D, but doesn't override f + + Requires: + + x.f() -> 'B' + call_f(x) -> 'B' + + Implies: B.f invokes B::f non-virtually. If it were virtual, x.f() + would cause infinite recursion, because we've already + determined that Bcb::f must invoke call_method to look up + the Python method override. + +7. Python B object holds a C* + + Requires: + + x.f() -> 'C' + call_f(x) -> 'C' + + Implies: B.f invokes B::f virtually. + +8. C object constructed from Python + + Requires: + + x.f() -> 'C' + call_f(x) -> 'C' + + Implies: nothing new. + +------ + +Total implications: + +2: A.f invokes A::f() (virtually or otherwise) +3: B.f invokes B::f (virtually or otherwise) +4: B.f invokes B::f non-virtually. Bcb::f invokes B::f non-virtually +6: B.f invokes B::f non-virtually. +7: B.f invokes B::f virtually. + +5: Bcb::f invokes call_method to look up the Python method + +Though (4) is avoidable, clearly 6 and 7 are not, and they +conflict. The implication is that B.f must choose its behavior +according to the type of the contained C++ object. If it is Bcb, a +non-virtual call to B::f must occur. Otherwise, a virtual call to B::f +must occur. This is essentially the same scheme we had with +Boost.Python v1. + +Note: in early versions of Boost.Python v1, we solved this problem by +introducing a new Python class in the hierarchy, so that D and E +actually derive from a B', and B'.f invokes B::f non-virtually, while +B.f invokes B::f virtually. However, people complained about the +artificial class in the hierarchy, which was revealed when they tried +to do normal kinds of Python introspection. + +------- + +Assumption: we will have a function which builds a virtual function +dispatch callable Python object. + + make_virtual_function(pvmf, default_impl, call_policies, dispatch_type) + +Pseudocode: + + Get first argument from Python arg tuple + if it contains dispatch_type + call default_impl + else + call through pvmf + + +Open questions: + + 1. What about Python multiple inheritance? Do we have the right + check in the if clause above? + + A: Not quite. The correct test looks like: + + Deduce target type of pvmf, i.e. T in R(T::*)(A1...AN). + Find holder in first argument which holds T + if it holds dispatch_type... + + 2. Can we make this more efficient? + + The current "returning" mechanism will look up a holder for T + again. I don't know if we know how to avoid that. + + + OK, the solution involves reworking the call mechanism. This is + neccesary anyway in order to enable wrapping of function objects. + + It can result in a reduction in the overall amount of source code, + because returning<> won't need to be specialized for every + combination of function and member function... though it will still + need a void specialization. We will still need a way to dispatch to + member functions through a regular function interface. mem_fn is + almost the right tool, but it only goes up to 8 + arguments. Forwarding is tricky if you don't want to incur copies. + I think the trick is to use arg_from_python<T>::result_type for each + argument to the forwarder. + + Another option would be to use separate function, function object, + and member function dispatchers. Once you know you have a member + function, you don't need cv-qualified overloads to call it. + + Hmm, while we're at this, maybe we should solve the write-back + converter problem. Can we do it? Maybe not. Ralf doesn't want to + write special write-back functions here, does he? He wants the + converter to do the work automatically. We could add + cleanup/destructor registration. That would relieve the client from + having accessible destructors for types which are being converted by + rvalue. I'm not sure that this will really save any code, + however. It rather depends on the linker, doesn't it? I wonder if + this can be done in a backwards-compatible fashion by generating the + delete function when it's not supplied? + + diff --git a/libs/python/doc/projects.html b/libs/python/doc/projects.html new file mode 100644 index 000000000..05eb52326 --- /dev/null +++ b/libs/python/doc/projects.html @@ -0,0 +1,472 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st September 2004), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html"> + <link rel="stylesheet" type="text/css" href="boost.css"> + + <title>Boost.Python - Projects using Boost.Python</title> +</head> + +<body link="#0000FF" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="index.html">Boost.Python</a></h1> + + <h2 align="center">Projects using Boost.Python</h2> + </td> + </tr> + </table> + <hr> + + <h2>Introduction</h2> + + <p>This is a partial list of projects using Boost.Python. If you are using + Boost.Python as your Python/C++ binding solution, we'd be proud to list + your project on this page. Just <a href= + "mailto:c++-sig@python.org">post</a> a short description of your project + and how Boost.Python helps you get the job done, and we'll add it to this + page .</p> + <hr> + + <h3>Data Analysis</h3> + + <dl class="page-index"> + <dt><b><a href="http://www.neuralynx.com">NeuraLab</a></b></dt> + + <dd>Neuralab is a data analysis environment specifically tailored for + neural data from <a href="http://www.neuralynx.com">Neuralynx</a> + acquisition systems. Neuralab combines presentation quality graphics, a + numerical analysis library, and the <a href= + "http://www.python.org">Python</a> scripting engine in a single + application. With Neuralab, Neuralynx users can perform common analysis + tasks with just a few mouse clicks. More advanced users can create custom + Python scripts, which can optionally be assigned to menus and mouse + clicks.</dd> + </dl> + + <dl class="page-index"> + <dt><b>TSLib</b> - <a href="http://www.fortressinv.com">Fortress + Investment Group LLC</a></dt> + + <dd> + Fortress Investment Group has contracted <a href= + "http://www.boost-consulting.com">Boost Consulting</a> to develop core + internal financial analysis tools in C++ and to prepare Python bindings + for them using Boost.Python. + + <p>Tom Barket of Fortress writes:</p> + + <blockquote> + We have a large C++ analytical library specialized for research in + finance and economics, built for speed and mission critical + stability. Yet Python offers us the flexibility to test out new ideas + quickly and increase the productivity of our time versus working in + C++. There are several key features which make Python stand out. Its + elegance, stability, and breadth of resources on the web are all + valuable, but the most important is its extensibility, due to its + open source transparency. Boost.Python makes Python extensibility + extremely simple and straightforward, yet preserves a great deal of + power and control. + </blockquote> + </dd> + </dl> + + <h3>Educational</h3> + + <dl class="page-index"> + <dt><a href="http://edu.kde.org/kig"><b>Kig</b></a></dt> + + <dd> + <p>KDE Interactive Geometry is a high-school level educational tool, + built for the KDE desktop. It is a nice tool to let students work with + geometrical constructions. It is meant to be the most intuitive, yet + featureful application of its kind.</p> + + <p>Versions after 0.6.x (will) support objects built by the user + himself in the Python language. The exporting of the relevant internal + API's were done using Boost.Python, which made the process very + easy.</p> + </dd> + </dl> + + <h3>Enterprise Software</h3> + + <dl class="page-index"> + <dt><b><a href="http://openwbem.sourceforge.net">OpenWBEM</a></b></dt> + + <dd> + The OpenWBEM project is an effort to develop an open-source + implementation of Web Based Enterprise Management suitable for + commercial and non-commercial application + + <p><a href="mailto:dnuffer@sco.com">Dan Nuffer</a> writes:</p> + + <blockquote> + I'm using Boost.Python to wrap the client API of OpenWBEM.This will + make it easier to do rapid prototyping, testing, and scripting when + developing management solutions that use WBEM. + </blockquote> + </dd> + + <dt><b><a href="http://www.transversal.com">Metafaq</a></b></dt> + + <dd> + Metafaq, from <a href="http://www.transversal.com">Transversal, + Inc.</a>, is an enterprise level online knowledge base management + system. + + <p><a href="mailto:ben.young-at-transversal.com">Ben Young</a> + writes:</p> + + <blockquote> + Boost.Python is used in an automated process to generate python + bindings to our api which is exposed though multiple backends and + frontends. This allows us to write quick tests and bespoke scripts to + perform one off tasks without having to go through the full + compilation cycle. + </blockquote> + </dd> + </dl> + + <h3>Games</h3> + + <dl> + <dt><b><a href="http://www.firaxis.com">Civilization IV</a></b></dt> + </dl> + + <blockquote> + “The fourth game in the PC strategy series that has sold over five + million copies, Sid Meier's Civilization IV is a bold step forward for + the franchise, with spectacular new 3D graphics and all-new single and + multiplayer content. Civilization IV will also set a new standard for + user-modification, allowing gamers to create their own add-ons using + Python and XML. + + <p>Sid Meier's Civilization IV will be released for PC in late 2005. For + more information please visit <a href= + "http://www.firaxis.com">http://www.firaxis.com</a> or write <a href= + "mailto:kgilmore@firaxis.com">kgilmore@firaxis.com</a>”</p> + </blockquote> + + <p>Boost.Python is used as the interface layer between the C++ game code + and Python. Python is used for many purposes in the game, including map + generation, interface screens, game events, tools, tutorials, etc. Most + high-level game operations have been exposed to Python in order to give + modders the power they need to customize the game.</p> + + <blockquote> + -Mustafa Thamer, Civ4 Lead Programmer + </blockquote> + + <dl class="page-index"> + <dt><b><a href="http://vegastrike.sourceforge.net">Vega + Strike</a></b></dt> + + <dd> + <a href="http://vegastrike.sourceforge.net">Vega Strike</a> is the 3D + Space Simulator that allows you to trade and bounty hunt in a vast + universe. Players face dangers, decisions, piracy, and aliens. + + <p><a href="http://vegastrike.sourceforge.net">Vega Strike</a> has + decided to base its scripting on python, using boost as the layer + between the class hierarchy in python and the class hierarchy in C++. + The result is a very flexible scripting system that treats units as + native python classes when designing missions or writing AI's.</p> + + <p>A large economic and planetary simulation is currently being run in + the background in python and the results are returned back into C++ in + the form of various factions' spaceships appearing near worlds that + they are simulated to be near in python if the player is in the general + neighborhood.</p> + </dd> + </dl> + + <h3>Graphics</h3> + + <dl class="page-index"> + <dt><b><a href="http://sourceforge.net/projects/pyosg">OpenSceneGraph + Bindings</a></b></dt> + + <dd><a href="mailto:gideon@computer.org">Gideon May</a> has created a set + of bindings for <a href= + "http://www.openscenegraph.org">OpenSceneGraph</a>, a cross-platform + C++/OpenGL library for the real-time visualization.<br> + </dd> + + <dt><b><a href= + "http://www.slac.stanford.edu/grp/ek/hippodraw/index.html">HippoDraw</a></b></dt> + + <dd> + HippoDraw is a data analysis environment consisting of a canvas upon + which graphs such as histograms, scattter plots, etc, are prsented. It + has a highly interactive GUI interface, but some things you need to do + with scripts. HippoDraw can be run as Python extension module so that + all the manipulation can be done from either Python or the GUI. + + <p>Before the web page came online, <a href= + "mailto:Paul_Kunz@SLAC.Stanford.EDU">Paul F. Kunz</a> wrote:</p> + + <blockquote> + Don't have a web page for the project, but the organization's is + <a href= + "http://www.slac.stanford.edu">http://www.slac.stanford.edu</a> (the + first web server site in America, I installed it). + </blockquote>Which was just too cool a piece of trivia to omit.<br> + + </dd> + + <dt><a href="http://www.iplt.org"><b>IPLT</b></a></dt> + + <dd> + <a href="mailto:ansgar.philippsen-at-unibas.ch">Ansgar Philippsen</a> + writes: + + <blockquote> + IPLT is an image processing library and toolbox for the structural + biology electron microscopy community. I would call it a + budding/evolving project, since it is currently not in production + stage, but rather under heavy development. Python is used as the main + scripting/interaction level, but also for rapid prototyping, since + the underlying C++ class library is pretty much fully exposed via + boost.python (at least the high-level interface). The combined power + of C++ and Python for this project turned out to be just awesome. + </blockquote><br> + + </dd> + + <dt><a href= + "http://www.procoders.net/pythonmagick"><b>PythonMagick</b></a></dt> + + <dd>PythonMagick binds the <a href= + "http://www.graphicsmagick.org">GraphicsMagick</a> image manipulation + library to Python.<br> + </dd> + + <dt><a href="http://www.vpython.org"><b>VPython</b></a></dt> + + <dd> + <a href="mailto:Bruce_Sherwood-at-ncsu.edu">Bruce Sherwood</a> writes: + + <blockquote> + VPython is an extension for Python that makes it easy to create + navigable 3D animations, which are generated as a side effect of + computational code. VPython is used in education for various + purposes, including teaching physics and programming, but it has also + been used by research scientists to visualize systems or data in 3D. + </blockquote><br> + + </dd> + </dl> + + <h3>Scientific Computing</h3> + + <dl class="page index"> + <dt><a href="http://camfr.sourceforge.net"><b>CAMFR</b></a></dt> + + <dd> + CAMFR is a photonics and electromagnetics modelling tool. Python is + used for computational steering. + + <p><a href="mailto:Peter.Bienstman@rug.ac.be">Peter Bienstman</a> + writes:</p> + + <blockquote> + Thanks for providing such a great tool! + </blockquote> + </dd> + + <dt><a href="http://cctbx.sourceforge.net"><b>cctbx - Computational + Crystallography Toolbox</b></a></dt> + + <dd> + Computational Crystallography is concerned with the derivation of + atomic models of crystal structures, given experimental X-ray + diffraction data. The cctbx is an open-source library of fundamental + algorithms for crystallographic computations. The core algorithms are + implemented in C++ and accessed through higher-level Python interfaces. + + <p>The cctbx grew together with Boost.Python and is designed from the + ground up as a hybrid Python/C++ system. With one minor exception, + run-time polymorphism is completely handled by Python. C++ compile-time + polymorphism is used to implement performance critical algorithms. The + Python and C++ layers are seamlessly integrated using Boost.Python.</p> + + <p>The SourceForge cctbx project is organized in modules to facilitate + use in non-crystallographic applications. The scitbx module implements + a general purpose array family for scientific applications and pure C++ + ports of FFTPACK and the L-BFGS quasi-Newton minimizer.</p> + </dd> + + <dt><a href="http://www.llnl.gov/CASC/emsolve"><b>EMSolve</b></a></dt> + + <dd>EMSolve is a provably stable, charge conserving, and energy + conserving solver for Maxwell's equations.<br> + </dd> + + <dt><b><a href="http://cern.ch/gaudi">Gaudi</a></b> and <b><a href= + "http://cern.ch/Gaudi/RootPython/">RootPython</a></b></dt> + + <dd> + Gaudi is a framework for particle physics collision data processing + applications developed in the context of the LHCb and ATLAS experiments + at CERN. + + <p><a href="mailto:Pere.Mato@cern.ch">Pere Mato Vila</a> writes:</p> + + <blockquote> + We are using Boost.Python to provide scripting/interactive capability + to our framework. We have a module called "GaudiPython" implemented + using Boost.Python that allows the interaction with any framework + service or algorithm from python. RootPython also uses Boost.Python + to provide a generic "gateway" between the <a href= + "http://root.cern.ch">ROOT</a> framework and python + + <p>Boost.Python is great. We managed very quickly to interface our + framework to python, which is great language. We are trying to + facilitate to our physicists (end-users) a rapid analysis application + development environment based on python. For that, Boost.Python plays + and essential role.</p> + </blockquote> + </dd> + + <dt><b><a href="http://www.esss.com.br">ESSS</a></b></dt> + + <dd> + ESSS (Engineering Simulation and Scientific Software) is a company that + provides engineering solutions and acts in the brazilian and + south-american market providing products and services related to + Computational Fluid Dynamics and Image Analysis. + + <p><a href="mailto:bruno@esss.com.br">Bruno da Silva de Oliveira</a> + writes:</p> + + <blockquote> + Recently we moved our work from working exclusively with C++ to an + hybrid-language approach, using Python and C++, with Boost.Python + providing the layer between the two. The results are great so far! + </blockquote> + + <p>Two projects have been developed so far with this technology:</p> + + <p><b><a href= + "http://www.esss.com.br/index.php?pg=dev_projetos">Simba</a></b> + provides 3D visualization of geological formations gattered from the + simulation of the evolution of oil systems, allowing the user to + analyse various aspects of the simulation, like deformation, pressure + and fluids, along the time of the simulation.</p> + + <p><b><a href= + "http://www.esss.com.br/index.php?pg=dev_projetos">Aero</a></b> aims to + construct a CFD with brazilian technology, which involves various + companies and universities. ESSS is responsible for various of the + application modules, including GUI and post-processing of results.</p> + </dd> + + <dt><b><a href="http://polybori.sourceforge.net/">PolyBoRi</a></b></dt> + + <dd> + <p><a href="mailto:brickenstein@mfo.de" + >Michael Brickenstein</a> writes:</p> + + <blockquote> + <p>The core of PolyBoRi is a C++ library, which provides + high-level data types for Boolean polynomials and monomials, + exponent vectors, as well as for the underlying polynomial + rings and subsets of the powerset of the Boolean variables. As + a unique approach, binary decision diagrams are used as + internal storage type for polynomial structures. On top of + this C++-library we provide a Python interface. This allows + parsing of complex polynomial systems, as well as sophisticated + and extendable strategies for Gröbner basis computation. + Boost.Python has helped us to create this interface in a + very clean way.</p> + </blockquote> + </dd> + + <dt><b><a href="http://pyrap.googlecode.com/">Pyrap</a></b></dt> + <dd> + <p><a href="diepen@astron.nl" + >Ger van Diepen</a> writes:</p> + + <blockquote> + <p>Pyrap is the python interface to the Radio-Astronomical Package + casacore (<a href="http://casacore.googlecode.com/" + >casacore.googlecode.com</a>). Astronomers love pyrap because + it makes it easily possible to get their data (observed with + radio-astronomical telescopes like LOFAR, ASKAP, and eVLA) in numpy + arrays and do basic data inspection and manipulation using the many + python packages that are available.</p> + + <p>Boost.Python made it quite easily possible to create converters for + the various data types, also for numpy arrays and individual elements + of a numpy array. It's nice they work fully recursively. Mapping C++ + functions to Python was straightforward.</p> + </blockquote> + </dd> + + <dt><b><a href="http://www.rdkit.org/" + >RDKit: Cheminformatics and Machine Learning Software</a></b></dt> + + <dd> + A collection of cheminformatics and machine-learning software + written in C++ and Python. + </dd> + </dl> + + <h3>Systems Libraries</h3> + + <dl> + <dt><a href="http://itamarst.org/software"><b>Fusion</b></a></dt> + + <dd> + <p>Fusion is a library that supports implementing protocols in C++ for + use with Twisted, allowing control over memory allocation strategies, + fast method calls internally, etc.. Fusion supports TCP, UDP and + multicast, and is implemented using the Boost.Python python + bindings.</p> + + <p>Fusion is licensed under the MIT license, and available for download + from <a href= + "http://itamarst.org/software">http://itamarst.org/software</a>.</p> + </dd> + </dl> + + <h3>Tools</h3> + + <dl> + <dt><a href="http://www.jayacard.org"><b>Jayacard</b></a></dt> + + <dd> + Jayacard aims at developing a secure portable open source operating + system for contactless smart cards and a complete suite of high quality + development tools to ease smart card OS and application development. + + <p>The core of the smart card reader management is written in C++ but + all the development tools are written in the friendly Python language. + Boost plays the fundamental role of binding the tools to our core smart + card reader library.</p> + </dd> + </dl> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 29 May, 2008</p> + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002-2008.</i></p> +</body> +</html> diff --git a/libs/python/doc/support.html b/libs/python/doc/support.html new file mode 100644 index 000000000..319856341 --- /dev/null +++ b/libs/python/doc/support.html @@ -0,0 +1,74 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="boost.css"> + + <title>Boost.Python - Support Resources</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="index.html">Boost.Python</a></h1> + + <h2 align="center">Support Resources</h2> + </td> + </tr> + </table> + <hr> + + <h2>Synopsis</h2> + + <p>This is a list of available resources for support with Boost.Python + problems and feature requests. <b>Please try to resist emailing the + Boost.Python developers directly for support.</b> Use the following + resources instead; the developers are listening!</p> + <hr> + + <dl class="page-index"> + <dt><b><a href="http://www.boost-consulting.com">Boost + Consulting</a></b> - Commercial support, development, training, and + distribution for all the Boost libraries, from the people who brought + you Boost.Python.<br> + </dt> + + <dt><b><a href= + "http://www.boost.org/more/mailing_lists.htm#cplussig">The Python + C++-sig</a></b> mailing list is a forum for discussing Python/C++ + interoperability, and Boost.Python in particular. Post your + Boost.Python questions here.<br> + </dt> + + <dt>The <b>Boost.Python <a href= + "http://www.python.org/cgi-bin/moinmoin/boost_2epython">Wiki + Pages</a></b> established by Mike Rovner as part of the <a href= + "http://www.python.org/cgi-bin/moinmoin">PythonInfo Wiki</a> serves as + a forum to gather peoples' experience and as a cookbook.<br> + </dt> + </dl> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 12 Sept, 2003 <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2003.</i></p> + </body> +</html> + diff --git a/libs/python/doc/tutorial/doc/Jamfile.v2 b/libs/python/doc/tutorial/doc/Jamfile.v2 new file mode 100644 index 000000000..ba8882636 --- /dev/null +++ b/libs/python/doc/tutorial/doc/Jamfile.v2 @@ -0,0 +1,18 @@ +# Copyright Joel de Guzman 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +project boost/libs/python/doc/tutorial/doc ; + +import boostbook : boostbook ; +using quickbook ; + +path-constant images : html ; + +boostbook tutorial + : + tutorial.qbk + : + <xsl:param>boost.root=../../../../../.. + <format>pdf:<xsl:param>img.src.path=$(images)/ + <format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/python/doc/tutorial/doc/html + ; diff --git a/libs/python/doc/tutorial/doc/html/images/alert.png b/libs/python/doc/tutorial/doc/html/images/alert.png Binary files differnew file mode 100644 index 000000000..b4645bc7e --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/alert.png diff --git a/libs/python/doc/tutorial/doc/html/images/home.png b/libs/python/doc/tutorial/doc/html/images/home.png Binary files differnew file mode 100644 index 000000000..5584aacb0 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/home.png diff --git a/libs/python/doc/tutorial/doc/html/images/jam.png b/libs/python/doc/tutorial/doc/html/images/jam.png Binary files differnew file mode 100644 index 000000000..224ed7914 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/jam.png diff --git a/libs/python/doc/tutorial/doc/html/images/next.png b/libs/python/doc/tutorial/doc/html/images/next.png Binary files differnew file mode 100644 index 000000000..59800b4e8 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/next.png diff --git a/libs/python/doc/tutorial/doc/html/images/note.png b/libs/python/doc/tutorial/doc/html/images/note.png Binary files differnew file mode 100644 index 000000000..3ed047cac --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/note.png diff --git a/libs/python/doc/tutorial/doc/html/images/prev.png b/libs/python/doc/tutorial/doc/html/images/prev.png Binary files differnew file mode 100644 index 000000000..d88a40f92 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/prev.png diff --git a/libs/python/doc/tutorial/doc/html/images/python.png b/libs/python/doc/tutorial/doc/html/images/python.png Binary files differnew file mode 100644 index 000000000..cc2ff1d54 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/python.png diff --git a/libs/python/doc/tutorial/doc/html/images/smiley.png b/libs/python/doc/tutorial/doc/html/images/smiley.png Binary files differnew file mode 100644 index 000000000..30a77f71c --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/smiley.png diff --git a/libs/python/doc/tutorial/doc/html/images/tip.png b/libs/python/doc/tutorial/doc/html/images/tip.png Binary files differnew file mode 100644 index 000000000..9f596b0b8 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/tip.png diff --git a/libs/python/doc/tutorial/doc/html/images/up.png b/libs/python/doc/tutorial/doc/html/images/up.png Binary files differnew file mode 100644 index 000000000..17d9c3ec4 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/up.png diff --git a/libs/python/doc/tutorial/doc/html/index.html b/libs/python/doc/tutorial/doc/html/index.html new file mode 100644 index 000000000..c324f065c --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/index.html @@ -0,0 +1,142 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Chapter 1. python 2.0</title> +<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="index.html" title="Chapter 1. python 2.0"> +<link rel="next" href="python/hello.html" title="Building Hello World"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"><a accesskey="n" href="python/hello.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a></div> +<div class="chapter"> +<div class="titlepage"><div> +<div><h2 class="title"> +<a name="python"></a>Chapter 1. python 2.0</h2></div> +<div><div class="author"><h3 class="author"> +<span class="firstname">Joel</span> <span class="surname">de Guzman</span> +</h3></div></div> +<div><div class="author"><h3 class="author"> +<span class="firstname">David</span> <span class="surname">Abrahams</span> +</h3></div></div> +<div><p class="copyright">Copyright © 2002-2005 Joel + de Guzman, David Abrahams</p></div> +<div><div class="legalnotice"> +<a name="python.legal"></a><p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></div> +</div></div> +<div class="toc"> +<p><b>Table of Contents</b></p> +<dl> +<dt><span class="section"><a href="index.html#python.quickstart">QuickStart</a></span></dt> +<dt><span class="section"><a href="python/hello.html">Building Hello World</a></span></dt> +<dt><span class="section"><a href="python/exposing.html">Exposing Classes</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/exposing.html#python.constructors">Constructors</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_data_members">Class Data Members</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_properties">Class Properties</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.inheritance">Inheritance</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt> +</dl></dd> +<dt><span class="section"><a href="python/functions.html">Functions</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/functions.html#python.call_policies">Call Policies</a></span></dt> +<dt><span class="section"><a href="python/functions.html#python.overloading">Overloading</a></span></dt> +<dt><span class="section"><a href="python/functions.html#python.default_arguments">Default Arguments</a></span></dt> +<dt><span class="section"><a href="python/functions.html#python.auto_overloading">Auto-Overloading</a></span></dt> +</dl></dd> +<dt><span class="section"><a href="python/object.html">Object Interface</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/object.html#python.basic_interface">Basic Interface</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.derived_object_types">Derived Object types</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.enums">Enums</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.creating_python_object">Creating <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> from <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code></a></span></dt> +</dl></dd> +<dt><span class="section"><a href="python/embedding.html">Embedding</a></span></dt> +<dd><dl><dt><span class="section"><a href="python/embedding.html#python.using_the_interpreter">Using the interpreter</a></span></dt></dl></dd> +<dt><span class="section"><a href="python/iterators.html">Iterators</a></span></dt> +<dt><span class="section"><a href="python/exception.html">Exception Translation</a></span></dt> +<dt><span class="section"><a href="python/techniques.html">General Techniques</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/techniques.html#python.creating_packages">Creating Packages</a></span></dt> +<dt><span class="section"><a href="python/techniques.html#python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt> +<dt><span class="section"><a href="python/techniques.html#python.reducing_compiling_time">Reducing Compiling Time</a></span></dt> +</dl></dd> +</dl> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.quickstart"></a>QuickStart</h2></div></div></div> +<p> + 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). + </p> +<h3> +<a name="quickstart.hello_world"></a> + Hello World + </h3> +<p> + Following C/C++ tradition, let's start with the "hello, world". A + C++ Function: + </p> +<pre class="programlisting"><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*</span> <span class="identifier">greet</span><span class="special">()</span> +<span class="special">{</span> + <span class="keyword">return</span> <span class="string">"hello, world"</span><span class="special">;</span> +<span class="special">}</span> +</pre> +<p> + can be exposed to Python by writing a Boost.Python wrapper: + </p> +<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello_ext</span><span class="special">)</span> +<span class="special">{</span> + <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span> + <span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="identifier">greet</span><span class="special">);</span> +<span class="special">}</span> +</pre> +<p> + 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: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">hello_ext</span> +<span class="special">>>></span> <span class="keyword">print</span> <span class="identifier">hello_ext</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span> +<span class="identifier">hello</span><span class="special">,</span> <span class="identifier">world</span> +</pre> +<div class="blockquote"><blockquote class="blockquote"><p> + <span class="emphasis"><em><span class="bold"><strong>Next stop... Building your Hello World module + from start to finish...</strong></span></em></span> + </p></blockquote></div> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"><p><small>Last revised: December 26, 2011 at 21:58:39 GMT</small></p></td> +<td align="right"><div class="copyright-footer"></div></td> +</tr></table> +<hr> +<div class="spirit-nav"><a accesskey="n" href="python/hello.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a></div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/embedding.html b/libs/python/doc/tutorial/doc/html/python/embedding.html new file mode 100644 index 000000000..4e1c21857 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/embedding.html @@ -0,0 +1,269 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Embedding</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="object.html" title="Object Interface"> +<link rel="next" href="iterators.html" title="Iterators"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="object.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="iterators.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.embedding"></a>Embedding</h2></div></div></div> +<div class="toc"><dl><dt><span class="section"><a href="embedding.html#python.using_the_interpreter">Using the interpreter</a></span></dt></dl></div> +<p> + By now you should know how to use Boost.Python to call your C++ code from Python. + However, sometimes you may need to do the reverse: call Python code from the + C++-side. This requires you to <span class="emphasis"><em>embed</em></span> the Python interpreter + into your C++ program. + </p> +<p> + Currently, Boost.Python does not directly support everything you'll need when + embedding. Therefore you'll need to use the <a href="http://www.python.org/doc/current/api/api.html" target="_top">Python/C + API</a> to fill in the gaps. However, Boost.Python already makes embedding + a lot easier and, in a future version, it may become unnecessary to touch the + Python/C API at all. So stay tuned... <span class="inlinemediaobject"><img src="../images/smiley.png" alt="smiley"></span> + </p> +<h3> +<a name="embedding.building_embedded_programs"></a> + Building embedded programs + </h3> +<p> + To be able to embed python into your programs, you have to link to both Boost.Python's + as well as Python's own runtime library. + </p> +<p> + Boost.Python's library comes in two variants. Both are located in Boost's + <code class="literal">/libs/python/build/bin-stage</code> subdirectory. On Windows, the + variants are called <code class="literal">boost_python.lib</code> (for release builds) + and <code class="literal">boost_python_debug.lib</code> (for debugging). If you can't + find the libraries, you probably haven't built Boost.Python yet. See <a href="../../../../building.html" target="_top">Building and Testing</a> on how to do this. + </p> +<p> + Python's library can be found in the <code class="literal">/libs</code> subdirectory + of your Python directory. On Windows it is called pythonXY.lib where X.Y is + your major Python version number. + </p> +<p> + Additionally, Python's <code class="literal">/include</code> subdirectory has to be added + to your include path. + </p> +<p> + In a Jamfile, all the above boils down to: + </p> +<pre class="programlisting">projectroot c:\projects\embedded_program ; # location of the program + +# bring in the rules for python +SEARCH on python.jam = $(BOOST_BUILD_PATH) ; +include python.jam ; + +exe embedded_program # name of the executable + : #sources + embedded_program.cpp + : # requirements + <find-library>boost_python <library-path>c:\boost\libs\python + $(PYTHON_PROPERTIES) + <library-path>$(PYTHON_LIB_PATH) + <find-library>$(PYTHON_EMBEDDED_LIBRARY) ; +</pre> +<h3> +<a name="embedding.getting_started"></a> + Getting started + </h3> +<p> + Being able to build is nice, but there is nothing to build yet. Embedding the + Python interpreter into one of your C++ programs requires these 4 steps: + </p> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + #include <code class="literal"><boost/python.hpp></code> + </li> +<li class="listitem"> + Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652" target="_top">Py_Initialize</a>() + to start the interpreter and create the <code class="literal">__main__</code> module. + </li> +<li class="listitem"> + Call other Python C API routines to use the interpreter. + </li> +</ol></div> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + <span class="bold"><strong>Note that at this time you must not call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656" target="_top">Py_Finalize</a>() + to stop the interpreter. This may be fixed in a future version of boost.python.</strong></span> + </p></td></tr> +</table></div> +<p> + (Of course, there can be other C++ code between all of these steps.) + </p> +<div class="blockquote"><blockquote class="blockquote"><p> + <span class="emphasis"><em><span class="bold"><strong>Now that we can embed the interpreter in + our programs, lets see how to put it to use...</strong></span></em></span> + </p></blockquote></div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.using_the_interpreter"></a>Using the interpreter</h3></div></div></div> +<p> + As you probably already know, objects in Python are reference-counted. Naturally, + the <code class="literal">PyObject</code>s of the Python C API are also reference-counted. + There is a difference however. While the reference-counting is fully automatic + in Python, the Python C API requires you to do it <a href="http://www.python.org/doc/current/c-api/refcounting.html" target="_top">by + hand</a>. This is messy and especially hard to get right in the presence + of C++ exceptions. Fortunately Boost.Python provides the <a href="../../../../v2/handle.html" target="_top">handle</a> + and <a href="../../../../v2/object.html" target="_top">object</a> class templates to + automate the process. + </p> +<h3> +<a name="using_the_interpreter.running_python_code"></a> + Running Python code + </h3> +<p> + Boost.python provides three related functions to run Python code from C++. + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">eval</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">expression</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">globals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">(),</span> <span class="identifier">object</span> <span class="identifier">locals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">())</span> +<span class="identifier">object</span> <span class="identifier">exec</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">code</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">globals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">(),</span> <span class="identifier">object</span> <span class="identifier">locals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">())</span> +<span class="identifier">object</span> <span class="identifier">exec_file</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">filename</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">globals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">(),</span> <span class="identifier">object</span> <span class="identifier">locals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">())</span> +</pre> +<p> + eval evaluates the given expression and returns the resulting value. exec + executes the given code (typically a set of statements) returning the result, + and exec_file executes the code contained in the given file. + </p> +<p> + The <code class="literal">globals</code> and <code class="literal">locals</code> parameters are + Python dictionaries containing the globals and locals of the context in which + to run the code. For most intents and purposes you can use the namespace + dictionary of the <code class="literal">__main__</code> module for both parameters. + </p> +<p> + Boost.python provides a function to import a module: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">import</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">name</span><span class="special">)</span> +</pre> +<p> + import imports a python module (potentially loading it into the running process + first), and returns it. + </p> +<p> + Let's import the <code class="literal">__main__</code> module and run some Python code + in its namespace: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">main_module</span> <span class="special">=</span> <span class="identifier">import</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">);</span> +<span class="identifier">object</span> <span class="identifier">main_namespace</span> <span class="special">=</span> <span class="identifier">main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span> + +<span class="identifier">object</span> <span class="identifier">ignored</span> <span class="special">=</span> <span class="identifier">exec</span><span class="special">(</span><span class="string">"hello = file('hello.txt', 'w')\n"</span> + <span class="string">"hello.write('Hello world!')\n"</span> + <span class="string">"hello.close()"</span><span class="special">,</span> + <span class="identifier">main_namespace</span><span class="special">);</span> +</pre> +<p> + This should create a file called 'hello.txt' in the current directory containing + a phrase that is well-known in programming circles. + </p> +<h3> +<a name="using_the_interpreter.manipulating_python_objects"></a> + Manipulating Python objects + </h3> +<p> + Often we'd like to have a class to manipulate Python objects. But we have + already seen such a class above, and in the <a href="object.html" target="_top">previous + section</a>: the aptly named <code class="literal">object</code> class and its + derivatives. We've already seen that they can be constructed from a <code class="literal">handle</code>. + The following examples should further illustrate this fact: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">main_module</span> <span class="special">=</span> <span class="identifier">import</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">);</span> +<span class="identifier">object</span> <span class="identifier">main_namespace</span> <span class="special">=</span> <span class="identifier">main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span> +<span class="identifier">object</span> <span class="identifier">ignored</span> <span class="special">=</span> <span class="identifier">exec</span><span class="special">(</span><span class="string">"result = 5 ** 2"</span><span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">);</span> +<span class="keyword">int</span> <span class="identifier">five_squared</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">main_namespace</span><span class="special">[</span><span class="string">"result"</span><span class="special">]);</span> +</pre> +<p> + Here we create a dictionary object for the <code class="literal">__main__</code> module's + namespace. Then we assign 5 squared to the result variable and read this + variable from the dictionary. Another way to achieve the same result is to + use eval instead, which returns the result directly: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">eval</span><span class="special">(</span><span class="string">"5 ** 2"</span><span class="special">);</span> +<span class="keyword">int</span> <span class="identifier">five_squared</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">result</span><span class="special">);</span> +</pre> +<h3> +<a name="using_the_interpreter.exception_handling"></a> + Exception handling + </h3> +<p> + If an exception occurs in the evaluation of the python expression, <a href="../../../../v2/errors.html#error_already_set-spec" target="_top">error_already_set</a> + is thrown: + </p> +<pre class="programlisting"><span class="keyword">try</span> +<span class="special">{</span> + <span class="identifier">object</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">eval</span><span class="special">(</span><span class="string">"5/0"</span><span class="special">);</span> + <span class="comment">// execution will never get here:</span> + <span class="keyword">int</span> <span class="identifier">five_divided_by_zero</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">result</span><span class="special">);</span> +<span class="special">}</span> +<span class="keyword">catch</span><span class="special">(</span><span class="identifier">error_already_set</span> <span class="keyword">const</span> <span class="special">&)</span> +<span class="special">{</span> + <span class="comment">// handle the exception in some way</span> +<span class="special">}</span> +</pre> +<p> + The <code class="literal">error_already_set</code> exception class doesn't carry any + information in itself. To find out more about the Python exception that occurred, + you need to use the <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">exception + handling functions</a> of the Python C API in your catch-statement. This + can be as simple as calling <a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70" target="_top">PyErr_Print()</a> + to print the exception's traceback to the console, or comparing the type + of the exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html" target="_top">standard + exceptions</a>: + </p> +<pre class="programlisting"><span class="keyword">catch</span><span class="special">(</span><span class="identifier">error_already_set</span> <span class="keyword">const</span> <span class="special">&)</span> +<span class="special">{</span> + <span class="keyword">if</span> <span class="special">(</span><span class="identifier">PyErr_ExceptionMatches</span><span class="special">(</span><span class="identifier">PyExc_ZeroDivisionError</span><span class="special">))</span> + <span class="special">{</span> + <span class="comment">// handle ZeroDivisionError specially</span> + <span class="special">}</span> + <span class="keyword">else</span> + <span class="special">{</span> + <span class="comment">// print all other errors to stderr</span> + <span class="identifier">PyErr_Print</span><span class="special">();</span> + <span class="special">}</span> +<span class="special">}</span> +</pre> +<p> + (To retrieve even more information from the exception you can use some of + the other exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">here</a>.) + </p> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="object.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="iterators.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/exception.html b/libs/python/doc/tutorial/doc/html/python/exception.html new file mode 100644 index 000000000..7c053a7e8 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/exception.html @@ -0,0 +1,63 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Exception Translation</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="iterators.html" title="Iterators"> +<link rel="next" href="techniques.html" title="General Techniques"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="iterators.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="techniques.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.exception"></a>Exception Translation</h2></div></div></div> +<p> + 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: + </p> +<pre class="programlisting"><span class="keyword">raise</span> <span class="identifier">RuntimeError</span><span class="special">,</span> <span class="string">'unidentifiable C++ Exception'</span> +</pre> +<p> + Users may provide custom translation. Here's an example: + </p> +<pre class="programlisting"><span class="identifier">struct</span> <span class="identifier">PodBayDoorException</span><span class="special">;</span> +<span class="identifier">void</span> <span class="identifier">translator</span><span class="special">(</span><span class="identifier">PodBayDoorException</span> <span class="identifier">const</span><span class="special">&</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span> + <span class="identifier">PyErr_SetString</span><span class="special">(</span><span class="identifier">PyExc_UserWarning</span><span class="special">,</span> <span class="string">"I'm sorry Dave..."</span><span class="special">);</span> +<span class="special">}</span> +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">kubrick</span><span class="special">)</span> <span class="special">{</span> + <span class="identifier">register_exception_translator</span><span class="special"><</span> + <span class="identifier">PodBayDoorException</span><span class="special">>(</span><span class="identifier">translator</span><span class="special">);</span> + <span class="special">...</span> +</pre> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="iterators.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="techniques.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/exposing.html b/libs/python/doc/tutorial/doc/html/python/exposing.html new file mode 100644 index 000000000..5547b2f20 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/exposing.html @@ -0,0 +1,591 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Exposing Classes</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="hello.html" title="Building Hello World"> +<link rel="next" href="functions.html" title="Functions"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="hello.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.exposing"></a>Exposing Classes</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="exposing.html#python.constructors">Constructors</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_data_members">Class Data Members</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_properties">Class Properties</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.inheritance">Inheritance</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt> +</dl></div> +<p> + Now let's expose a C++ class to Python. + </p> +<p> + Consider a C++ class/struct that we want to expose to Python: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">World</span> +<span class="special">{</span> + <span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span> + <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">greet</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span> + <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">;</span> +<span class="special">};</span> +</pre> +<p> + We can expose this to Python by writing a corresponding Boost.Python C++ Wrapper: + </p> +<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> +<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span> + <span class="special">;</span> +<span class="special">}</span> +</pre> +<p> + Here, we wrote a C++ class wrapper that exposes the member functions <code class="literal">greet</code> + and <code class="literal">set</code>. Now, after building our module as a shared library, + we may use our class <code class="literal">World</code> in Python. Here's a sample Python + session: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">hello</span> +<span class="special">>>></span> <span class="identifier">planet</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span> +<span class="special">>>></span> <span class="identifier">planet</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="string">'howdy'</span><span class="special">)</span> +<span class="special">>>></span> <span class="identifier">planet</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span> +<span class="string">'howdy'</span> +</pre> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.constructors"></a>Constructors</h3></div></div></div> +<p> + Our previous example didn't have any explicit constructors. Since <code class="literal">World</code> + 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 + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">planet</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span> +</pre> +<p> + We may wish to wrap a class with a non-default constructor. Let us build + on our previous example: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">World</span> +<span class="special">{</span> + <span class="identifier">World</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">):</span> <span class="identifier">msg</span><span class="special">(</span><span class="identifier">msg</span><span class="special">)</span> <span class="special">{}</span> <span class="comment">// added constructor</span> + <span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span> + <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">greet</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span> + <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">;</span> +<span class="special">};</span> +</pre> +<p> + This time <code class="literal">World</code> has no default constructor; our previous + wrapping code would fail to compile when the library tried to expose it. + We have to tell <code class="literal">class_<World></code> about the constructor + we want to expose instead. + </p> +<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> +<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>())</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span> + <span class="special">;</span> +<span class="special">}</span> +</pre> +<p> + <code class="literal">init<std::string>()</code> exposes the constructor taking + in a <code class="literal">std::string</code> (in Python, constructors are spelled + "<code class="literal">"__init__"</code>"). + </p> +<p> + We can expose additional constructors by passing more <code class="literal">init<...></code>s + to the <code class="literal">def()</code> member function. Say for example we have + another World constructor taking in two doubles: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>())</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</span><span class="special">>())</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span> +<span class="special">;</span> +</pre> +<p> + On the other hand, if we do not wish to expose any constructors at all, we + may use <code class="literal">no_init</code> instead: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Abstract</span><span class="special">>(</span><span class="string">"Abstract"</span><span class="special">,</span> <span class="identifier">no_init</span><span class="special">)</span> +</pre> +<p> + This actually adds an <code class="literal">__init__</code> method which always raises + a Python RuntimeError exception. + </p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.class_data_members"></a>Class Data Members</h3></div></div></div> +<p> + 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 <span class="bold"><strong>read-only</strong></span> + or <span class="bold"><strong>read-write</strong></span>. Consider this class <code class="literal">Var</code>: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Var</span> +<span class="special">{</span> + <span class="identifier">Var</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">name</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">name</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span> <span class="identifier">value</span><span class="special">()</span> <span class="special">{}</span> + <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span> <span class="identifier">name</span><span class="special">;</span> + <span class="keyword">float</span> <span class="identifier">value</span><span class="special">;</span> +<span class="special">};</span> +</pre> +<p> + Our C++ <code class="literal">Var</code> class and its data members can be exposed + to Python: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Var</span><span class="special">>(</span><span class="string">"Var"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>())</span> + <span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">name</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def_readwrite</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span> +</pre> +<p> + Then, in Python, assuming we have placed our Var class inside the namespace + hello as we did before: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">Var</span><span class="special">(</span><span class="string">'pi'</span><span class="special">)</span> +<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> <span class="special">=</span> <span class="number">3.14</span> +<span class="special">>>></span> <span class="keyword">print</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">name</span><span class="special">,</span> <span class="string">'is around'</span><span class="special">,</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> +<span class="identifier">pi</span> <span class="keyword">is</span> <span class="identifier">around</span> <span class="number">3.14</span> +</pre> +<p> + Note that <code class="literal">name</code> is exposed as <span class="bold"><strong>read-only</strong></span> + while <code class="literal">value</code> is exposed as <span class="bold"><strong>read-write</strong></span>. + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">name</span> <span class="special">=</span> <span class="string">'e'</span> <span class="comment"># can't change name</span> +<span class="identifier">Traceback</span> <span class="special">(</span><span class="identifier">most</span> <span class="identifier">recent</span> <span class="identifier">call</span> <span class="identifier">last</span><span class="special">):</span> + <span class="identifier">File</span> <span class="string">"<stdin>"</span><span class="special">,</span> <span class="identifier">line</span> <span class="number">1</span><span class="special">,</span> <span class="keyword">in</span> <span class="error">?</span> +<span class="identifier">AttributeError</span><span class="special">:</span> <span class="identifier">can</span><span class="error">'</span><span class="identifier">t</span> <span class="identifier">set</span> <span class="identifier">attribute</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.class_properties"></a>Class Properties</h3></div></div></div> +<p> + 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: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Num</span> +<span class="special">{</span> + <span class="identifier">Num</span><span class="special">();</span> + <span class="keyword">float</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span> + <span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="keyword">float</span> <span class="identifier">value</span><span class="special">);</span> + <span class="special">...</span> +<span class="special">};</span> +</pre> +<p> + 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 <code class="literal">Num</code> + class using Boost.Python: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Num</span><span class="special">>(</span><span class="string">"Num"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span> +</pre> +<p> + And at last, in Python: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">Num</span><span class="special">()</span> +<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> <span class="special">=</span> <span class="number">3.14</span> +<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">rovalue</span> +<span class="special">(</span><span class="number">3.14</span><span class="special">,</span> <span class="number">3.14</span><span class="special">)</span> +<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">rovalue</span> <span class="special">=</span> <span class="number">2.17</span> <span class="comment"># error!</span> +</pre> +<p> + Take note that the class property <code class="literal">rovalue</code> is exposed as + <span class="bold"><strong>read-only</strong></span> since the <code class="literal">rovalue</code> + setter member function is not passed in: + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.inheritance"></a>Inheritance</h3></div></div></div> +<p> + 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. + </p> +<p> + Consider this trivial inheritance structure: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Base</span> <span class="special">{</span> <span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">Base</span><span class="special">();</span> <span class="special">};</span> +<span class="keyword">struct</span> <span class="identifier">Derived</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{};</span> +</pre> +<p> + And a set of C++ functions operating on <code class="literal">Base</code> and <code class="literal">Derived</code> + object instances: + </p> +<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">b</span><span class="special">(</span><span class="identifier">Base</span><span class="special">*);</span> +<span class="keyword">void</span> <span class="identifier">d</span><span class="special">(</span><span class="identifier">Derived</span><span class="special">*);</span> +<span class="identifier">Base</span><span class="special">*</span> <span class="identifier">factory</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="keyword">new</span> <span class="identifier">Derived</span><span class="special">;</span> <span class="special">}</span> +</pre> +<p> + We've seen how we can wrap the base class <code class="literal">Base</code>: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Base</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span> + <span class="comment">/*...*/</span> + <span class="special">;</span> +</pre> +<p> + Now we can inform Boost.Python of the inheritance relationship between <code class="literal">Derived</code> + and its base class <code class="literal">Base</code>. Thus: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Derived</span><span class="special">,</span> <span class="identifier">bases</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span> <span class="special">>(</span><span class="string">"Derived"</span><span class="special">)</span> + <span class="comment">/*...*/</span> + <span class="special">;</span> +</pre> +<p> + Doing so, we get some things for free: + </p> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + Derived automatically inherits all of Base's Python methods (wrapped + C++ member functions) + </li> +<li class="listitem"> + <span class="bold"><strong>If</strong></span> Base is polymorphic, <code class="literal">Derived</code> + objects which have been passed to Python via a pointer or reference to + <code class="literal">Base</code> can be passed where a pointer or reference to + <code class="literal">Derived</code> is expected. + </li> +</ol></div> +<p> + Now, we will expose the C++ free functions <code class="literal">b</code> and <code class="literal">d</code> + and <code class="literal">factory</code>: + </p> +<pre class="programlisting"><span class="identifier">def</span><span class="special">(</span><span class="string">"b"</span><span class="special">,</span> <span class="identifier">b</span><span class="special">);</span> +<span class="identifier">def</span><span class="special">(</span><span class="string">"d"</span><span class="special">,</span> <span class="identifier">d</span><span class="special">);</span> +<span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span> <span class="identifier">factory</span><span class="special">);</span> +</pre> +<p> + Note that free function <code class="literal">factory</code> is being used to generate + new instances of class <code class="literal">Derived</code>. In such cases, we use + <code class="literal">return_value_policy<manage_new_object></code> to instruct + Python to adopt the pointer to <code class="literal">Base</code> and hold the instance + in a new Python <code class="literal">Base</code> object until the the Python object + is destroyed. We will see more of Boost.Python <a class="link" href="functions.html#python.call_policies" title="Call Policies">call + policies</a> later. + </p> +<pre class="programlisting"><span class="comment">// Tell Python to take ownership of factory's result</span> +<span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span> <span class="identifier">factory</span><span class="special">,</span> + <span class="identifier">return_value_policy</span><span class="special"><</span><span class="identifier">manage_new_object</span><span class="special">>());</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.class_virtual_functions"></a>Class Virtual Functions</h3></div></div></div> +<p> + In this section, we will learn how to make functions behave polymorphically + through virtual functions. Continuing our example, let us add a virtual function + to our <code class="literal">Base</code> class: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Base</span> +<span class="special">{</span> + <span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">Base</span><span class="special">()</span> <span class="special">{}</span> + <span class="keyword">virtual</span> <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> +<span class="special">};</span> +</pre> +<p> + 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. It is not ideal to add anything + to our class <code class="computeroutput"><span class="identifier">Base</span></code>. Yet, when + you have a virtual function that's going to be overridden in Python and called + polymorphically <span class="bold"><strong>from C++</strong></span>, we'll need to + add some scaffoldings to make things work properly. What we'll do is write + a class wrapper that derives from <code class="computeroutput"><span class="identifier">Base</span></code> + that will unintrusively hook into the virtual functions so that a Python + override may be called: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">BaseWrap</span> <span class="special">:</span> <span class="identifier">Base</span><span class="special">,</span> <span class="identifier">wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span> +<span class="special">{</span> + <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> + <span class="special">{</span> + <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">)();</span> + <span class="special">}</span> +<span class="special">};</span> +</pre> +<p> + Notice too that in addition to inheriting from <code class="computeroutput"><span class="identifier">Base</span></code>, + we also multiply- inherited <code class="computeroutput"><span class="identifier">wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span></code> (See <a href="../../../../v2/wrapper.html" target="_top">Wrapper</a>). + The <code class="computeroutput"><span class="identifier">wrapper</span></code> template makes + the job of wrapping classes that are meant to overridden in Python, easier. + </p> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><strong>MSVC6/7 Workaround</strong></span> + </p> +<p> + If you are using Microsoft Visual C++ 6 or 7, you have to write <code class="computeroutput"><span class="identifier">f</span></code> as: + </p> +<p> + <code class="computeroutput"><span class="keyword">return</span> <span class="identifier">call</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">).</span><span class="identifier">ptr</span><span class="special">());</span></code>. + </p> +</div> +<p> + BaseWrap's overridden virtual member function <code class="computeroutput"><span class="identifier">f</span></code> + in effect calls the corresponding method of the Python object through <code class="computeroutput"><span class="identifier">get_override</span></code>. + </p> +<p> + Finally, exposing <code class="computeroutput"><span class="identifier">Base</span></code>: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">BaseWrap</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">pure_virtual</span><span class="special">(&</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">))</span> + <span class="special">;</span> +</pre> +<p> + <code class="computeroutput"><span class="identifier">pure_virtual</span></code> signals Boost.Python + that the function <code class="computeroutput"><span class="identifier">f</span></code> is a + pure virtual function. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"> +<p> + <span class="bold"><strong>member function and methods</strong></span> + </p> +<p> + Python, like many object oriented languages uses the term <span class="bold"><strong>methods</strong></span>. + Methods correspond roughly to C++'s <span class="bold"><strong>member functions</strong></span> + </p> +</td></tr> +</table></div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.virtual_functions_with_default_implementations"></a>Virtual Functions with Default Implementations</h3></div></div></div> +<p> + We've seen in the previous section how classes with pure virtual functions + are wrapped using Boost.Python's <a href="../../../../v2/wrapper.html" target="_top">class + wrapper</a> facilities. If we wish to wrap <span class="bold"><strong>non</strong></span>-pure-virtual + functions instead, the mechanism is a bit different. + </p> +<p> + Recall that in the <a class="link" href="exposing.html#python.class_virtual_functions" title="Class Virtual Functions">previous + section</a>, we wrapped a class with a pure virtual function that we then + implemented in C++, or Python classes derived from it. Our base class: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Base</span> +<span class="special">{</span> + <span class="keyword">virtual</span> <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> +<span class="special">};</span> +</pre> +<p> + had a pure virtual function <code class="literal">f</code>. If, however, its member + function <code class="literal">f</code> was not declared as pure virtual: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Base</span> +<span class="special">{</span> + <span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">Base</span><span class="special">()</span> <span class="special">{}</span> + <span class="keyword">virtual</span> <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> <span class="special">}</span> +<span class="special">};</span> +</pre> +<p> + We wrap it this way: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">BaseWrap</span> <span class="special">:</span> <span class="identifier">Base</span><span class="special">,</span> <span class="identifier">wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span> +<span class="special">{</span> + <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> + <span class="special">{</span> + <span class="keyword">if</span> <span class="special">(</span><span class="identifier">override</span> <span class="identifier">f</span> <span class="special">=</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">))</span> + <span class="keyword">return</span> <span class="identifier">f</span><span class="special">();</span> <span class="comment">// *note*</span> + <span class="keyword">return</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span> + <span class="special">}</span> + + <span class="keyword">int</span> <span class="identifier">default_f</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span> <span class="special">}</span> +<span class="special">};</span> +</pre> +<p> + Notice how we implemented <code class="computeroutput"><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">f</span></code>. Now, + we have to check if there is an override for <code class="computeroutput"><span class="identifier">f</span></code>. + If none, then we call <code class="computeroutput"><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">()</span></code>. + </p> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><strong>MSVC6/7 Workaround</strong></span> + </p> +<p> + If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line + with the <code class="computeroutput"><span class="special">*</span><span class="identifier">note</span><span class="special">*</span></code> as: + </p> +<p> + <code class="computeroutput"><span class="keyword">return</span> <span class="identifier">call</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*>(</span><span class="identifier">f</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">());</span></code>. + </p> +</div> +<p> + Finally, exposing: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">BaseWrap</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span> <span class="special">&</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span> + <span class="special">;</span> +</pre> +<p> + Take note that we expose both <code class="computeroutput"><span class="special">&</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span></code> and <code class="computeroutput"><span class="special">&</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span></code>. Boost.Python needs to keep track + of 1) the dispatch function <code class="literal">f</code> and 2) the forwarding function + to its default implementation <code class="literal">default_f</code>. There's a special + <code class="literal">def</code> function for this purpose. + </p> +<p> + In Python, the results would be as expected: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">base</span> <span class="special">=</span> <span class="identifier">Base</span><span class="special">()</span> +<span class="special">>>></span> <span class="keyword">class</span> <span class="identifier">Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span> +<span class="special">...</span> <span class="keyword">def</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span> +<span class="special">...</span> <span class="keyword">return</span> <span class="number">42</span> +<span class="special">...</span> +<span class="special">>>></span> <span class="identifier">derived</span> <span class="special">=</span> <span class="identifier">Derived</span><span class="special">()</span> +</pre> +<p> + Calling <code class="literal">base.f()</code>: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">base</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span> +<span class="number">0</span> +</pre> +<p> + Calling <code class="literal">derived.f()</code>: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span> +<span class="number">42</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.class_operators_special_functions"></a>Class Operators/Special Functions</h3></div></div></div> +<h3> +<a name="class_operators_special_functions.python_operators"></a> + Python Operators + </h3> +<p> + 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. + </p> +<p> + Consider a file position class <code class="literal">FilePos</code> and a set of operators + that take on FilePos instances: + </p> +<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">FilePos</span> <span class="special">{</span> <span class="comment">/*...*/</span> <span class="special">};</span> + +<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">+(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="keyword">int</span><span class="special">);</span> +<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">+(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span> +<span class="keyword">int</span> <span class="keyword">operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span> +<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="keyword">int</span><span class="special">);</span> +<span class="identifier">FilePos</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">+=(</span><span class="identifier">FilePos</span><span class="special">&,</span> <span class="keyword">int</span><span class="special">);</span> +<span class="identifier">FilePos</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">-=(</span><span class="identifier">FilePos</span><span class="special">&,</span> <span class="keyword">int</span><span class="special">);</span> +<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special"><(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span> +</pre> +<p> + The class and the various operators can be mapped to Python rather easily + and intuitively: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">FilePos</span><span class="special">>(</span><span class="string">"FilePos"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">+</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __add__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="keyword">int</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">self</span><span class="special">)</span> <span class="comment">// __radd__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-</span> <span class="identifier">self</span><span class="special">)</span> <span class="comment">// __sub__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __sub__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">+=</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __iadd__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-=</span> <span class="identifier">other</span><span class="special"><</span><span class="keyword">int</span><span class="special">>())</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special"><</span> <span class="identifier">self</span><span class="special">);</span> <span class="comment">// __lt__</span> +</pre> +<p> + 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 + <code class="literal">self</code> refers to FilePos object. Also, not every class + <code class="literal">T</code> that you might need to interact with in an operator + expression is (cheaply) default-constructible. You can use <code class="literal">other<T>()</code> + in place of an actual <code class="literal">T</code> instance when writing "self + expressions". + </p> +<h3> +<a name="class_operators_special_functions.special_methods"></a> + Special Methods + </h3> +<p> + Python has a few more <span class="emphasis"><em>Special Methods</em></span>. 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 <span class="emphasis"><em>special functions</em></span>. + Example: + </p> +<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">Rational</span> +<span class="special">{</span> <span class="keyword">public</span><span class="special">:</span> <span class="keyword">operator</span> <span class="keyword">double</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span> <span class="special">};</span> + +<span class="identifier">Rational</span> <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">,</span> <span class="identifier">Rational</span><span class="special">);</span> +<span class="identifier">Rational</span> <span class="identifier">abs</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">);</span> +<span class="identifier">ostream</span><span class="special">&</span> <span class="keyword">operator</span><span class="special"><<(</span><span class="identifier">ostream</span><span class="special">&,</span><span class="identifier">Rational</span><span class="special">);</span> + +<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Rational</span><span class="special">>(</span><span class="string">"Rational"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">float_</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __float__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">other</span><span class="special"><</span><span class="identifier">Rational</span><span class="special">>))</span> <span class="comment">// __pow__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">abs</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __abs__</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __str__</span> + <span class="special">;</span> +</pre> +<p> + Need we say more? + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + What is the business of <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code>? Well, the method <code class="computeroutput"><span class="identifier">str</span></code> requires the <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> to do its work (i.e. <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> + is used by the method defined by <code class="computeroutput"><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span></code>. + </p></td></tr> +</table></div> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="hello.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/functions.html b/libs/python/doc/tutorial/doc/html/python/functions.html new file mode 100644 index 000000000..ddd5bc7b7 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/functions.html @@ -0,0 +1,586 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Functions</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="exposing.html" title="Exposing Classes"> +<link rel="next" href="object.html" title="Object Interface"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exposing.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.functions"></a>Functions</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="functions.html#python.call_policies">Call Policies</a></span></dt> +<dt><span class="section"><a href="functions.html#python.overloading">Overloading</a></span></dt> +<dt><span class="section"><a href="functions.html#python.default_arguments">Default Arguments</a></span></dt> +<dt><span class="section"><a href="functions.html#python.auto_overloading">Auto-Overloading</a></span></dt> +</dl></div> +<p> + In this chapter, we'll look at Boost.Python powered functions in closer detail. + We will see some facilities to make exposing C++ functions to Python safe from + potential pifalls such as dangling pointers and references. We will 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. + </p> +<div class="blockquote"><blockquote class="blockquote"><p> + <span class="emphasis"><em>Read on...</em></span> + </p></blockquote></div> +<p> + But before you do, you might want to fire up Python 2.2 or later and type + <code class="literal">>>> import this</code>. + </p> +<pre class="programlisting">>>> 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 <span class="bold"><strong>right</strong></span> 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! +</pre> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.call_policies"></a>Call Policies</h3></div></div></div> +<p> + 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: + </p> +<pre class="programlisting"><span class="identifier">X</span><span class="special">&</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">);</span> +</pre> +<p> + 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 + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">)</span> <span class="preprocessor"># x</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">some</span> <span class="identifier">C</span><span class="special">++</span> <span class="identifier">X</span> +<span class="special">>>></span> <span class="identifier">del</span> <span class="identifier">y</span> +<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span> <span class="preprocessor"># CRASH</span><span class="special">!</span> +</pre> +<p> + What's the problem? + </p> +<p> + Well, what if f() was implemented as shown below: + </p> +<pre class="programlisting"><span class="identifier">X</span><span class="special">&</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">y</span><span class="special">.</span><span class="identifier">z</span> <span class="special">=</span> <span class="identifier">z</span><span class="special">;</span> + <span class="keyword">return</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span> +<span class="special">}</span> +</pre> +<p> + 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. + </p> +<p> + Here's what's happening: + </p> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + <code class="literal">f</code> is called passing in a reference to <code class="literal">y</code> + and a pointer to <code class="literal">z</code> + </li> +<li class="listitem"> + A reference to <code class="literal">y.x</code> is returned + </li> +<li class="listitem"> + <code class="literal">y</code> is deleted. <code class="literal">x</code> is a dangling reference + </li> +<li class="listitem"> + <code class="literal">x.some_method()</code> is called + </li> +<li class="listitem"> + <span class="bold"><strong>BOOM!</strong></span> + </li> +</ol></div> +<p> + We could copy result into a new object: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">).</span><span class="identifier">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span> <span class="comment"># Result disappears</span> +<span class="special">>>></span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="comment"># No crash, but still bad</span> +<span class="number">3.14</span> +</pre> +<p> + 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. + </p> +<p> + Our problems do not end there. Suppose Y is implemented as follows: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Y</span> +<span class="special">{</span> + <span class="identifier">X</span> <span class="identifier">x</span><span class="special">;</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">;</span> + <span class="keyword">int</span> <span class="identifier">z_value</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">z</span><span class="special">-></span><span class="identifier">value</span><span class="special">();</span> <span class="special">}</span> +<span class="special">};</span> +</pre> +<p> + Notice that the data member <code class="literal">z</code> is held by class Y using + a raw pointer. Now we have a potential dangling pointer problem inside Y: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">)</span> <span class="preprocessor"># y</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">z</span> +<span class="special">>>></span> <span class="identifier">del</span> <span class="identifier">z</span> <span class="preprocessor"># Kill</span> <span class="identifier">the</span> <span class="identifier">z</span> <span class="identifier">object</span> +<span class="special">>>></span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span> <span class="preprocessor"># CRASH</span><span class="special">!</span> +</pre> +<p> + For reference, here's the implementation of <code class="literal">f</code> again: + </p> +<pre class="programlisting"><span class="identifier">X</span><span class="special">&</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">y</span><span class="special">.</span><span class="identifier">z</span> <span class="special">=</span> <span class="identifier">z</span><span class="special">;</span> + <span class="keyword">return</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span> +<span class="special">}</span> +</pre> +<p> + Here's what's happening: + </p> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + <code class="literal">f</code> is called passing in a reference to <code class="literal">y</code> + and a pointer to <code class="literal">z</code> + </li> +<li class="listitem"> + A pointer to <code class="literal">z</code> is held by <code class="literal">y</code> + </li> +<li class="listitem"> + A reference to <code class="literal">y.x</code> is returned + </li> +<li class="listitem"> + <code class="literal">z</code> is deleted. <code class="literal">y.z</code> is a dangling + pointer + </li> +<li class="listitem"> + <code class="literal">y.z_value()</code> is called + </li> +<li class="listitem"> + <code class="literal">z->value()</code> is called + </li> +<li class="listitem"> + <span class="bold"><strong>BOOM!</strong></span> + </li> +</ol></div> +<h3> +<a name="call_policies.call_policies"></a> + Call Policies + </h3> +<p> + Call Policies may be used in situations such as the example detailed above. + In our example, <code class="literal">return_internal_reference</code> and <code class="literal">with_custodian_and_ward</code> + are our friends: + </p> +<pre class="programlisting"><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">,</span> + <span class="identifier">return_internal_reference</span><span class="special"><</span><span class="number">1</span><span class="special">,</span> + <span class="identifier">with_custodian_and_ward</span><span class="special"><</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="special">>());</span> +</pre> +<p> + What are the <code class="literal">1</code> and <code class="literal">2</code> parameters, you + ask? + </p> +<pre class="programlisting"><span class="identifier">return_internal_reference</span><span class="special"><</span><span class="number">1</span> +</pre> +<p> + Informs Boost.Python that the first argument, in our case <code class="literal">Y& + y</code>, is the owner of the returned reference: <code class="literal">X&</code>. + The "<code class="literal">1</code>" simply specifies the first argument. + In short: "return an internal reference <code class="literal">X&</code> owned + by the 1st argument <code class="literal">Y& y</code>". + </p> +<pre class="programlisting"><span class="identifier">with_custodian_and_ward</span><span class="special"><</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> +</pre> +<p> + Informs Boost.Python that the lifetime of the argument indicated by ward + (i.e. the 2nd argument: <code class="literal">Z* z</code>) is dependent on the lifetime + of the argument indicated by custodian (i.e. the 1st argument: <code class="literal">Y& + y</code>). + </p> +<p> + 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: + </p> +<pre class="programlisting"><span class="identifier">policy1</span><span class="special"><</span><span class="identifier">args</span><span class="special">...,</span> + <span class="identifier">policy2</span><span class="special"><</span><span class="identifier">args</span><span class="special">...,</span> + <span class="identifier">policy3</span><span class="special"><</span><span class="identifier">args</span><span class="special">...></span> <span class="special">></span> <span class="special">></span> +</pre> +<p> + Here is the list of predefined call policies. A complete reference detailing + these can be found <a href="../../../../v2/reference.html#models_of_call_policies" target="_top">here</a>. + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + <span class="bold"><strong>with_custodian_and_ward</strong></span>: Ties lifetimes + of the arguments + </li> +<li class="listitem"> + <span class="bold"><strong>with_custodian_and_ward_postcall</strong></span>: Ties + lifetimes of the arguments and results + </li> +<li class="listitem"> + <span class="bold"><strong>return_internal_reference</strong></span>: Ties lifetime + of one argument to that of result + </li> +<li class="listitem"> + <span class="bold"><strong>return_value_policy<T> with T one of:</strong></span> + <div class="itemizedlist"><ul class="itemizedlist" type="circle"> +<li class="listitem"> + <span class="bold"><strong>reference_existing_object</strong></span>: naive + (dangerous) approach + </li> +<li class="listitem"> + <span class="bold"><strong>copy_const_reference</strong></span>: Boost.Python + v1 approach + </li> +<li class="listitem"> + <span class="bold"><strong>copy_non_const_reference</strong></span>: + </li> +<li class="listitem"> + <span class="bold"><strong>manage_new_object</strong></span>: Adopt a pointer + and hold the instance + </li> +</ul></div> + </li> +</ul></div> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/smiley.png" alt="smiley"></span> <span class="bold"><strong>Remember the Zen, Luke:</strong></span> + </p> +<p> + "Explicit is better than implicit" + </p> +<p> + "In the face of ambiguity, refuse the temptation to guess" + </p> +</div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.overloading"></a>Overloading</h3></div></div></div> +<p> + The following illustrates a scheme for manually wrapping an overloaded member + functions. Of course, the same technique can be applied to wrapping overloaded + non-member functions. + </p> +<p> + We have here our C++ class: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">X</span> +<span class="special">{</span> + <span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">)</span> + <span class="special">{</span> + <span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span> + <span class="special">}</span> + + <span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">b</span><span class="special">)</span> + <span class="special">{</span> + <span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span> + <span class="special">}</span> + + <span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span> + <span class="special">{</span> + <span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span> + <span class="special">}</span> + + <span class="keyword">int</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">c</span><span class="special">)</span> + <span class="special">{</span> + <span class="keyword">return</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">;</span> + <span class="special">};</span> +<span class="special">};</span> +</pre> +<p> + Class X has 4 overloaded functions. We will start by introducing some member + function pointer variables: + </p> +<pre class="programlisting"><span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span> +<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span> +<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx3</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">char</span><span class="special">)=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span> +<span class="keyword">int</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx4</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span> +</pre> +<p> + With these in hand, we can proceed to define and wrap this for Python: + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx1</span><span class="special">)</span> +<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx2</span><span class="special">)</span> +<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx3</span><span class="special">)</span> +<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx4</span><span class="special">)</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.default_arguments"></a>Default Arguments</h3></div></div></div> +<p> + Boost.Python wraps (member) function pointers. Unfortunately, C++ function + pointers carry no default argument info. Take a function <code class="literal">f</code> + with default arguments: + </p> +<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span> <span class="special">=</span> <span class="number">3.14</span><span class="special">,</span> <span class="keyword">char</span> <span class="keyword">const</span><span class="special">*</span> <span class="special">=</span> <span class="string">"hello"</span><span class="special">);</span> +</pre> +<p> + But the type of a pointer to the function <code class="literal">f</code> has no information + about its default arguments: + </p> +<pre class="programlisting"><span class="keyword">int</span><span class="special">(*</span><span class="identifier">g</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">double</span><span class="special">,</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*)</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">;</span> <span class="comment">// defaults lost!</span> +</pre> +<p> + When we pass this function pointer to the <code class="literal">def</code> function, + there is no way to retrieve the default arguments: + </p> +<pre class="programlisting"><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">);</span> <span class="comment">// defaults lost!</span> +</pre> +<p> + Because of this, when wrapping C++ code, we had to resort to manual wrapping + as outlined in the <a class="link" href="functions.html#python.overloading" title="Overloading">previous section</a>, + or writing thin wrappers: + </p> +<pre class="programlisting"><span class="comment">// write "thin wrappers"</span> +<span class="keyword">int</span> <span class="identifier">f1</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span> <span class="special">}</span> +<span class="keyword">int</span> <span class="identifier">f2</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">);</span> <span class="special">}</span> + +<span class="comment">/*...*/</span> + + <span class="comment">// in module init</span> + <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">);</span> <span class="comment">// all arguments</span> + <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f2</span><span class="special">);</span> <span class="comment">// two arguments</span> + <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f1</span><span class="special">);</span> <span class="comment">// one argument</span> +</pre> +<p> + When you want to wrap functions (or member functions) that either: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + have default arguments, or + </li> +<li class="listitem"> + are overloaded with a common sequence of initial arguments + </li> +</ul></div> +<h3> +<a name="default_arguments.boost_python_function_overloads"></a> + BOOST_PYTHON_FUNCTION_OVERLOADS + </h3> +<p> + Boost.Python now has a way to make it easier. For instance, given a function: + </p> +<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">1</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="identifier">c</span> <span class="special">=</span> <span class="number">2</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="number">3</span><span class="special">)</span> +<span class="special">{</span> + <span class="comment">/*...*/</span> +<span class="special">}</span> +</pre> +<p> + The macro invocation: + </p> +<pre class="programlisting"><span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">4</span><span class="special">)</span> +</pre> +<p> + will automatically create the thin wrappers for us. This macro will create + a class <code class="literal">foo_overloads</code> that can be passed on to <code class="literal">def(...)</code>. + The third and fourth macro argument are the minimum arguments and maximum + arguments, respectively. In our <code class="literal">foo</code> function the minimum + number of arguments is 1 and the maximum number of arguments is 4. The <code class="literal">def(...)</code> + function will automatically add all the foo variants for us: + </p> +<pre class="programlisting"><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="identifier">foo_overloads</span><span class="special">());</span> +</pre> +<h3> +<a name="default_arguments.boost_python_member_function_overloads"></a> + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS + </h3> +<p> + Objects here, objects there, objects here there everywhere. More frequently + than anything else, we need to expose member functions of our classes to + Python. Then again, we have the same inconveniences as before when default + arguments or overloads with a common sequence of initial arguments come into + play. Another macro is provided to make this a breeze. + </p> +<p> + Like <code class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</code>, <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> + may be used to automatically create the thin wrappers for wrapping member + functions. Let's have an example: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">george</span> +<span class="special">{</span> + <span class="keyword">void</span> + <span class="identifier">wack_em</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span> <span class="special">=</span> <span class="char">'x'</span><span class="special">)</span> + <span class="special">{</span> + <span class="comment">/*...*/</span> + <span class="special">}</span> +<span class="special">};</span> +</pre> +<p> + The macro invocation: + </p> +<pre class="programlisting"><span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">george_overloads</span><span class="special">,</span> <span class="identifier">wack_em</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span> +</pre> +<p> + will generate a set of thin wrappers for george's <code class="literal">wack_em</code> + member function accepting a minimum of 1 and a maximum of 3 arguments (i.e. + the third and fourth macro argument). The thin wrappers are all enclosed + in a class named <code class="literal">george_overloads</code> that can then be used + as an argument to <code class="literal">def(...)</code>: + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"wack_em"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">george</span><span class="special">::</span><span class="identifier">wack_em</span><span class="special">,</span> <span class="identifier">george_overloads</span><span class="special">());</span> +</pre> +<p> + See the <a href="../../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec" target="_top">overloads + reference</a> for details. + </p> +<h3> +<a name="default_arguments.init_and_optional"></a> + init and optional + </h3> +<p> + A similar facility is provided for class constructors, again, with default + arguments or a sequence of overloads. Remember <code class="literal">init<...></code>? + For example, given a class X with a constructor: + </p> +<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">X</span> +<span class="special">{</span> + <span class="identifier">X</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">b</span> <span class="special">=</span> <span class="char">'D'</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">c</span> <span class="special">=</span> <span class="string">"constructor"</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="number">0.0</span><span class="special">);</span> + <span class="comment">/*...*/</span> +<span class="special">}</span> +</pre> +<p> + You can easily add this constructor to Boost.Python in one shot: + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">optional</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="keyword">double</span><span class="special">></span> <span class="special">>())</span> +</pre> +<p> + Notice the use of <code class="literal">init<...></code> and <code class="literal">optional<...></code> + to signify the default (optional arguments). + </p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.auto_overloading"></a>Auto-Overloading</h3></div></div></div> +<p> + It was mentioned in passing in the previous section that <code class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</code> + and <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> can also be + used for overloaded functions and member functions with a common sequence + of initial arguments. Here is an example: + </p> +<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">foo</span><span class="special">()</span> +<span class="special">{</span> + <span class="comment">/*...*/</span> +<span class="special">}</span> + +<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">)</span> +<span class="special">{</span> + <span class="comment">/*...*/</span> +<span class="special">}</span> + +<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">)</span> +<span class="special">{</span> + <span class="comment">/*...*/</span> +<span class="special">}</span> + +<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span> +<span class="special">{</span> + <span class="comment">/*...*/</span> +<span class="special">}</span> +</pre> +<p> + Like in the previous section, we can generate thin wrappers for these overloaded + functions in one-shot: + </p> +<pre class="programlisting"><span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="number">0</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span> +</pre> +<p> + Then... + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="special">(</span><span class="keyword">void</span><span class="special">(*)(</span><span class="keyword">bool</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">char</span><span class="special">))</span><span class="number">0</span><span class="special">,</span> <span class="identifier">foo_overloads</span><span class="special">());</span> +</pre> +<p> + Notice though that we have a situation now where we have a minimum of zero + (0) arguments and a maximum of 3 arguments. + </p> +<h3> +<a name="auto_overloading.manual_wrapping"></a> + Manual Wrapping + </h3> +<p> + It is important to emphasize however that <span class="bold"><strong>the overloaded + functions must have a common sequence of initial arguments</strong></span>. Otherwise, + our scheme above will not work. If this is not the case, we have to wrap + our functions <a class="link" href="functions.html#python.overloading" title="Overloading">manually</a>. + </p> +<p> + Actually, we can mix and match manual wrapping of overloaded functions and + automatic wrapping through <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> + and its sister, <code class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</code>. Following + up on our example presented in the section <a class="link" href="functions.html#python.overloading" title="Overloading">on + overloading</a>, since the first 4 overload functins have a common sequence + of initial arguments, we can use <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> + to automatically wrap the first three of the <code class="literal">def</code>s and + manually wrap just the last. Here's how we'll do this: + </p> +<pre class="programlisting"><span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">xf_overloads</span><span class="special">,</span> <span class="identifier">f</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">4</span><span class="special">)</span> +</pre> +<p> + Create a member function pointers as above for both X::f overloads: + </p> +<pre class="programlisting"><span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">char</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span> +<span class="keyword">int</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span> +</pre> +<p> + Then... + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx1</span><span class="special">,</span> <span class="identifier">xf_overloads</span><span class="special">());</span> +<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx2</span><span class="special">)</span> +</pre> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exposing.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/hello.html b/libs/python/doc/tutorial/doc/html/python/hello.html new file mode 100644 index 000000000..b78573826 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/hello.html @@ -0,0 +1,195 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Building Hello World</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="next" href="exposing.html" title="Exposing Classes"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="../index.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exposing.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.hello"></a>Building Hello World</h2></div></div></div> +<h3> +<a name="hello.from_start_to_finish"></a> + From Start To Finish + </h3> +<p> + 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 will outline the steps necessary + to achieve that. We will use the build tool that comes bundled with every boost + distribution: <span class="bold"><strong>bjam</strong></span>. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"> +<p> + <span class="bold"><strong>Building without bjam</strong></span> + </p> +<p> + 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 <code class="literal">bjam</code>. + </p> +<p> + Take note however that the preferred build tool for Boost.Python is bjam. + There are so many ways to set up the build incorrectly. Experience shows + that 90% of the "I can't build Boost.Python" problems come from + people who had to use a different tool. + </p> +</td></tr> +</table></div> +<p> + We will 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: <a href="../../../../building.html" target="_top">building.html</a>. After + this brief <span class="emphasis"><em>bjam</em></span> tutorial, we should have built the DLLs + and run a python program using the extension. + </p> +<p> + The tutorial example can be found in the directory: <code class="literal">libs/python/example/tutorial</code>. + There, you can find: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + hello.cpp + </li> +<li class="listitem"> + hello.py + </li> +<li class="listitem"> + Jamroot + </li> +</ul></div> +<p> + The <code class="literal">hello.cpp</code> file is our C++ hello world example. The + <code class="literal">Jamroot</code> is a minimalist <span class="emphasis"><em>bjam</em></span> script + that builds the DLLs for us. Finally, <code class="literal">hello.py</code> is our Python + program that uses the extension in <code class="literal">hello.cpp</code>. + </p> +<p> + Before anything else, you should have the bjam executable in your boost directory + or somewhere in your path such that <code class="literal">bjam</code> can be executed + in the command line. Pre-built Boost.Jam executables are available for most + platforms. The complete list of Bjam executables can be found <a href="http://sourceforge.net/project/showfiles.php?group_id=7586" target="_top">here</a>. + </p> +<h3> +<a name="hello.let_s_jam_"></a> + Let's Jam! + </h3> +<p> + <span class="inlinemediaobject"><img src="../images/jam.png" alt="jam"></span> + </p> +<p> + <a href="../../../../../example/tutorial/Jamroot" target="_top">Here</a> is our minimalist + Jamroot file. Simply copy the file and tweak <code class="literal">use-project boost</code> + to where your boost root directory is and your OK. + </p> +<p> + The comments contained in the Jamrules file above should be sufficient to get + you going. + </p> +<h3> +<a name="hello.running_bjam"></a> + Running bjam + </h3> +<p> + <span class="emphasis"><em>bjam</em></span> is run using your operating system's command line + interpreter. + </p> +<div class="blockquote"><blockquote class="blockquote"><p> + Start it up. + </p></blockquote></div> +<p> + A file called user-config.jam in your home directory is used to configure your + tools. In Windows, your home directory can be found by typing: + </p> +<pre class="programlisting">ECHO %HOMEDRIVE%%HOMEPATH% +</pre> +<p> + into a command prompt window. Your file should at least have the rules for + your compiler and your python installation. A specific example of this on Windows + would be: + </p> +<pre class="programlisting"># MSVC configuration +using msvc : 8.0 ; + +# Python configuration +using python : 2.4 : C:<span class="emphasis"><em>dev/tools/Python</em></span> ; +</pre> +<p> + The first rule tells Bjam to use the MSVC 8.0 compiler and associated tools. + The second rule provides information on Python, its version and where it is + located. The above assumes that the Python installation is in <code class="literal">C:<span class="emphasis"><em>dev/tools\/Python</em></span></code>. + If you have one fairly "standard" python installation for your platform, + you might not need to do this. + </p> +<p> + Now we are ready... Be sure to <code class="literal">cd</code> to <code class="literal">libs/python/example/tutorial</code> + where the tutorial <code class="literal">"hello.cpp"</code> and the <code class="literal">"Jamroot"</code> + is situated. + </p> +<p> + Finally: + </p> +<pre class="programlisting"><span class="identifier">bjam</span> +</pre> +<p> + It should be building now: + </p> +<pre class="programlisting">cd C:\dev\boost\libs\python\example\tutorial +bjam +...patience... +...found 1101 targets... +...updating 35 targets... +</pre> +<p> + And so on... Finally: + </p> +<pre class="programlisting">Creating library <span class="emphasis"><em>path-to-boost_python.dll</em></span> + Creating library /path-to-hello_ext.exp/ +**passed** ... hello.test +...updated 35 targets... +</pre> +<p> + Or something similar. If all is well, you should now have built the DLLs and + run the Python program. + </p> +<div class="blockquote"><blockquote class="blockquote"><p> + <span class="bold"><strong>There you go... Have fun!</strong></span> + </p></blockquote></div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="../index.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exposing.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/iterators.html b/libs/python/doc/tutorial/doc/html/python/iterators.html new file mode 100644 index 000000000..9fb402b6b --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/iterators.html @@ -0,0 +1,187 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Iterators</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="embedding.html" title="Embedding"> +<link rel="next" href="exception.html" title="Exception Translation"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="embedding.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exception.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.iterators"></a>Iterators</h2></div></div></div> +<p> + In C++, and STL in particular, we see iterators everywhere. Python also has + iterators, but these are two very different beasts. + </p> +<p> + <span class="bold"><strong>C++ iterators:</strong></span> + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + C++ has 5 type categories (random-access, bidirectional, forward, input, + output) + </li> +<li class="listitem"> + There are 2 Operation categories: reposition, access + </li> +<li class="listitem"> + A pair of iterators is needed to represent a (first/last) range. + </li> +</ul></div> +<p> + <span class="bold"><strong>Python Iterators:</strong></span> + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + 1 category (forward) + </li> +<li class="listitem"> + 1 operation category (next()) + </li> +<li class="listitem"> + Raises StopIteration exception at end + </li> +</ul></div> +<p> + The typical Python iteration protocol: <code class="literal"><span class="bold"><strong>for y + in x...</strong></span></code> is as follows: + </p> +<pre class="programlisting"><span class="identifier">iter</span> <span class="special">=</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">__iter__</span><span class="special">()</span> <span class="comment"># get iterator</span> +<span class="keyword">try</span><span class="special">:</span> + <span class="keyword">while</span> <span class="number">1</span><span class="special">:</span> + <span class="identifier">y</span> <span class="special">=</span> <span class="identifier">iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">()</span> <span class="comment"># get each item</span> + <span class="special">...</span> <span class="comment"># process y</span> +<span class="keyword">except</span> <span class="identifier">StopIteration</span><span class="special">:</span> <span class="keyword">pass</span> <span class="comment"># iterator exhausted</span> +</pre> +<p> + Boost.Python provides some mechanisms to make C++ iterators play along nicely + as Python iterators. What we need to do is to produce appropriate <code class="computeroutput"><span class="identifier">__iter__</span></code> function from C++ iterators that + is compatible with the Python iteration protocol. For example: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">get_iterator</span> <span class="special">=</span> <span class="identifier">iterator</span><span class="special"><</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>();</span> +<span class="identifier">object</span> <span class="identifier">iter</span> <span class="special">=</span> <span class="identifier">get_iterator</span><span class="special">(</span><span class="identifier">v</span><span class="special">);</span> +<span class="identifier">object</span> <span class="identifier">first</span> <span class="special">=</span> <span class="identifier">iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">();</span> +</pre> +<p> + Or for use in class_<>: + </p> +<pre class="programlisting"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"__iter__"</span><span class="special">,</span> <span class="identifier">iterator</span><span class="special"><</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>())</span> +</pre> +<p> + <span class="bold"><strong>range</strong></span> + </p> +<p> + We can create a Python savvy iterator using the range function: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + range(start, finish) + </li> +<li class="listitem"> + range<Policies,Target>(start, finish) + </li> +</ul></div> +<p> + Here, start/finish may be one of: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + member data pointers + </li> +<li class="listitem"> + member function pointers + </li> +<li class="listitem"> + adaptable function object (use Target parameter) + </li> +</ul></div> +<p> + <span class="bold"><strong>iterator</strong></span> + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> + iterator<T, Policies>() + </li></ul></div> +<p> + Given a container <code class="literal">T</code>, iterator is a shortcut that simply + calls <code class="literal">range</code> with &T::begin, &T::end. + </p> +<p> + Let's put this into action... Here's an example from some hypothetical bogon + Particle accelerator code: + </p> +<pre class="programlisting"><span class="identifier">f</span> <span class="special">=</span> <span class="identifier">Field</span><span class="special">()</span> +<span class="keyword">for</span> <span class="identifier">x</span> <span class="keyword">in</span> <span class="identifier">f</span><span class="special">.</span><span class="identifier">pions</span><span class="special">:</span> + <span class="identifier">smash</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> +<span class="keyword">for</span> <span class="identifier">y</span> <span class="keyword">in</span> <span class="identifier">f</span><span class="special">.</span><span class="identifier">bogons</span><span class="special">:</span> + <span class="identifier">count</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span> +</pre> +<p> + Now, our C++ Wrapper: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">F</span><span class="special">>(</span><span class="string">"Field"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"pions"</span><span class="special">,</span> <span class="identifier">range</span><span class="special">(&</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_begin</span><span class="special">,</span> <span class="special">&</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_end</span><span class="special">))</span> + <span class="special">.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"bogons"</span><span class="special">,</span> <span class="identifier">range</span><span class="special">(&</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_begin</span><span class="special">,</span> <span class="special">&</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_end</span><span class="special">));</span> +</pre> +<p> + <span class="bold"><strong>stl_input_iterator</strong></span> + </p> +<p> + So far, we have seen how to expose C++ iterators and ranges to Python. Sometimes + we wish to go the other way, though: we'd like to pass a Python sequence to + an STL algorithm or use it to initialize an STL container. We need to make + a Python iterator look like an STL iterator. For that, we use <code class="computeroutput"><span class="identifier">stl_input_iterator</span><span class="special"><></span></code>. + Consider how we might implement a function that exposes <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">assign</span><span class="special">()</span></code> to Python: + </p> +<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> +<span class="keyword">void</span> <span class="identifier">list_assign</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">>&</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">o</span><span class="special">)</span> <span class="special">{</span> + <span class="comment">// Turn a Python sequence into an STL input range</span> + <span class="identifier">stl_input_iterator</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="identifier">begin</span><span class="special">(</span><span class="identifier">o</span><span class="special">),</span> <span class="identifier">end</span><span class="special">;</span> + <span class="identifier">l</span><span class="special">.</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">begin</span><span class="special">,</span> <span class="identifier">end</span><span class="special">);</span> +<span class="special">}</span> + +<span class="comment">// Part of the wrapper for list<int></span> +<span class="identifier">class_</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>(</span><span class="string">"list_int"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"assign"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">list_assign</span><span class="special"><</span><span class="keyword">int</span><span class="special">>)</span> + <span class="comment">// ...</span> + <span class="special">;</span> +</pre> +<p> + Now in Python, we can assign any integer sequence to <code class="computeroutput"><span class="identifier">list_int</span></code> + objects: + </p> +<pre class="programlisting"><span class="identifier">x</span> <span class="special">=</span> <span class="identifier">list_int</span><span class="special">();</span> +<span class="identifier">x</span><span class="special">.</span><span class="identifier">assign</span><span class="special">([</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">4</span><span class="special">,</span><span class="number">5</span><span class="special">])</span> +</pre> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="embedding.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exception.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/object.html b/libs/python/doc/tutorial/doc/html/python/object.html new file mode 100644 index 000000000..7bc2aa255 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/object.html @@ -0,0 +1,360 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Object Interface</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="functions.html" title="Functions"> +<link rel="next" href="embedding.html" title="Embedding"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="functions.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.object"></a>Object Interface</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="object.html#python.basic_interface">Basic Interface</a></span></dt> +<dt><span class="section"><a href="object.html#python.derived_object_types">Derived Object types</a></span></dt> +<dt><span class="section"><a href="object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt> +<dt><span class="section"><a href="object.html#python.enums">Enums</a></span></dt> +<dt><span class="section"><a href="object.html#python.creating_python_object">Creating <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> from <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code></a></span></dt> +</dl></div> +<p> + 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 <code class="literal">object</code>. We will see in this + chapter how to deal with Python objects. + </p> +<p> + 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++ <code class="literal">object</code>s are as close as possible to Python. This should + minimize the learning curve significantly. + </p> +<p> + <span class="inlinemediaobject"><img src="../images/python.png" alt="python"></span> + </p> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.basic_interface"></a>Basic Interface</h3></div></div></div> +<p> + Class <code class="literal">object</code> wraps <code class="literal">PyObject*</code>. All the + intricacies of dealing with <code class="literal">PyObject</code>s such as managing + reference counting are handled by the <code class="literal">object</code> class. C++ + object interoperability is seamless. Boost.Python C++ <code class="literal">object</code>s + can in fact be explicitly constructed from any C++ object. + </p> +<p> + To illustrate, this Python code snippet: + </p> +<pre class="programlisting"><span class="keyword">def</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">):</span> + <span class="keyword">if</span> <span class="special">(</span><span class="identifier">y</span> <span class="special">==</span> <span class="string">'foo'</span><span class="special">):</span> + <span class="identifier">x</span><span class="special">[</span><span class="number">3</span><span class="special">:</span><span class="number">7</span><span class="special">]</span> <span class="special">=</span> <span class="string">'bar'</span> + <span class="keyword">else</span><span class="special">:</span> + <span class="identifier">x</span><span class="special">.</span><span class="identifier">items</span> <span class="special">+=</span> <span class="identifier">y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span> <span class="identifier">x</span><span class="special">)</span> + <span class="keyword">return</span> <span class="identifier">x</span> + +<span class="keyword">def</span> <span class="identifier">getfunc</span><span class="special">():</span> + <span class="keyword">return</span> <span class="identifier">f</span><span class="special">;</span> +</pre> +<p> + Can be rewritten in C++ using Boost.Python facilities this way: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">object</span> <span class="identifier">x</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span> + <span class="keyword">if</span> <span class="special">(</span><span class="identifier">y</span> <span class="special">==</span> <span class="string">"foo"</span><span class="special">)</span> + <span class="identifier">x</span><span class="special">.</span><span class="identifier">slice</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">7</span><span class="special">)</span> <span class="special">=</span> <span class="string">"bar"</span><span class="special">;</span> + <span class="keyword">else</span> + <span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"items"</span><span class="special">)</span> <span class="special">+=</span> <span class="identifier">y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span> <span class="identifier">x</span><span class="special">);</span> + <span class="keyword">return</span> <span class="identifier">x</span><span class="special">;</span> +<span class="special">}</span> +<span class="identifier">object</span> <span class="identifier">getfunc</span><span class="special">()</span> <span class="special">{</span> + <span class="keyword">return</span> <span class="identifier">object</span><span class="special">(</span><span class="identifier">f</span><span class="special">);</span> +<span class="special">}</span> +</pre> +<p> + 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. + </p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.derived_object_types"></a>Derived Object types</h3></div></div></div> +<p> + Boost.Python comes with a set of derived <code class="literal">object</code> types + corresponding to that of Python's: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + list + </li> +<li class="listitem"> + dict + </li> +<li class="listitem"> + tuple + </li> +<li class="listitem"> + str + </li> +<li class="listitem"> + long_ + </li> +<li class="listitem"> + enum + </li> +</ul></div> +<p> + These derived <code class="literal">object</code> types act like real Python types. + For instance: + </p> +<pre class="programlisting"><span class="identifier">str</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">==></span> <span class="string">"1"</span> +</pre> +<p> + Wherever appropriate, a particular derived <code class="literal">object</code> has + corresponding Python type's methods. For instance, <code class="literal">dict</code> + has a <code class="literal">keys()</code> method: + </p> +<pre class="programlisting"><span class="identifier">d</span><span class="special">.</span><span class="identifier">keys</span><span class="special">()</span> +</pre> +<p> + <code class="literal">make_tuple</code> is provided for declaring <span class="emphasis"><em>tuple literals</em></span>. + Example: + </p> +<pre class="programlisting"><span class="identifier">make_tuple</span><span class="special">(</span><span class="number">123</span><span class="special">,</span> <span class="char">'D'</span><span class="special">,</span> <span class="string">"Hello, World"</span><span class="special">,</span> <span class="number">0.0</span><span class="special">);</span> +</pre> +<p> + In C++, when Boost.Python <code class="literal">object</code>s are used as arguments + to functions, subtype matching is required. For example, when a function + <code class="literal">f</code>, as declared below, is wrapped, it will only accept + instances of Python's <code class="literal">str</code> type and subtypes. + </p> +<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">name</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">object</span> <span class="identifier">n2</span> <span class="special">=</span> <span class="identifier">name</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"upper"</span><span class="special">)();</span> <span class="comment">// NAME = name.upper()</span> + <span class="identifier">str</span> <span class="identifier">NAME</span> <span class="special">=</span> <span class="identifier">name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span> <span class="comment">// better</span> + <span class="identifier">object</span> <span class="identifier">msg</span> <span class="special">=</span> <span class="string">"%s is bigger than %s"</span> <span class="special">%</span> <span class="identifier">make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span> +<span class="special">}</span> +</pre> +<p> + In finer detail: + </p> +<pre class="programlisting"><span class="identifier">str</span> <span class="identifier">NAME</span> <span class="special">=</span> <span class="identifier">name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span> +</pre> +<p> + Illustrates that we provide versions of the str type's methods as C++ member + functions. + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">msg</span> <span class="special">=</span> <span class="string">"%s is bigger than %s"</span> <span class="special">%</span> <span class="identifier">make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span> +</pre> +<p> + Demonstrates that you can write the C++ equivalent of <code class="literal">"format" + % x,y,z</code> in Python, which is useful since there's no easy way to + do that in std C++. + </p> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><strong>Beware</strong></span> the common pitfall + of forgetting that the constructors of most of Python's mutable types make + copies, just as in Python. + </p> +</div> +<p> + Python: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">dict</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">)</span> <span class="comment"># copies x.__dict__</span> +<span class="special">>>></span> <span class="identifier">d</span><span class="special">[</span><span class="string">'whatever'</span><span class="special">]</span> <span class="special">=</span> <span class="number">3</span> <span class="comment"># modifies the copy</span> +</pre> +<p> + C++: + </p> +<pre class="programlisting"><span class="identifier">dict</span> <span class="identifier">d</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span> <span class="comment">// copies x.__dict__</span> +<span class="identifier">d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span> <span class="special">=</span> <span class="number">3</span><span class="special">;</span> <span class="comment">// modifies the copy</span> +</pre> +<h3> +<a name="derived_object_types.class__lt_t_gt__as_objects"></a> + class_<T> as objects + </h3> +<p> + Due to the dynamic nature of Boost.Python objects, any <code class="literal">class_<T></code> + may also be one of these types! The following code snippet wraps the class + (type) object. + </p> +<p> + We can use this to create wrapped instances. Example: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">vec345</span> <span class="special">=</span> <span class="special">(</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">>(</span><span class="string">"Vec2"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</span><span class="special">>())</span> + <span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"length"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">length</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"angle"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">angle</span><span class="special">)</span> + <span class="special">)(</span><span class="number">3.0</span><span class="special">,</span> <span class="number">4.0</span><span class="special">);</span> + +<span class="identifier">assert</span><span class="special">(</span><span class="identifier">vec345</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">)</span> <span class="special">==</span> <span class="number">5.0</span><span class="special">);</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.extracting_c___objects"></a>Extracting C++ objects</h3></div></div></div> +<p> + At some point, we will need to get C++ values out of object instances. This + can be achieved with the <code class="literal">extract<T></code> function. Consider + the following: + </p> +<pre class="programlisting"><span class="keyword">double</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">);</span> <span class="comment">// compile error</span> +</pre> +<p> + In the code above, we got a compiler error because Boost.Python <code class="literal">object</code> + can't be implicitly converted to <code class="literal">double</code>s. Instead, what + we wanted to do above can be achieved by writing: + </p> +<pre class="programlisting"><span class="keyword">double</span> <span class="identifier">l</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="keyword">double</span><span class="special">>(</span><span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">));</span> +<span class="identifier">Vec2</span><span class="special">&</span> <span class="identifier">v</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">&>(</span><span class="identifier">o</span><span class="special">);</span> +<span class="identifier">assert</span><span class="special">(</span><span class="identifier">l</span> <span class="special">==</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">length</span><span class="special">());</span> +</pre> +<p> + The first line attempts to extract the "length" attribute of the + Boost.Python <code class="literal">object</code>. The second line attempts to <span class="emphasis"><em>extract</em></span> + the <code class="literal">Vec2</code> object from held by the Boost.Python <code class="literal">object</code>. + </p> +<p> + Take note that we said "attempt to" above. What if the Boost.Python + <code class="literal">object</code> does not really hold a <code class="literal">Vec2</code> + type? This is certainly a possibility considering the dynamic nature of Python + <code class="literal">object</code>s. 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: + </p> +<pre class="programlisting"><span class="identifier">extract</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">&></span> <span class="identifier">x</span><span class="special">(</span><span class="identifier">o</span><span class="special">);</span> +<span class="keyword">if</span> <span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">check</span><span class="special">())</span> <span class="special">{</span> + <span class="identifier">Vec2</span><span class="special">&</span> <span class="identifier">v</span> <span class="special">=</span> <span class="identifier">x</span><span class="special">();</span> <span class="special">...</span> +</pre> +<p> + <span class="inlinemediaobject"><img src="../images/tip.png" alt="tip"></span> The astute reader might have noticed that the <code class="literal">extract<T></code> + facility in fact solves the mutable copying problem: + </p> +<pre class="programlisting"><span class="identifier">dict</span> <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="identifier">dict</span><span class="special">>(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span> +<span class="identifier">d</span><span class="special">[</span><span class="string">"whatever"</span><span class="special">]</span> <span class="special">=</span> <span class="number">3</span><span class="special">;</span> <span class="comment">// modifies x.__dict__ !</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.enums"></a>Enums</h3></div></div></div> +<p> + Boost.Python has a nifty facility to capture and wrap C++ enums. While Python + has no <code class="literal">enum</code> type, we'll often want to expose our C++ enums + to Python as an <code class="literal">int</code>. 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: + </p> +<pre class="programlisting"><span class="keyword">enum</span> <span class="identifier">choice</span> <span class="special">{</span> <span class="identifier">red</span><span class="special">,</span> <span class="identifier">blue</span> <span class="special">};</span> +</pre> +<p> + the construct: + </p> +<pre class="programlisting"><span class="identifier">enum_</span><span class="special"><</span><span class="identifier">choice</span><span class="special">>(</span><span class="string">"choice"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span> <span class="identifier">red</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span> <span class="identifier">blue</span><span class="special">)</span> + <span class="special">;</span> +</pre> +<p> + can be used to expose to Python. The new enum type is created in the current + <code class="literal">scope()</code>, which is usually the current module. The snippet + above creates a Python class derived from Python's <code class="literal">int</code> + type which is associated with the C++ type passed as its first parameter. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"> +<p> + <span class="bold"><strong>what is a scope?</strong></span> + </p> +<p> + 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 <a href="../../../../v2/scope.html" target="_top">here</a>. + </p> +</td></tr> +</table></div> +<p> + You can access those values in Python as + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span> +<span class="identifier">my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span> +</pre> +<p> + where my_module is the module where the enum is declared. You can also create + a new scope around a class: + </p> +<pre class="programlisting"><span class="identifier">scope</span> <span class="identifier">in_X</span> <span class="special">=</span> <span class="identifier">class_</span><span class="special"><</span><span class="identifier">X</span><span class="special">>(</span><span class="string">"X"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span> <span class="special">...</span> <span class="special">)</span> + <span class="special">.</span><span class="identifier">def</span><span class="special">(</span> <span class="special">...</span> <span class="special">)</span> + <span class="special">;</span> + +<span class="comment">// Expose X::nested as X.nested</span> +<span class="identifier">enum_</span><span class="special"><</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">>(</span><span class="string">"nested"</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span> <span class="identifier">red</span><span class="special">)</span> + <span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span> <span class="identifier">blue</span><span class="special">)</span> + <span class="special">;</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.creating_python_object"></a>Creating <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> from <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code> +</h3></div></div></div> +<p> + When you want a <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> to manage a pointer to <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code> + pyobj one does: + </p> +<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span> <span class="identifier">o</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">handle</span><span class="special"><>(</span><span class="identifier">pyobj</span><span class="special">));</span> +</pre> +<p> + In this case, the <code class="computeroutput"><span class="identifier">o</span></code> object, + manages the <code class="computeroutput"><span class="identifier">pyobj</span></code>, it won’t + increase the reference count on construction. + </p> +<p> + Otherwise, to use a borrowed reference: + </p> +<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span> <span class="identifier">o</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">handle</span><span class="special"><>(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">pyobj</span><span class="special">)));</span> +</pre> +<p> + In this case, <code class="computeroutput"><span class="identifier">Py_INCREF</span></code> is + called, so <code class="computeroutput"><span class="identifier">pyobj</span></code> is not destructed + when object o goes out of scope. + </p> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="functions.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/techniques.html b/libs/python/doc/tutorial/doc/html/python/techniques.html new file mode 100644 index 000000000..34cfc4442 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/techniques.html @@ -0,0 +1,440 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>General Techniques</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="exception.html" title="Exception Translation"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exception.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.techniques"></a>General Techniques</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="techniques.html#python.creating_packages">Creating Packages</a></span></dt> +<dt><span class="section"><a href="techniques.html#python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt> +<dt><span class="section"><a href="techniques.html#python.reducing_compiling_time">Reducing Compiling Time</a></span></dt> +</dl></div> +<p> + Here are presented some useful techniques that you can use while wrapping code + with Boost.Python. + </p> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.creating_packages"></a>Creating Packages</h3></div></div></div> +<p> + A Python package is a collection of modules that provide to the user a certain + functionality. If you're not familiar on how to create packages, a good introduction + to them is provided in the <a href="http://www.python.org/doc/current/tut/node8.html" target="_top">Python + Tutorial</a>. + </p> +<p> + But we are wrapping C++ code, using Boost.Python. How can we provide a nice + package interface to our users? To better explain some concepts, let's work + with an example. + </p> +<p> + We have a C++ library that works with sounds: reading and writing various + formats, applying filters to the sound data, etc. It is named (conveniently) + <code class="literal">sounds</code>. Our library already has a neat C++ namespace hierarchy, + like so: + </p> +<pre class="programlisting"><span class="identifier">sounds</span><span class="special">::</span><span class="identifier">core</span> +<span class="identifier">sounds</span><span class="special">::</span><span class="identifier">io</span> +<span class="identifier">sounds</span><span class="special">::</span><span class="identifier">filters</span> +</pre> +<p> + We would like to present this same hierarchy to the Python user, allowing + him to write code like this: + </p> +<pre class="programlisting"><span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span> +<span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span> <span class="comment"># echo is a C++ function</span> +</pre> +<p> + The first step is to write the wrapping code. We have to export each module + separately with Boost.Python, like this: + </p> +<pre class="programlisting"><span class="special">/*</span> <span class="identifier">file</span> <span class="identifier">core</span><span class="special">.</span><span class="identifier">cpp</span> <span class="special">*/</span> +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">core</span><span class="special">)</span> +<span class="special">{</span> + <span class="special">/*</span> <span class="identifier">export</span> <span class="identifier">everything</span> <span class="keyword">in</span> <span class="identifier">the</span> <span class="identifier">sounds</span><span class="special">::</span><span class="identifier">core</span> <span class="identifier">namespace</span> <span class="special">*/</span> + <span class="special">...</span> +<span class="special">}</span> + +<span class="special">/*</span> <span class="identifier">file</span> <span class="identifier">io</span><span class="special">.</span><span class="identifier">cpp</span> <span class="special">*/</span> +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">io</span><span class="special">)</span> +<span class="special">{</span> + <span class="special">/*</span> <span class="identifier">export</span> <span class="identifier">everything</span> <span class="keyword">in</span> <span class="identifier">the</span> <span class="identifier">sounds</span><span class="special">::</span><span class="identifier">io</span> <span class="identifier">namespace</span> <span class="special">*/</span> + <span class="special">...</span> +<span class="special">}</span> + +<span class="special">/*</span> <span class="identifier">file</span> <span class="identifier">filters</span><span class="special">.</span><span class="identifier">cpp</span> <span class="special">*/</span> +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">filters</span><span class="special">)</span> +<span class="special">{</span> + <span class="special">/*</span> <span class="identifier">export</span> <span class="identifier">everything</span> <span class="keyword">in</span> <span class="identifier">the</span> <span class="identifier">sounds</span><span class="special">::</span><span class="identifier">filters</span> <span class="identifier">namespace</span> <span class="special">*/</span> + <span class="special">...</span> +<span class="special">}</span> +</pre> +<p> + Compiling these files will generate the following Python extensions: <code class="literal">core.pyd</code>, + <code class="literal">io.pyd</code> and <code class="literal">filters.pyd</code>. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + The extension <code class="literal">.pyd</code> is used for python extension modules, + which are just shared libraries. Using the default for your system, like + <code class="literal">.so</code> for Unix and <code class="literal">.dll</code> for Windows, + works just as well. + </p></td></tr> +</table></div> +<p> + Now, we create this directory structure for our Python package: + </p> +<pre class="programlisting">sounds/ + __init__.py + core.pyd + filters.pyd + io.pyd +</pre> +<p> + The file <code class="literal">__init__.py</code> is what tells Python that the directory + <code class="literal">sounds/</code> is actually a Python package. It can be a empty + file, but can also perform some magic, that will be shown later. + </p> +<p> + Now our package is ready. All the user has to do is put <code class="literal">sounds</code> + into his <a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000" target="_top">PYTHONPATH</a> + and fire up the interpreter: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">io</span> +<span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span> +<span class="special">>>></span> <span class="identifier">sound</span> <span class="special">=</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="string">'file.mp3'</span><span class="special">)</span> +<span class="special">>>></span> <span class="identifier">new_sound</span> <span class="special">=</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">,</span> <span class="number">1.0</span><span class="special">)</span> +</pre> +<p> + Nice heh? + </p> +<p> + This is the simplest way to create hierarchies of packages, but it is not + very flexible. What if we want to add a <span class="emphasis"><em>pure</em></span> Python + function to the filters package, for instance, one that applies 3 filters + in a sound object at once? Sure, you can do this in C++ and export it, but + why not do so in Python? You don't have to recompile the extension modules, + plus it will be easier to write it. + </p> +<p> + If we want this flexibility, we will have to complicate our package hierarchy + a little. First, we will have to change the name of the extension modules: + </p> +<pre class="programlisting"><span class="comment">/* file core.cpp */</span> +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_core</span><span class="special">)</span> +<span class="special">{</span> + <span class="special">...</span> + <span class="comment">/* export everything in the sounds::core namespace */</span> +<span class="special">}</span> +</pre> +<p> + Note that we added an underscore to the module name. The filename will have + to be changed to <code class="literal">_core.pyd</code> as well, and we do the same + to the other extension modules. Now, we change our package hierarchy like + so: + </p> +<pre class="programlisting">sounds/ + __init__.py + core/ + __init__.py + <span class="underline">core.pyd + filters/ + \</span>_init__.py + <span class="underline">filters.pyd + io/ + \</span>_init__.py + _io.pyd +</pre> +<p> + Note that we created a directory for each extension module, and added a __init__.py + to each one. But if we leave it that way, the user will have to access the + functions in the core module with this syntax: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span> +<span class="special">>>></span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">.</span><span class="identifier">foo</span><span class="special">(...)</span> +</pre> +<p> + which is not what we want. But here enters the <code class="literal">__init__.py</code> + magic: everything that is brought to the <code class="literal">__init__.py</code> namespace + can be accessed directly by the user. So, all we have to do is bring the + entire namespace from <code class="literal">_core.pyd</code> to <code class="literal">core/__init__.py</code>. + So add this line of code to <code class="literal">sounds/core/__init__.py</code>: + </p> +<pre class="programlisting"><span class="keyword">from</span> <span class="identifier">_core</span> <span class="keyword">import</span> <span class="special">*</span> +</pre> +<p> + We do the same for the other packages. Now the user accesses the functions + and classes in the extension modules like before: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span> +<span class="special">>>></span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span> +</pre> +<p> + with the additional benefit that we can easily add pure Python functions + to any module, in a way that the user can't tell the difference between a + C++ function and a Python function. Let's add a <span class="emphasis"><em>pure</em></span> + Python function, <code class="literal">echo_noise</code>, to the <code class="literal">filters</code> + package. This function applies both the <code class="literal">echo</code> and <code class="literal">noise</code> + filters in sequence in the given <code class="literal">sound</code> object. We create + a file named <code class="literal">sounds/filters/echo_noise.py</code> and code our + function: + </p> +<pre class="programlisting"><span class="keyword">import</span> <span class="identifier">_filters</span> +<span class="keyword">def</span> <span class="identifier">echo_noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">):</span> + <span class="identifier">s</span> <span class="special">=</span> <span class="identifier">_filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span> + <span class="identifier">s</span> <span class="special">=</span> <span class="identifier">_filters</span><span class="special">.</span><span class="identifier">noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span> + <span class="keyword">return</span> <span class="identifier">s</span> +</pre> +<p> + Next, we add this line to <code class="literal">sounds/filters/__init__.py</code>: + </p> +<pre class="programlisting"><span class="keyword">from</span> <span class="identifier">echo_noise</span> <span class="keyword">import</span> <span class="identifier">echo_noise</span> +</pre> +<p> + And that's it. The user now accesses this function like any other function + from the <code class="literal">filters</code> package: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span> +<span class="special">>>></span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo_noise</span><span class="special">(...)</span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.extending_wrapped_objects_in_python"></a>Extending Wrapped Objects in Python</h3></div></div></div> +<p> + Thanks to Python's flexibility, you can easily add new methods to a class, + even after it was already created: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">class</span> <span class="identifier">C</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span> <span class="keyword">pass</span> +<span class="special">>>></span> +<span class="special">>>></span> <span class="comment"># a regular function</span> +<span class="special">>>></span> <span class="keyword">def</span> <span class="identifier">C_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span> <span class="keyword">return</span> <span class="string">'A C instance!'</span> +<span class="special">>>></span> +<span class="special">>>></span> <span class="comment"># now we turn it in a member function</span> +<span class="special">>>></span> <span class="identifier">C</span><span class="special">.</span><span class="identifier">__str__</span> <span class="special">=</span> <span class="identifier">C_str</span> +<span class="special">>>></span> +<span class="special">>>></span> <span class="identifier">c</span> <span class="special">=</span> <span class="identifier">C</span><span class="special">()</span> +<span class="special">>>></span> <span class="keyword">print</span> <span class="identifier">c</span> +<span class="identifier">A</span> <span class="identifier">C</span> <span class="identifier">instance</span><span class="special">!</span> +<span class="special">>>></span> <span class="identifier">C_str</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span> +<span class="identifier">A</span> <span class="identifier">C</span> <span class="identifier">instance</span><span class="special">!</span> +</pre> +<p> + Yes, Python rox. <span class="inlinemediaobject"><img src="../images/smiley.png" alt="smiley"></span> + </p> +<p> + We can do the same with classes that were wrapped with Boost.Python. Suppose + we have a class <code class="literal">point</code> in C++: + </p> +<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">point</span> <span class="special">{...};</span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">point</span><span class="special">>(</span><span class="string">"point"</span><span class="special">)...;</span> +<span class="special">}</span> +</pre> +<p> + If we are using the technique from the previous session, <a class="link" href="techniques.html#python.creating_packages" title="Creating Packages">Creating + Packages</a>, we can code directly into <code class="literal">geom/__init__.py</code>: + </p> +<pre class="programlisting"><span class="keyword">from</span> <span class="identifier">_geom</span> <span class="keyword">import</span> <span class="special">*</span> + +<span class="comment"># a regular function</span> +<span class="keyword">def</span> <span class="identifier">point_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span> + <span class="keyword">return</span> <span class="identifier">str</span><span class="special">((</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">self</span><span class="special">.</span><span class="identifier">y</span><span class="special">))</span> + +<span class="comment"># now we turn it into a member function</span> +<span class="identifier">point</span><span class="special">.</span><span class="identifier">__str__</span> <span class="special">=</span> <span class="identifier">point_str</span> +</pre> +<p> + <span class="bold"><strong>All</strong></span> point instances created from C++ will + also have this member function! This technique has several advantages: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + Cut down compile times to zero for these additional functions + </li> +<li class="listitem"> + Reduce the memory footprint to virtually zero + </li> +<li class="listitem"> + Minimize the need to recompile + </li> +<li class="listitem"> + Rapid prototyping (you can move the code to C++ if required without changing + the interface) + </li> +</ul></div> +<p> + You can even add a little syntactic sugar with the use of metaclasses. Let's + create a special metaclass that "injects" methods in other classes. + </p> +<pre class="programlisting"><span class="comment"># The one Boost.Python uses for all wrapped classes.</span> +<span class="comment"># You can use here any class exported by Boost instead of "point"</span> +<span class="identifier">BoostPythonMetaclass</span> <span class="special">=</span> <span class="identifier">point</span><span class="special">.</span><span class="identifier">__class__</span> + +<span class="keyword">class</span> <span class="identifier">injector</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span> + <span class="keyword">class</span> <span class="identifier">__metaclass__</span><span class="special">(</span><span class="identifier">BoostPythonMetaclass</span><span class="special">):</span> + <span class="keyword">def</span> <span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">bases</span><span class="special">,</span> <span class="identifier">dict</span><span class="special">):</span> + <span class="keyword">for</span> <span class="identifier">b</span> <span class="keyword">in</span> <span class="identifier">bases</span><span class="special">:</span> + <span class="keyword">if</span> <span class="identifier">type</span><span class="special">(</span><span class="identifier">b</span><span class="special">)</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">type</span><span class="special">):</span> + <span class="keyword">for</span> <span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span> <span class="keyword">in</span> <span class="identifier">dict</span><span class="special">.</span><span class="identifier">items</span><span class="special">():</span> + <span class="identifier">setattr</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span><span class="special">)</span> + <span class="keyword">return</span> <span class="identifier">type</span><span class="special">.</span><span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">bases</span><span class="special">,</span> <span class="identifier">dict</span><span class="special">)</span> + +<span class="comment"># inject some methods in the point foo</span> +<span class="keyword">class</span> <span class="identifier">more_point</span><span class="special">(</span><span class="identifier">injector</span><span class="special">,</span> <span class="identifier">point</span><span class="special">):</span> + <span class="keyword">def</span> <span class="identifier">__repr__</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span> + <span class="keyword">return</span> <span class="string">'Point(x=%s, y=%s)'</span> <span class="special">%</span> <span class="special">(</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">self</span><span class="special">.</span><span class="identifier">y</span><span class="special">)</span> + <span class="keyword">def</span> <span class="identifier">foo</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span> + <span class="keyword">print</span> <span class="string">'foo!'</span> +</pre> +<p> + Now let's see how it got: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">print</span> <span class="identifier">point</span><span class="special">()</span> +<span class="identifier">Point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">10</span><span class="special">,</span> <span class="identifier">y</span><span class="special">=</span><span class="number">10</span><span class="special">)</span> +<span class="special">>>></span> <span class="identifier">point</span><span class="special">().</span><span class="identifier">foo</span><span class="special">()</span> +<span class="identifier">foo</span><span class="special">!</span> +</pre> +<p> + Another useful idea is to replace constructors with factory functions: + </p> +<pre class="programlisting"><span class="identifier">_point</span> <span class="special">=</span> <span class="identifier">point</span> + +<span class="keyword">def</span> <span class="identifier">point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">0</span><span class="special">,</span> <span class="identifier">y</span><span class="special">=</span><span class="number">0</span><span class="special">):</span> + <span class="keyword">return</span> <span class="identifier">_point</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">)</span> +</pre> +<p> + In this simple case there is not much gained, but for constructurs with many + overloads and/or arguments this is often a great simplification, again with + virtually zero memory footprint and zero compile-time overhead for the keyword + support. + </p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.reducing_compiling_time"></a>Reducing Compiling Time</h3></div></div></div> +<p> + If you have ever exported a lot of classes, you know that it takes quite + a good time to compile the Boost.Python wrappers. Plus the memory consumption + can easily become too high. If this is causing you problems, you can split + the class_ definitions in multiple files: + </p> +<pre class="programlisting"><span class="comment">/* file point.cpp */</span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> + +<span class="keyword">void</span> <span class="identifier">export_point</span><span class="special">()</span> +<span class="special">{</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">point</span><span class="special">>(</span><span class="string">"point"</span><span class="special">)...;</span> +<span class="special">}</span> + +<span class="comment">/* file triangle.cpp */</span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> + +<span class="keyword">void</span> <span class="identifier">export_triangle</span><span class="special">()</span> +<span class="special">{</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">triangle</span><span class="special">>(</span><span class="string">"triangle"</span><span class="special">)...;</span> +<span class="special">}</span> +</pre> +<p> + Now you create a file <code class="literal">main.cpp</code>, which contains the <code class="literal">BOOST_PYTHON_MODULE</code> + macro, and call the various export functions inside it. + </p> +<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">export_point</span><span class="special">();</span> +<span class="keyword">void</span> <span class="identifier">export_triangle</span><span class="special">();</span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">export_point</span><span class="special">();</span> + <span class="identifier">export_triangle</span><span class="special">();</span> +<span class="special">}</span> +</pre> +<p> + Compiling and linking together all this files produces the same result as + the usual approach: + </p> +<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span> +<span class="special">{</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">point</span><span class="special">>(</span><span class="string">"point"</span><span class="special">)...;</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">triangle</span><span class="special">>(</span><span class="string">"triangle"</span><span class="special">)...;</span> +<span class="special">}</span> +</pre> +<p> + but the memory is kept under control. + </p> +<p> + This method is recommended too if you are developing the C++ library and + exporting it to Python at the same time: changes in a class will only demand + the compilation of a single cpp, instead of the entire wrapper code. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + If you're exporting your classes with <a href="../../../../../pyste/index.html" target="_top">Pyste</a>, + take a look at the <code class="literal">--multiple</code> option, that generates + the wrappers in various files as demonstrated here. + </p></td></tr> +</table></div> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + This method is useful too if you are getting the error message <span class="emphasis"><em>"fatal + error C1204:Compiler limit:internal structure overflow"</em></span> + when compiling a large source file, as explained in the <a href="../../../../v2/faq.html#c1204" target="_top">FAQ</a>. + </p></td></tr> +</table></div> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"></td> +<td align="right"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top"> + http://www.boost.org/LICENSE_1_0.txt </a>) + </p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exception.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/tutorial.qbk b/libs/python/doc/tutorial/doc/tutorial.qbk new file mode 100644 index 000000000..10a452200 --- /dev/null +++ b/libs/python/doc/tutorial/doc/tutorial.qbk @@ -0,0 +1,1985 @@ +[library python + [version 2.0] + [authors [de Guzman, Joel], [Abrahams, David]] + [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams] + [category inter-language support] + [purpose + Reflects C++ classes and functions into Python + ] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + <ulink url="http://www.boost.org/LICENSE_1_0.txt"> + http://www.boost.org/LICENSE_1_0.txt + </ulink>) + ] +] + +[/ QuickBook Document version 0.9 ] + +[def __note__ [$images/note.png]] +[def __alert__ [$images/alert.png]] +[def __tip__ [$images/tip.png]] +[def :-) [$images/smiley.png]] +[def __jam__ [$images/jam.png]] + +[section 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). + +[h2 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> + + BOOST_PYTHON_MODULE(hello_ext) + { + using namespace boost::python; + 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: + +[python] + + >>> import hello_ext + >>> print hello_ext.greet() + hello, world + +[c++] + +[:['[*Next stop... Building your Hello World module from start to finish...]]] + +[endsect] +[section:hello Building Hello World] + +[h2 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 will outline the steps +necessary to achieve that. We will use the build tool that comes bundled +with every boost distribution: [*bjam]. + +[note [*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]. + +Take note however that the preferred build tool for Boost.Python is bjam. +There are so many ways to set up the build incorrectly. Experience shows +that 90% of the "I can't build Boost.Python" problems come from people +who had to use a different tool. +] + +We will 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 +building.html]. After this brief ['bjam] tutorial, we should have built +the DLLs and run a python program using the extension. + +The tutorial example can be found in the directory: +[^libs/python/example/tutorial]. There, you can find: + +* hello.cpp +* hello.py +* Jamroot + +The [^hello.cpp] file is our C++ hello world example. The [^Jamroot] is +a minimalist ['bjam] script that builds the DLLs for us. Finally, +[^hello.py] is our Python program that uses the extension in +[^hello.cpp]. + +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. The complete list of Bjam executables can be found +[@http://sourceforge.net/project/showfiles.php?group_id=7586 here]. + +[h2 Let's Jam!] +__jam__ + +[@../../../../example/tutorial/Jamroot Here] is our minimalist Jamroot +file. Simply copy the file and tweak [^use-project boost] to where your +boost root directory is and your OK. + +The comments contained in the Jamrules file above should be sufficient +to get you going. + +[h2 Running bjam] + +['bjam] is run using your operating system's command line interpreter. + +[:Start it up.] + +A file called user-config.jam in your home directory is used to +configure your tools. In Windows, your home directory can be found by +typing: + +[pre +ECHO %HOMEDRIVE%%HOMEPATH% +] + +into a command prompt window. Your file should at least have the rules +for your compiler and your python installation. A specific example of +this on Windows would be: + +[pre +# MSVC configuration +using msvc : 8.0 ; + +# Python configuration +using python : 2.4 : C:/dev/tools/Python/ ; +] + +The first rule tells Bjam to use the MSVC 8.0 compiler and associated +tools. The second rule provides information on Python, its version and +where it is located. The above assumes that the Python installation is +in [^C:/dev/tools\/Python/]. If you have one fairly "standard" python +installation for your platform, you might not need to do this. + +Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial] +where the tutorial [^"hello.cpp"] and the [^"Jamroot"] is situated. + +Finally: + + bjam + +It should be building now: + +[pre +cd C:\dev\boost\libs\python\example\tutorial +bjam +...patience... +...found 1101 targets... +...updating 35 targets... +] + +And so on... Finally: + +[pre + Creating library /path-to-boost_python.dll/ + Creating library /path-to-'''hello_ext'''.exp/ +'''**passed**''' ... hello.test +...updated 35 targets... +] + +Or something similar. If all is well, you should now have built the DLLs and +run the Python program. + +[:[*There you go... Have fun!]] + +[endsect] +[section:exposing 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: + +[python] + + >>> import hello + >>> planet = hello.World() + >>> planet.set('howdy') + >>> planet.greet() + 'howdy' + +[section 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: + +[c++] + + 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. + +[endsect] +[section 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, assuming we have placed our Var class inside the namespace +hello as we did before: + +[python] + + >>> x = hello.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 + +[endsect] +[section 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: + +[c++] + + 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", &Num::get) + .add_property("value", &Num::get, &Num::set); + +And at last, in Python: + +[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: + +[c++] + + .add_property("rovalue", &Num::get) + +[endsect] +[section 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: + +# Derived automatically inherits all of Base's Python methods + (wrapped C++ member functions) +# [*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 will 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 will see more of +Boost.Python [link python.call_policies call policies] later. + + // Tell Python to take ownership of factory's result + def("factory", factory, + return_value_policy<manage_new_object>()); + +[endsect] + +[section Class Virtual Functions] + +In this section, we will 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 ~Base() {} + virtual int f() = 0; + }; + +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. It is not ideal to add anything to our class +`Base`. Yet, when you have a virtual function that's going to be overridden in +Python and called polymorphically *from C++*, we'll need to add some +scaffoldings to make things work properly. What we'll do is write a class +wrapper that derives from `Base` that will unintrusively hook into the virtual +functions so that a Python override may be called: + + struct BaseWrap : Base, wrapper<Base> + { + int f() + { + return this->get_override("f")(); + } + }; + +Notice too that in addition to inheriting from `Base`, we also multiply- +inherited `wrapper<Base>` (See [@../../../v2/wrapper.html Wrapper]). The +`wrapper` template makes the job of wrapping classes that are meant to +overridden in Python, easier. + +[blurb __alert__ [*MSVC6/7 Workaround] + +If you are using Microsoft Visual C++ 6 or 7, you have to write `f` as: + +`return call<int>(this->get_override("f").ptr());`.] + +BaseWrap's overridden virtual member function `f` in effect calls the +corresponding method of the Python object through `get_override`. + +Finally, exposing `Base`: + + class_<BaseWrap, boost::noncopyable>("Base") + .def("f", pure_virtual(&Base::f)) + ; + +`pure_virtual` signals Boost.Python that the function `f` is a pure virtual +function. + +[note [*member function and methods] + +Python, like many object oriented languages uses the term [*methods]. +Methods correspond roughly to C++'s [*member functions]] + +[endsect] + +[section Virtual Functions with Default Implementations] + +We've seen in the previous section how classes with pure virtual functions are +wrapped using Boost.Python's [@../../../v2/wrapper.html class wrapper] +facilities. If we wish to wrap [*non]-pure-virtual functions instead, the +mechanism is a bit different. + +Recall that in the [link python.class_virtual_functions previous section], we +wrapped a class with a pure virtual function that we then implemented in C++, or +Python classes derived from it. Our base class: + + struct Base + { + virtual int f() = 0; + }; + +had a pure virtual function [^f]. If, however, its member function [^f] was +not declared as pure virtual: + + struct Base + { + virtual ~Base() {} + virtual int f() { return 0; } + }; + +We wrap it this way: + + struct BaseWrap : Base, wrapper<Base> + { + int f() + { + if (override f = this->get_override("f")) + return f(); // *note* + return Base::f(); + } + + int default_f() { return this->Base::f(); } + }; + +Notice how we implemented `BaseWrap::f`. Now, we have to check if there is an +override for `f`. If none, then we call `Base::f()`. + +[blurb __alert__ [*MSVC6/7 Workaround] + +If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line +with the `*note*` as: + +`return call<char const*>(f.ptr());`.] + +Finally, exposing: + + class_<BaseWrap, boost::noncopyable>("Base") + .def("f", &Base::f, &BaseWrap::default_f) + ; + +Take note that we expose both `&Base::f` and `&BaseWrap::default_f`. +Boost.Python needs to keep track of 1) the dispatch function [^f] and 2) the +forwarding function to its default implementation [^default_f]. There's a +special [^def] function for this purpose. + +In Python, the results would be as expected: + +[python] + + >>> base = Base() + >>> class Derived(Base): + ... def f(self): + ... return 42 + ... + >>> derived = Derived() + +Calling [^base.f()]: + + >>> base.f() + 0 + +Calling [^derived.f()]: + + >>> derived.f() + 42 + +[endsect] +[section Class Operators/Special Functions] + +[h2 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: + +[c++] + + 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()) // __sub__ + .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". + +[h2 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 + { public: operator double() const; }; + + Rational pow(Rational, Rational); + Rational abs(Rational); + ostream& operator<<(ostream&,Rational); + + class_<Rational>("Rational") + .def(float_(self)) // __float__ + .def(pow(self, other<Rational>)) // __pow__ + .def(abs(self)) // __abs__ + .def(str(self)) // __str__ + ; + +Need we say more? + +[note What is the business of `operator<<`? +Well, the method `str` requires the `operator<<` to do its work (i.e. +`operator<<` is used by the method defined by `def(str(self))`.] + +[endsect] +[endsect] [/ Exposing Classes ] + +[section Functions] + +In this chapter, we'll look at Boost.Python powered functions in closer +detail. We will see some facilities to make exposing C++ functions to +Python safe from potential pifalls such as dangling pointers and +references. We will 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]. + +[pre +>>> 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! +] + +[section 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: + +# [^f] is called passing in a reference to [^y] and a pointer to [^z] +# A reference to [^y.x] is returned +# [^y] is deleted. [^x] is a dangling reference +# [^x.some_method()] is called +# [*BOOM!] + +We could copy result into a new object: + +[python] + + >>> 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: + +[c++] + + 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: + +# [^f] is called passing in a reference to [^y] and a pointer to [^z] +# A pointer to [^z] is held by [^y] +# A reference to [^y.x] is returned +# [^z] is deleted. [^y.z] is a dangling pointer +# [^y.z_value()] is called +# [^z->value()] is called +# [*BOOM!] + +[h2 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 [@../../../v2/reference.html#models_of_call_policies here]. + +* [*with_custodian_and_ward]: Ties lifetimes of the arguments +* [*with_custodian_and_ward_postcall]: Ties lifetimes of the arguments and results +* [*return_internal_reference]: Ties lifetime of one argument to that of result +* [*return_value_policy<T> with T one of:] + * [*reference_existing_object]: naive (dangerous) approach + * [*copy_const_reference]: Boost.Python v1 approach + * [*copy_non_const_reference]: + * [*manage_new_object]: Adopt a pointer and hold the instance + +[blurb :-) [*Remember the Zen, Luke:] + +"Explicit is better than implicit" + +"In the face of ambiguity, refuse the temptation to guess" +] + +[endsect] +[section Overloading] + +The following illustrates a scheme for manually wrapping an overloaded +member functions. Of course, the same technique can be applied to wrapping +overloaded non-member functions. + +We have here our C++ class: + + struct X + { + bool f(int a) + { + return true; + } + + bool f(int a, double b) + { + return true; + } + + bool f(int a, double b, char c) + { + return true; + } + + int f(int a, int b, int c) + { + return a + b + c; + }; + }; + +Class X has 4 overloaded functions. We will start by introducing some +member function pointer variables: + + bool (X::*fx1)(int) = &X::f; + bool (X::*fx2)(int, double) = &X::f; + bool (X::*fx3)(int, double, char)= &X::f; + int (X::*fx4)(int, int, int) = &X::f; + +With these in hand, we can proceed to define and wrap this for Python: + + .def("f", fx1) + .def("f", fx2) + .def("f", fx3) + .def("f", fx4) + +[endsect] +[section 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, we had to resort to manual +wrapping as outlined in the [link python.overloading previous section], or +writing thin wrappers: + + // write "thin wrappers" + int f1(int x) { return f(x); } + int f2(int x, double y) { return 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: + +* have default arguments, or +* are overloaded with a common sequence of initial arguments + +[h2 BOOST_PYTHON_FUNCTION_OVERLOADS] + +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()); + +[h2 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] + +Objects here, objects there, objects here there everywhere. More frequently +than anything else, we need to expose member functions of our classes to +Python. Then again, we have the same inconveniences as before when default +arguments or overloads with a common sequence of initial arguments come +into play. Another macro is provided to make this a breeze. + +Like [^BOOST_PYTHON_FUNCTION_OVERLOADS], +[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] may be used to automatically create +the thin wrappers for wrapping member functions. Let's have an example: + + struct george + { + void + wack_em(int a, int b = 0, char c = 'x') + { + /*...*/ + } + }; + +The macro invocation: + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3) + +will generate a set of thin wrappers for george's [^wack_em] member function +accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and +fourth macro argument). The thin wrappers are all enclosed in a class named +[^george_overloads] that can then be used as an argument to [^def(...)]: + + .def("wack_em", &george::wack_em, george_overloads()); + +See the [@../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference] +for details. + +[h2 init and optional] + +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). + +[endsect] +[section Auto-Overloading] + +It was mentioned in passing in the previous section that +[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] +can also be used for overloaded functions and member functions with a +common sequence of initial arguments. Here is an example: + + void foo() + { + /*...*/ + } + + void foo(bool a) + { + /*...*/ + } + + void foo(bool a, int b) + { + /*...*/ + } + + void foo(bool a, int b, char c) + { + /*...*/ + } + +Like in the previous section, we can generate thin wrappers for these +overloaded functions in one-shot: + + BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3) + +Then... + + .def("foo", (void(*)(bool, int, char))0, foo_overloads()); + +Notice though that we have a situation now where we have a minimum of zero +(0) arguments and a maximum of 3 arguments. + +[h2 Manual Wrapping] + +It is important to emphasize however that [*the overloaded functions must +have a common sequence of initial arguments]. Otherwise, our scheme above +will not work. If this is not the case, we have to wrap our functions +[link python.overloading manually]. + +Actually, we can mix and match manual wrapping of overloaded functions and +automatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] and +its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our example +presented in the section [link python.overloading on overloading], since the +first 4 overload functins have a common sequence of initial arguments, we +can use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap the +first three of the [^def]s and manually wrap just the last. Here's +how we'll do this: + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4) + +Create a member function pointers as above for both X::f overloads: + + bool (X::*fx1)(int, double, char) = &X::f; + int (X::*fx2)(int, int, int) = &X::f; + +Then... + + .def("f", fx1, xf_overloads()); + .def("f", fx2) + +[endsect] +[endsect] [/ Functions ] + +[section:object 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 will 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++ [^object]s are as close as possible to Python. This +should minimize the learning curve significantly. + +[$images/python.png] + +[section Basic Interface] + +Class [^object] wraps [^PyObject*]. All the intricacies of dealing with +[^PyObject]s such as managing reference counting are handled by the +[^object] class. C++ object interoperability is seamless. Boost.Python C++ +[^object]s can in fact be explicitly constructed from any C++ object. + +To illustrate, this Python code snippet: + +[python] + + 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: + +[c++] + + 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. + +[endsect] +[section Derived Object types] + +Boost.Python comes with a set of derived [^object] types corresponding to +that of Python's: + +* list +* dict +* tuple +* str +* long_ +* enum + +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 [^object]s 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++. + +[blurb + __alert__ [*Beware] the common pitfall of forgetting that the constructors + of most of Python's mutable types make copies, just as in Python. +] + +Python: +[python] + + >>> d = dict(x.__dict__) # copies x.__dict__ + >>> d['whatever'] = 3 # modifies the copy + +C++: +[c++] + + dict d(x.attr("__dict__")); // copies x.__dict__ + d['whatever'] = 3; // modifies the copy + +[h2 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); + +[endsect] +[section 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 [^double]s. 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]. The second line attempts to ['extract] the [^Vec2] object from held +by the Boost.Python [^object]. + +Take note that we said "attempt to" above. What if the Boost.Python [^object] +does not really hold a [^Vec2] type? This is certainly a possibility considering +the dynamic nature of Python [^object]s. 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(); ... + +__tip__ 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__ ! + + +[endsect] +[section 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. + +[note [*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 +[@../../../v2/scope.html here].] + +You can access those values in Python as + +[python] + + >>> 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: + +[c++] + + scope in_X = class_<X>("X") + .def( ... ) + .def( ... ) + ; + + // Expose X::nested as X.nested + enum_<X::nested>("nested") + .value("red", red) + .value("blue", blue) + ; + +[def Py_Initialize [@http://www.python.org/doc/current/api/initialization.html#l2h-652 Py_Initialize]] +[def Py_Finalize [@http://www.python.org/doc/current/api/initialization.html#l2h-656 Py_Finalize]] +[def Py_XINCREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-65 Py_XINCREF]] +[def Py_XDECREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-67 Py_XDECREF]] +[def PyImport_AppendInittab [@http://www.python.org/doc/current/api/importing.html#l2h-137 PyImport_AppendInittab]] +[def PyImport_AddModule [@http://www.python.org/doc/current/api/importing.html#l2h-125 PyImport_AddModule]] +[def PyModule_New [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-591 PyModule_New]] +[def PyModule_GetDict [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-594 PyModule_GetDict]] + +[endsect] + +[section:creating_python_object Creating `boost::python::object` from `PyObject*`] + +When you want a `boost::python::object` to manage a pointer to `PyObject*` pyobj one does: + + boost::python::object o(boost::python::handle<>(pyobj)); + +In this case, the `o` object, manages the `pyobj`, it won’t increase the reference count on construction. + +Otherwise, to use a borrowed reference: + + boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj))); + +In this case, `Py_INCREF` is called, so `pyobj` is not destructed when object o goes out of scope. + +[endsect] [/ creating_python_object ] + +[endsect] [/ Object Interface] + +[section Embedding] + +By now you should know how to use Boost.Python to call your C++ code from +Python. However, sometimes you may need to do the reverse: call Python code +from the C++-side. This requires you to ['embed] the Python interpreter +into your C++ program. + +Currently, Boost.Python does not directly support everything you'll need +when embedding. Therefore you'll need to use the +[@http://www.python.org/doc/current/api/api.html Python/C API] to fill in +the gaps. However, Boost.Python already makes embedding a lot easier and, +in a future version, it may become unnecessary to touch the Python/C API at +all. So stay tuned... :-) + +[h2 Building embedded programs] + +To be able to embed python into your programs, you have to link to +both Boost.Python's as well as Python's own runtime library. + +Boost.Python's library comes in two variants. Both are located +in Boost's [^/libs/python/build/bin-stage] subdirectory. On Windows, the +variants are called [^boost_python.lib] (for release builds) and +[^boost_python_debug.lib] (for debugging). If you can't find the libraries, +you probably haven't built Boost.Python yet. See +[@../../../building.html Building and Testing] on how to do this. + +Python's library can be found in the [^/libs] subdirectory of +your Python directory. On Windows it is called pythonXY.lib where X.Y is +your major Python version number. + +Additionally, Python's [^/include] subdirectory has to be added to your +include path. + +In a Jamfile, all the above boils down to: + +[pre +projectroot c:\projects\embedded_program ; # location of the program + +# bring in the rules for python +SEARCH on python.jam = $(BOOST_BUILD_PATH) ; +include python.jam ; + +exe embedded_program # name of the executable + : #sources + embedded_program.cpp + : # requirements + <find-library>boost_python <library-path>c:\boost\libs\python + $(PYTHON_PROPERTIES) + <library-path>$(PYTHON_LIB_PATH) + <find-library>$(PYTHON_EMBEDDED_LIBRARY) ; +] + +[h2 Getting started] + +Being able to build is nice, but there is nothing to build yet. Embedding +the Python interpreter into one of your C++ programs requires these 4 +steps: + +# '''#include''' [^<boost/python.hpp>] + +# Call Py_Initialize() to start the interpreter and create the [^__main__] module. + +# Call other Python C API routines to use the interpreter. + +[/ # Call Py_Finalize() to stop the interpreter and release its resources.] + +[note [*Note that at this time you must not call Py_Finalize() to stop the +interpreter. This may be fixed in a future version of boost.python.] +] + +(Of course, there can be other C++ code between all of these steps.) + +[:['[*Now that we can embed the interpreter in our programs, lets see how to put it to use...]]] + +[section Using the interpreter] + +As you probably already know, objects in Python are reference-counted. +Naturally, the [^PyObject]s of the Python C API are also reference-counted. +There is a difference however. While the reference-counting is fully +automatic in Python, the Python C API requires you to do it +[@http://www.python.org/doc/current/c-api/refcounting.html by hand]. This is +messy and especially hard to get right in the presence of C++ exceptions. +Fortunately Boost.Python provides the [@../../../v2/handle.html handle] and +[@../../../v2/object.html object] class templates to automate the process. + +[h2 Running Python code] + +Boost.python provides three related functions to run Python code from C++. + + object eval(str expression, object globals = object(), object locals = object()) + object exec(str code, object globals = object(), object locals = object()) + object exec_file(str filename, object globals = object(), object locals = object()) + +eval evaluates the given expression and returns the resulting value. +exec executes the given code (typically a set of statements) returning the result, +and exec_file executes the code contained in the given file. + +The [^globals] and [^locals] parameters are Python dictionaries +containing the globals and locals of the context in which to run the code. +For most intents and purposes you can use the namespace dictionary of the +[^__main__] module for both parameters. + +Boost.python provides a function to import a module: + + object import(str name) + +import imports a python module (potentially loading it into the running process +first), and returns it. + +Let's import the [^__main__] module and run some Python code in its namespace: + + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + + object ignored = exec("hello = file('hello.txt', 'w')\n" + "hello.write('Hello world!')\n" + "hello.close()", + main_namespace); + +This should create a file called 'hello.txt' in the current directory +containing a phrase that is well-known in programming circles. + +[h2 Manipulating Python objects] + +Often we'd like to have a class to manipulate Python objects. +But we have already seen such a class above, and in the +[@python/object.html previous section]: the aptly named [^object] class +and its derivatives. We've already seen that they can be constructed from +a [^handle]. The following examples should further illustrate this fact: + + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + object ignored = exec("result = 5 ** 2", main_namespace); + int five_squared = extract<int>(main_namespace["result"]); + +Here we create a dictionary object for the [^__main__] module's namespace. +Then we assign 5 squared to the result variable and read this variable from +the dictionary. Another way to achieve the same result is to use eval instead, +which returns the result directly: + + object result = eval("5 ** 2"); + int five_squared = extract<int>(result); + +[h2 Exception handling] + +If an exception occurs in the evaluation of the python expression, +[@../../../v2/errors.html#error_already_set-spec error_already_set] is thrown: + + try + { + object result = eval("5/0"); + // execution will never get here: + int five_divided_by_zero = extract<int>(result); + } + catch(error_already_set const &) + { + // handle the exception in some way + } + +The [^error_already_set] exception class doesn't carry any information in itself. +To find out more about the Python exception that occurred, you need to use the +[@http://www.python.org/doc/api/exceptionHandling.html exception handling functions] +of the Python C API in your catch-statement. This can be as simple as calling +[@http://www.python.org/doc/api/exceptionHandling.html#l2h-70 PyErr_Print()] to +print the exception's traceback to the console, or comparing the type of the +exception with those of the [@http://www.python.org/doc/api/standardExceptions.html +standard exceptions]: + + catch(error_already_set const &) + { + if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) + { + // handle ZeroDivisionError specially + } + else + { + // print all other errors to stderr + PyErr_Print(); + } + } + +(To retrieve even more information from the exception you can use some of the other +exception handling functions listed [@http://www.python.org/doc/api/exceptionHandling.html here].) + +[endsect] +[endsect] [/ Embedding] + +[section Iterators] + +In C++, and STL in particular, we see iterators everywhere. Python also has +iterators, but these are two very different beasts. + +[*C++ iterators:] + +* C++ has 5 type categories (random-access, bidirectional, forward, input, output) +* There are 2 Operation categories: reposition, access +* A pair of iterators is needed to represent a (first/last) range. + +[*Python Iterators:] + +* 1 category (forward) +* 1 operation category (next()) +* Raises StopIteration exception at end + +The typical Python iteration protocol: [^[*for y in x...]] is as follows: + +[python] + + 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: + +[c++] + + 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: + +* range(start, finish) +* range<Policies,Target>(start, finish) + +Here, start/finish may be one of: + +* member data pointers +* member function pointers +* adaptable function object (use Target parameter) + +[*iterator] + +* iterator<T, Policies>() + +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: + +[python] + + f = Field() + for x in f.pions: + smash(x) + for y in f.bogons: + count(y) + +Now, our C++ Wrapper: + +[c++] + + class_<F>("Field") + .property("pions", range(&F::p_begin, &F::p_end)) + .property("bogons", range(&F::b_begin, &F::b_end)); + +[*stl_input_iterator] + +So far, we have seen how to expose C++ iterators and ranges to Python. +Sometimes we wish to go the other way, though: we'd like to pass a +Python sequence to an STL algorithm or use it to initialize an STL +container. We need to make a Python iterator look like an STL iterator. +For that, we use `stl_input_iterator<>`. Consider how we might +implement a function that exposes `std::list<int>::assign()` to +Python: + +[c++] + + template<typename T> + void list_assign(std::list<T>& l, object o) { + // Turn a Python sequence into an STL input range + stl_input_iterator<T> begin(o), end; + l.assign(begin, end); + } + + // Part of the wrapper for list<int> + class_<std::list<int> >("list_int") + .def("assign", &list_assign<int>) + // ... + ; + +Now in Python, we can assign any integer sequence to `list_int` objects: + +[python] + + x = list_int(); + x.assign([1,2,3,4,5]) + +[endsect] +[section:exception 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 const& x) { + PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave..."); + } + BOOST_PYTHON_MODULE(kubrick) { + register_exception_translator< + PodBayDoorException>(translator); + ... + +[endsect] +[section:techniques General Techniques] + +Here are presented some useful techniques that you can use while wrapping code with Boost.Python. + +[section Creating Packages] + +A Python package is a collection of modules that provide to the user a certain +functionality. If you're not familiar on how to create packages, a good +introduction to them is provided in the +[@http://www.python.org/doc/current/tut/node8.html Python Tutorial]. + +But we are wrapping C++ code, using Boost.Python. How can we provide a nice +package interface to our users? To better explain some concepts, let's work +with an example. + +We have a C++ library that works with sounds: reading and writing various +formats, applying filters to the sound data, etc. It is named (conveniently) +[^sounds]. Our library already has a neat C++ namespace hierarchy, like so: + + sounds::core + sounds::io + sounds::filters + +We would like to present this same hierarchy to the Python user, allowing him +to write code like this: + + import sounds.filters + sounds.filters.echo(...) # echo is a C++ function + +The first step is to write the wrapping code. We have to export each module +separately with Boost.Python, like this: + + /* file core.cpp */ + BOOST_PYTHON_MODULE(core) + { + /* export everything in the sounds::core namespace */ + ... + } + + /* file io.cpp */ + BOOST_PYTHON_MODULE(io) + { + /* export everything in the sounds::io namespace */ + ... + } + + /* file filters.cpp */ + BOOST_PYTHON_MODULE(filters) + { + /* export everything in the sounds::filters namespace */ + ... + } + +Compiling these files will generate the following Python extensions: +[^core.pyd], [^io.pyd] and [^filters.pyd]. + +[note The extension [^.pyd] is used for python extension modules, which +are just shared libraries. Using the default for your system, like [^.so] for +Unix and [^.dll] for Windows, works just as well.] + +Now, we create this directory structure for our Python package: + +[pre +sounds/ + \_\_init\_\_.py + core.pyd + filters.pyd + io.pyd +] + +The file [^\_\_init\_\_.py] is what tells Python that the directory [^sounds/] is +actually a Python package. It can be a empty file, but can also perform some +magic, that will be shown later. + +Now our package is ready. All the user has to do is put [^sounds] into his +[@http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000 PYTHONPATH] +and fire up the interpreter: + +[python] + + >>> import sounds.io + >>> import sounds.filters + >>> sound = sounds.io.open('file.mp3') + >>> new_sound = sounds.filters.echo(sound, 1.0) + +Nice heh? + +This is the simplest way to create hierarchies of packages, but it is not very +flexible. What if we want to add a ['pure] Python function to the filters +package, for instance, one that applies 3 filters in a sound object at once? +Sure, you can do this in C++ and export it, but why not do so in Python? You +don't have to recompile the extension modules, plus it will be easier to write +it. + +If we want this flexibility, we will have to complicate our package hierarchy a +little. First, we will have to change the name of the extension modules: + +[c++] + + /* file core.cpp */ + BOOST_PYTHON_MODULE(_core) + { + ... + /* export everything in the sounds::core namespace */ + } + +Note that we added an underscore to the module name. The filename will have to +be changed to [^_core.pyd] as well, and we do the same to the other extension modules. +Now, we change our package hierarchy like so: + +[pre +sounds/ + \_\_init\_\_.py + core/ + \_\_init\_\_.py + _core.pyd + filters/ + \_\_init\_\_.py + _filters.pyd + io/ + \_\_init\_\_.py + _io.pyd +] + +Note that we created a directory for each extension module, and added a +\_\_init\_\_.py to each one. But if we leave it that way, the user will have to +access the functions in the core module with this syntax: + +[python] + + >>> import sounds.core._core + >>> sounds.core._core.foo(...) + +which is not what we want. But here enters the [^\_\_init\_\_.py] magic: everything +that is brought to the [^\_\_init\_\_.py] namespace can be accessed directly by the +user. So, all we have to do is bring the entire namespace from [^_core.pyd] +to [^core/\_\_init\_\_.py]. So add this line of code to [^sounds/core/\_\_init\_\_.py]: + + from _core import * + +We do the same for the other packages. Now the user accesses the functions and +classes in the extension modules like before: + + >>> import sounds.filters + >>> sounds.filters.echo(...) + +with the additional benefit that we can easily add pure Python functions to +any module, in a way that the user can't tell the difference between a C++ +function and a Python function. Let's add a ['pure] Python function, +[^echo_noise], to the [^filters] package. This function applies both the +[^echo] and [^noise] filters in sequence in the given [^sound] object. We +create a file named [^sounds/filters/echo_noise.py] and code our function: + + import _filters + def echo_noise(sound): + s = _filters.echo(sound) + s = _filters.noise(sound) + return s + +Next, we add this line to [^sounds/filters/\_\_init\_\_.py]: + + from echo_noise import echo_noise + +And that's it. The user now accesses this function like any other function +from the [^filters] package: + + >>> import sounds.filters + >>> sounds.filters.echo_noise(...) + +[endsect] +[section Extending Wrapped Objects in Python] + +Thanks to Python's flexibility, you can easily add new methods to a class, +even after it was already created: + + >>> class C(object): pass + >>> + >>> # a regular function + >>> def C_str(self): return 'A C instance!' + >>> + >>> # now we turn it in a member function + >>> C.__str__ = C_str + >>> + >>> c = C() + >>> print c + A C instance! + >>> C_str(c) + A C instance! + +Yes, Python rox. :-) + +We can do the same with classes that were wrapped with Boost.Python. Suppose +we have a class [^point] in C++: + +[c++] + + class point {...}; + + BOOST_PYTHON_MODULE(_geom) + { + class_<point>("point")...; + } + +If we are using the technique from the previous session, +[link python.creating_packages Creating Packages], we can code directly +into [^geom/\_\_init\_\_.py]: + +[python] + + from _geom import * + + # a regular function + def point_str(self): + return str((self.x, self.y)) + + # now we turn it into a member function + point.__str__ = point_str + +[*All] point instances created from C++ will also have this member function! +This technique has several advantages: + +* Cut down compile times to zero for these additional functions +* Reduce the memory footprint to virtually zero +* Minimize the need to recompile +* Rapid prototyping (you can move the code to C++ if required without changing the interface) + +You can even add a little syntactic sugar with the use of metaclasses. Let's +create a special metaclass that "injects" methods in other classes. + + # The one Boost.Python uses for all wrapped classes. + # You can use here any class exported by Boost instead of "point" + BoostPythonMetaclass = point.__class__ + + class injector(object): + class __metaclass__(BoostPythonMetaclass): + def __init__(self, name, bases, dict): + for b in bases: + if type(b) not in (self, type): + for k,v in dict.items(): + setattr(b,k,v) + return type.__init__(self, name, bases, dict) + + # inject some methods in the point foo + class more_point(injector, point): + def __repr__(self): + return 'Point(x=%s, y=%s)' % (self.x, self.y) + def foo(self): + print 'foo!' + +Now let's see how it got: + + >>> print point() + Point(x=10, y=10) + >>> point().foo() + foo! + +Another useful idea is to replace constructors with factory functions: + + _point = point + + def point(x=0, y=0): + return _point(x, y) + +In this simple case there is not much gained, but for constructurs with +many overloads and/or arguments this is often a great simplification, again +with virtually zero memory footprint and zero compile-time overhead for +the keyword support. + +[endsect] +[section Reducing Compiling Time] + +If you have ever exported a lot of classes, you know that it takes quite a good +time to compile the Boost.Python wrappers. Plus the memory consumption can +easily become too high. If this is causing you problems, you can split the +class_ definitions in multiple files: + +[c++] + + /* file point.cpp */ + #include <point.h> + #include <boost/python.hpp> + + void export_point() + { + class_<point>("point")...; + } + + /* file triangle.cpp */ + #include <triangle.h> + #include <boost/python.hpp> + + void export_triangle() + { + class_<triangle>("triangle")...; + } + +Now you create a file [^main.cpp], which contains the [^BOOST_PYTHON_MODULE] +macro, and call the various export functions inside it. + + void export_point(); + void export_triangle(); + + BOOST_PYTHON_MODULE(_geom) + { + export_point(); + export_triangle(); + } + +Compiling and linking together all this files produces the same result as the +usual approach: + + #include <boost/python.hpp> + #include <point.h> + #include <triangle.h> + + BOOST_PYTHON_MODULE(_geom) + { + class_<point>("point")...; + class_<triangle>("triangle")...; + } + +but the memory is kept under control. + +This method is recommended too if you are developing the C++ library and +exporting it to Python at the same time: changes in a class will only demand +the compilation of a single cpp, instead of the entire wrapper code. + +[note If you're exporting your classes with [@../../../../pyste/index.html Pyste], +take a look at the [^--multiple] option, that generates the wrappers in +various files as demonstrated here.] + +[note This method is useful too if you are getting the error message +['"fatal error C1204:Compiler limit:internal structure overflow"] when compiling +a large source file, as explained in the [@../../../v2/faq.html#c1204 FAQ].] + +[endsect] +[endsect] [/ General Techniques] + + diff --git a/libs/python/doc/tutorial/index.html b/libs/python/doc/tutorial/index.html new file mode 100644 index 000000000..792427772 --- /dev/null +++ b/libs/python/doc/tutorial/index.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta http-equiv="refresh" content="0; URL=doc/html/index.html"> + </head> + <body> + Automatic redirection failed, click this + <a href="doc/html/index.html">link</a> <hr> + <p>© Copyright Beman Dawes, 2001</p> + <p>Distributed under the Boost Software License, Version 1.0. (See + accompanying file <a href="../../../../LICENSE_1_0.txt"> + LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p> + </body> +</html> diff --git a/libs/python/doc/v2/Apr2002.html b/libs/python/doc/v2/Apr2002.html new file mode 100644 index 000000000..62350defa --- /dev/null +++ b/libs/python/doc/v2/Apr2002.html @@ -0,0 +1,166 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - April 2002 Progress Report</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">April 2002 Progress Report</h2> + </td> + </tr> +</table> +<hr> +<h2>Contents</h2> +<dl class="index"> + <dt><a href="#accomplishments">Accomplishments</a></dt> + <dl class="index"> + <dt><a href="#arity">Arbitrary Arity Support</a></dt> + <dt><a href="#callbacks">New Callback Interface</a></dt> + <dt><a href="#policies">Call Policies for Construtors</a></dt> + <dt><a href="#bugs">Real Users, Real Bugs</a></dt> + <dt><a href="#insights">New Insights</a></dt> + <dt><a href="#v1">Boost.Python V1 Maintenance</a></dt> + </dl> + + <dt><a href="#missing">What's Missing</a></dt> + +</dl> + +<h2><a name="accomplishments">Accomplishments</a></h2> + +April was a short month as far as Boost.Python was concerned, since +the spring ISO C++ Committee Meeting (and associated vacation) +occupied me for the 2nd half of the month. However, a suprising amount +of work got done... + +<h3><a name="arity">Arbitrary Arity Support</a></h3> + +I began using the <a +href="../../../preprocessor/doc/index.html">Boost.Preprocessor</a> +metaprogramming library to generate support for functions and member +functions of arbitrary arity, which was, to say the least, quite an +adventure. The feedback cycle resulting from my foray into +Boost.Preprocessor resulted in several improvements to the library, +most notably in its documentation. + +<p> + +Boost.Python now supports calls of up to 17 arguments on most +compilers. Because most EDG-based compilers have dismal preprocessor +performance, I had to "manually" expand the metaprograms for +arities from zero to fifteen arguments, and EDG-based compilers with +<code>__EDG_VERSION__ <= 245</code> only support 15 +arguments by default. If some crazy program finds a need for more than +the default arity support, users can increase the base support by +setting the <code>BOOST_PYTHON_MAX_ARITY</code> preprocessor symbol. + +<h3><a name="callbacks">New Callback Interface</a></h3> + +I mentioned in <a href="Mar2002.html">last month's report</a> that I +wasn't pleased with the interface for the interface for calling into +Python, so now it has been redesigned. The new interface is outlined +in <a +href="http://mail.python.org/pipermail/c++-sig/2002-April/000953.html">this +message</a> (though the GCC 2.95.3 bugs have been fixed). + +<h3><a name="policies">Call Policies for Constructors</a></h3> + +On April 2nd, I <a +href="http://mail.python.org/pipermail/c++-sig/2002-April/000916.html">announced</a> +support for the use of call policies with constructors. + +<h3><a name="bugs">Real Users, Real Bugs</a></h3> + +At least two people outside of Kull began actually using Boost.Python +v2 in earnest this month. Peter Bienstman and Pearu Pearson both +provided valuable real-world bug reports that helped me to improve the +library's robustness. + +<h3><a name="insights">New Insights</a></h3> + +<a +href="http://mail.python.org/pipermail/c++-sig/2002-May/001010.html" +>Answering some of Pearu's questions</a> about explicitly converting +objects between Python and C++ actually led me to a new understanding +of the role of the current conversion facilities. In Boost.Python v1, +all conversions between Python and C++ were handled by a single family +of functions, called <code>to_python()</code> and +<code>from_python()</code>. Since the primary role of Boost.Python is +to wrap C++ functions in Python, I used these names for the first kind +of converters I needed: those that extract C++ objects to be used as +function arguments and which C++ function return values to +Python. The better-considered approach in Boost.Python v2 uses a +completely different mechanism for conversions used when calling +Python from C++, as in wrapped virtual function implementations. I +usually think of this as a "callback", as in "calling +back into Python", and I named the converters used in callbacks +accordingly: <code>to_python_callback</code> and +<code>from_python_callback</code>. However, as it turns out, the +behavior of the "callback" converters is the appropriate one +for users who want to explicitly extract a C++ value from a Python +object, or create a Python object from a C++ value. The upshot is that +it probably makes sense to change the name of the existing <code>to_python</code> and +<code>from_python</code> so those names are available for the +user-friendly explicit converters. + +<p> +<a +href="http://mail.python.org/pipermail/c++-sig/2002-May/001013.html">Another +of Pearu's questions</a> pushes momentum further in the direction of a +more-sophisticated overloading mechanism than the current +simple-minded "first match" approach, as I suggested <a +href="Mar2002.html#implicit_conversions">last month</a>. + +<h3><a name="v1">Boost.Python V1 Maintenance</a></h3> + +As much as I'm looking forward to retiring Boost.Python v1, a +significant amount of effort has been being spent dealing with support +problems; the saying that code rots when left alone is true, and +Boost.Python is no exception. Eventually it became obvious to me that +we were going to have to invest some effort in keeping V1 healthy +while working on V2. Ralf and I have expanded support for various +compilers and stabilized the V1 codebase considerably. We discarded +the obsolete Visual Studio projects which were causing so much +confusion. Still to do before the next Boost release: +<ol> +<li>Update the build/test documentation with detailed instructions for +configuring various toolsets. +<li>Provide some links to Boost.Python v2 to let people know what's +coming. +</ol> + + +<h2><a name="missing">What's Missing</a></h2> + +Last month I announced that I would implement the following which are +not yet complete: +<ol> +<li>Document all implemented features +<li>Implement conversions for <code>char</code> types. This is +implemented but not tested, so we have to assume it doesn't work. +</ol> + +These are my first priority for this month (especially the +documentation). + +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> diff --git a/libs/python/doc/v2/CallPolicies.html b/libs/python/doc/v2/CallPolicies.html new file mode 100644 index 000000000..06384a23d --- /dev/null +++ b/libs/python/doc/v2/CallPolicies.html @@ -0,0 +1,165 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../../../../boost.css"> + + <title>Boost.Python - CallPolicies Concept</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">CallPolicies Concept</h2> + </td> + </tr> + </table> + <hr> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#composition">CallPolicies Composition</a></dt> + + <dt><a href="#concept-requirements">Concept Requirements</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#CallPolicies-concept">CallPolicies Concept</a></dt> + </dl> + </dd> + </dl> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Models of the CallPolicies concept are used to specialize the behavior + of Python callable objects generated by Boost.Python to wrapped C++ + objects like function and member function pointers, providing three + behaviors:</p> + + <ol> + <li><code>precall</code> - Python argument tuple management before the + wrapped object is invoked</li> + + <li><code>result_converter</code> - C++ return value handling</li> + + <li><code>postcall</code> - Python argument tuple and result management + after the wrapped object is invoked</li> + <li><code>extract_return_type</code> - metafunction for extracting the return type from a given signature type sequence</li> + </ol> + + <h2><a name="composition"></a>CallPolicies Composition</h2> + In order to allow the use of multiple models of CallPolicies in the same + callable object, Boost.Python's CallPolicies class templates provide a + chaining interface which allows them to be recursively composed. This + interface takes the form of an optional template parameter, + <code>Base</code> which defaults to <a href= + "default_call_policies.html#default_call_policies-spec"><code>default_call_policies</code></a>. + By convention, the <code>precall</code> function of the <code>Base</code> + is invoked <i>after</i> the <code>precall</code> function supplied by the + outer template, and the <code>postcall</code> function of the + <code>Base</code> is invoked <i>before</i> the <code>postcall</code> + function of the outer template. If a <code>result_converter</code> is + supplied by the outer template, it <i>replaces</i> any + <code>result_converter</code> supplied by the <code>Base</code>. For an + example, see <a href= + "return_internal_reference.html#return_internal_reference-spec"><code>return_internal_reference</code></a>. + + + <h2><a name="concept-requirements"></a>Concept Requirements</h2> + + <h3><a name="CallPolicies-concept"></a>CallPolicies Concept</h3> + + <p>In the table below, <code><b>x</b></code> denotes an object whose type + <code><b>P</b></code> is a model of CallPolicies, <code><b>a</b></code> + denotes a <code>PyObject*</code> pointing to a Python argument tuple + object, and <code><b>r</b></code> denotes a <code>PyObject*</code> + referring to a "preliminary" result object.</p> + + <table summary="CallPolicies expressions" border="1" cellpadding="5"> + <tr> + <td><b>Expression</b></td> + + <td><b>Type</b></td> + + <td><b>Result/Semantics</b></td> + </tr> + + <tr> + <td valign="top"><code>x.precall(a)</code></td> + + <td>convertible to <code>bool</code></td> + + <td>returns <code>false</code> and <code><a href= + "http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code> + upon failure, <code>true</code> otherwise.</td> + </tr> + + <tr> + <td valign="top"><code>P::result_converter</code></td> + + <td>A model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a>.</td> + + <td>An MPL unary <a href= + "../../../mpl/doc/refmanual/metafunction-class.html">Metafunction + Class</a> used produce the "preliminary" result object.</td> + </tr> + + <tr> + <td valign="top"><code>x.postcall(a, r)</code></td> + + <td>convertible to <code>PyObject*</code></td> + + <td>0 <code>0</code> and <code><a href= + "http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code> + upon failure. Must "conserve references" even in the event of an + exception. In other words, if <code>r</code> is not returned, its + reference count must be decremented; if another existing object is + returned, its reference count must be incremented.</td> + </tr> + <tr> + <td valign="top"><code>P::extract_return_type</code></td> + + <td>A model of <a href= + "../../../mpl/doc/refmanual/metafunction.html">Metafunction</a>.</td> + + <td>An MPL unary <a href= + "../../../mpl/doc/refmanual/metafunction.html">Metafunction</a> used extract the return type from a given signature. By default it is derived from mpl::front.</td> + </tr> + </table> + Models of CallPolicies are required to be <a href= + "../../../utility/CopyConstructible.html">CopyConstructible</a>. + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + + <p>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.</p> + </body> +</html> + diff --git a/libs/python/doc/v2/Dereferenceable.html b/libs/python/doc/v2/Dereferenceable.html new file mode 100644 index 000000000..f7c53fd23 --- /dev/null +++ b/libs/python/doc/v2/Dereferenceable.html @@ -0,0 +1,74 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../../../../boost.css"> +<title>Boost.Python - Dereferenceable Concept</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">Dereferenceable Concept</h2> + </td> + </tr> +</table> +<hr> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#concept-requirements">Concept Requirements</a></dt> + <dl class="page-index"> + <dt><a href="#Dereferenceable-concept">Dereferenceable Concept</a></dt> + </dl> +</dl> + +<h2><a name="introduction"></a>Introduction</h2> + +<p>Instances of a Dereferenceable type can be used like a pointer to access an lvalue. + +<h2><a name="concept-requirements"></a>Concept Requirements</h2> +<h3><a name="Dereferenceable-concept"></a>Dereferenceable Concept</h3> + +<p>In the table below, <code><b>T</b></code> is a model of +Dereferenceable, and <code><b>x</b></code> denotes an object of +type <code>T</code>. In addition, all pointers are Dereferenceable. + +<table summary="Dereferenceable expressions" border="1" cellpadding="5"> + + <tr> + <td><b>Expression</b></td> + <td><b>Result</b></td> + <td><b>Operational Semantics</b></td> + </tr> + + <tr> + <td><code>get_pointer(x)</code></td> + <td>convertible to <code><a href="pointee.html#pointee-spec">pointee</a><T>::type*</code> + <td><code>&*x</code>, or a null pointer + </tr> +<tr> + +</table> + +<hr> +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 18 December, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002-2003. </i> + +<p>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. +</body> +</html> diff --git a/libs/python/doc/v2/Extractor.html b/libs/python/doc/v2/Extractor.html new file mode 100644 index 000000000..441ca38b3 --- /dev/null +++ b/libs/python/doc/v2/Extractor.html @@ -0,0 +1,96 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../../../../boost.css"> +<title>Boost.Python - Extractor Concept</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">Extractor Concept</h2> + </td> + </tr> +</table> +<hr> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#concept-requirements">Concept Requirements</a></dt> + <dl class="page-index"> + <dt><a href="#Extractor-concept">Extractor Concept</a></dt> + </dl> + <dt><a href="#notes">Notes</a></dt> +</dl> + +<h2><a name="introduction"></a>Introduction</h2> + +<p>An Extractor is a class which Boost.Python can use to extract C++ +objects from Python objects, and is typically used by facilities that +define <code>from_python</code> conversions for +"traditional" Python extension types. + +<h2><a name="concept-requirements"></a>Concept Requirements</h2> +<h3><a name="Extractor-concept"></a>Extractor Concept</h3> + +<p>In the table below, <code><b>X</b></code> denotes a model of +Extractor and <code><b>a</b></code> denotes an instance of a Python +object type. + +<table summary="Extractor expressions" border="1" cellpadding="5"> + + <tr> + <td><b>Expression</b></td> + <td><b>Type</b></td> + <td><b>Semantics</b></td> + </tr> + + <tr> + <td valign="top"><code>X::execute(a)</code></td> + <td>non-void + <td>Returns the C++ object being extracted. The + <code>execute</code> function must not be overloaded. + </tr> + + <tr> + <td valign="top"><code>&a.ob_type</code> + <td><code><a + href="http://www.python.org/doc/2.2/ext/dnt-type-methods.html">PyTypeObject</a>**</code> + <td>Points to the <code>ob_type</code> field of an object which is + layout-compatible with <code>PyObject</code> + </tr> + + </tr> + +</table> + +<h2><a name="notes"></a>Notes</h2> + +Informally, an Extractor's <code>execute</code> member must be a +non-overloaded static function whose single argument is a Python +object type. Acceptable Python object types include those publicly (and +unambiguously) derived from <code>PyObject</code>, and POD types which +are layout-compatible with PyObject. + +<hr> +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> + +<p>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. +</body> +</html> diff --git a/libs/python/doc/v2/HolderGenerator.html b/libs/python/doc/v2/HolderGenerator.html new file mode 100644 index 000000000..58b4265af --- /dev/null +++ b/libs/python/doc/v2/HolderGenerator.html @@ -0,0 +1,74 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../../../../boost.css"> +<title>Boost.Python - Holder Concept</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">HolderGenerator Concept</h2> + </td> + </tr> +</table> +<hr> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#concept-requirements">Concept Requirements</a></dt> + <dl class="page-index"> + <dt><a href="#HolderGenerator-concept">HolderGenerator Concept</a></dt> + </dl> +</dl> + +<h2><a name="introduction"></a>Introduction</h2> + +<p>A HolderGenerator is a unary metafunction class which returns types +suitable for holding instances of its argument in a wrapped C++ class +instance. + +<h2><a name="concept-requirements"></a>Concept Requirements</h2> +<h3><a name="HolderGenerator-concept"></a>HolderGenerator Concept</h3> + +<p>In the table below, <code><b>G</b></code> denotes an type which +models HolderGenerator, and <code><b>X</b></code> denotes a class +type. + +<table summary="Holder expressions" border="1" cellpadding="5"> + + <tr> + <td><b>Expression</b></td> + <td><b>Requirements</b></td> + </tr> + + <tr> + <td valign="top"><code>G::apply<X>::type</code></td> + <td>A concrete subclass of <a + href="instance_holder.html#instance_holder-spec">instance_holder</a> + which can hold objects of type <code>X</code>. + </tr> +</table> + +<hr> +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> + +<p>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. +</body> +</html> diff --git a/libs/python/doc/v2/Jun2002.html b/libs/python/doc/v2/Jun2002.html new file mode 100644 index 000000000..db1fc25c6 --- /dev/null +++ b/libs/python/doc/v2/Jun2002.html @@ -0,0 +1,229 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - June 2002 Progress Report</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">June 2002 Progress Report</h2> + </td> + </tr> +</table> +<hr> +<h2>Contents</h2> +<dl class="index"> + <dt><a href="#intro">Introduction</a></dt> + <dt><a href="#handle"><code>handle<T></code></a></dt> + <dt><a href="#object"><code>object</code></a></dt> + <dl class="index"> + <dt><a href="#operators"><code>object</code> operators</a></dt> + <dt><a href="#conversions"><code>object</code> conversions</a></dt> + </dl> + <dt><a href="#list"><code>list</code></a></dt> + <dt><a href="#numerics"><code>Numerics</code></a></dt> + <dt><a href="#community">Community</a></dt> + <dt><a href="#next">What's Next</a></dt> +</dl> + +<h2><a name="intro">Introduction</a></h2> + +July was mostly focused on allowing expressive manipulation of +individual Python objects, or what Ralf Grosse-Kunstleve calls +"Writing Python in C++". The work began with this <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001311.html">posting</a>, +which outlines the issues and intention. + +<h2><a name="handle"><code>handle<T></code></a></h2> + +The most basic element needed was a replacement for the +<code>reference<></code> class template and the +<code>ref</code> typedef from Boost.Python v1, a simple smart +pointer to a Python object. The old v1 typedef +"<code>ref</code>" (for +<code>reference<PyObject></code>) had to be retired because I +thought it would be too confusing given the importance of <code><a +href="../../../bind/ref.html">boost::ref</a>()</code> to this +library. I began a <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001311.html">discussion</a>of +possible names, and it was eventually <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001337.html">decided</a> +to rename <code>reference</code> to <code>handle</code> and supply a +default argument so that <code>ref</code> could be spelled +<code>handle<></code> without an additional typedef. There +were also some interface changes to make it safer and more-efficient +to interface with the raw +<code>PyObject*</code>s forced on us by Python's 'C' API. A +discussion of those protocols can be found <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001401.html">here</a>. + +<h2><a name="handle"><code>object</code></a></h2> + +It is intended that users will seldom need or want to work with +<code>handle<></code>; its major distinguishing features are +that it gives direct access to the underlying object representation +through <code>operator*</code> and <code>operator-></code>, and +that can be <code>NULL</code>, both sources of danger. Instead the +library provides a class called <code>object</code>, which +encapsulates a valid Python object and provides a similar interface to +Python's. + +<h3><a name="operators"><code>object</code> operators</a></h3> + +The first challenge was to provide support for object manipulations +using a Python-like syntax, mostly in the form of operator overloads: + +<table border="1"> +<tr><th>Python <th>C++ + +<tr> + <td><code>y = x.foo</code> <td><code>y = x.attr("foo"); +<tr> + <td><code>x.foo = 1</code> <td><code>x.attr("foo") = 1; + +<tr> + <td><code>y = x[z]</code> <td><code>y = x[z]; +<tr> + <td><code>x[z] = 1</code> <td><code>x[z] = 1; + +<tr> + <td><code>y = x[3:-1]</code> <td><code>y = x.slice(3,-1); + +<tr> + <td><code>y = x[3:]</code> <td><code>y = x.slice(3,_); + +<tr> + <td><code>y = x[:-2]</code> <td><code>y = x.slice(_,-2); + +<tr> + <td><code>z = x(1, y)</code> <td><code>z = x(1, y); +<tr> + <td><code>z = x.f(1, y)</code> <td><code>z = x.attr("f")(1, y); + +<tr> + <td><code>not x</code> <td><code>!x + +<tr> + <td><code>x and y</code> <td><code>x and y +</table> + +I'm still a unsatisfied with the interface for attribute access. There +original proposal used a syntax like this one: +<pre> +y = x._("foo"); +x._("foo") = 1; +</pre> + +which was only marginally better than what we've got. Niki Spahiev +then <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001447.html">pointed +out</a> a potential conflict with the macro which GNU Gettext <a +href="http://www.gnu.org/manual/gettext/html_mono/gettext.html#SEC6">suggests</a> +people define. This unfortunate state of affairs forced us into using +<code>attr</code> instead. I'd still like to find a better interface, +but the lack of overloadable C++ operators which aren't already used +in Python is an obstacle. The comma operator is still a possibility, +but it has the wrong precedence: +<pre> +y = x,"foo" // error +x,"foo" = 1; // error + +y = (x,"foo"); // ok +(x,"foo") = 1; // ok +</pre> + +Well, I guess we could consider adding that to the interface without +removing <code>attr()</code>, to see how it plays out... + +<h3><a name="operators"><code>object</code> conversions</a></h3> + +The <code>object</code> class also provided an opportunity to replace +Boost.Python v1's <code>to_python()</code> as a user-level +interface. Instead, <code>object</code> has a templated constructor +which can be used to convert any C++ object to Python using the same +underlying mechanisms used for the arguments to <code><a +href="call.html">call</a><></code>. + +<p>Incidentally, the implementation of operator and conversion support +for object uncovered an inordinate number of compiler bugs in our +targeted platforms. It was a lot more "interesting" than it +should have been. + +<h2><a name="list"><code>list</code></a></h2> + +With <code>object</code> implemented, it was time to begin replacing +the ad-hoc implementations of <code>list</code>, <code>string</code>, +and <code>dictionary</code> supplied by Boost.Python v1 with something +more robust. I started with <code>list</code> as an example. Because +<code>object</code> already provides all of the requisite operators, +publicly deriving <code>list</code> from object seemed like a good +choice. The remaining issues were what do do about the one-argument +list constructor (which in Python attempts to convert its argument to +a list), and how to deal converting with <code>list</code> arguments +to wrapped functions. Some of the issues are laid out in <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001551.html">this +thread</a>. Ultimately, it was decided that <code>list(x)</code> +should do the same thing in C++ as in Python (conversion), while +<code>list</code> arguments should only match Python +<code>list</code>s (and <code>list</code> subclasses). The +implementation worked well, and provided a <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001586.html">roadmap</a> +for the protocol to be used for implementation of the other built-in +types. + +<h2><a name="numerics">Numerics</a></h2> + +Support for C++ <code>long long</code> and <code>unsigned long +long</code> +(and <code>__int64</code> on MSVC) to/from python conversions was +added this month. We also improved handling of numeric overflows when +converting, e.g., a Python int to a type with a more limited range of +representation. + +<h2><a name="community">Community</a></h2> + +<ul> +<li>Ralf W. Grosse-Kunstleve and Nick Sauter have implemented +<a href="http://cci.lbl.gov/boost/">multiplatform nightly +build-and-test</a> runs for Boost.Python V2 at LBL. + +<li>Dave Hawkes has made significant progress on generating the +Python <a +href="http://mail.python.org/pipermail/c++-sig/2002-June/001503.html">built-in +function and API wrappers</a> + +<li>Achim Domma has agreed to take up the job of implementing the +<code>str</code>, <code>dict</code>, and <code>tuple</code> classes. +</ul> + +Deep thanks to all the Boost.Python contributors! This project +wouldn't be possible without your participation. + + <h2><a name="next">What's Next</a></h2> + +As I write this we are already well into the month of July, so I +suggest you consult the <a +href="http://mail.python.org/pipermail/c++-sig/2002-July/">Mailing +List Archive</a> if you want to know what's been happening. Otherwise +you'll just have to wait till next month (hopefully the beginning). + +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> diff --git a/libs/python/doc/v2/Mar2002.html b/libs/python/doc/v2/Mar2002.html new file mode 100644 index 000000000..97444d229 --- /dev/null +++ b/libs/python/doc/v2/Mar2002.html @@ -0,0 +1,237 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - March 2002 Progress Report</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">March 2002 Progress Report</h2> + </td> + </tr> +</table> +<hr> +<h2>Contents</h2> +<dl class="index"> + <dt><a href="#accomplishments">Accomplishments</a></dt> + <dl class="index"> + <dt><a href="#calling_python">Calling Python from C++</a></dt> + <dt><a href="#virtual_functions">Virtual Functions</a></dt> + <dt><a href="#abstract_classes">Abstract Classes</a></dt> + <dt><a href="#implicit_conversions">C++ Implicit Conversions</a></dt> + <dt><a href="#data_members">C++ Data Members</a></dt> + <dt><a href="#miscellaneous">Miscellaneous</a></dt> + </dl> + + <dt><a href="#future">The Near future</a></dt> + + <dt><a href="#notes">Notes</a></dt> + +</dl> + +<h2><a name="accomplishments">Accomplishments</a></h2> + +March was mostly devoted to the reimplementation of features from +Boost.Python v1, and some new features. Re-examination of the features +from Boost.Python v1 allowed me to make significant improvements. + +<h3><a name="calling_python">Calling Python from C++</a></h3> + +The ability to call Python from C++ is crucial for virtual function +support. Implementing this feature well for V2 proved to be more +interesting than I expected. You can review most of the relevant +design decisions +<a href="callbacks.txt">here</a>. + +<p> +One point which <i>isn't</i> emphasized in that document is that there +are subtle differences in the way <code>from_python</code> conversions +work when used for C++ function arguments and Python function return +values. In particular, while <code>T const&</code> arguments may +invoke rvalue converters, a reference-to-const return value requires +an lvalue converter, since a temporary conversion result would leave +the returned reference dangling. + +<p>I'm not particularly pleased with the current callback interface, +since it usually results in constructs like: +<pre> +<u>return returning</u><X&>::call(f, obj); +</pre> +However, I think the following may be possible and I plan to investigate: +<pre> +return apply<X&>(f, obj); +</pre> +I'm open to suggestion for better names (and syntaxes)! + +<h3><a name="virtual_functions">Virtual Functions</a></h3> + +Once Python callbacks were implemented, it was just a short step to +implementing virtual functions. Python extension class exposing a C++ +class whose virtual functions are overridable in Python must actually +hold a C++ instance of a class <i>derived</i> from the one exposed to +Python. Needing some way for users to specify that class, I added an +optional template argument to <code>value_holder_generator</code> and +<code>pointer_holder_generator<></code> to specify the class +actually held. This move began to put pressure on the +<code>class_<></code> interface, since the need for the user to +produce complicated instantations of +<code>class_<></code> was increased: + +<pre> +class<Foo, bases<>, value_holder_generator<Foo_callback> >("Foo") +.def("hello", &Foo::hello) +... +</pre> + +<h3><a name="abstract_classes">Abstract Classes</a></h3> + +Normally when a C++ class is exposed to Python, the library registers +a conversion function which allows users to wrap functions returning +values of that type. Naturally, these return values are temporaries, +so the conversion function must make a copy in some +dynamically-allocated storage (a "holder") which is managed +by the corresponding Python object. + +<p>Unfortunately, in the case of abstract classes (and other types +without a publicly-accessible copy constructor), instantiating this +conversion function causes a compilation error. In order to support +non-copyable classes, there had to be some way to prevent the library +from trying to instantiate the conversion function. The only practical +approach I could think of was to add an additional template parameter +to the <code>class_<></code> interface. When the number of +template parameters with useful defaults begins to grow, it is often +hard to choose an order which allows users to take advantage of the +defaults. + +<p> + +This was the straw that broke the +<code>class_<></code> interface's back and caused the redesign +whose outcome is detailed <a +href="http://mail.python.org/pipermail/c++-sig/2002-March/000892.html">here</a>. +The approach allows the user to supply the optional parameters in an +arbitrary order. It was inspired by the use of <a +href="../../../utility/iterator_adaptors.htm#named_tempalte_parameters">named +template parameters</a> in the <a +href="../../../utility/iterator_adaptors.htm">Boost Iterator Adaptor +Library</a>, though in this case it is possible to deduce the meaning +of the template parameters entirely from their type properties, +resulting in a simpler interface. Although the move from a +policy-based design to what resembles a configuration DSL usually +implies a loss of flexibility, in this case I think any costs are far +outweighed by the advantages. + +<p>Note: working around the limitations of the various compilers I'm +supporting was non-trivial, and resulted in a few messy implementation +details. It might be a good idea to switch to a more-straightforward +approach once Metrowerks CodeWarrior Pro8 is released. + +<h3><a name="implicit_conversions">C++ Implicit Conversions</a></h3> + +Support for C++ implicit conversion involves creating +<code>from_python</code> converters for a type <code>U</code> which in +turn use <code>from_python</code> converters registered for a type +<code>T</code> where there exists a implicit conversion from +<code>T</code> to <code>U</code>. The current implementation is +subject to two inefficiencies: +<ol> + +<li>Because an rvalue <code>from_python</code> converter produces two +pieces of data (a function and a <code>void*</code>) from its +<code>convertible()</code> function, we end up calling the function +for <code>T</code> twice: once when the converter is looked up in the +registry, and again when the conversion is actually performed. + +<li>A vector is used to mark the "visited" converters, preventing +infinite recursion as <code>T</code> to +<code>U</code> and <code>U</code> to <code>T</code> converters +continually search through one-another. + +</ol> + +I consider the former to be a minor issue. The second may or may not +prove to be computationally significant, but I believe that +architecturally, it points toward a need for more sophisticated +overload resolution. It may be that we want CLOS-style multimethod +dispatching along with C++ style rules that prevent more than one +implicit conversion per argument. + +<h3><a name="data_members">C++ Data Members</a></h3> + +To supply the ability to directly access data members, I was able to +hijack the new Python <a +href="http://www.python.org/2.2/descrintro.html#property">property</a> +type. I had hoped that I would also be able to re-use the work of <a +href="make_function.html">make_function</a> to create callable python +objects from C++ functions which access a data member of a given +class. C++ facilities for specifying data member pointer non-type +template arguments require the user to explicitly specify the type of +the data member and this under-utilized feature is also not +well-implemented on all compilers, so passing the member pointer as a +runtime value is the only practical approach. The upshot is that any +such entity would actually have to be a function <i>object</i>, and I +haven't implemented automatic wrapping of C++ callable function +objects yet, so there is less re-use in the implementation than I'd +like. I hope to implement callable object wrapping and refactor this +code one day. I also hope to implement static data member support, +for which Python's property will not be an appropriate descriptor. + +<h3><a name="miscellaneous">Miscellaneous</a></h3> +<ul> +<li>Moved <code>args<></code> and <code>bases<></code> from unnamed namespace to <code>boost::python</code> in their own header files. +<li>Convert <code>NULL</code> pointers returned from wrapped C++ functions to <code>None</code>. +<li>Improved some compile-time error checks. +<li>Eliminated <code>boost/python/detail/eval.hpp</code> in favor of +more-general <code>boost/mpl/apply.hpp</code>. +<li>General code cleanup and refactoring. +<li>Works with Microsoft Visual C++ 7.0 +<li>Warning suppression for many compilers +<li>Elegant interface design for exporting <code>enum</code> types. +</ul> +<hr> + +<h2><a name="future">The Near Future</a></h2> + +Before April 15th I plan to +<ol> +<li>Document all implemented features +<li>Implement a <code>CallPolicy</code> interface for constructors of wrapped +classes +<li>Implement conversions for <code>char</code> types. +<li>Implement automated code generation for all headers containing +families of overloaded functions to handle arbitrary arity. +</ol> + +I also hope to implement a mechanism for generating conversions +between arbitrary Python sequences and C++ containers, if time permits +(and others haven't already done it)! + +<h2><a name="notes">Notes</a></h2> + +The older version of KCC used by Kull is generating lots of warnings +about a construct I use to instantiate static members of various class +templates. I'm thinking of moving to an idiom which uses a function +template to suppress it, but worry about bloating the size of debug +builds. Since KCC users may be moving to GCC, I'm not sure that it's +worth doing anything about it. + +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> diff --git a/libs/python/doc/v2/May2002.html b/libs/python/doc/v2/May2002.html new file mode 100644 index 000000000..5e5b6aaa4 --- /dev/null +++ b/libs/python/doc/v2/May2002.html @@ -0,0 +1,311 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - May 2002 Progress Report</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">May 2002 Progress Report</h2> + </td> + </tr> +</table> +<hr> +<h2>Contents</h2> +<dl class="index"> + <dt><a href="#intro">Introduction</a></dt> + <dt><a href="#features">New Features</a></dt> + <dl> + <dt><a href="#aix_shared">Shared Library Support for AIX</a><dd> + <dt><a href="#class_enhancements">Class Enhancements</a><dd> + <dl> + <dt><a href="#operators">Operators</a><dd> + <dt><a href="#iterators">Iterators</a><dd> + <dt><a href="#properties">Properties</a><dd> + <dt><a href="#setattr">setattr</a><dd> + <dt><a href="#module">__module__ Attribute</a><dd> + </dl> + <dt><a href="#back_reference">back_reference</a><dd> + </dl> + + <dt><a href="#documentation">Documentation</a></dt> + <dt><a href="#misc">Miscellaneous</a></dt> + <dl class="index"> + <dt><a href="#converters">Converters</a></dt> + <dt><a href="#checkins">Checkins Mailing List</a></dt> + <dt><a href="#shared">Shared Libraries</a></dt> + </dl> + + <dt><a href="#next">What's Next</a></dt> +</dl> + +<h2><a name="intro">Introduction</a></h2> + +Aside from library development, work on Boost.Python in May was +focused on reducing the support burden. In recent weeks, responding to +requests for support, espcially surrounding building the library, had +begun to impede progress on development. There was a major push to +release a stable 1.28.0 of Boost, including documentation of <a +href="../../../../tools/build/v1/build_system.htm">Boost.Build</a> and specific +<a href="../building.html">instructions</a> for building Boost.Python +v1. The documentation for Boost.Python v2 was also updated as +described <a href="#documentation">here</a>. + +<h2><a name="features">New Features</a></h2> + + <h3><a name="aix_shared">Shared Library Support for AIX</a></h3> + + The Kull group required the ability to build and test Boost.Python + extensions on AIX, a platform with "creatively designed" + shared library semantics. Making this work was a multi-pronged + effort, involving changes to Boost.Build and some great research by + Martin Casado which uncovered the key mechanism required to allow + shared libraries to use functions from the Python executable. The + current solution used in Boost.Build relies on a <a + href="../../../../tools/build/v1/gen_aix_import_file.py">Python + Script</a> as part of the build process. This is not a problem for + Boost.Python, as Python will be available. However, the commands + issued by the script are so simple that a 100%-pure-Boost.Jam + solution is surely possible. Linking on AIX is sufficiently + interesting to have skewed the Boost.Python development schedule a + bit. + + <h3><a name="class_enhancements">Class Enhancements</a></h3> + + <h4><a name="operators">Operators</a></h4> + +Support for exposing C++ operators and functions as the corresponding +Python special methods was added. Thinking that the Boost.Python +v1 interface was a little too esoteric (especially the use of +<code>left_operand<...>/right_operand<...></code> for +asymmetric operands), I introduced a simple form of <a +href="http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html">expression +templates</a> which allow users to simply write the expressions that +should be wrapped, as in this <a href="operators.html#examples">example</a>. + + <h4><a name="iterators">Iterators</a></h4> + +Python iterator support as required by the Kull project resulted in a +highly flexible interface allowing: + +<dl> + +<dt>Direct exposure of a class' <code>begin()</code> and +<code>end()</code> functions: + +<pre> + ... + .def("__iter__", iterator<list_int>()) +</pre> +<dd> + +<dt>Creation of iterators from member functions... +<pre> + ... + .def("__iter__" + , range(&my_class::x_begin, &my_class::x_end)) + ) +</pre> +<dd> + +<dt>...and member data: +<pre> + ... + .def("__iter__" + , range(&std::pair<char*,char*>::first, &std::pair<char*,char*>::second)) + ) +</pre> +<dd> + +<dt>The ability to specify <a +href="CallPolicies.html">CallPolicies</a>, e.g. to prevent copying of +heavyweight values: + +<pre> + ... + .def("__iter__", + , range<return_value_policy<copy_non_const_reference> >( + &my_sequence<heavy>::begin + , &my_sequence<heavy>::end)) +</pre> +<dd> + +</dl> + + <h4><a name="properties">Properties</a></h4> + +The Kull iteration interfaces also required the ability to iterate +over a sequence specified by an instance's attribute: +<pre> +>>> f = field() +>>> for e in f.elements: +... print e, +</pre> + +This forced the exposure of the <a + href="http://www.python.org/2.2/descrintro.html#property"><code>property</code></a> + interface used internally to implement the data member exposure + facility described in <a + href="Mar2002.html#data_members">March</a>. Properties are an + incredibly useful idiom, so it's good to be able to provide them + at little new development cost. + + <h4><a name="setattr">setattr</a></h4> + +<code>class_<></code> acquired a <code>setattr</code> member +function which allows users to easily add new Python objects as class +attributes. + + <h4><a name="module">__module__ Attribute</a></h4> + +Ralf Grosse-Kunstleve has been working on pickling support for v2. To +make it work correctly, he had to make sure that a class' +<code>__module__</code> attribute was set correctly. + +<h3><a name="back_reference"><code>back_reference</code></a></h3> + +The new <code>back_reference<T></code> template can be used as a +function parameter when the user needs access to both a <code>T</code> +argument and to the Python object which manages it. The function will +only match in the overload resolution process if it would match the +same function signature with <code>T</code> substituted for +<code>back_reference<T></code>. This feature is not yet +documented. + +<h2><a name="documentation">Documentation</a></h2> + +In a major effort to prepare Boost.Python v2 to replace v1, many pages +of new reference documentation were added: + +<blockquote> + +<dl> + <dt><a href="CallPolicies.html">CallPolicies.html</a><dd> + <dt><a href="Dereferenceable.html">Dereferenceable.html</a><dd> + <dt><a href="Extractor.html">Extractor.html</a><dd> + <dt><a href="HolderGenerator.html">HolderGenerator.html</a><dd> + <dt><a href="ResultConverter.html">ResultConverter.html</a><dd> + <dt><a href="call_method.html">call_method.html</a><dd> + <dt><a href="callbacks.html">callbacks.html</a><dd> + <dt><a href="data_members.html">data_members.html</a><dd> + <dt><a href="has_back_reference.html">has_back_reference.html</a><dd> + <dt><a href="implicit.html">implicit.html</a><dd> + <dt><a href="instance_holder.html">instance_holder.html</a><dd> + <dt><a href="operators.html">operators.html</a><dd> + <dt><a href="ptr.html">ptr.html</a><dd> + <dt><a href="type_id.html">type_id.html</a><dd> + <dt><a href="with_custodian_and_ward.html">with_custodian_and_ward.html</a><dd> +</dl> + +</blockquote> +Major updates were made to the following pages: + + +<blockquote> +<dl> + <dt><a href="call.html">call.html</a><dd> <dt>updated<dd> + <dt><a href="class.html">class.html</a><dd> + <dt><a href="reference.html">reference.html</a><dd> +</dl> +</blockquote> + + As usual, careful documentation forces one to consider the + interface again, and there were many interface changes + associated with this effort, including the elevation of the + following components from implementation detail to + first-class library citizen: + +<blockquote> +<dl> + <dt>type_id.hpp<dd> + <dt>pointee.hpp<dd> + <dt>lvalue_from_pytype.hpp<dd></dl> +</dl> +</blockquote> + +<h2><a name="misc">Miscellaneous</a></h2> + + <h3><a name="converters">Converters</a></h3> + +It appears that the world of C++ <==> Python conversion rules is +an endlessly-rich area of exploration. Completing the conversions for +<code>char</code> and <code>char const*</code> types, as described at +the end of <a href="Apr2002.html#missing">April's report</a>, +uncovered some interesting new shades to the problem. It turns out to +be worth distinguishing mutable and immutable lvalue conversions, +because despite the fact that Python doesn't understand +<code>const</code>, it does understand immutability (c.f. Python +strings, which expose an immutable <code>char</code> pointer). It is +also worth recognizing types which represent lvalue <i>sequences</i>, +to prevent Python <code>"foobar"</code> from being silently +truncated to C++ <code>'f'</code>. More details on this insight can be +found in the mailing list <a +href="http://mail.python.org/pipermail/c++-sig/2002-May/001023.html"> +archive</a>. I don't plan to do anything about this immediately, but I +do think it's the right direction to go in the long run. + + <h3><a name="checkins">Checkins Mailing List</a></h3> + +In order to better coordinate changes made by multiple developers, I +enabled <a +href="http://sourceforge.net/docman/display_doc.php?docid=772&group_id=1">syncmail</a> +for the Boost.Python CVS trees, and established an associated <a +href="http://lists.sourceforge.net/lists/listinfo/boost-python-cvs">mailing +list</a>. Subscribe to this list to receive notices of each new +checkin. + + <h3><a name="shared">Shared Libraries</a></h3> + +Beyond the vagaries of dynamic linking on AIX, I have been +participating in a more-general discussion of dynamic linking for +C++. Needless to say, C++ dynamic linking is of critical importance to +Boost.Python: all extension modules are normally built as shared +libraries, and Boost.Python extension modules share a common library +as well. + +In fact, there are at least two separate conversations. One +in the C++ standard extensions mailing list concerns what can be +standardized for C++ and shared libraries; the other, mostly on the <a +href="http://gcc.gnu.org/ml/gcc/">gcc</a> mailing list, concerns the +behavior of GCC on Posix/ELF platforms. + +Some of the GCC threads are here: + +<blockquote> +<a +href="http://gcc.gnu.org/ml/gcc/2002-05/msg02002.html">http://gcc.gnu.org/ml/gcc/2002-05/msg02002.html</a><br> +<a +href="http://gcc.gnu.org/ml/gcc/2002-05/msg02945.html">http://gcc.gnu.org/ml/gcc/2002-05/msg02945.html</a><br> +<a href="http://gcc.gnu.org/ml/gcc/2002-05/msg01758.html">http://gcc.gnu.org/ml/gcc/2002-05/msg01758.html</a> +</blockquote> + + <h2><a name="next">What's Next</a></h2> + +Development is focused on what's needed to be able to retire +Boost.Python v1. At the moment, that means deciding the user-friendly +interfaces for to_/from_python conversion, and formally exposing the +Python object smart pointers and object wrapper classes. Quite a few +questions have also been showing up recently about how to embed Python +with Boost.Python, and how to link with it statically; the solutions +to these issues will probably have to be formalized before long. + +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> diff --git a/libs/python/doc/v2/ObjectWrapper.html b/libs/python/doc/v2/ObjectWrapper.html new file mode 100644 index 000000000..7962e69fa --- /dev/null +++ b/libs/python/doc/v2/ObjectWrapper.html @@ -0,0 +1,153 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - ObjectWrapper Concept</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">ObjectWrapper and TypeWrapper Concepts</h2> + </td> + </tr> + </table> + <hr> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#concept-requirements">Concept Requirements</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#ObjectWrapper-concept">ObjectWrapper Concept</a></dt> + + <dt><a href="#TypeWrapper-concept">TypeWrapper Concept</a></dt> + </dl> + </dd> + + <dt><a href="#caveat">Caveat</a></dt> + </dl> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>This page defines two concepts used to describe classes which manage a + Python objects, and which are intended to support usage with a + Python-like syntax.</p> + + <h2><a name="concept-requirements"></a>Concept Requirements</h2> + + <h3><a name="ObjectWrapper-concept"></a>ObjectWrapper Concept</h3> + Models of the ObjectWrapper concept have <a href= + "object.html#object-spec">object</a> as a publicly-accessible base class, + and are used to supply special construction behavior and/or additional + convenient functionality through (often templated) member functions. + Except when the return type <code>R</code> is itself an <a href= + "#TypeWrapper-concept">TypeWrapper</a>, a member function invocation of + the form +<pre> +x.<i>some_function</i>(<i>a<small>1</small>, a<small>2</small>,...a<small>n</small></i>) +</pre> + always has semantics equivalent to: +<pre> +<a href= +"extract.html#extract-spec">extract</a><R>(x.attr("<i>some_function</i>")(<a + href= +"object.html#object-spec-ctors">object</a>(<i>a<small>1</small></i>), <a +href= +"object.html#object-spec-ctors">object</a>(<i>a<small>2</small></i>),...<a +href="object.html#object-spec-ctors">object</a>(<i>a<small>n</small></i>)))() +</pre> + When the <code>R</code> is an <a href= + "#TypeWrapper-concept">TypeWrapper</a>, the result type may be + constructed by taking direct posession of: +<pre> +x.attr("<i>some_function</i>")(<a href= +"object.html#object-spec-ctors">object</a>(<i>a<small>1</small></i>), <a + href= +"object.html#object-spec-ctors">object</a>(<i>a<small>2</small></i>),...<a + href= +"object.html#object-spec-ctors">object</a>(<i>a<small>n</small></i>)).ptr() +</pre> + [see <a href="#caveat">caveat</a> below] + + <h3><a name="TypeWrapper-concept"></a>TypeWrapper Concept</h3> + TypeWrapper is a refinement of ObjectWrapper which is associated with a + particular Python type <code>X</code>. For a given TypeWrapper + <code>T</code>, a valid constructor expression +<pre> +T(<i>a<small>1</small>, a<small>2</small>,...a<small>n</small></i>) +</pre> + builds a new <code>T</code> object managing the result of invoking + <code>X</code> with arguments corresponding to +<pre> +<a href= +"object.html#object-spec-ctors">object</a>(<i>a<small>1</small></i>), <a + href= +"object.html#object-spec-ctors">object</a>(<i>a<small>2</small></i>),...<a + href= +"object.html#object-spec-ctors">object</a>(<i>a<small>n</small></i>) +</pre> + +When used as arguments to wrapped C++ functions, or as the template +parameter to <code><a +href="extract.html#extract-spec">extract</a><></code>, only +instances of the associated Python type will be considered a match. + + <h3><a name="caveat">Caveat</a></h3> + The upshot of the special member function invocation rules when the + return type is a TypeWrapper is that it is possible for the returned + object to manage a Python object of an inappropriate type. This is not + usually a serious problem; the worst-case result is that errors will be + detected at runtime a little later than they might otherwise be. For an + example of how this can occur, note that the <code><a href= + "dict.html#dict-spec">dict</a></code> member function <code>items</code> + returns an object of type <code><a href= + "list.html#list-spec">list</a></code>. Now suppose the user defines this + <code>dict</code> subclass in Python: +<pre> +>>> class mydict(dict): +... def items(self): +... return tuple(dict.items(self)) # return a tuple +</pre> + Since an instance of <code>mydict</code> is also an instance of + <code>dict</code>, when used as an argument to a wrapped C++ function, + <code><a href="dict.html#dict-spec">boost::python::dict</a></code> can + accept objects of Python type <code>mydict</code>. Invoking + <code>items()</code> on this object can result in an instance of <code><a + href="list.html#list-spec">boost::python::list</a></code> which actually + holds a Python tuple. Subsequent attempts to use list methods (e.g. + <code>append</code>, or any other mutating operation) on this object will + raise the same exception that would occur if you tried to do it from + Python. + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/ResultConverter.html b/libs/python/doc/v2/ResultConverter.html new file mode 100644 index 000000000..be53a9b97 --- /dev/null +++ b/libs/python/doc/v2/ResultConverter.html @@ -0,0 +1,124 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../../../../boost.css"> +<title>Boost.Python - ResultConverter Concept</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">ResultConverter Concept</h2> + </td> + </tr> +</table> +<hr> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#concept-requirements">Concept Requirements</a></dt> + <dd> + <dl class="page-index"> + <dt><a href="#ResultConverter-concept">ResultConverter Concept</a></dt> + <dt><a href="#ResultConverterGenerator-concept">ResultConverterGenerator Concept</a></dt> + </dl> + </dd> +</dl> + +<h2><a name="introduction"></a>Introduction</h2> + +<p>A ResultConverter for a type <code>T</code> is a type whose +instances can be used to convert C++ return values of type +<code>T</code> <code>to_python</code>. A ResultConverterGenerator is +an MPL unary metafunction class which, given the return type of a C++ +function, returns a ResultConverter for that type. ResultConverters in +Boost.Python generally inspect library's registry of converters to +find a suitable converter, but converters which don't use the registry +are also possible. + +<h2><a name="concept-requirements"></a>Concept Requirements</h2> +<h3><a name="ResultConverter-concept"></a>ResultConverter Concept</h3> + +<p>In the table below, <code><b>C</b></code> denotes a ResultConverter +type for a type <b><code>R</code></b> , <code><b>c</b></code> denotes +an object of type <code><b>C</b></code> , and <code><b>r</b></code> +denotes an object of type <code><b>R</b></code>. + +<table summary="ResultConverter expressions" border="1" cellpadding="5"> + + <tr> + <td><b>Expression</b></td> + <td><b>Type</b></td> + <td><b>Semantics</b></td> + </tr> + + <tr> + <td valign="top"><code>C c;</code></td> + <td> + <td>Constructs a <code>C</code> object. + </tr> + + <tr> + <td valign="top"><code>c.convertible()</code></td> + <td>convertible to <code>bool</code></td> + <td><code>false</code> iff no conversion from any <code>R</code> value + to a Python object is possible.</td> + </tr> + + <tr> + <td valign="top"><code>c(r)</code></td> + <td>convertible to <code>PyObject*</code></td> + <td>A pointer to a Python object corresponding to <code>r</code>, + or <code>0</code> iff <code>r</code> could not be converted + <code>to_python</code>, in which case <a + href="http://www.python.org/doc/current/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a> + should return non-zero.</td> + </tr> + <tr> + <td valign="top"><code>c.get_pytype()</code></td> + <td><code>PyTypeObject const*</code></td> + <td>A pointer to a Python Type object corresponding to result of the conversion, + or <code>0</code>. Used for documentation generation. If <code>0</code> is returned + the generated type in the documentation will be <b>object</b> .</td> + </tr> +</table> + +<h3><a name="ResultConverterGenerator-concept"></a>ResultConverterGenerator Concept</h3> +<p>In the table below, <code><b>G</b></code> denotes a +ResultConverterGenerator type and <code><b>R</b></code> denotes a possible +C++ function return type. + +<table summary="ResultConverterGenerator expressions" border="1" cellpadding="5"> + <tr> + <td><b>Expression</b></td> + <td><b>Requirements</b></td> + </tr> + <tr> + <td valign="top"><code>G::apply<R>::type</code></td> + <td>A ResultConverter type for <code>R</code>.</td> +</table> + +<hr> +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 09 May, 2002 <!--Luann's birthday! --> + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> + +<p>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. +</body> +</html> diff --git a/libs/python/doc/v2/acknowledgments.html b/libs/python/doc/v2/acknowledgments.html new file mode 100644 index 000000000..28f1b1dbd --- /dev/null +++ b/libs/python/doc/v2/acknowledgments.html @@ -0,0 +1,135 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Acknowledgments</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Acknowledgments</h2> + </td> + </tr> + </table> + <hr> + + <p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> is + the architect, designer, and implementor of <b>Boost.Python</b>.</p> + + <p><a href="mailto:brett.calcott@paradise.net.nz">Brett Calcott</a> + contributed and maintains the Visual Studio project files and + documentation.</p> + + <p><a href="mailto:Gottfried.Ganssauge-at-haufe.de">Gottfried + Ganßauge</a> supplied support for opaque pointer conversions, + complete with documentation and a regression test (and I didn't + even have to ask him for those)! + + <p>Joel de Guzman implemented the <a href="overloads.html">default + argument support</a> and wrote the excellent <a href= + "../tutorial/index.html">tutorial documentation</a>.</p> + + <p><a href="http://www.boost.org/people/ralf_w_grosse_kunstleve.htm">Ralf W. + Grosse-Kunstleve</a> implemented the <a href="pickle.html">pickle + support</a>, and has enthusiastically supported the library since its + birth, contributing to design decisions and providing invaluable + real-world insight into user requirements. Ralf has written some <a href= + "faq.html#question2">extensions</a> for converting C++ containers that I + hope will be incorporated into the library soon. He also implemented the + cross-module support in the first version of Boost.Python. More + importantly, Ralf makes sure nobody forgets the near-perfect synergy of + C++ and Python for solving the problems of large-scale software + construction.</p> + + <p><a href="http://www.boost.org/people/aleksey_gurtovoy.htm">Aleksey Gurtovoy</a> + wrote an incredible C++ <a href="http://www.mywikinet.com/mpl">Template + Metaprogramming Library</a> which allows Boost.Python to perform much of + its compile-time magic. In addition, Aleksey very generously contributed + his time and deep knowledge of the quirks of various buggy compilers to + help us get around problems at crucial moments.</p> + + <p><a href="http://www.boost.org/people/paul_mensonides.htm">Paul Mensonides</a>, + building on the work <a href="http://www.boost.org/people/vesa_karvonen.htm">Vesa + Karvonen</a>, wrote a similarly amazing <a href= + "../../../preprocessor/doc/index.html">Preprocessor Metaprogramming + Library</a>, and generously contributed the time and expertise to get it + working in the Boost.Python library, rewriting much of Boost.Python to + use the new preproccessor metaprogramming constructs and helping us to + work around buggy and slow C++ preprocessors.</p> + + <p><a href="mailto:nicodemus-at-globalite.com.br">Bruno da Silva de + Oliveira</a> contributed the ingenious <a + href="../../pyste/index.html">Pyste</a> ("Pie-Steh") + code generator. + + <p><a href="mailto:nickm@sitius.com">Nikolay Mladenov</a> contributed + <code>staticmethod</code> support.</p> + + <p>Martin Casado solved some sticky problems which allow us to build the + Boost.Python shared library for AIX's crazy dynamic linking model.</p> + + <p><a href="mailto:achim@procoders.net">Achim Domma</a> contributed some + of the <a href="reference.html#object_wrappers">Object Wrappers</a> and + HTML templates for this documentation. Dave Hawkes contributed + inspiration for the use of the <code><a href= + "scope.html#scope-spec">scope</a></code> class to simplify module + definition syntax. Pearu Pearson wrote some of the test cases that are in + the current test suite.</p> + + <p>The development of this version of Boost.Python was funded in part by + the <a href="http://www.llnl.gov/">Lawrence Livermore National + Laboratories</a> and by the <a href="http://cci.lbl.gov/">Computational + Crystallography Initiative</a> at Lawrence Berkeley National + Laboratories.</p> + + <p><a href="http://kogs-www.informatik.uni-hamburg.de/~koethe/">Ullrich + Koethe</a> had independently developed a similar system. When he + discovered Boost.Python v1, he generously contributed countless hours of + coding and much insight into improving it. He is responsible for an early + version of the support for function overloading and wrote the support for + reflecting C++ inheritance relationships. He has helped to improve + error-reporting from both Python and C++ (we hope to do as well in v2 + again soon), and has designed the original support for exposing numeric + operators, including a way to avoid explicit coercion by means of + overloading.</p> + + <p>The members of the boost mailing list and the Python community + supplied invaluable early feedback. In particular, Ron Clarke, Mark + Evans, Anton Gluck, Chuck Ingold, Prabhu Ramachandran, and Barry Scott + took the brave step of trying to use Boost.Python while it was still in + early stages of development.</p> + + <p>The first version of Boost.Python would not have been possible without + the support of Dragon Systems, which supported its development and + release as a Boost library.</p> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 26 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/args.html b/libs/python/doc/v2/args.html new file mode 100644 index 000000000..e04720b7e --- /dev/null +++ b/libs/python/doc/v2/args.html @@ -0,0 +1,199 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/args.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/args.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#keyword-expression"><i>keyword-expressions</i></a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#arg-spec">class <code>arg</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#arg-synopsis">class <code>arg</code> + synopsis</a></dt> + + <dt><a href="#arg-ctor">class <code>arg</code> + constructor</a></dt> + + <dt><a href="#arg-operator">class <code>arg</code> template + <code>operator =</code></a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#keyword-expression-operators"><i>Keyword-expression</i> + operator <code>,</code></a></dt> + + <dt><a href="#functions">Functions (deprecated)</a></dt> + + <dd> + <dl class="page-index"> + <dt><code><a href= + "#args-spec">args</a>(</code>...<code>)</code></dt> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Supplies a family of overloaded functions for specifying argument + keywords for wrapped C++ functions.</p> + + <h2><a name="keyword-expression"></a><i>keyword-expressions</i></h2> + + <p>A <b>keyword-expression</b> results in an object which holds a + sequence of <a href="definitions.html#ntbs">ntbs</a>es, and whose type + encodes the number of keywords specified. The <b>keyword-expression</b> + may contain default values for some or all of the keywords it holds</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="arg-spec"></a><code>class arg;</code></h3> + + <p>The objects of class arg are keyword-expressions holding one keyword ( + size one )</p> + + <h4><a name="arg-synopsis"></a>Class <code>arg</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct arg + { + template <class T> + arg &operator = (T const &value); + explicit arg (char const *name){elements[0].name = name;} + }; + +}} +</pre> + + <h4><a name="arg-ctor"></a>Class <code>arg</code> constructor</h4> +<pre> +arg(char const* name); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> The argument must be a <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> Constructs an <code>arg</code> object holding a + keyword with name <code>name</code>.</dt> + </dl> + + <h4><a name="arg-operator"></a>Class <code>arg</code> operator =</h4> +<pre> +template <class T> arg &operator = (T const &value); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> The argument must convertible to python.</dt> + + <dt><b>Effects:</b> Assigns default value for the keyword.</dt> + + <dt><b>Returns:</b> Reference to <code>this</code>.</dt> + </dl> + + <h2><a name="keyword-expression-operators"><i>Keyword-expression</i> + operator <code>,</code></a></h2> +<pre> + <i>keyword-expression</i> operator , (<i>keyword-expression</i>, const arg &kw) const + <i>keyword-expression</i> operator , (<i>keyword-expression</i>, const char *name) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> The argument <code>name</code> must be a <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> Extends the <i>keyword-expression</i> argument with + one more keyword.</dt> + + <dt><b>Returns:</b> The extended <i>keyword-expression</i>.</dt> + </dl> + + <h2><font color="#7F7F7F"><a name="functions"></a>Functions + (deprecated)</font></h2> + + <h3><a name="args-spec"></a><code><font color= + "#7F7F7F">args</font>(</code>...<code>)</code></h3> +<pre> +<font color="#7F7F7F"> <i>unspecified1</i> args(char const*); + <i>unspecified2</i> args(char const*, char const*); + . + . + . + <i>unspecifiedN</i> args(char const*, char const*, ... char const*); +</font> +</pre> + + <dl class="function-semantics"> + <dt><font color="#7F7F7F"><b>Requires:</b> Every argument must be a <a + href="definitions.html#ntbs">ntbs</a>.</font></dt> + + <dt><font color="#7F7F7F"><b>Returns:</b> an object representing a <a + href="#keyword-expression"><i>keyword-expression</i></a> encapsulating + the arguments passed.</font></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> +<pre> +#include <boost/python/def.hpp> +using namespace boost::python; + +int f(double x, double y, double z=0.0, double w=1.0); + +BOOST_PYTHON_MODULE(xxx) +{ + def("f", f + , ( arg("x"), "y", arg("z")=0.0, arg("w")=1.0 ) + ); +} +</pre> + + <p>Revised 01 August, 2003</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002-2003.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/call.html b/libs/python/doc/v2/call.html new file mode 100644 index 000000000..adba2b5fe --- /dev/null +++ b/libs/python/doc/v2/call.html @@ -0,0 +1,85 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - <call.hpp></title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">Header <call.hpp></h2> + </td> + </tr> +</table> +<hr> +<h2>Contents</h2> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#functions">Functions</a></dt> + <dl class="page-index"> + <dt><a href="#call-spec">call</a></dt> + </dl> + + <dt><a href="#examples">Example(s)</a></dt> + +</dl> +<hr> +<h2><a name="introduction"></a>Introduction</h2> +<p> + <code><boost/python/call.hpp></code> defines the <a + href="#call-spec"><code>call</code></a> family of overloaded function + templates, used to invoke Python callable objects from C++. + +<h2><a name="functions"></a>Functions</h2> +<pre> +<a name="call-spec">template <class R, class A1, class A2, ... class A<i>n</i>></a> +R call(PyObject* callable, A1 const&, A2 const&, ... A<i>n</i> const&) +</pre> +<dl class="function-semantics"> + <dt><b>Requires:</b> <code>R</code> is a pointer type, reference + type, or a complete type with an accessible copy constructor</dt> + + <dt><b>Effects:</b> Invokes <code>callable(a1, a2, ...a<i>n</i>)</code> in + Python, where <code>a1</code>...<code>a<i>n</i></code> are the arguments to + <code>call()</code>, converted to Python objects. + <dt><b>Returns:</b> The result of the Python call, converted to the C++ type <code>R</code>.</dt> + +</dt> + <dt><b>Rationale:</b> For a complete semantic description and + rationale, see <a href="callbacks.html">this page</a>. +</dt> +</dl> + +<h2><a name="examples"></a>Example(s)</h2> + +The following C++ function applies a Python callable object to its two +arguments and returns the result. If a Python exception is raised or +the result can't be converted to a <code>double</code>, an exception +is thrown. + +<pre> +double apply2(PyObject* func, double x, double y) +{ + return boost::python::call<double>(func, x, y); +} +</pre> + +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 9 May, 2002 <!-- Luann's birthday! --> + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> diff --git a/libs/python/doc/v2/call_method.html b/libs/python/doc/v2/call_method.html new file mode 100644 index 000000000..e54ffb26a --- /dev/null +++ b/libs/python/doc/v2/call_method.html @@ -0,0 +1,161 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <call_method.hpp></title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <call_method.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#call_method-spec">call_method</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/call_method.hpp></code> defines the <a href= + "#call_method-spec"><code>call_method</code></a> family of overloaded + function templates, used to invoke callable attributes of Python objects + from C++.</p> + + <h2><a name="functions"></a>Functions</h2> +<pre> +<a name= +"call_method-spec">template <class R, class A1, class A2, ... class A<i>n</i>></a> +R call_method(PyObject* self, char const* method, A1 const&, A2 const&, ... A<i>n</i> const&) +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>R</code> is a pointer type, reference type, + or a complete type with an accessible copy constructor</dt> + + <dt><b>Effects:</b> Invokes + <code>self.<i>method</i>(a1, a2, ...a<i>n</i>)</code> in + Python, where <code>a1</code>...<code>a<i>n</i></code> are the + arguments to <code>call_method()</code>, converted to Python objects. + For a complete semantic description, see <a href="callbacks.html">this + page</a>.</dt> + + <dt><b>Returns:</b> The result of the Python call, converted to the C++ + type <code>R</code>.</dt> + + <dt><b>Rationale:</b> <code>call_method</code> is critical to + implementing C++ virtual functions which are overridable in Python, as + shown by the example below.</dt> + </dl> + + <h2><a name="examples"></a>Example(s)</h2> + The following C++ illustrates the use of <code>call_method</code> in + wrapping a class with a virtual function that can be overridden in + Python: + + <h3>C++ Module Definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/utility.hpp> +#include <cstring> + +// class to be wrapped +class Base +{ + public: + virtual char const* class_name() const { return "Base"; } + virtual ~Base(); +}; + +bool is_base(Base* b) +{ + return !std::strcmp(b->class_name(), "Base"); +} + +// Wrapper code begins here +using namespace boost::python; + +// Callback class +class Base_callback : public Base +{ + public: + Base_callback(PyObject* self) : m_self(self) {} + + char const* class_name() const { return <b>call_method</b><char const*>(m_self, "class_name"); } + char const* Base_name() const { return Base::class_name(); } + private: + PyObject* const m_self; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + def("is_base", is_base); + + class_<Base,Base_callback, noncopyable>("Base") + .def("class_name", &Base_callback::Base_name) + ; + +} +</pre> + + <h3>Python Code</h3> +<pre> +>>> from my_module import * +>>> class Derived(Base): +... def __init__(self): +... Base.__init__(self) +... def class_name(self): +... return self.__class__.__name__ +... +>>> is_base(Base()) # calls the class_name() method from C++ +1 +>>> is_base(Derived()) +0 +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/callbacks.html b/libs/python/doc/v2/callbacks.html new file mode 100644 index 000000000..4e91befad --- /dev/null +++ b/libs/python/doc/v2/callbacks.html @@ -0,0 +1,254 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Calling Python Functions and Methods</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Calling Python Functions and Methods</h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#argument_handling">Argument Handling</a></dt> + + <dt><a href="#result_handling">Result Handling</a></dt> + + <dt><a href="#result_handling">Rationale</a></dt> + </dl> + <hr> + + <h2><a name="introduction">Introduction</a></h2> + The simplest way to call a Python function from C++, given an <code><a + href="object.html#object-spec">object</a></code> instance <code>f</code> + holding the function, is simply to invoke its function call operator. +<pre> +f("tea", 4, 2) // In Python: f('tea', 4, 2) +</pre> + And of course, a method of an <code><a href= + "object.html#object-spec">object</a></code> instance <code>x</code> can + be invoked by using the function-call operator of the corresponding + attribute: +<pre> +x.attr("tea")(4, 2); // In Python: x.tea(4, 2) +</pre> + + <p>If you don't have an <code>object</code> instance, Boost.Python + provides two families of function templates, <code><a href= + "call.html#call-spec">call</a></code> and <code><a href= + "call_method.html#call_method-spec">call_method</a></code>, for invoking + Python functions and methods respectively on <code>PyObject*</code>s. The + interface for calling a Python function object (or any Python callable + object) looks like:</p> +<pre> +call<ResultType>(callable_object, a1, a2... a<i>N</i>); +</pre> + Calling a method of a Python object is similarly easy: +<pre> +call_method<ResultType>(self_object, "<i>method-name</i>", a1, a2... a<i>N</i>); +</pre> + This comparitively low-level interface is the one you'll use when + implementing C++ virtual functions that can be overridden in Python. + + <h2><a name="argument_handling">Argument Handling</a></h2> + + <p>Arguments are converted to Python according to their type. By default, + the arguments <code>a1</code>...<code>a<i>N</i></code> are copied into + new Python objects, but this behavior can be overridden by the use of + <code><a href="ptr.html#ptr-spec">ptr()</a></code> and <a href= + "../../../bind/ref.html">ref()</a>:</p> +<pre> +class X : boost::noncopyable +{ + ... +}; + +void apply(PyObject* callable, X& x) +{ + // Invoke callable, passing a Python object which holds a reference to x + boost::python::call<void>(callable, boost::ref(x)); +} +</pre> + In the table below, <code><b>x</b></code> denotes the actual argument + object and <code><b>cv</b></code> denotes an optional + <i>cv-qualification</i>: "<code>const</code>", "<code>volatile</code>", + or "<code>const volatile</code>". + + <table border="1" summary="class_ template parameters"> + <tr> + <th>Argument Type</th> + + <th>Behavior</th> + </tr> + + <tr> + <td><code>T cv&</code><br> + <code>T cv</code></td> + + <td>The Python argument is created by the same means used for the + return value of a wrapped C++ function returning <code>T</code>. When + <code>T</code> is a class type, that normally means <code>*x</code> + is copy-constructed into the new Python object.</td> + </tr> + + <tr> + <td><code>T*</code></td> + + <td>If <code>x == 0</code>, the Python argument will be + <code><a href= + "http://www.python.org/doc/current/lib/bltin-null-object.html">None</a></code>. + Otherwise, the Python argument is created by the same means used for + the return value of a wrapped C++ function returning <code>T</code>. + When <code>T</code> is a class type, that normally means + <code>*x</code> is copy-constructed into the new Python object.</td> + </tr> + + <tr> + <td><code><a href= + "../../../bind/ref.html">boost::reference_wrapper</a><T></code></td> + + <td>The Python argument contains a pointer to, rather than a copy of, + <code>x.get()</code>. Note: failure to ensure that no Python code + holds a reference to the resulting object beyond the lifetime of + <code>*x.get()</code> <b>may result in a crash!</b></td> + </tr> + + <tr> + <td><code><a href= + "ptr.html#pointer_wrapper-spec">pointer_wrapper</a><T></code></td> + + <td>If <code>x.get() == 0</code>, the Python argument will + be <code><a href= + "http://www.python.org/doc/current/lib/bltin-null-object.html">None</a></code>. + Otherwise, the Python argument contains a pointer to, rather than a + copy of, <code>*x.get()</code>. Note: failure to ensure that no + Python code holds a reference to the resulting object beyond the + lifetime of <code>*x.get()</code> <b>may result in a crash!</b></td> + </tr> + </table> + + <h2><a name="result_handling">Result Handling</a></h2> + In general, <code>call<ResultType>()</code> and + <code>call_method<ResultType>()</code> return + <code>ResultType</code> by exploiting all lvalue and rvalue + <code>from_python</code> converters registered for ResultType and + returning a copy of the result. However, when <code>ResultType</code> is + a pointer or reference type, Boost.Python searches only for lvalue + converters. To prevent dangling pointers and references, an exception + will be thrown if the Python result object has only a single reference + count. + + <h2><a name="rationale">Rationale</a></h2> + In general, to get Python arguments corresponding to + <code>a1</code>...<code>a<i>N</i></code>, a new Python object must be + created for each one; should the C++ object be copied into that Python + object, or should the Python object simply hold a reference/pointer to + the C++ object? In general, the latter approach is unsafe, since the + called function may store a reference to the Python object somewhere. If + the Python object is used after the C++ object is destroyed, we'll crash + Python. + + <p>In keeping with the philosophy that users on the Python side shouldn't + have to worry about crashing the interpreter, the default behavior is to + copy the C++ object, and to allow a non-copying behavior only if the user + writes <code><a href="../../../bind/ref.html">boost::ref</a>(a1)</code> + instead of a1 directly. At least this way, the user doesn't get dangerous + behavior "by accident". It's also worth noting that the non-copying + ("by-reference") behavior is in general only available for class types, + and will fail at runtime with a Python exception if used otherwise[<a + href="#1">1</a>].</p> + + <p>However, pointer types present a problem: one approach is to refuse to + compile if any aN has pointer type: after all, a user can always pass + <code>*aN</code> to pass "by-value" or <code>ref(*aN)</code> to indicate + a pass-by-reference behavior. However, this creates a problem for the + expected null pointer to <code>None</code> conversion: it's illegal to + dereference a null pointer value.</p> + + <p>The compromise I've settled on is this:</p> + + <ol> + <li>The default behavior is pass-by-value. If you pass a non-null + pointer, the pointee is copied into a new Python object; otherwise the + corresponding Python argument will be None.</li> + + <li>if you want by-reference behavior, use <code>ptr(aN)</code> if + <code>aN</code> is a pointer and <code>ref(aN)</code> otherwise. If a + null pointer is passed to <code>ptr(aN)</code>, the corresponding + Python argument will be <code>None</code>.</li> + </ol> + + <p>As for results, we have a similar problem: if <code>ResultType</code> + is allowed to be a pointer or reference type, the lifetime of the object + it refers to is probably being managed by a Python object. When that + Python object is destroyed, our pointer dangles. The problem is + particularly bad when the <code>ResultType</code> is char const* - the + corresponding Python String object is typically uniquely-referenced, + meaning that the pointer dangles as soon as <code>call<char + const*>(...)</code> returns.</p> + + <p>The old Boost.Python v1 deals with this issue by refusing to compile + any uses of <code>call<char const*>()</code>, but this goes both + too far and not far enough. It goes too far because there are cases where + the owning Python string object survives beyond the call (just for + instance, when it's the name of a Python class), and it goes not far + enough because we might just as well have the same problem with a + returned pointer or reference of any other type.</p> + + <p>In Boost.Python v2 this is dealt with by:</p> + + <ol> + <li>lifting the compile-time restriction on const char* callback + returns</li> + + <li>detecting the case when the reference count on the result Python + object is 1 and throwing an exception inside of + <code>call<U>(...)</code> when <code>U</code> is a pointer or + reference type.</li> + </ol> + This should be acceptably safe because users have to explicitly specify a + pointer/reference for <code>U</code> in <code>call<U></code>, and + they will be protected against dangles at runtime, at least long enough + to get out of the <code>call<U>(...)</code> invocation. + <hr> + <a name="1">[1]</a> It would be possible to make it fail at compile-time + for non-class types such as int and char, but I'm not sure it's a good + idea to impose this restriction yet. + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/callbacks.txt b/libs/python/doc/v2/callbacks.txt new file mode 100644 index 000000000..2795680fd --- /dev/null +++ b/libs/python/doc/v2/callbacks.txt @@ -0,0 +1,92 @@ +.. Copyright David Abrahams 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +Here's the plan: + +I aim to provide an interface similar to that of Boost.Python v1's +callback<>::call(...) for dealing with callbacks. The interface will +look like: + + returning<ResultType>::call("method_name", self_object, a1, a2...); + +or + + returning<ResultType>::call(callable_object, a1, a2...); + +ARGUMENT HANDLING + +There is an issue concerning how to make Python objects from the +arguments a1...aN. A new Python object must be created; should the C++ +object be copied into that Python object, or should the Python object +simply hold a reference/pointer to the C++ object? In general, the +latter approach is unsafe, since the called function may store a +reference to the Python object somewhere. If the Python object is used +after the C++ object is destroyed, we'll crash Python. + +I plan to make the copying behavior the default, and to allow a +non-copying behavior if the user writes boost::ref(a1) instead of a1 +directly. At least this way, the user doesn't get dangerous behavior "by +accident". It's also worth noting that the non-copying ("by-reference") +behavior is in general only available for class types, and will fail at +runtime with a Python exception if used otherwise** + +However, pointer types present a problem: My first thought is to refuse +to compile if any aN has pointer type: after all, a user can always pass +*aN to pass "by-value" or ref(*aN) to indicate a pass-by-reference +behavior. However, this creates a problem for the expected NULL pointer +=> None conversion: it's illegal to dereference a null pointer value. + +We could use another construct, say "ptr(aN)", to deal with null +pointers, but then what does it mean? We know what it does when aN is +NULL, but it might either have by-value or by-reference behavior when aN +is non-null. + +The compromise I've settled on is this: + +1. The default behavior is pass-by-value. If you pass a non-null + pointer, the pointee is copied into a new Python object; otherwise + the corresponding Python argument will be None. + +2. if you want by-reference behavior, use ptr(aN) if aN is a pointer + and ref(aN) otherwise. If a null pointer is passed to ptr(aN), the + corresponding Python argument will be None. + +RESULT HANDLING + +As for results, we have a similar problem: if ResultType is allowed to +be a pointer or reference type, the lifetime of the object it refers to +is probably being managed by a Python object. When that Python object is +destroyed, our pointer dangles. The problem is particularly bad when the +ResultType is char const* - the corresponding Python String object is +typically uniquely-referenced, meaning that the pointer dangles as soon +as returning<char const*>::call() returns. + +Boost.Python v1 deals with this issue by refusing to compile any uses of +callback<char const*>::call(), but IMO this goes both too far and not +far enough. It goes too far because there are cases where the owning +String object survives beyond the call (just for instance when it's the +name of a Python class), and it goes not far enough because we might +just as well have the same problem with any returned pointer or +reference. + +I propose to address this in Boost.Python v2 by + + 1. lifting the compile-time restriction on const + char* callback returns + + 2. detecting the case when the reference count on the + result Python object is 1 and throwing an exception + inside of returning<U>::call() when U is a pointer or + reference type. + +I think this is acceptably safe because users have to explicitly specify +a pointer/reference for U in returning<U>, and they will be protected +against dangles at runtime, at least long enough to get out of the +returning<U>::call() invocation. + +-Dave + +**It would be possible to make it fail at compile-time for non-class +types such as int and char, but I'm not sure it's a good idea to impose +this restriction yet. diff --git a/libs/python/doc/v2/class.html b/libs/python/doc/v2/class.html new file mode 100644 index 000000000..edfc60970 --- /dev/null +++ b/libs/python/doc/v2/class.html @@ -0,0 +1,790 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st September 2004), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-latin-1-dos"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/class.hpp>, + <boost/python/class_fwd.hpp></title> +</head> + +<body link="#0000FF" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Headers <boost/python/class.hpp>, + <boost/python/class_fwd.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#class_-spec">Class template + <code>class_</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#class_-spec-synopsis">Class <code>class_</code> + synopsis</a></dt> + + <dt><a href="#class_-spec-ctors">Class <code>class_</code> + constructors</a></dt> + + <dt><a href="#class_-spec-modifiers">Class <code>class_</code> + modifier functions</a></dt> + </dl> + </dd> + + <dt><a href="#bases-spec">Class template <code>bases</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#bases-spec-synopsis">Class template + <code>bases</code> synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction" id="introduction"></a>Introduction</h2> + + <p><code><boost/python/class.hpp></code> defines the interface + through which users expose their C++ classes to Python. It declares the + <code>class_</code> class template, which is parameterized on the class + type being exposed. It also exposes the <code>init</code>, + <code>optional</code> and <code>bases</code> utility class templates, which + are used in conjunction with <code>class_</code>.</p> + + <p><code><boost/python/class_fwd.hpp></code> contains a forward + declaration of the <code>class_</code> class template.</p> + + <h2><a name="classes" id="classes"></a>Classes</h2> + + <h3><a name="class_-spec" id="class_-spec"></a>Class template + <code>class_<T, <font color="#007F00">Bases, HeldType, + NonCopyable</font>></code></h3> + + <p>Creates a Python class associated with the C++ type passed as its first + parameter. Although it has four template parameters, only the first one is + required. The three optional arguments can actually be supplied + <font color="#007F00"><b>in any order</b></font>; Boost.Python determines + the role of the argument from its type.<br> + <br></p> + + <table border="1" summary="class_ template parameters"> + <tr> + <th>Template Parameter</th> + + <th>Requirements</th> + + <th>Semantics</th> + + <th>Default</th> + </tr> + + <tr> + <td><code>T</code></td> + + <td>A class type.</td> + + <td>The class being wrapped</td> + </tr> + + <tr> + <td><code><font color="#007F00">Bases</font></code></td> + + <td>A specialization of <a href= + "#bases-spec"><code>bases<</code>...<code>></code></a> which + specifies previously-exposed C++ base classes of <code>T</code><a href= + "#footnote_1">[1]</a>.</td> + + <td>Registers <code>from_python</code> conversions from wrapped + <code>T</code> instances to each of its exposed direct and indirect + bases. For each polymorphic base <code>B</code>, registers conversions + from indirectly-held wrapped <code>B</code> instances to + <code>T</code>.</td> + + <td><code><a href="#bases-spec">bases<></a></code></td> + </tr> + + <tr> + <td><code><font color="#007F00">HeldType</font></code></td> + + <td>Must be <code>T</code>, a class derived from <code>T</code>, or a + <a href="Dereferenceable.html">Dereferenceable</a> type for which + <code><a href= + "pointee.html#pointee-spec">pointee</a><HeldType>::type</code> is + <code>T</code> or a class derived from <code>T</code>.</td> + + <td>Specifies the type that is actually embedded in a Python object + wrapping a <code>T</code> instance when <code>T</code>'s constructor is + called or when a <code>T</code> or <code>T*</code> is converted to + Python without the use of <a href= + "http://www.boost.org/libs/python/doc/v2/callbacks.html#argument_handling"> + <code>ptr</code></a>, <a href= + "http://www.boost.org/libs/python/doc/v2/callbacks.html#argument_handling"> + <code>ref</code></a>, or <a href="CallPolicies.html">Call Policies</a> + such as <code><a href= + "return_internal_reference.html">return_internal_reference</a></code>. + More details <a href="#HeldType">below</a>.</td> + + <td><code>T</code></td> + </tr> + + <tr> + <td><code><font color="#007F00">NonCopyable</font></code></td> + + <td>If supplied, must be <a href= + "../../../utility/utility.htm#Class_noncopyable">boost::noncopyable</a>.</td> + + <td>Suppresses automatic registration of <code>to_python</code> + conversions which copy <code>T</code> instances. Required when + <code>T</code> has no publicly-accessible copy constructor.</td> + + <td>An unspecified type other than + <code>boost::noncopyable</code>.</td> + </tr> + </table> + + <h4><a name="HeldType" id="HeldType">HeldType Semantics</a></h4> + + <ol> + <li>If <code>HeldType</code> is derived from T, its exposed + constructor(s) must accept an initial <code>PyObject*</code> argument + which refers back to the Python object that contains the + <code>HeldType</code> instance, as shown in <a href= + "call_method.html#examples">this example</a>. This argument is not + included in the <em><a href= + "init.html#init-expressions">init-expression</a></em> passed to <a href= + "#class_-spec-modifiers"><code>def(init_expr)</code></a>, below, nor is + it passed explicitly by users when Python instances of <code>T</code> are + created. This idiom allows C++ virtual functions which will be overridden + in Python to access the Python object so the Python method can be + invoked. Boost.Python automatically registers additional converters which + allow wrapped instances of <code>T</code> to be passed to wrapped C++ + functions expecting <code>HeldType</code> arguments.</li> + + <li>Because Boost.Python will always allow wrapped instances of + <code>T</code> to be passed in place of <code>HeldType</code> arguments, + specifying a smart pointer for <code>HeldType</code> allows users to pass + Python <code>T</code> instances where a smart pointer-to-<code>T</code> + is expected. Smart pointers such as <code>std::auto_ptr<></code> or + <code><a href= + "../../../smart_ptr/shared_ptr.htm">boost::shared_ptr<></a></code> + which contain a nested type <code>element_type</code> designating the + referent type are automatically supported; additional smart pointer types + can be supported by specializing <a href= + "pointee.html#pointee-spec">pointee<HeldType></a>.</li> + + <li>As in case 1 above, when <code>HeldType</code> is a smart pointer to + a class derived from <code>T</code>, the initial <code>PyObject*</code> + argument must be supplied by all of <code>HeldType</code>'s exposed + constructors.</li> + + <li>Except in cases 1 and 3, users may optionally specify that T itself + gets initialized with a similar initial <code>PyObject*</code> argument + by specializing <a href= + "has_back_reference.html#has_back_reference-spec">has_back_reference<T></a>.</li> + </ol> + + <h4><a name="class_-spec-synopsis" id="class_-spec-synopsis"></a>Class + template <code>class_</code> synopsis</h4> + <pre> +namespace boost { namespace python +{ + template <class T + <font color="#007F00"> , class Bases = bases<> + , class HeldType = T + , class NonCopyable = <i>unspecified</i> + > +</font> class class_ : public <a href="object.html#object-spec">object</a> + { + // Constructors with default __init__ + class_(char const* name); + class_(char const* name, char const* docstring); + + // Constructors, specifying non-default __init__ + template <class Init> + class_(char const* name, Init); + template <class Init> + class_(char const* name, char const* docstring, Init); + + // Exposing additional __init__ functions + template <class Init> + class_& def(Init); + + // defining methods + template <class F> + class_& def(char const* name, F f); + template <class Fn, class A1> + class_& def(char const* name, Fn fn, A1 const&); + template <class Fn, class A1, class A2> + class_& def(char const* name, Fn fn, A1 const&, A2 const&); + template <class Fn, class A1, class A2, class A3> + class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&); + + // declaring method as static + class_& staticmethod(char const* name); + + // exposing operators + template <<i>unspecified</i>> + class_& def(<a href= +"operators.html#operator_-spec">detail::operator_</a><unspecified>); + + // Raw attribute modification + template <class U> + class_& setattr(char const* name, U const&); + + // exposing data members + template <class D> + class_& def_readonly(char const* name, D T::*pm); + + template <class D> + class_& def_readwrite(char const* name, D T::*pm); + + // exposing static data members + template <class D> + class_& def_readonly(char const* name, D const& d); + template <class D> + class_& def_readwrite(char const* name, D& d); + + // property creation + template <class Get> + void add_property(char const* name, Get const& fget, char const* doc=0); + template <class Get, class Set> + void add_property( + char const* name, Get const& fget, Set const& fset, char const* doc=0); + + template <class Get> + void add_static_property(char const* name, Get const& fget); + template <class Get, class Set> + void add_static_property(char const* name, Get const& fget, Set const& fset); + + // pickle support + template <typename PickleSuite> + self& def_pickle(PickleSuite const&); + self& enable_pickling(); + }; +}} +</pre> + + <h4><a name="class_-spec-ctors" id="class_-spec-ctors"></a>Class template + <code>class_</code> constructors</h4> + <pre> +class_(char const* name); +class_(char const* name, char const* docstring); +template <class Init> +class_(char const* name, Init init_spec); +template <class Init> +class_(char const* name, char const* docstring, Init init_spec); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>. If <code>docstring</code> is supplied, it must be an + <a href="definitions.html#ntbs">ntbs</a>. If <code>init_spec</code> is + supplied, it must be either the special enumeration constant + <code>no_init</code> or an <a href= + "init.html#init-expressions">init-expression</a> compatible with + <code>T</code>.</dt> + + <dt><b>Effects:</b> Constructs a <code>class_</code> object holding a + Boost.Python extension class named <code>name</code>. The + <code>name</code>d attribute of the <a href= + "scope.html#introduction">current scope</a> is bound to the new extension + class.</dt> + + <dd> + <ul> + <li>If supplied, the value of <code>docstring</code> is bound to the + <code>__doc__</code> attribute of the extension class.</li> + + <li>If <code>init_spec</code> is <code>no_init</code>, a special + <code>__init__</code> function is generated which always raises a + Python exception. Otherwise, <code>this->def(init_spec)</code> is + called.</li> + + <li>If <code>init_spec</code> is not supplied, + <code>this->def(init<>())</code> is called.</li> + </ul> + </dd> + + <dt><b>Rationale:</b>Allowing the user to specify constructor arguments + in the <code>class_<></code> constructor helps her to avoid the + common run-time errors which result from invoking wrapped member + functions without having exposed an <code>__init__</code> function which + creates the requisite <code>T</code> instance. Types which are not + default-constructible will cause a compile-time error unless + <code>Init</code> is supplied. The user must always supply + <code>name</code> as there is currently no portable method to derive the + text of the class name from its type.</dt> + </dl> + + <h4><a name="class_-spec-modifiers" id="class_-spec-modifiers"></a>Class + template <code>class_</code> modifier functions</h4> + <pre> +template <class Init> +class_& def(Init init_expr); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>init_expr</code> is the result of an <a href= + "init.html#init-expressions">init-expression</a> compatible with + <code>T</code>.</dt> + + <dt><b>Effects:</b> For each <a href="init.html#init-expressions">valid + prefix</a> <em>P</em> of <code>Init</code>, adds an + <code>__init__(</code>...<code>)</code> function overload to the + extension class accepting <em>P</em> as arguments. Each overload + generated constructs an object of <code>HeldType</code> according to the + semantics described <a href="#HeldType">above</a>, using a copy of + <code>init_expr</code>'s <a href="CallPolicies.html">call policies</a>. + If the longest <a href="init.html#init-expressions">valid prefix</a> of + <code>Init</code> contains <em>N</em> types and <code>init_expr</code> + holds <em>M</em> keywords, an initial sequence of the keywords are used + for all but the first <em>N</em> - <em>M</em> arguments of each + overload.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Allows users to easily expose a class' constructor + to Python.</dt> + </dl><br> + <pre> +template <class F> +class_& def(char const* name, Fn fn); +template <class Fn, class A1> +class_& def(char const* name, Fn fn, A1 const& a1); +template <class Fn, class A1, class A2> +class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2); +template <class Fn, class A1, class A2, class A3> +class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>.</dt> + + <dd> + <ul> + <li>If <code>a1</code> is the result of an <a href= + "overloads.html#overload-dispatch-expression"><em>overload-dispatch-expression</em></a>, + only the second form is allowed and fn must be a pointer to function + or pointer to member function whose <a href="definitions.html#arity"> + arity</a> is the same as A1's <a href= + "overloads.html#overload-dispatch-expression"><em>maximum + arity</em></a>. + + <dl> + <dt><b>Effects:</b> For each prefix <em>P</em> of + <code>Fn</code>'s sequence of argument types, beginning with the + one whose length is <code>A1</code>'s <a href= + "overloads.html#overload-dispatch-expression"><em>minimum + arity</em></a>, adds a + <code><em>name</em>(</code>...<code>)</code> method overload to + the extension class. Each overload generated invokes + <code>a1</code>'s call-expression with <em>P</em>, using a copy + of <code>a1</code>'s <a href="CallPolicies.html">call + policies</a>. If the longest valid prefix of <code>A1</code> + contains <em>N</em> types and <code>a1</code> holds <em>M</em> + keywords, an initial sequence of the keywords are used for all + but the first <em>N</em> - <em>M</em> arguments of each + overload.<br></dt> + </dl> + </li> + + <li>Otherwise, a single method overload is built around fn, which + must not be null: + + <ul> + <li>If fn is a function pointer, its first argument must be of + the form <code>U</code>, <code>U <em>cv</em>&</code>, <code>U + <em>cv</em>*</code>, or <code>U <em>cv</em>* const&</code>, + where <code>T*</code> is convertible to <code>U*</code>, and + <code>a1</code>-<code>a3</code>, if supplied, may be selected in + any order from the table below.</li> + + <li>Otherwise, if fn is a member function pointer, its target + must be <code>T</code> or one of its public base classes, and + <code>a1</code>-<code>a3</code>, if supplied, may be selected in + any order from the table below.</li> + + <li>Otherwise, <code>Fn</code> must be [derived from] + <code><a href="object.html#object-spec">object</a></code>, and + <code>a1-a2</code>, if supplied, may be selcted in any order from + the first two rows of the table below. To be useful, + <code>fn</code> should be <a href= + "http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6"> + callable</a>.</li> + </ul> + + <table border="1" summary="def() optional arguments"> + <tr> + <th>Memnonic Name</th> + + <th>Requirements/Type properties</th> + + <th>Effects</th> + </tr> + + <tr> + <td>docstring</td> + + <td>Any <a href="definitions.html#ntbs">ntbs</a>.</td> + + <td>Value will be bound to the <code>__doc__</code> attribute + of the resulting method overload. If an earlier overload + supplied a docstring, two newline characters and the new + docstring are appended to it.</td> + </tr> + + <tr> + <td>policies</td> + + <td>A model of <a href= + "CallPolicies.html">CallPolicies</a></td> + + <td>A copy will be used as the call policies of the resulting + method overload.</td> + </tr> + + <tr> + <td>keywords</td> + + <td>The result of a <a href= + "args.html#keyword-expression"><em>keyword-expression</em></a> + specifying no more arguments than the <a href= + "definitions.html#arity">arity</a> of <code>fn</code>.</td> + + <td>A copy will be used as the call policies of the resulting + method overload.</td> + </tr> + </table> + </li> + </ul> + </dd> + + <dt><b>Returns:</b> <code>*this</code></dt> + </dl> + <pre> +class_& staticmethod(char const* name); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>, and corresponds to a method whose overloads have all + been defined.</dt> + + <dt><b>Effects:</b> Replaces the existing named attribute <i>x</i> with + the result of invoking <code>staticmethod(</code><i>x</i><code>)</code> + in Python. Specifies that the corresponding method is static and + therefore no object instance will be passed to it. This is equivalent to + the Python statement:</dt> + + <dd> + <pre> +setattr(self, name, staticmethod(getattr(self, name))) +</pre> + </dd> + + <dt><b>Note:</b> Attempting to invoke <code>def(name,...)</code> after + invoking <code>staticmethod(name)</code> will <a href= + "definitions.html#raise">raise</a> a RuntimeError.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + </dl><br> + <pre> +template <<i>unspecified</i>> +class_& def(<a href= +"operators.html#operator_-spec">detail::operator_</a><unspecified>); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Adds a Python <a href= + "http://www.python.org/doc/ref/specialnames.html">special method</a> as + described <a href="operators.html">here</a>.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + </dl> + <pre> +template <class U> +class_& setattr(char const* name, U const& u); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>.</dt> + + <dt><b>Effects:</b> Converts u to Python and adds it to the attribute + dictionary of the extension class:</dt> + + <dd> + <blockquote> + <code><a href= + "http://www.python.org/doc/current/api/object.html#l2h-166">PyObject_SetAttrString</a>(this->ptr(), + name, <a href= + "object.html#object-spec-ctors">object</a>(u).ptr());</code> + </blockquote> + </dd> + + <dt><b>Returns:</b> <code>*this</code></dt> + </dl><br> + <pre> +template <class Get> +void add_property(char const* name, Get const& fget, char const* doc=0); +template <class Get, class Set> +void add_property( + char const* name, Get const& fget, Set const& fset, char const* doc=0); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conform to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>.</dt> + + <dt><b>Effects:</b> Creates a new Python <a href= + "http://www.python.org/2.2.2/descrintro.html#property"><code>property</code></a> + class instance, passing <code><a href= + "object.html#object-spec-ctors">object</a>(fget)</code> (and + <code><a href="object.html#object-spec-ctors">object</a>(fset)</code> in + the second form) with an (optional) docstring <code>doc</code> to its + constructor, then adds that property to the Python class object under + construction with the given attribute <code>name</code>.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Allows users to easily expose functions that can be + invoked from Python with attribute access syntax.</dt> + </dl><br> + <pre> +template <class Get> +void add_static_property(char const* name, Get const& fget); +template <class Get, class Set> +void add_static_property(char const* name, Get const& fget, Set const& fset); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>.</dt> + + <dt><b>Effects:</b> Creates a Boost.Python.StaticProperty object, passing + <code><a href="object.html#object-spec-ctors">object</a>(fget)</code> + (and <code><a href= + "object.html#object-spec-ctors">object</a>(fset)</code> in the second + form) to its constructor, then adds that property to the Python class + under construction with the given attribute <code>name</code>. + StaticProperty is a special subclass of Python's <a href= + "http://www.python.org/2.2.2/descrintro.html#property"><code>property</code></a> + class which can be called without an initial <code>self</code> + argument.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Allows users to easily expose functions that can be + invoked from Python with static attribute access syntax.</dt> + </dl><br> + <pre> +template <class D> +class_& def_readonly(char const* name, D T::*pm, char const* doc=0); +template <class D> +class_& def_readonly(char const* name, D const& d); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>. <code>doc</code> is also an ntbs.</dt> + + <dt><b>Effects:</b></dt> + + <dd> + <pre> +this->add_property(name, <a href= +"data_members.html#make_getter-spec">make_getter</a>(pm), doc); +</pre>and + <pre> +this->add_static_property(name, <a href= +"data_members.html#make_getter-spec">make_getter</a>(d)); +</pre>respectively.<br> + <br> + </dd> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Allows users to easily expose a class' data member + or free variable such that it can be inspected from Python with a natural + syntax.</dt> + </dl> + <pre> +template <class D> +class_& def_readwrite(char const* name, D T::*pm, char const* doc=0); +template <class D> +class_& def_readwrite(char const* name, D& d); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b></dt> + + <dd> + <pre> +this->add_property(name, <a href= +"data_members.html#make_getter-spec">make_getter</a>(pm), <a href= +"data_members.html#make_setter-spec">make_setter</a>(pm), doc); +</pre>and + <pre> +this->add_static_property(name, <a href= +"data_members.html#make_getter-spec">make_getter</a>(d), <a href= +"data_members.html#make_setter-spec">make_setter</a>(d)); +</pre>respectively.<br> + <br> + </dd> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Allows users to easily expose a class' data or free + variable member such that it can be inspected and set from Python with a + natural syntax.</dt> + </dl> + <pre> +template <typename PickleSuite> +class_& def_pickle(PickleSuite const&); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> PickleSuite must be publically derived from <a href= + "pickle.html"><code>pickle_suite</code></a>.</dt> + + <dt><b>Effects:</b> Defines a legal combination of the special attributes + and methods: <code>__getinitargs__</code>, <code>__getstate__</code>, + <code>__setstate__</code>, <code>__getstate_manages_dict__</code>, + <code>__safe_for_unpickling__</code>, <code>__reduce__</code></dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Provides an <a href="pickle.html">easy to use + high-level interface</a> for establishing complete pickle support for the + wrapped class. The user is protected by compile-time consistency + checks.</dt> + </dl><br> + <pre> +class_& enable_pickling(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Defines the <code>__reduce__</code> method and the + <code>__safe_for_unpickling__</code> attribute.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + <dt><b>Rationale:</b> Light-weight alternative to + <code>def_pickle()</code>. Enables implementation of <a href= + "pickle.html">pickle support</a> from Python.</dt> + </dl><br> + + <h3><a name="bases-spec" id="bases-spec"></a>Class template + <code>bases<T1, T2,</code>...<code>TN></code></h3> + + <p>An <a href="../../../mpl/doc/refmanual/forward-sequence.html">MPL + sequence</a> which can be used in + <code>class_<</code>...<code>></code> instantiations indicate a list + of base classes.</p> + + <h4><a name="bases-spec-synopsis" id="bases-spec-synopsis"></a>Class + template <code>bases</code> synopsis</h4> + <pre> +namespace boost { namespace python +{ + template <T1 = <i>unspecified</i>,...T<i>n</i> = <i>unspecified</i>> + struct bases + {}; +}} +</pre> + + <h2><a name="examples" id="examples"></a>Example(s)</h2> + + <p>Given a C++ class declaration:</p> + <pre> +class Foo : public Bar, public Baz +{ + public: + Foo(int x, char const* y); + Foo(double); + + std::string const& name() { return m_name; } + void name(char const*); + + double value; // public data + private: + ... +}; +</pre>A corresponding Boost.Python extension class can be created with: + <pre> +using namespace boost::python; + +class_<Foo,bases<Bar,Baz> >("Foo", + "This is Foo's docstring." + "It describes our Foo extension class", + + init<int,char const*>(args("x","y"), "__init__ docstring") + ) + .def(init<double>()) + .def("get_name", &Foo::get_name, return_internal_reference<>()) + .def("set_name", &Foo::set_name) + .def_readwrite("value", &Foo::value) + ; +</pre> + <hr> + <a name="footnote_1" id="footnote_1">[1]</a> By "previously-exposed" we + mean that the for each <code>B</code> in <code>bases</code>, an instance of + <code>class_<B<font color="#007F00">, ...</font>></code> must have + already been constructed. + <pre> +class_<Base>("Base"); +class_<Derived, bases<Base> >("Derived"); +</pre>Revised +<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 1 November, 2005 <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002.</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/configuration.html b/libs/python/doc/v2/configuration.html new file mode 100644 index 000000000..1be862ed6 --- /dev/null +++ b/libs/python/doc/v2/configuration.html @@ -0,0 +1,217 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Configuration</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Configuration</h2> + </td> + </tr> + </table> + <hr> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#app-defined">Application Defined Macros</a></dt> + + <dt><a href="#lib-defined-impl">Library Defined Implementation + Macros</a></dt> + </dl> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><b>Boost.Python</b> uses several configuration macros in <a href= + "http://www.boost.org/libs/config/config.htm"><boost/config.hpp></a>, + as well as configuration macros meant to be supplied by the application. + These macros are documented here.</p> + + <h2><a name="app-defined"></a>Application Defined Macros</h2> + + <p>These are the macros that may be defined by an application using + <b>Boost.Python</b>. Note that if you extend a strict interpretation of + the C++ standard to cover dynamic libraries, using different values of + these macros when compiling different libraries (including extension + modules and the <b>Boost.Python</b> library itself) is a violation of the + <a href="definitions.html#ODR">ODR</a>. However, we know of no C++ + implementations on which this particular violation is detectable or + causes any problems.</p> + + <table summary="application defined macros" width="100%" cellpadding= + "10"> + <tr> + <th align="left"><b>Macro</b></th> + + <th><b>Default</b></th> + + <th align="left"><b>Meaning</b></th> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_MAX_ARITY</code></td> + + <td valign="top" align="center">15</td> + + <td valign="top">The maximum <a href= + "definitions.html#arity">arity</a> of any function, member function, + or constructor to be wrapped, invocation of a <b>Boost.Python</b> + function wich is specified as taking arguments + <code>x1, x2,</code>...<code>X</code><i>n</i>. This includes, in + particular, callback mechanisms such as <code><a href= + "object.html#object-spec">object</a>::operator()(</code>...<code>)</code> + or <code><a href= + "call_method.html#call_method-spec">call_method</a><R>(</code>... + <code>)</code>.</td> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_MAX_BASES</code></td> + + <td valign="top" align="center">10</td> + + <td valign="top">The maximum number of template arguments to the + <code><a href= + "class.html#bases-spec">bases</a><</code>...<code>></code> + class template, which is used to specify the bases of a wrapped C++ + class..</td> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_STATIC_MODULE</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined, prevents your module initialization + function from being treated as an exported symbol on platforms which + support that distinction in-code</td> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_ENABLE_CDECL</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined, allows functions using the <code>__cdecl + </code> calling convention to be wrapped.</td> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_ENABLE_STDCALL</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined, allows functions using the <code>__stdcall + </code> calling convention to be wrapped.</td> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_ENABLE_FASTCALL</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined, allows functions using the <code>__fastcall + </code> calling convention to be wrapped.</td> + </tr> + </table> + + <h2><a name="lib-defined-impl"></a>Library Defined Implementation + Macros</h2> + + <p>These macros are defined by <b>Boost.Python</b> and are implementation + details of interest only to implementors and those porting to new + platforms.</p> + + <table summary="library defined implementation macros" width="100%" + cellpadding="10"> + <tr> + <th align="left"><b>Macro</b></th> + + <th><b>Default</b></th> + + <th align="left"><b>Meaning</b></th> + </tr> + + <tr> + <td valign="top"><code>BOOST_PYTHON_TYPE_ID_NAME</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined, this indicates that the type_info + comparison across shared library boundaries does not work on this + platform. In other words, if shared-lib-1 passes + <code>typeid(T)</code> to a function in shared-lib-2 which compares + it to <code>typeid(T)</code>, that comparison may return + <code>false</code>. If this macro is #defined, Boost.Python uses and + compares <code>typeid(T).name()</code> instead of using and comparing + the <code>std::type_info</code> objects directly.</td> + </tr> + <tr> + <td valign="top"><code>BOOST_PYTHON_NO_PY_SIGNATURES</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined for a module no pythonic signatures are generated + for the docstrings of the module functions, and no python type is associated with any + of the converters registered by the module. This also reduces the binary size of the + module by about 14% (gcc compiled).<br> + If defined for the boost_python runtime library, the default for the + <code>docstring_options.enable_py_signatures()</code> is set to <code>false</code>. + </td> + + </tr> + <tr> + <td valign="top"><code>BOOST_PYTHON_SUPPORTS_PY_SIGNATURES</code></td> + + <td valign="top" align="center"><i>defined if <code>BOOST_PYTHON_NO_PY_SIGNATURES</code> is undefined</i></td> + + <td valign="top">This macro is defined to enable a smooth transition from older Boost.Python versions + which do not support pythonic signatures. For example usage see + <a href="pytype_function.html#examples">here</a>. + </td> + + </tr> + <tr> + <td valign="top"><code>BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE</code></td> + + <td valign="top" align="center"><i>not defined</i></td> + + <td valign="top">If defined the python type of <code>__init__</code> method "self" parameters + is properly generated, otherwise <code><b>object</b></code> is used. It is undefined + by default because it increases the binary size of the module by about 14% (gcc compiled).</td> + + </tr> + </table> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 7 January, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/copy_const_reference.html b/libs/python/doc/v2/copy_const_reference.html new file mode 100644 index 000000000..97c2a282c --- /dev/null +++ b/libs/python/doc/v2/copy_const_reference.html @@ -0,0 +1,149 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/copy_const_reference.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/copy_const_reference.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#copy_const_reference-spec">Class + <code>copy_const_reference</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#copy_const_reference-spec-synopsis">Class + <code>copy_const_reference</code> synopsis</a></dt> + + <dt><a href="#copy_const_reference-spec-metafunctions">Class + <code>copy_const_reference</code> metafunctions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="copy_const_reference-spec"></a>Class + <code>copy_const_reference</code></h3> + + <p><code>copy_const_reference</code> is a model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> + which can be used to wrap C++ functions returning a reference-to-const + type such that the referenced value is copied into a new Python + object.</p> + + <h4><a name="copy_const_reference-spec-synopsis"></a>Class + <code>copy_const_reference</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct copy_const_reference + { + template <class T> struct apply; + }; +}} +</pre> + + <h4><a name="copy_const_reference-spec-metafunctions"></a>Class + <code>copy_const_reference</code> metafunctions</h4> +<pre> +template <class T> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Requires:</b> <code>T</code> is <code>U const&</code> for + some <code>U</code>.</dt> + + <dt><b>Returns:</b> <code>typedef <a href= + "to_python_value.html#to_python_value-spec">to_python_value</a><T> + type;</code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ Module Definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar const& get_bar() const { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_<Bar>("Bar"); + + class_<Foo>("Foo", init<int>()) + .def("get_bar", &Foo::get_bar + , return_value_policy<copy_const_reference>()) + ; +} +</pre> + + <h3>Python Code</h3> +<pre> +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/copy_non_const_reference.html b/libs/python/doc/v2/copy_non_const_reference.html new file mode 100644 index 000000000..987efad83 --- /dev/null +++ b/libs/python/doc/v2/copy_non_const_reference.html @@ -0,0 +1,149 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/copy_non_const_reference.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/copy_non_const_reference.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#copy_non_const_reference-spec">Class + <code>copy_non_const_reference</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#copy_non_const_reference-spec-synopsis">Class + <code>copy_non_const_reference</code> synopsis</a></dt> + + <dt><a href= + "#copy_non_const_reference-spec-metafunctions">Class + <code>copy_non_const_reference</code> metafunctions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="copy_non_const_reference-spec"></a>Class + <code>copy_non_const_reference</code></h3> + + <p><code>copy_non_const_reference</code> is a model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> + which can be used to wrap C++ functions returning a + reference-to-non-const type such that the referenced value is copied into + a new Python object.</p> + + <h4><a name="copy_non_const_reference-spec-synopsis"></a>Class + <code>copy_non_const_reference</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct copy_non_const_reference + { + template <class T> struct apply; + }; +}} +</pre> + + <h4><a name="copy_non_const_reference-spec-metafunctions"></a>Class + <code>copy_non_const_reference</code> metafunctions</h4> +<pre> +template <class T> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Requires:</b> <code>T</code> is <code>U&</code> for some + non-const <code>U</code>.</dt> + + <dt><b>Returns:</b> <code>typedef <a href= + "to_python_value.html#to_python_value-spec">to_python_value</a><T> + type;</code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <p>C++ code:</p> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/copy_non_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar& get_bar() { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_<Bar>("Bar"); + + class_<Foo>("Foo", init<int>()) + .def("get_bar", &Foo::get_bar + , return_value_policy<copy_non_const_reference>()) + ; +} +</pre> + Python Code: +<pre> +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/data_members.html b/libs/python/doc/v2/data_members.html new file mode 100644 index 000000000..36f818d3d --- /dev/null +++ b/libs/python/doc/v2/data_members.html @@ -0,0 +1,229 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/data_members.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/data_members.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#make_getter-spec">make_getter</a></dt> + + <dt><a href="#make_setter-spec">make_setter</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><a href="#make_getter-spec">make_getter</a>()</code> and + <code><a href="#make_setter-spec">make_setter</a>()</code> are the + functions used internally by <code>class_<>::<a href= + "class.html#class_-spec-modifiers">def_readonly</a></code> and + <code>class_<>::<a href= + "class.html#class_-spec-modifiers">def_readwrite</a></code> to produce + Python callable objects which wrap C++ data members.</p> + + <h2><a name="functions"></a>Functions</h2> +<pre> +<a name="make_getter-spec">template <class C, class D></a> +<a href="object.html#object-spec">object</a> make_getter(D C::*pm); + +template <class C, class D, class Policies> +<a href= +"object.html#object-spec">object</a> make_getter(D C::*pm, Policies const& policies); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>Policies</code> is a model of <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>Effects:</b> Creates a Python callable object which accepts a + single argument that can be converted <code>from_python</code> to + <code>C*</code>, and returns the corresponding member <code>D</code> + member of the <code>C</code> object, converted <code>to_python</code>. + If <code>policies</code> is supplied, it will be applied to the + function as described <a href="CallPolicies.html">here</a>. Otherwise, + the library attempts to determine whether <code>D</code> is a + user-defined class type, and if so uses <code><a href= + "return_internal_reference.html#return_internal_reference-spec">return_internal_reference</a><></code></dt> + + <dt>for <code>Policies</code>. Note that this test may inappropriately + choose <code>return_internal_reference<></code> in some cases + when <code>D</code> is a smart pointer type. This is a known + defect.</dt> + + <dt><b>Returns:</b> An instance of <a href= + "object.html#object-spec">object</a> which holds the new Python + callable object.</dt> + </dl> +<pre> +template <class D> +<a href="object.html#object-spec">object</a> make_getter(D const& d); +template <class D, class Policies> +<a href= +"object.html#object-spec">object</a> make_getter(D const& d, Policies const& policies); + +template <class D> +<a href="object.html#object-spec">object</a> make_getter(D const* p); +template <class D, class Policies> +<a href= +"object.html#object-spec">object</a> make_getter(D const* p, Policies const& policies); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>Policies</code> is a model of <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>Effects:</b> Creates a Python callable object which accepts no + arguments and returns <code>d</code> or <code>*p</code>, converted + <code>to_python</code> on demand. If <code>policies</code> is supplied, + it will be applied to the function as described <a href= + "CallPolicies.html">here</a>. Otherwise, the library attempts to + determine whether <code>D</code> is a user-defined class type, and if + so uses <code><a href= + "reference_existing_object.html#reference_existing_object-spec">reference_existing_object</a></code></dt> + + <dt>for <code>Policies</code>.</dt> + + <dt><b>Returns:</b> An instance of <a href= + "object.html#object-spec">object</a> which holds the new Python + callable object.</dt> + </dl> +<pre> +<a name="make_setter-spec">template <class C, class D></a> +<a href="object.html#object-spec">object</a> make_setter(D C::*pm); + +template <class C, class D, class Policies> +<a href= +"object.html#object-spec">object</a> make_setter(D C::*pm, Policies const& policies); +</pre> + + <dl class="function*-semantics"> + <dt><b>Requires:</b> <code>Policies</code> is a model of <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>Effects:</b> Creates a Python callable object which, when called + from Python, expects two arguments which can be converted + <code>from_python</code> to <code>C*</code> and + <code>D const&</code>, respectively, and sets the + corresponding <code>D</code> member of the <code>C</code> object. If + <code>policies</code> is supplied, it will be applied to the function + as described <a href="CallPolicies.html">here</a>.</dt> + + <dt><b>Returns:</b> An instance of <a href= + "object.html#object-spec">object</a> which holds the new Python + callable object.</dt> + </dl> +<pre> +template <class D> +<a href="object.html#object-spec">object</a> make_setter(D& d); +template <class D, class Policies> +<a href= +"object.html#object-spec">object</a> make_setter(D& d, Policies const& policies); + +template <class D> +<a href="object.html#object-spec">object</a> make_setter(D* p); +template <class D, class Policies> +<a href= +"object.html#object-spec">object</a> make_setter(D* p, Policies const& policies); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>Policies</code> is a model of <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>Effects:</b> Creates a Python callable object which accepts one + argument, which is converted from Python to <code>D const&</code> + and written into <code>d</code> or <code>*p</code>, respectively. If + <code>policies</code> is supplied, it will be applied to the function + as described <a href="CallPolicies.html">here</a>.</dt> + + <dt><b>Returns:</b> An instance of <a href= + "object.html#object-spec">object</a> which holds the new Python + callable object.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <p>The code below uses make_getter and make_setter to expose a data + member as functions:</p> +<pre> +#include <boost/python/data_members.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> + +struct X +{ + X(int x) : y(x) {} + int y; +}; + +using namespace boost::python; + +BOOST_PYTHON_MODULE_INIT(data_members_example) +{ + class_<X>("X", init<int>()) + .def("get", make_getter(&X::y)) + .def("set", make_setter(&X::y)) + ; +} +</pre> + It can be used this way in Python: +<pre> +>>> from data_members_example import * +>>> x = X(1) +>>> x.get() +1 +>>> x.set(2) +>>> x.get() +2 +</pre> + + <p> + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 5 August, 2003 <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/def.html b/libs/python/doc/v2/def.html new file mode 100644 index 000000000..3c71fd363 --- /dev/null +++ b/libs/python/doc/v2/def.html @@ -0,0 +1,191 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/def.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/def.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#def-spec">def</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><a href="#def-spec">def</a>()</code> is the function which can + be used to expose C++ functions and callable objects as Python functions + in the current <code><a href="scope.html">scope</a></code>.</p> + + <h2><a name="functions"></a>Functions</h2> + <a name="def-spec"></a>def +<pre> +template <class F> +void def(char const* name, F f); + +template <class Fn, class A1> +void def(char const* name, Fn fn, A1 const&); + +template <class Fn, class A1, class A2> +void def(char const* name, Fn fn, A1 const&, A2 const&); + +template <class Fn, class A1, class A2, class A3> +void def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>.</dt> + + <dd> + <ul> + <li>If <code>Fn</code> is [derived from] <code><a href= + "object.html#object-spec">object</a></code>, it will be added to + the current scope as a single overload. To be useful, + <code>fn</code> should be <a href= + "http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6">callable</a>.</li> + + <li> + If <code>a1</code> is the result of an <a href= + "overloads.html#overload-dispatch-expression"><em>overload-dispatch-expression</em></a>, + only the second form is allowed and fn must be a pointer to + function or pointer to member function whose <a href= + "definitions.html#arity">arity</a> is the same as A1's <a href= + "overloads.html#overload-dispatch-expression"><em>maximum + arity</em></a>. + + <dl> + <dt><b>Effects:</b> For each prefix <em>P</em> of + <code>Fn</code>'s sequence of argument types, beginning with + the one whose length is <code>A1</code>'s <a href= + "overloads.html#overload-dispatch-expression"><em>minimum + arity</em></a>, adds a + <code><em>name</em>(</code>...<code>)</code> function overload + to the <a href="scope.html">current scope</a>. Each overload + generated invokes <code>a1</code>'s call-expression with + <em>P</em>, using a copy of <code>a1</code>'s <a href= + "CallPolicies.html">call policies</a>. If the longest valid + prefix of <code>A1</code> contains <em>N</em> types and + <code>a1</code> holds <em>M</em> keywords, an initial sequence + of the keywords are used for all but the first + <em>N</em> - <em>M</em> arguments of each + overload.<br> + </dt> + </dl> + </li> + + <li>Otherwise, fn must be a non-null function or member function + pointer, and a single function overload built around fn is added to + the <a href="scope.html">current scope</a>. If any of + <code>a1</code>-<code>a3</code> are supplied, they may be selected + in any order from the table below.</li> + </ul> + + <table border="1" summary="def() optional arguments"> + <tr> + <th>Memnonic Name</th> + + <th>Requirements/Type properties</th> + + <th>Effects</th> + </tr> + + <tr> + <td>docstring</td> + + <td>Any <a href="definitions.html#ntbs">ntbs</a>.</td> + + <td>Value will be bound to the <code>__doc__</code> attribute of + the resulting method overload.</td> + </tr> + + <tr> + <td>policies</td> + + <td>A model of <a href="CallPolicies.html">CallPolicies</a></td> + + <td>A copy will be used as the call policies of the resulting + method overload.</td> + </tr> + + <tr> + <td>keywords</td> + + <td>The result of a <a href= + "args.html#keyword-expression"><em>keyword-expression</em></a> + specifying no more arguments than the <a href= + "definitions.html#arity">arity</a> of <code>fn</code>.</td> + + <td>A copy will be used as the call policies of the resulting + method overload.</td> + </tr> + </table> + </dd> + </dl> + + <h2><a name="examples"></a>Example</h2> +<pre> +#include <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/args.hpp> + +using namespace boost::python; + +char const* foo(int x, int y) { return "foo"; } + +BOOST_PYTHON_MODULE(def_test) +{ + def("foo", foo, args("x", "y"), "foo's docstring"); +} +</pre> + + <p> + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 7 March, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/def_visitor.html b/libs/python/doc/v2/def_visitor.html new file mode 100644 index 000000000..08fa0c514 --- /dev/null +++ b/libs/python/doc/v2/def_visitor.html @@ -0,0 +1,137 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="Microsoft FrontPage 5.0"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/def_visitor.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html"><font size="7">Boost.Python</font></a></h1> + + <h2 align="center">Header <boost/python/def_visitor.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a> + <dt><a href="#classes">Classes</a> + <dd> + <dl class="page-index"> + <dt><a href="#def_visitor-spec">Class <code>def_visitor</code></a> + <dd> <a href="#def_visitor-synopsis">Class <code>def_visitor</code> + synopsis</a></dd> + <dd> <a href="#def_visitor-requirements">Class <code>def_visitor</code> + requirements</a></dd> + </dl> + <dt><a href="#examples">Example</a> +</dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + +<p><code><boost/python/def_visitor.hpp></code> provides a generic visitation + interface through which the <a href="class.html">class_</a> <b>def</b> member + functionality can be extended non-intrusively to avoid cluttering the <a href="class.html">class_</a> + interface. It declares the <code>def_visitor<T> </code>class template, + which is parameterized on the derived type <tt>DerivedVisitor</tt>, which provides + the actual <b>def</b> functionality through its <b>visit</b> member functions. +<h2><a name="classes"></a>Classes</h2> + + <h3><a name="def_visitor-spec"></a>Class template <code>def_visitor<DerivedVisitor></code></h3> + + +<p>The class def_visitor is a base class paramaterized by its derived class. The + def_visitor class is a protocol class. Its derived class, DerivedVisitor, is + expected to have a member function visit. The def_visitor class is never instantiated + directly. Instead, an instance of its subclass, DerivedVisitor, is passed + on as an argument to the <a href="class.html">class_</a> def member function. +<h4> +<a name="def_visitor-synopsis" id="def_visitor-synopsis"></a>Class <code>def_visitor </code>synopsis</h4> +<pre>namespace boost { namespace python { + + template <class DerivedVisitor> + class def_visitor {}; +}</pre> +<h3><a name="def_visitor-requirements"></a><code>def_visitor </code>requirements</h3> + + +<p>The <span class="pre">client supplied class </span><span class="pre"></span><tt class="literal"><span class="pre">DerivedVisitor</span></tt> + template parameter is expected to: +<ul> + <li>be privately derived from def_visitor</li> + <li>grant friend access to class def_visitor_access</li> + <li>define either or both visit member functions listed in the table below:</li> +</ul> + + +<table border class="table"> + <tr> + <td width="181" nowrap><b>Expression</b></td> + <td width="85"><b>Return Type</b></td> + <td width="330"><b>Requirements</b></td> + <td width="259"><b>Effects</b></td> + </tr> + <tr> + <td nowrap>visitor.visit(cls)</td> + <td>void</td> + <td>cls is an instance of a <a href="class.html">class_</a> being wrapped + to Python. visitor is a def_visitor derived class.</td> + <td>A call to cls.def(visitor) forwards to this member function.</td> + </tr> + <tr> + <td nowrap>visitor.visit(cls, name, options)</td> + <td>void</td> + <td>cls is a class_ instance, name is a C string. visitor is a def_visitor + derived class. options is a context specific optional argument.</td> + <td>A call to cls.def(name, visitor) or cls.def(name, visitor, options) forwards + to this member function. </td> + </tr> +</table> + + <h2><a name="examples"></a>Example</h2> + + +<pre>class X {/*...*/};<br> +class my_def_visitor : boost::python::def_visitor<my_def_visitor> +{ + friend class def_visitor_access; + + template <class classT> + void visit(classT& c) const + { + c + .def("foo", &my_def_visitor::foo) + .def("bar", &my_def_visitor::bar) + ; + } + + static void foo(X& self); + static void bar(X& self); +}; + +BOOST_PYTHON_MODULE(my_ext) +{ + class_<X>("X") + .def(my_def_visitor()) + ; +} +</pre> + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->27 August, 2003<!--webbot bot="Timestamp" endspan i-checksum="34484" --> + </p> + + + <p><i>© Copyright Joel de Guzman 2003. </i> Distributed under the Boost + Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libs/python/doc/v2/default_call_policies.html b/libs/python/doc/v2/default_call_policies.html new file mode 100644 index 000000000..30d0a50de --- /dev/null +++ b/libs/python/doc/v2/default_call_policies.html @@ -0,0 +1,173 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/default_call_policies.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/default_call_policies.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a> + + <dd> + <dl class="page-index"> + <dt><a href="#default_call_policies-spec">Class + <code>default_call_policies</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#default_call_policies-spec-synopsis">Class + <code>default_call_policies</code> synopsis</a> + + <dt><a href="#default_call_policies-spec-statics">Class + <code>default_call_policies</code> static functions</a> + </dl> + + <dt><a href="#default_result_converter-spec">Class + <code>default_result_converter</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#default_result_converter-spec-synopsis">Class + <code>default_result_converter</code> synopsis</a> + + <dt><a href="#default_result_converter-spec-metafunctions">Class + <code>default_result_converter</code> metafunctions</a> + </dl> + </dl> + + <dt><a href="#examples">Example</a> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="default_call_policies-spec"></a>Class + <code>default_call_policies</code></h3> + + <p><code>default_call_policies</code> is a model of <a href= + "CallPolicies.html">CallPolicies</a> with no <code>precall</code> or + <code>postcall</code> behavior and a <code>result_converter</code> which + handles by-value returns. Wrapped C++ functions and member functions use + <code>default_call_policies</code> unless otherwise specified. You may find + it convenient to derive new models of <a href= + "CallPolicies.html">CallPolicies</a> from + <code>default_call_policies</code>. + + <h4><a name="default_call_policies-spec-synopsis"></a>Class + <code>default_call_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct default_call_policies + { + static bool precall(PyObject*); + static PyObject* postcall(PyObject*, PyObject* result); + typedef <a href= +"#default_result_converter-spec">default_result_converter</a> result_converter; + template <class Sig> struct extract_return_type : mpl::front<Sig>{}; + }; +}} +</pre> + + <h4><a name="default_call_policies-spec-statics"></a>Class + <code>default_call_policies</code> static functions</h4> +<pre> +bool precall(PyObject*); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>true</code> + + <dt><b>Throws:</b> nothing + </dl> +<pre> +PyObject* postcall(PyObject*, PyObject* result); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>result</code> + + <dt><b>Throws:</b> nothing + </dl> + + <h3><a name="default_result_converter-spec"></a>Class + <code>default_result_converter</code></h3> + + <p><code>default_result_converter</code> is a model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> which can be + used to wrap C++ functions returning non-pointer types, <code>char + const*</code>, and <code>PyObject*</code>, by-value. + + <h4><a name="default_result_converter-spec-synopsis"></a>Class + <code>default_result_converter</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct default_result_converter + { + template <class T> struct apply; + }; +}} +</pre> + + <h4><a name="default_result_converter-spec-metafunctions"></a>Class + <code>default_result_converter</code> metafunctions</h4> +<pre> +template <class T> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Requires:</b> <code>T</code> is not a reference type. If + <code>T</code> is a pointer type, <code>T</code> is <code>const + char*</code> or <code>PyObject*</code>. + + <dt><b>Returns:</b> <code>typedef <a href= + "to_python_value.html#to_python_value-spec">to_python_value</a><T + const&> type;</code> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <p>This example comes from the Boost.Python implementation itself. Because + the <a href= + "return_value_policy.html#return_value_policy-spec">return_value_policy</a> + class template does not implement <code>precall</code> or + <code>postcall</code> behavior, its default base class is + <code>default_call_policies</code>: +<pre> +template <class Handler, class Base = default_call_policies> +struct return_value_policy : Base +{ + typedef Handler result_converter; +}; +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 11 June, 2007 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002.</i> Distributed under the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/doc/v2/definitions.html b/libs/python/doc/v2/definitions.html new file mode 100644 index 000000000..cfec181c7 --- /dev/null +++ b/libs/python/doc/v2/definitions.html @@ -0,0 +1,102 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Definitions</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Definitions</h2> + </td> + </tr> + </table> + <hr> + + <dl class="definitions"> + <dt><b><a name="arity">arity</a>:</b> The number of arguments accepted + by a function or member function. Unless otherwise specified, the + hidden "<code>this</code>" argument to member functions is not counted + when specifying arity</dt> + + <dd><br> + </dd> + + <dt><b><a name="ntbs">ntbs</a>:</b> Null-Terminated Byte String, or + `C'-string. C++ string literals are <strong>ntbs</strong>es. An + <strong>ntbs</strong> must never be null.</dt> + + <dd><br> + </dd> + + <dt><b><a name="raise">raise</a>:</b> Exceptions in Python are + "raised", not "thrown", as they are in C++. When this documentation + says that some Python exception is "raised" in the context of C++ code, + it means that the corresponding Python exception is set via the <a + href= + "http://www.python.org/doc/current/api/exceptionHandling.html">Python/'C' + API</a>, and <code><a href= + "errors.html#throw_error_already_set-spec">throw_error_already_set</a>()</code> + is called.</dt> + + <dd><br> + </dd> + + <dt><b><a name="POD">POD</a>:</b> A technical term from the C++ + standard. Short for "Plain Ol'Data": A POD-struct is an aggregate class + that has no non-static data members of type pointer to member, + non-POD-struct, non-POD-union (or array of such types) or reference, + and has no user-defined copy assign- ment operator and no user-defined + destructor. Similarly, a POD-union is an aggregate union that has no + non-static data members of type pointer to member, non-POD-struct, + non-POD-union (or array of such types) or reference, and has no + user-defined copy assignment operator and no user-defined destructor. A + POD class is a class that is either a POD-struct or a POD-union. An + aggregate is an array or a class (clause 9) with no user-declared + constructors (12.1), no private or protected non-static data members + (clause 11), no base classes (clause 10), and no virtual functions + (10.3).</dt> + + <dd><br> + </dd> + + <dt><b><a name="ODR">ODR</a>:</b> The "One Definition + Rule", which says that any entity in a C++ program must have the same definition in all translation units (object files) which make up a program. + </dt> + + <dd><br> + </dd> + + + </dl> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/dict.html b/libs/python/doc/v2/dict.html new file mode 100644 index 000000000..82ea13653 --- /dev/null +++ b/libs/python/doc/v2/dict.html @@ -0,0 +1,152 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/dict.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/dict.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#dict-spec">Class <code>dict</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#dict-spec-synopsis">Class <code>dict</code> + synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> for the Python + <a href= + "http://www.python.org/dev/doc/devel/lib/typesmapping.html">dict</a> + type.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="dict-spec"></a>Class <code>dict</code></h3> + + <p>Exposes the <a href= + "http://www.python.org/dev/doc/devel/lib/typesmapping.html">mapping + protocol</a> of Python's built-in <code>dict</code> type. The semantics + of the constructors and member functions defined below can be fully + understood by reading the <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept + definition. Since <code>dict</code> is publicly derived from <code><a + href="object.html#object-spec">object</a></code>, the public object + interface applies to <code>dict</code> instances as well.</p> + + <h4><a name="dict-spec-synopsis"></a>Class <code>dict</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class dict : public object + { + dict(); + + template< class T > + dict(T const & data); + + // modifiers + void clear(); + dict copy(); + + template <class T1, class T2> + tuple popitem(); + + template <class T> + object setdefault(T const &k); + + template <class T1, class T2> + object setdefault(T1 const & k, T2 const & d); + + void update(object_cref E); + + template< class T > + void update(T const & E); + + // observers + list values() const; + + object get(object_cref k) const; + + template<class T> + object get(T const & k) const; + + object get(object_cref k, object_cref d) const; + object get(T1 const & k, T2 const & d) const; + + bool has_key(object_cref k) const; + + template< class T > + bool has_key(T const & k) const; + + list items() const; + object iteritems() const; + object iterkeys() const; + object itervalues() const; + list keys() const; + }; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> +<pre> +using namespace boost::python; +dict swap_object_dict(object target, dict d) +{ + dict result = extract<dict>(target.attr("__dict__")); + target.attr("__dict__") = d; + return result; +} +</pre> + + <p>Revised 30 September, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/docstring_options.html b/libs/python/doc/v2/docstring_options.html new file mode 100644 index 000000000..a2a0cc645 --- /dev/null +++ b/libs/python/doc/v2/docstring_options.html @@ -0,0 +1,386 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta name="generator" content= + "HTML Tidy for Linux/x86 (vers 1st September 2004), see www.w3.org"> + <meta http-equiv="Content-Type" content= + "text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/docstring_options.hpp></title> +</head> + +<body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png" border= + "0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href= + "../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/docstring_options.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#docstring_options-spec">Class + <code>docstring_options</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#docstring_options-spec-synopsis">Class + <code>docstring_options</code> synopsis</a></dt> + + <dt><a href="#docstring_options-spec-ctors">Class + <code>docstring_options</code> constructors</a></dt> + + <dt><a href="#docstring_options-spec-dtors">Class + <code>docstring_options</code> destructors</a></dt> + + <dt><a href="#docstring_options-spec-modifiers">Class + <code>docstring_options</code> modifiers</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction" id= + "introduction"></a>Introduction</h2> + + <p>Boost.Python supports user-defined docstrings with automatic + appending of C++ signatures. These features are enabled by + default. The <code>class docstring_options</code> is available to + selectively suppress the user-defined docstrings, signatures, or + both.</p> + + <h2><a name="classes" id="classes"></a>Classes</h2> + + <h3><a name="docstring_options-spec" id= + "docstring_options-spec"></a>Class + <code>docstring_options</code></h3> + + <p>Controls the appearance of docstrings of wrapped functions and + member functions for the life-time of the instance. The instances + are noncopyable to eliminate the possibility of surprising side + effects.</p> + + <h4><a name="docstring_options-spec-synopsis" id= + "docstring_options-spec-synopsis"></a>Class + <code>docstring_options</code> synopsis</h4> + <pre> +namespace boost { namespace python { + + class docstring_options : boost::noncopyable + { + public: + docstring_options(bool show_all=true); + + docstring_options(bool show_user_defined, bool show_signatures); + + docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); + + ~docstring_options(); + + void + disable_user_defined(); + + void + enable_user_defined(); + + void + disable_signatures(); + + void + enable_signatures(); + + void + disable_py_signatures(); + + void + enable_py_signatures(); + + void + disable_cpp_signatures(); + + void + enable_cpp_signatures(); + + void + disable_all(); + + void + enable_all(); + }; + +}} +</pre> + + <h4><a name="docstring_options-spec-ctors" id= + "docstring_options-spec-ctors"></a>Class + <code>docstring_options</code> constructors</h4> + <pre> +docstring_options(bool show_all=true); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Constructs a <code>docstring_options</code> + object which controls the appearance of function and + member-function docstrings defined in the code that follows. If + <code>show_all</code> is <code>true</code>, both the + user-defined docstrings and the automatically generated Python and C++ + signatures are shown. If <code>show_all</code> is + <code>false</code> the <code>__doc__</code> attributes are + <code>None</code>.</dt> + </dl> + <pre> +docstring_options(bool show_user_defined, bool show_signatures); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Constructs a <code>docstring_options</code> + object which controls the appearance of function and + member-function docstrings defined in the code that follows. + Iff <code>show_user_defined</code> is <code>true</code>, the + user-defined docstrings are shown. Iff + <code>show_signatures</code> is <code>true</code>, Python and C++ + signatures are automatically added. If both + <code>show_user_defined</code> and <code>show_signatures</code> + are <code>false</code>, the <code>__doc__</code> attributes are + <code>None</code>.</dt> + </dl> + <pre> +docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Constructs a <code>docstring_options</code> + object which controls the appearance of function and + member-function docstrings defined in the code that follows. + Iff <code>show_user_defined</code> is <code>true</code>, the + user-defined docstrings are shown. Iff + <code>show_py_signatures</code> is <code>true</code>, Python + signatures are automatically added. Iff + <code>show_cpp_signatures</code> is <code>true</code>, C++ + signatures are automatically added. If all parameters are + <code>false</code>, the <code>__doc__</code> attributes are + <code>None</code>.</dt> + </dl> + + <h4><a name="docstring_options-spec-dtors" id= + "docstring_options-spec-dtors"></a>Class + <code>docstring_options</code> destructors</h4> + <pre> +~docstring_options(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Restores the previous state of the + docstring options. In particular, if + <code>docstring_options</code> instances are in nested C++ + scopes the settings effective in the enclosing scope are + restored. If the last <code>docstring_options</code> instance + goes out of scope the default "all on" settings are + restored.</dt> + </dl> + + <h4><a name="docstring_options-spec-modifiers" id= + "docstring_options-spec-modifiers"></a>Class + <code>docstring_options</code> modifier functions</h4> + <pre> +void disable_user_defined(); +void enable_user_defined(); +void disable_signatures(); +void enable_signatures(); +void disable_py_signatures(); +void enable_py_signatures(); +void disable_cpp_signatures(); +void enable_cpp_signatures(); +void disable_all(); +void enable_all(); +</pre> + + <dl class="function-semantics"> + <dt>These member functions dynamically change the appearance of + docstrings in the code that follows. The + <code>*_user_defined()</code> and <code>*_signatures()</code> + member functions are provided for fine-grained control. The + <code>*_all()</code> member functions are convenient shortcuts + to manipulate all settings simultaneously.</dt> + </dl> + + <h2><a name="examples" id="examples"></a>Examples</h2> + + <h4>Docstring options defined at compile time</h4> + <pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/docstring_options.hpp> + +void foo() {} + +BOOST_PYTHON_MODULE(demo) +{ + using namespace boost::python; + docstring_options doc_options(DEMO_DOCSTRING_SHOW_ALL); + def("foo", foo, "foo doc"); +} +</pre>If compiled with <code>-DDEMO_DOCSTRING_SHOW_ALL=true</code>: + <pre> +>>> import demo +>>> print demo.foo.__doc__ +foo() -> None : foo doc +C++ signature: + foo(void) -> void +</pre>If compiled with +<code>-DDEMO_DOCSTRING_SHOW_ALL=false</code>: + <pre> +>>> import demo +>>> print demo.foo.__doc__ +None +</pre> + + <h4>Selective suppressions</h4> + <pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/args.hpp> +#include <boost/python/docstring_options.hpp> + +int foo1(int i) { return i; } +int foo2(long l) { return static_cast<int>(l); } +int foo3(float f) { return static_cast<int>(f); } +int foo4(double d) { return static_cast<int>(d); } + +BOOST_PYTHON_MODULE(demo) +{ + using namespace boost::python; + docstring_options doc_options; + def("foo1", foo1, arg("i"), "foo1 doc"); + doc_options.disable_user_defined(); + def("foo2", foo2, arg("l"), "foo2 doc"); + doc_options.disable_signatures(); + def("foo3", foo3, arg("f"), "foo3 doc"); + doc_options.enable_user_defined(); + def("foo4", foo4, arg("d"), "foo4 doc"); + doc_options.enable_py_signatures(); + def("foo5", foo4, arg("d"), "foo5 doc"); + doc_options.disable_py_signatures(); + doc_options.enable_cpp_signatures(); + def("foo6", foo4, arg("d"), "foo6 doc"); +} +</pre>Python code: + <pre> +>>> import demo +>>> print demo.foo1.__doc__ +foo1( (int)i) -> int : foo1 doc +C++ signature: + foo1(int i) -> int +>>> print demo.foo2.__doc__ +foo2( (int)l) -> int : +C++ signature: + foo2(long l) -> int +>>> print demo.foo3.__doc__ +None +>>> print demo.foo4.__doc__ +foo4 doc +>>> print demo.foo5.__doc__ +foo5( (float)d) -> int : foo5 doc +>>> print demo.foo6.__doc__ +foo6 doc +C++ signature: + foo6(double d) -> int +</pre> + + <h4>Wrapping from multiple C++ scopes</h4> + <pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/args.hpp> +#include <boost/python/docstring_options.hpp> + +int foo1(int i) { return i; } +int foo2(long l) { return static_cast<int>(l); } + +int bar1(int i) { return i; } +int bar2(long l) { return static_cast<int>(l); } + +namespace { + + void wrap_foos() + { + using namespace boost::python; + // no docstring_options here + // -> settings from outer C++ scope are in effect + def("foo1", foo1, arg("i"), "foo1 doc"); + def("foo2", foo2, arg("l"), "foo2 doc"); + } + + void wrap_bars() + { + using namespace boost::python; + bool show_user_defined = true; + bool show_signatures = false; + docstring_options doc_options(show_user_defined, show_signatures); + def("bar1", bar1, arg("i"), "bar1 doc"); + def("bar2", bar2, arg("l"), "bar2 doc"); + } +} + +BOOST_PYTHON_MODULE(demo) +{ + boost::python::docstring_options doc_options(false); + wrap_foos(); + wrap_bars(); +} +</pre>Python code: + <pre> +>>> import demo +>>> print demo.foo1.__doc__ +None +>>> print demo.foo2.__doc__ +None +>>> print demo.bar1.__doc__ +bar1 doc +>>> print demo.bar2.__doc__ +bar2 doc +</pre> + + <h4>See also: <code>boost/libs/python/test/docstring.cpp</code> + and <code>docstring.py</code></h4> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 16 January, 2006 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --></p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/ralf_w_grosse_kunstleve.htm">Ralf W. + Grosse-Kunstleve</a> 2006.</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/enum.html b/libs/python/doc/v2/enum.html new file mode 100644 index 000000000..c5ec2b921 --- /dev/null +++ b/libs/python/doc/v2/enum.html @@ -0,0 +1,234 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/enum.hpp></title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/enum.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#enum_-spec">Class template + <code>enum_</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#enum_-spec-synopsis">Class template <code>enum_</code> + synopsis</a></dt> + + <dt><a href="#enum_-spec-ctors">Class template <code>enum_</code> + constructors</a></dt> + + <dt><a href="#enum_-spec-modifiers">Class template <code>enum_</code> + modifier functions</a></dt> + </dl> + </dd> + + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/enum.hpp></code> defines the + interface through which users expose their C++ enumeration types + to Python. It declares the + <code>enum_</code> class template, which is parameterized on the + enumeration type being exposed. </p> + + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="enum_-spec"></a>Class template + <code>enum_<T></code></h3> + + <p>Creates a Python class derived from Python's <code>int</code> + type which is associated with the C++ type passed as its first + parameter. + + <h4><a name="enum_-spec-synopsis"></a>Class template <code>enum_</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T> + class enum_ : public <a href="object.html#object-spec">object</a> + { + enum_(char const* name, char const* doc = 0); + enum_<T>& value(char const* name, T); + enum_<T>& export_values(); + }; +}} +</pre> + + <h4><a name="enum_-spec-ctors"></a>Class template <code>enum_</code> + constructors</h4> +<pre> +enum_(char const* name, char const* doc=0); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>. + + <dt><b>Effects:</b> Constructs an <code>enum_</code> object + holding a Python extension type derived from <code>int</code> + which is named <code>name</code>. The + <code>name</code>d attribute of the <a href= + "scope.html#introduction">current scope</a> is bound to the new + extension type.</dt> + </dl> + + <h4><a name="enum_-spec-modifiers"></a>Class template + <code>enum_</code> modifier functions</h4> +<pre> +inline enum_<T>& value(char const* name, T x); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is an <a href= + "definitions.html#ntbs">ntbs</a> which conforms to Python's <a + href= + "http://www.python.org/doc/current/ref/identifiers.html">identifier + naming rules</a>. + + <dt><b>Effects:</b> adds an instance of the wrapped enumeration + type with value <code>x</code> to the type's dictionary as the + <code>name</code>d attribute.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + </dl> + +<pre> +inline enum_<T>& export_values(); +</pre> + + <dl class="function-semantics"> + + <dt><b>Effects:</b> sets attributes in the current <a + href="scope.html#scope-spec"><code>scope</code></a> with the + same names and values as all enumeration values exposed so far + by calling <code>value()</code>.</dt> + + <dt><b>Returns:</b> <code>*this</code></dt> + + </dl> + + <h2><a name="examples"></a>Example(s)</h2> + + <p>C++ module definition +<pre> +#include <boost/python/enum.hpp> +#include <boost/python/def.hpp> +#include <boost/python/module.hpp> + +using namespace boost::python; + +enum color { red = 1, green = 2, blue = 4 }; + +color identity_(color x) { return x; } + +BOOST_PYTHON_MODULE(enums) +{ + enum_<color>("color") + .value("red", red) + .value("green", green) + .export_values() + .value("blue", blue) + ; + + def("identity", identity_); +} +</pre> + <p>Interactive Python: +<pre> +>>> from enums import * + +>>> identity(red) +enums.color.red + +>>> identity(color.red) +enums.color.red + +>>> identity(green) +enums.color.green + +>>> identity(color.green) +enums.color.green + +>>> identity(blue) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +NameError: name blue' is not defined + +>>> identity(color.blue) +enums.color.blue + +>>> identity(color(1)) +enums.color.red + +>>> identity(color(2)) +enums.color.green + +>>> identity(color(3)) +enums.color(3) + +>>> identity(color(4)) +enums.color.blue + +>>> identity(1) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: bad argument type for built-in operation +</pre> + <hr> + + Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 December, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/errors.html b/libs/python/doc/v2/errors.html new file mode 100644 index 000000000..69a3cf570 --- /dev/null +++ b/libs/python/doc/v2/errors.html @@ -0,0 +1,289 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/errors.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/errors.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#error_already_set-spec">Class + <code>error_already_set</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#error_already_set-spec-synopsis">Class + <code>error_already_set</code> synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#handle_exception-spec">handle_exception</a></dt> + + <dt><a href="#expect_non_null-spec">expect_non_null</a></dt> + + <dt><a href= + "#throw_error_already_set-spec">throw_error_already_set</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/errors.hpp></code> provides types and + functions for managing and translating between Python and C++ exceptions. + This is relatively low-level functionality that is mostly used internally + by Boost.Python. Users should seldom need it.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="error_already_set-spec"></a>Class + <code>error_already_set</code></h3> + + <p><code>error_already_set</code> is an exception type which can be + thrown to indicate that a Python error has occurred. If thrown, the + precondition is that <a href= + "http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred()</a> + returns a value convertible to <code>true</code>. Portable code shouldn't + throw this exception type directly, but should instead use <code><a href= + "#throw_error_already_set-spec">throw_error_already_set</a>()</code>, + below.</p> + + <h4><a name="error_already_set-spec-synopsis"></a>Class error_already_set + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class error_already_set {}; +}} +</pre> + + <h2><a name="functions"></a>Functions</h2> +<pre> +<a name= +"handle_exception-spec">template <class T> bool handle_exception</a>(T f) throw(); + +void handle_exception() throw(); +</pre> + + <dl class="handle_exception-semantics"> + <dt><b>Requires:</b> The first form requires that the expression + <code><a href= + "../../../../doc/html/functionN.html">function0</a><void>(f)</code> + is valid. The second form requires that a C++ exception is currently + being handled (see section 15.1 in the C++ standard).</dt> + + <dt><b>Effects:</b> The first form calls <code>f()</code> inside a + <code>try</code> block which first attempts to use all registered <a + href="exception_translator.html">exception translators</a>. If none of + those translates the exception, the <code>catch</code> clauses then set + an appropriate Python exception for the C++ exception caught, returning + <code>true</code> if an exception was thrown, <code>false</code> + otherwise. The second form passes a function which rethrows the + exception currently being handled to the first form.</dt> + + <dt><b>Postconditions:</b> No exception is being handled</dt> + + <dt><b>Throws:</b> nothing</dt> + + <dt><b>Rationale:</b> At inter-language boundaries it is important to + ensure that no C++ exceptions escape, since the calling language + usually doesn't have the equipment necessary to properly unwind the + stack. Use <code>handle_exception</code> to manage exception + translation whenever your C++ code is called directly from the Python + API. This is done for you automatically by the usual function wrapping + facilities: <code><a href= + "make_function.html#make_function-spec">make_function</a>()</code>, + <code><a href= + "make_function.html#make_constructor-spec">make_constructor</a>()</code>, + <code><a href="def.html#class_-spec-modifiers">def</a>()</code> and <code><a href= + "class.html#def-spec">class_::def</a>()</code>. The second form can be + more convenient to use (see the <a href="#examples">example</a> below), + but various compilers have problems when exceptions are rethrown from + within an enclosing <code>try</code> block.</dt> + </dl> +<pre> +<a name= +"expect_non_null-spec">template <class T> T* expect_non_null(T* x);</a> +</pre> + + <dl class="expect_non_null-semantics"> + <dt><b>Returns:</b> <code>x</code></dt> + + <dt><b>Throws:</b> <code><a href= + "#error_already_set-spec">error_already_set</a>()</code> iff <code>x == + 0</code>.</dt> + + <dt><b>Rationale:</b> Simplifies error-handling when calling functions + in the <a href="http://www.python.org/doc/2.2/api/api.html">Python/C + API</a> which return 0 on error.</dt> + </dl> +<pre> +<a name="throw_error_already_set-spec">void throw_error_already_set();</a> +</pre> + + <dl class="throw_error_already_set-semantics"> + <dt><b>Effects:</b> <code>throw <a href= + "#error_already_set-spec">error_already_set</a>();</code></dt> + </dl> + + <dl> + <dt><b>Rationale:</b> Many platforms and compilers are not able to + consistently catch exceptions thrown across shared library boundaries. + Using this function from the Boost.Python library ensures that the + appropriate <code>catch</code> block in <code><a href= + "#handle_exception-spec">handle_exception</a>()</code> can catch the + exception.</dt> + </dl> + + <h2><a name="examples"></a>Examples</h2> +<pre> +#include <string> +#include <boost/python/errors.hpp> +#include <boost/python/object.hpp> +#include <boost/python/handle.hpp> + +// Returns a std::string which has the same value as obj's "__name__" +// attribute. +std::string get_name(boost::python::object obj) +{ + // throws if there's no __name__ attribute + PyObject* p = boost::python::expect_non_null( + PyObject_GetAttrString(obj.ptr(), "__name__")); + + char const* s = PyString_AsString(p); + if (s != 0) + Py_DECREF(p); + + // throws if it's not a Python string + std::string result( + boost::python::expect_non_null( + PyString_AsString(p))); + + Py_DECREF(p); // Done with p + + return result; +} + +// +// Demonstrate form 1 of handle_exception +// + +// Place into result a Python Int object whose value is 1 if a and b have +// identical "__name__" attributes, 0 otherwise. +void same_name_impl(PyObject*& result, boost::python::object a, boost::python::object b) +{ + result = PyInt_FromLong( + get_name(a) == get_name(a2)); +} + +object borrowed_object(PyObject* p) +{ + return boost::python::object( + boost::python::handle<>( + boost::python::borrowed(a1))); +} + +// This is an example Python 'C' API interface function +extern "C" PyObject* +same_name(PyObject* args, PyObject* keywords) +{ + PyObject* a1; + PyObject* a2; + PyObject* result = 0; + + if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2)) + return 0; + + // Use boost::bind to make an object compatible with + // boost::Function0<void> + if (boost::python::handle_exception( + boost::bind<void>(same_name_impl, boost::ref(result), borrowed_object(a1), borrowed_object(a2)))) + { + // an exception was thrown; the Python error was set by + // handle_exception() + return 0; + } + + return result; +} + +// +// Demonstrate form 2 of handle_exception. Not well-supported by all +// compilers. +// +extern "C" PyObject* +same_name2(PyObject* args, PyObject* keywords) +{ + PyObject* a1; + PyObject* a2; + PyObject* result = 0; + + if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2)) + return 0; + + try { + return PyInt_FromLong( + get_name(borrowed_object(a1)) == get_name(borrowed_object(a2))); + } + catch(...) + { + // If an exception was thrown, translate it to Python + boost::python::handle_exception(); + return 0; + } +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/exception_translator.html b/libs/python/doc/v2/exception_translator.html new file mode 100644 index 000000000..4cc7bb91b --- /dev/null +++ b/libs/python/doc/v2/exception_translator.html @@ -0,0 +1,150 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/exception_translator.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/exception_translator.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href= + "#register_exception_translator-spec">register_exception_translator</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>As described <a href="errors.html#handle_exception-spec">here</a>, it + is important to make sure that exceptions thrown by C++ code do not pass + into the Python interpreter core. By default, Boost.Python translates all + C++ exceptions thrown by wrapped functions and module init functions into + Python, but the default translators are extremely limited: most C++ + exceptions will appear in Python as a <a href= + "http://www.python.org/doc/current/lib/module-exceptions.html">RuntimeError</a> + exception whose representation is + <code>'Unidentifiable C++ Exception'</code>. To produce better + error messages, users can register additional exception translators as + described below.</p> + + <h2><a name="functions"></a>Functions</h2> + +<h3><code><a name="register_exception_translator-spec">register_exception_translator</a></code></h3> + +<pre> +<a name="register_exception_translator-spec">template<class ExceptionType, class Translate></a> +void register_exception_translator(Translate translate); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b></dt> + + <dd> + <code>Translate</code> is <a href= + "../../../utility/CopyConstructible.html">Copyconstructible</a>, and + the following code must be well-formed: +<pre> +void f(ExceptionType x) { translate(x); } +</pre> + The expression <code>translate(x)</code> must either throw a C++ + exception, or a subsequent call to <code><a href= + "http://www.python.org/doc/current/api/exceptionHandling.html">PyErr_Occurred</a>()</code> + must return 1. + </dd> + + <p> + + <dt><b>Effects:</b> Adds a copy of <code>translate</code> to the sequence of + exception translators tried when Boost.Python catches an exception that + is about to pass into Python's core interpreter. The new translator + will get "first shot" at translating all exceptions matching the catch + clause shown above. Any subsequently-registered translators will be + allowed to translate the exception earlier. A translator which cannot + translate a given C++ exception can re-throw it, and it will be handled + by a translator which was registered earlier (or by the default + translator).</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/exception_translator.hpp> +#include <exception> + +struct my_exception : std::exception +{ + char const* what() throw() { return "One of my exceptions"; } +}; + +void translate(my_exception const& e) +{ + // Use the Python 'C' API to set up an exception object + PyErr_SetString(PyExc_RuntimeError, e.what()); +} + +void something_which_throws() +{ + ... + throw my_exception(); + ... +} + +BOOST_PYTHON_MODULE(exception_translator_ext) +{ + using namespace boost::python; + register_exception_translator<my_exception>(&translate); + + def("something_which_throws", something_which_throws); +} +</pre> + <br> + <br> + + <hr> + + <p>Revised 03 October, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/exec.html b/libs/python/doc/v2/exec.html new file mode 100644 index 000000000..83d2c9b89 --- /dev/null +++ b/libs/python/doc/v2/exec.html @@ -0,0 +1,163 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/exec.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/exec.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#eval-spec"><code>eval</code></a></dt> + <dt><a href="#exec-spec"><code>exec</code></a></dt> + <dt><a href="#exec_file-spec"><code>exec_file</code></a></dt> + </dl> + </dd> + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a mechanism for embedding the python interpreter into C++ code.</p> + + <h2><a name="functions"></a>Functions</h2> + + <h3><a name="eval-spec"></a><code>eval</code></h3> + <pre> +object eval(str expression, + object globals = object(), + object locals = object()); + </pre> + <dl class="function-semantics"> + <dt><b>Effects:</b> + Evaluate Python expression from <code>expression</code> in the context + specified by the dictionaries <code>globals</code> and <code>locals</code>. + </dt> + <dt><b>Returns:</b> + An instance of <a href="object.html#object-spec">object</a> + which holds the value of the expression. + </dt> + </dl> + + <h3><a name="exec-spec"></a><code>exec</code></h3> + <pre> +object exec(str code, + object globals = object(), + object locals = object()); + </pre> + <dl class="function-semantics"> + <dt><b>Effects:</b> + Execute Python source code from <code>code</code> in the context + specified by the dictionaries <code>globals</code> and <code>locals</code>. + </dt> + <dt><b>Returns:</b> + An instance of <a href="object.html#object-spec">object</a> + which holds the result of executing the code. + </dt> + </dl> + + <h3><a name="exec_file-spec"></a><code>exec_file</code></h3> + <pre> +object exec_file(str filename, + object globals = object(), + object locals = object()); + </pre> + <dl class="function-semantics"> + <dt><b>Effects:</b> + Execute Python source code from the file named by <code>filename</code> + in the context specified by the dictionaries <code>globals</code> and + <code>locals</code>. + </dt> + <dt><b>Returns:</b> + An instance of <a href="object.html#object-spec">object</a> + which holds the result of executing the code. + </dt> + </dl> + + <h2><a name="examples"></a>Examples</h2> + + <para>The following example demonstrates the use of <function>import</function> + and <function>exec</function> to define a function in python, and later call + it from within C++.</para> + +<pre> +#include <iostream> +#include <string> + +using namespace boost::python; + +void greet() +{ + // Retrieve the main module. + object main = import("__main__"); + + // Retrieve the main module's namespace + object global(main.attr("__dict__")); + + // Define greet function in Python. + object result = exec( + "def greet(): \n" + " return 'Hello from Python!' \n", + global, global); + + // Create a reference to it. + object greet = global["greet"]; + + // Call it. + std::string message = extract<std::string>(greet()); + std::cout << message << std::endl; +} +</pre> + + <para>Instead of embedding the python script into a string, + we could also store it in an a file...</para> + +<pre> +def greet(): + return 'Hello from Python!' +</pre> + <para>... and execute that instead.</para> +<pre> + // ... + // Load the greet function from a file. + object result = exec_file(script, global, global); + // ... +} +</pre> + <p>Revised 01 November, 2005</p> + + <p><i>© Copyright Stefan Seefeld 2005.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/extract.html b/libs/python/doc/v2/extract.html new file mode 100644 index 000000000..3c6b77f2f --- /dev/null +++ b/libs/python/doc/v2/extract.html @@ -0,0 +1,232 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/extract.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/extract.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#extract-spec">Class <code>extract</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#extract-spec-synopsis">Class <code>extract</code> + synopsis</a></dt> + + <dt><a href="#extract-spec-ctors">Class <code>extract</code> + constructors and destructor</a></dt> + + <dt><a href="#extract-spec-observers">Class + <code>extract</code> observer functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a mechanism for extracting C++ object values from + generalized Python objects. Note that + <code>extract<</code>...<code>></code> can also be used to + "downcast" an <a + href="object.html#object-spec">object</a> to some specific <a + href="ObjectWrapper.html#ObjectWrapper-concept">ObjectWrapper</a>. Because + invoking a mutable python type with an argument of the same type + (e.g. <code>list([1,2])</code> typically makes a <em>copy</em> of + the argument object, this may be the only way to access the <a + href="ObjectWrapper.html#ObjectWrapper-concept">ObjectWrapper</a>'s + interface on the original object. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="extract-spec"></a>Class template <code>extract</code></h3> + + <p><code>extract<T></code> can be used to extract a value of + an arbitrary C++ type from an instance of <code><a + href="object.html#object-spec">object</a></code>. Two usages are supported: +<ol> +<li><b><code>extract<T>(o)</code></b> is a temporary object +which is implicitly convertible to <code>T</code> (explicit conversion +is also available through the object's function-call +operator). However, if no conversion is available which can convert +<code>o</code> to an object of type <code>T</code>, a Python +<code>TypeError</code> exception will be <a +href="definitions.html#raise">raised</a>. + +<li><b><code>extract<T> x(o);</code></b> constructs an extractor +whose <code>check()</code> member function can be used to ask whether +a conversion is available without causing an exception to be thrown. +</ol> + + <h4><a name="extract-spec-synopsis"></a>Class template <code>extract</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T> + struct extract + { + typedef <i>unspecified</i> result_type; + + extract(PyObject*); + extract(object const&); + + result_type operator()() const; + operator result_type() const; + + bool check() const; + }; +}} +</pre> + + <h4><a name="extract-spec-ctors"></a>Class <code>extract</code> + constructors and destructor</h4> +<pre> +extract(PyObject* p); +extract(object const&); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> The first form requires that <code>p</code> is non-null.</dt> + + <dt><b>Effects:</b>Stores a pointer to the Python object managed + by its constructor argument. In particular, the reference + count of the object is not incremented. The onus is on the user + to be sure it is not destroyed before the extractor's conversion + function is called.</dt> + </dl> + + <h4><a name="extract-spec-observers"></a>Class <code>extract</code> + observer functions</h4> +<pre> +result_type operator()() const; +operator result_type() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Converts the stored pointer to + <code>result_type</code>, which is either <code>T</code> or + <code>T const&</code>. + </dt> + + <dt><b>Returns:</b> An object of <code>result_type</code> + corresponding to the one referenced by the stored pointer.</dt> + + <dt><b>Throws:</b> <code><a + href="errors.html#error_already_set-spec">error_already_set</a></code> + and sets a <code>TypeError</code> if no such conversion is + available. May also emit other unspecified exceptions thrown by + the converter which is actually used.</dt> + </dl> + +<pre> +bool check() const; +</pre> + + <dl class="function-semantics"> + + <dt><b>Postconditions:</b> None. In particular, note that a + return value of <code>true</code> does not preclude an exception + being thrown from <code>operator result_type()</code> or + <code>operator()()</code>.</dt> + + <dt><b>Returns:</b> <code>false</code> <i>only</i> if no conversion from the + stored pointer to <code>T</code> is available.</dt> + + </dl> + + + <h2><a name="examples"></a>Examples</h2> + +<pre> +#include <cstdio> +using namespace boost::python; +int Print(str s) +{ + // extract a C string from the Python string object + char const* c_str = extract<char const*>(s); + + // Print it using printf + std::printf("%s\n", c_str); + + // Get the Python string's length and convert it to an int + return extract<int>(s.attr("__len__")()) +} +</pre> + +The following example shows how extract can be used along with +<code><a +href="class.html#class_-spec">class_</a><</code>...<code>></code> +to create and access an instance of a wrapped C++ class. + +<pre> +struct X +{ + X(int x) : v(x) {} + int value() { return v; } + private: + int v; +}; + +BOOST_PYTHON_MODULE(extract_ext) +{ + object x_class( + class_<X>("X", init<int>()) + .def("value", &X::value)) + ; + + // Instantiate an X object through the Python interface. + // Its lifetime is now managed by x_obj. + object x_obj = x_class(3); + + // Get a reference to the C++ object out of the Python object + X& x = extract<X&>(x_obj); + assert(x.value() == 3); +} +</pre> + <p>Revised 15 November, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/faq.html b/libs/python/doc/v2/faq.html new file mode 100644 index 000000000..75283d77c --- /dev/null +++ b/libs/python/doc/v2/faq.html @@ -0,0 +1,861 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - FAQ</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Frequently Asked Questions (FAQs)</h2> + </td> + </tr> + </table> + <hr> + + <dl class="page-index"> + + <dt><a href="#funcptr">How can I wrap a function which takes a + function pointer as an argument?</a><dd> + + <dt><a href="#dangling">I'm getting the "attempt to return dangling + reference" error. What am I doing wrong?</a></dt> + + <dt><a href="#question1">Is return_internal_reference + efficient?</a></dt> + + <dt><a href="#question2">How can I wrap functions which take C++ + containers as arguments?</a></dt> + + <dt><a href="#c1204">fatal error C1204:Compiler limit:internal + structure overflow</a></dt> + + <dt><a href="#debugging">How do I debug my Python extensions?</a></dt> + + <dt><a href="#imul">Why doesn't my <code>*=</code> operator + work?</a></dt> + + <dt><a href="#macosx">Does Boost.Python work with Mac OS X?</a></dt> + + <dt><a href="#xref">How can I find the existing PyObject that holds a + C++ object?</a></dt> + + <dt><a href="#ownership">How can I wrap a function which needs to take + ownership of a raw pointer?</a></dt> + + <dt><a href="#slow_compilation">Compilation takes too much time and eats too much memory! + What can I do to make it faster?</a></dt> + + <dt><a href="#packages">How do I create sub-packages using Boost.Python?</a></dt> + + <dt><a href="#msvcthrowbug" + >error C2064: term does not evaluate to a function taking 2 arguments</a> + </dt> + + <dt><a href="#custom_string" + >How can I automatically convert my custom string type to + and from a Python string?</a></dt> + + <dt><a href="#topythonconversionfailed">Why is my automatic to-python conversion not being + found?</a></dt> + + <dt><a href="#threadsupport">Is Boost.Python thread-aware/compatible with multiple interpreters?</a></dt> + </dl> + <hr> + + <h2><a name="funcptr">How can I wrap a function which takes a + function pointer as an argument?</a></h2> + + If what you're trying to do is something like this: +<pre> +typedef boost::function<void (string s) > funcptr; + +void foo(funcptr fp) +{ + fp("hello,world!"); +} + +BOOST_PYTHON_MODULE(test) +{ + def("foo",foo) ; +} +</pre> + +And then: + +<pre> +>>> def hello(s): +... print s +... +>>> foo(hello) +hello, world! +</pre> + + The short answer is: "you can't". This is not a + Boost.Python limitation so much as a limitation of C++. The + problem is that a Python function is actually data, and the only + way of associating data with a C++ function pointer is to store it + in a static variable of the function. The problem with that is + that you can only associate one piece of data with every C++ + function, and we have no way of compiling a new C++ function + on-the-fly for every Python function you decide to pass + to <code>foo</code>. In other words, this could work if the C++ + function is always going to invoke the <em>same</em> Python + function, but you probably don't want that. + + <p>If you have the luxury of changing the C++ code you're + wrapping, pass it an <code>object</code> instead and call that; + the overloaded function call operator will invoke the Python + function you pass it behind the <code>object</code>. + + <p>For more perspective on the issue, see <a + href="http://aspn.activestate.com/ASPN/Mail/Message/1554837">this + posting</a>. + + <hr> + + <h2><a name="dangling">I'm getting the "attempt to return dangling + reference" error. What am I doing wrong?</a></h2> + That exception is protecting you from causing a nasty crash. It usually + happens in response to some code like this: +<pre> +period const& get_floating_frequency() const +{ + return boost::python::call_method<period const&>( + m_self,"get_floating_frequency"); +} +</pre> + And you get: +<pre> +ReferenceError: Attempt to return dangling reference to object of type: +class period +</pre> + + <p>In this case, the Python method invoked by <code>call_method</code> + constructs a new Python object. You're trying to return a reference to a + C++ object (an instance of <code>class period</code>) contained within + and owned by that Python object. Because the called method handed back a + brand new object, the only reference to it is held for the duration of + <code>get_floating_frequency()</code> above. When the function returns, + the Python object will be destroyed, destroying the instance of + <code>class period</code>, and leaving the returned reference dangling. + That's already undefined behavior, and if you try to do anything with + that reference you're likely to cause a crash. Boost.Python detects this + situation at runtime and helpfully throws an exception instead of letting + you do that.<br> + </p> + <hr> + + <h2><a name="question1"></a>Is return_internal_reference efficient?</h2> + + <blockquote> + <b>Q:</b> <i>I have an object composed of 12 doubles. A const& to + this object is returned by a member function of another class. From the + viewpoint of using the returned object in Python I do not care if I get + a copy or a reference to the returned object. In Boost.Python Version 2 + I have the choice of using copy_const_reference or + return_internal_reference. Are there considerations that would lead me + to prefer one over the other, such as size of generated code or memory + overhead?</i> + + <p><b>A:</b> copy_const_reference will make an instance with storage + for one of your objects, size = base_size + 12 * sizeof(double). + return_internal_reference will make an instance with storage for a + pointer to one of your objects, size = base_size + sizeof(void*). + However, it will also create a weak reference object which goes in the + source object's weakreflist and a special callback object to manage the + lifetime of the internally-referenced object. My guess? + copy_const_reference is your friend here, resulting in less overall + memory use and less fragmentation, also probably fewer total + cycles.</p> + </blockquote> + <hr> + + <h2><a name="question2"></a>How can I wrap functions which take C++ + containers as arguments?</h2> + + <p>Ralf W. Grosse-Kunstleve provides these notes:</p> + + <ol> + <li> + Using the regular <code>class_<></code> wrapper: +<pre> +class_<std::vector<double> >("std_vector_double") + .def(...) + ... + ; +</pre> + This can be moved to a template so that several types (double, int, + long, etc.) can be wrapped with the same code. This technique is used + in the file + + <blockquote> + scitbx/include/scitbx/array_family/boost_python/flex_wrapper.h + </blockquote> + in the "scitbx" package. The file could easily be modified for + wrapping std::vector<> instantiations. + + <p>This type of C++/Python binding is most suitable for containers + that may contain a large number of elements (>10000).</p> + </li> + + <li> + Using custom rvalue converters. Boost.Python "rvalue converters" + match function signatures such as: +<pre> +void foo(std::vector<double> const& array); // pass by const-reference +void foo(std::vector<double> array); // pass by value +</pre> + Some custom rvalue converters are implemented in the file + + <blockquote> + scitbx/include/scitbx/boost_python/container_conversions.h + </blockquote> + This code can be used to convert from C++ container types such as + std::vector<> or std::list<> to Python tuples and vice + versa. A few simple examples can be found in the file + + <blockquote> + scitbx/array_family/boost_python/regression_test_module.cpp + </blockquote> + Automatic C++ container <-> Python tuple conversions are most + suitable for containers of moderate size. These converters generate + significantly less object code compared to alternative 1 above. + </li> + </ol> + A disadvantage of using alternative 2 is that operators such as + arithmetic +,-,*,/,% are not available. It would be useful to have custom + rvalue converters that convert to a "math_array" type instead of tuples. + This is currently not implemented but is possible within the framework of + Boost.Python V2 as it will be released in the next couple of weeks. [ed.: + this was posted on 2002/03/10] + + <p>It would also be useful to also have "custom lvalue converters" such + as std::vector<> <-> Python list. These converters would + support the modification of the Python list from C++. For example:</p> + + <p>C++:</p> +<pre> +void foo(std::vector<double>& array) +{ + for(std::size_t i=0;i<array.size();i++) { + array[i] *= 2; + } +} +</pre> + Python: +<pre> +>>> l = [1, 2, 3] +>>> foo(l) +>>> print l +[2, 4, 6] +</pre> + Custom lvalue converters require changes to the Boost.Python core library + and are currently not available. + + <p>P.S.:</p> + + <p>The "scitbx" files referenced above are available via anonymous + CVS:</p> +<pre> +cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login +cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx +</pre> + <hr> + + <h2><a name="c1204"></a>fatal error C1204:Compiler limit:internal + structure overflow</h2> + + <blockquote> + <b>Q:</b> <i>I get this error message when compiling a large source + file. What can I do?</i> + + <p><b>A:</b> You have two choices:</p> + + <ol> + <li>Upgrade your compiler (preferred)</li> + + <li> + Break your source file up into multiple translation units. + + <p><code><b>my_module.cpp</b></code>:</p> +<pre> +... +void more_of_my_module(); +BOOST_PYTHON_MODULE(my_module) +{ + def("foo", foo); + def("bar", bar); + ... + more_of_my_module(); +} +</pre> + <code><b>more_of_my_module.cpp</b></code>: +<pre> +void more_of_my_module() +{ + def("baz", baz); + ... +} +</pre> + If you find that a <code><a href= + "class.html#class_-spec">class_</a><...></code> declaration + can't fit in a single source file without triggering the error, you + can always pass a reference to the <code>class_</code> object to a + function in another source file, and call some of its member + functions (e.g. <code>.def(...)</code>) in the auxilliary source + file: + + <p><code><b>more_of_my_class.cpp</b></code>:</p> +<pre> +void more_of_my_class(class<my_class>& x) +{ + x + .def("baz", baz) + .add_property("xx", &my_class::get_xx, &my_class::set_xx) + ; + + ... +} +</pre> + </li> + </ol> + </blockquote> + <hr> + + <h2><a name="debugging"></a>How do I debug my Python extensions?</h2> + + <p>Greg Burley gives the following answer for Unix GCC users:</p> + + <blockquote> + Once you have created a boost python extension for your c++ library or + class, you may need to debug the code. Afterall this is one of the + reasons for wrapping the library in python. An expected side-effect or + benefit of using BPL is that debugging should be isolated to the c++ + library that is under test, given that python code is minimal and + boost::python either works or it doesn't. (ie. While errors can occur + when the wrapping method is invalid, most errors are caught by the + compiler ;-). + + <p>The basic steps required to initiate a gdb session to debug a c++ + library via python are shown here. Note, however that you should start + the gdb session in the directory that contains your BPL my_ext.so + module.</p> +<pre> +(gdb) target exec python +(gdb) run + >>> from my_ext import * + >>> [C-c] +(gdb) break MyClass::MyBuggyFunction +(gdb) cont + >>> pyobj = MyClass() + >>> pyobj.MyBuggyFunction() +Breakpoint 1, MyClass::MyBuggyFunction ... +Current language: auto; currently c++ +(gdb) do debugging stuff +</pre> + </blockquote> + + <p>Greg's approach works even better using Emacs' "<code>gdb</code>" + command, since it will show you each line of source as you step through + it.</p> + + <p>On <b>Windows</b>, my favorite debugging solution is the debugger that + comes with Microsoft Visual C++ 7. This debugger seems to work with code + generated by all versions of Microsoft and Metrowerks toolsets; it's rock + solid and "just works" without requiring any special tricks from the + user.</p> + + <p>Raoul Gough has provided the following for gdb on Windows:</p> + + <blockquote> + + <p>gdb support for Windows DLLs has improved lately, so it is + now possible to debug Python extensions using a few + tricks. Firstly, you will need an up-to-date gdb with support + for minimal symbol extraction from a DLL. Any gdb from version 6 + onwards, or Cygwin gdb-20030214-1 and onwards should do. A + suitable release will have a section in the gdb.info file under + Configuration – Native – Cygwin Native – + Non-debug DLL symbols. Refer to that info section for more + details of the procedures outlined here.</p> + + <p>Secondly, it seems necessary to set a breakpoint in the + Python interpreter, rather than using ^C to break execution. A + good place to set this breakpoint is PyOS_Readline, which will + stop execution immediately before reading each interactive + Python command. You have to let Python start once under the + debugger, so that it loads its own DLL, before you can set the + breakpoint:</p> + +<p> +<pre> +$ gdb python +GNU gdb 2003-09-02-cvs (cygwin-special) +[...] + +(gdb) run +Starting program: /cygdrive/c/Python22/python.exe +Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32 +Type "help", "copyright", "credits" or "license" for more information. +>>> ^Z + + +Program exited normally. +(gdb) break *&PyOS_Readline +Breakpoint 1 at 0x1e04eff0 +(gdb) run +Starting program: /cygdrive/c/Python22/python.exe +Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32 +Type "help", "copyright", "credits" or "license" for more information. + +Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline () + from /cygdrive/c/WINNT/system32/python22.dll +(gdb) cont +Continuing. +>>> from my_ext import * + +Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline () + from /cygdrive/c/WINNT/system32/python22.dll +(gdb) # my_ext now loaded (with any debugging symbols it contains) +</pre> + </blockquote> + + <h3>Debugging extensions through Boost.Build</h3> + If you are launching your extension module tests with <a href= + "../../../../tools/build/v1/build_system.htm">Boost.Build</a> using the + <code>boost-python-runtest</code> rule, you can ask it to launch your + debugger for you by adding "--debugger=<i>debugger</i>" to your bjam + command-line: +<pre> +bjam -sTOOLS=vc7.1 "--debugger=devenv /debugexe" test +bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test +</pre> + It can also be extremely useful to add the <code>-d+2</code> option when + you run your test, because Boost.Build will then show you the exact + commands it uses to invoke it. This will invariably involve setting up + PYTHONPATH and other important environment variables such as + LD_LIBRARY_PATH which may be needed by your debugger in order to get + things to work right. + <hr> + + <h2><a name="imul"></a>Why doesn't my <code>*=</code> operator work?</h2> + + <blockquote> + <b>Q:</b> <i>I have exported my class to python, with many overloaded + operators. it works fine for me except the</i> <code>*=</code> + <i>operator. It always tells me "can't multiply sequence with non int + type". If I use</i> <code>p1.__imul__(p2)</code> <i>instead of</i> + <code>p1 *= p2</code><i>, it successfully executes my code. What's + wrong with me?</i> + + <p><b>A:</b> There's nothing wrong with you. This is a bug in Python + 2.2. You can see the same effect in Pure Python (you can learn a lot + about what's happening in Boost.Python by playing with new-style + classes in Pure Python).</p> +<pre> +>>> class X(object): +... def __imul__(self, x): +... print 'imul' +... +>>> x = X() +>>> x *= 1 +</pre> + To cure this problem, all you need to do is upgrade your Python to + version 2.2.1 or later. + </blockquote> + <hr> + + <h2><a name="macosx"></a>Does Boost.Python work with Mac OS X?</h2> + + It is known to work under 10.2.8 and 10.3 using + Apple's gcc 3.3 compiler: + <pre>gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1493)</pre> + Under 10.2.8 get the August 2003 gcc update (free at + <a href="http://connect.apple.com/">http://connect.apple.com/</a>). + Under 10.3 get the Xcode Tools v1.0 (also free). + <p> + Python 2.3 is required. The Python that ships with 10.3 is + fine. Under 10.2.8 use these commands to install Python + as a framework: + <pre>./configure --enable-framework +make +make frameworkinstall</pre> + The last command requires root privileges because the target + directory is + <tt>/Library/Frameworks/Python.framework/Versions/2.3</tt>. + However, the installation does not interfere with the Python + version that ships with 10.2.8. + <p> + It is also crucial to increase the <tt>stacksize</tt> before + starting compilations, e.g.: + <pre>limit stacksize 8192k</pre> + If the <tt>stacksize</tt> is too small the build might crash with + internal compiler errors. + <p> + Sometimes Apple's compiler exhibits a bug by printing an error + like the following while compiling a + <tt>boost::python::class_<your_type></tt> + template instantiation: + <pre>.../inheritance.hpp:44: error: cannot + dynamic_cast `p' (of type `struct cctbx::boost_python::<unnamed>::add_pair* + ') to type `void*' (source type is not polymorphic)</pre> + + We do not know a general workaround, but if the definition of + <tt>your_type</tt> can be modified the following was found + to work in all cases encountered so far:<pre>struct your_type +{ + // before defining any member data +#if defined(__MACH__) && defined(__APPLE_CC__) && __APPLE_CC__ == 1493 + bool dummy_; +#endif + // now your member data, e.g. + double x; + int j; + // etc. +};</pre> + + <hr> + <h2><a name="xref">How can I find the existing PyObject that holds a C++ + object?</a></h2> + + <blockquote> + "I am wrapping a function that always returns a pointer to an + already-held C++ object." + </blockquote> + One way to do that is to hijack the mechanisms used for wrapping a class + with virtual functions. If you make a wrapper class with an initial + PyObject* constructor argument and store that PyObject* as "self", you + can get back to it by casting down to that wrapper type in a thin wrapper + function. For example: +<pre> +class X { X(int); virtual ~X(); ... }; +X* f(); // known to return Xs that are managed by Python objects + + +// wrapping code + +struct X_wrap : X +{ + X_wrap(PyObject* self, int v) : self(self), X(v) {} + PyObject* self; +}; + +handle<> f_wrap() +{ + X_wrap* xw = dynamic_cast<X_wrap*>(f()); + assert(xw != 0); + return handle<>(borrowed(xw->self)); +} + +... + +def("f", f_wrap()); +class_<X,X_wrap,boost::noncopyable>("X", init<int>()) + ... + ; +</pre> + Of course, if X has no virtual functions you'll have to use + <code>static_cast</code> instead of <code>dynamic_cast</code> with no + runtime check that it's valid. This approach also only works if the + <code>X</code> object was constructed from Python, because + <code>X</code>s constructed from C++ are of course never + <code>X_wrap</code> objects. + + <p>Another approach to this requires you to change your C++ code a bit; + if that's an option for you it might be a better way to go. work we've + been meaning to get to anyway. When a <code>shared_ptr<X></code> is + converted from Python, the shared_ptr actually manages a reference to the + containing Python object. When a shared_ptr<X> is converted back to + Python, the library checks to see if it's one of those "Python object + managers" and if so just returns the original Python object. So you could + just write <code>object(p)</code> to get the Python object back. To + exploit this you'd have to be able to change the C++ code you're wrapping + so that it deals with shared_ptr instead of raw pointers.</p> + + <p>There are other approaches too. The functions that receive the Python + object that you eventually want to return could be wrapped with a thin + wrapper that records the correspondence between the object address and + its containing Python object, and you could have your f_wrap function + look in that mapping to get the Python object out.</p> + + <hr> + + <h2><a name="ownership">How can I wrap a function which needs to take + ownership of a raw pointer?</a></h2> + + <blockquote> + <i>Part of an API that I'm wrapping goes something like this:</i> +<pre> +struct A {}; struct B { void add( A* ); } +where B::add() takes ownership of the pointer passed to it. +</pre> + + <p><i>However:</i></p> +<pre> +a = mod.A() +b = mod.B() +b.add( a ) +del a +del b +# python interpreter crashes +# later due to memory corruption. +</pre> + + <p><i>Even binding the lifetime of a</i> to b via + with_custodian_and_ward doesn't prevent the python object a from + ultimately trying to delete the object it's pointing to. Is there a way + to accomplish a 'transfer-of-ownership' of a wrapped C++ object?</p> + + <p><i>--Bruce Lowery</i></p> + </blockquote> + Yes: Make sure the C++ object is held by auto_ptr: +<pre> +class_<A, std::auto_ptr<A> >("A") + ... + ; +</pre> + Then make a thin wrapper function which takes an auto_ptr parameter: +<pre> +void b_insert(B& b, std::auto_ptr<A> a) +{ + b.insert(a.get()); + a.release(); +} +</pre> + Wrap that as B.add. Note that pointers returned via <code><a href= + "manage_new_object.html#manage_new_object-spec">manage_new_object</a></code> + will also be held by <code>auto_ptr</code>, so this transfer-of-ownership + will also work correctly. + + <hr> + <h2><a name="slow_compilation">Compilation takes too much time and eats too + much memory! What can I do to make it faster?</a></h2> + <p> + Please refer to the <a href="../tutorial/doc/html/python/techniques.html#python.reducing_compiling_time" + >Reducing Compiling Time</a> section in the tutorial. + </p> + + <hr> + <h2><a name="packages">How do I create sub-packages using Boost.Python?</a></h2> + <p> + Please refer to the <a href="../tutorial/doc/html/python/techniques.html#python.creating_packages" + >Creating Packages</a> section in the tutorial. + </p> + + <hr> + <h2><a name="msvcthrowbug"></a>error C2064: term does + not evaluate to a function taking 2 arguments</h2> + <font size="-1"><i>Niall Douglas provides these notes:</i></font><p> + If you see Microsoft Visual C++ 7.1 (MS Visual Studio .NET 2003) issue + an error message like the following it is most likely due to a bug + in the compiler: + <pre>boost\boost\python\detail\invoke.hpp(76): +error C2064: term does not evaluate to a function taking 2 arguments"</pre> + This message is triggered by code like the following: +<pre>#include <boost/python.hpp> + +using namespace boost::python; + +class FXThread +{ +public: + bool setAutoDelete(bool doso) throw(); +}; + +void Export_FXThread() +{ + class_< FXThread >("FXThread") + .def("setAutoDelete", &FXThread::setAutoDelete) + ; +} + </pre> + The bug is related to the <code>throw()</code> modifier. + As a workaround cast off the modifier. E.g.: +<pre> + .def("setAutoDelete", (bool (FXThread::*)(bool)) &FXThread::setAutoDelete)</pre> + <p>(The bug has been reported to Microsoft.)</p> + + <hr> + <h2><a name="custom_string"></a>How can I automatically + convert my custom string type to and from a Python string?</h2> + <font size="-1"><i>Ralf W. Grosse-Kunstleve provides these + notes:</i></font><p> + Below is a small, self-contained demo extension module that shows + how to do this. Here is the corresponding trivial test: + <pre>import custom_string +assert custom_string.hello() == "Hello world." +assert custom_string.size("california") == 10</pre> + + If you look at the code you will find: + + <ul> + <li>A custom <tt>to_python</tt> converter (easy): + <tt>custom_string_to_python_str</tt> + + <li>A custom lvalue converter (needs more code): + <tt>custom_string_from_python_str</tt> + </ul> + + The custom converters are registered in the global Boost.Python + registry near the top of the module initialization function. Once + flow control has passed through the registration code the automatic + conversions from and to Python strings will work in any module + imported in the same process. + +<pre>#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/to_python_converter.hpp> + +namespace sandbox { namespace { + + class custom_string + { + public: + custom_string() {} + custom_string(std::string const& value) : value_(value) {} + std::string const& value() const { return value_; } + private: + std::string value_; + }; + + struct custom_string_to_python_str + { + static PyObject* convert(custom_string const& s) + { + return boost::python::incref(boost::python::object(s.value()).ptr()); + } + }; + + struct custom_string_from_python_str + { + custom_string_from_python_str() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id<custom_string>()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PyString_Check(obj_ptr)) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + const char* value = PyString_AsString(obj_ptr); + if (value == 0) boost::python::throw_error_already_set(); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage<custom_string>*) + data)->storage.bytes; + new (storage) custom_string(value); + data->convertible = storage; + } + }; + + custom_string hello() { return custom_string("Hello world."); } + + std::size_t size(custom_string const& s) { return s.value().size(); } + + void init_module() + { + using namespace boost::python; + + boost::python::to_python_converter< + custom_string, + custom_string_to_python_str>(); + + custom_string_from_python_str(); + + def("hello", hello); + def("size", size); + } + +}} // namespace sandbox::<anonymous> + +BOOST_PYTHON_MODULE(custom_string) +{ + sandbox::init_module(); +}</pre> + + <hr> + <h2><a name="topythonconversionfailed"></a + >Why is my automatic to-python conversion not being found?</h2> + <font size="-1"><i>Niall Douglas provides these notes:</i></font><p> + If you define custom converters similar to the ones + shown above the <tt>def_readonly()</tt> and <tt>def_readwrite()</tt> + member functions provided by <tt>boost::python::class_</tt> for + direct access to your member data will not work as expected. + This is because <tt>def_readonly("bar", &foo::bar)</tt> is + equivalent to: + +<pre>.add_property("bar", make_getter(&foo::bar, return_internal_reference()))</pre> + + Similarly, <tt>def_readwrite("bar", &foo::bar)</tt> is + equivalent to: + +<pre>.add_property("bar", make_getter(&foo::bar, return_internal_reference()), + make_setter(&foo::bar, return_internal_reference())</pre> + + In order to define return value policies compatible with the + custom conversions replace <tt>def_readonly()</tt> and + <tt>def_readwrite()</tt> by <tt>add_property()</tt>. E.g.: + +<pre>.add_property("bar", make_getter(&foo::bar, return_value_policy<return_by_value>()), + make_setter(&foo::bar, return_value_policy<return_by_value>()))</pre> + + <hr> + <h2><a name="threadsupport"></a + >Is Boost.Python thread-aware/compatible with multiple interpreters?</h2> + <font size="-1"><i>Niall Douglas provides these notes:</i></font><p> + The quick answer to this is: no.</p> + <p> + The longer answer is that it can be patched to be so, but it's + complex. You will need to add custom lock/unlock wrapping of every + time your code enters Boost.Python (particularly every virtual + function override) plus heavily modify + <tt>boost/python/detail/invoke.hpp</tt> with custom unlock/lock + wrapping of every time Boost.Python enters your code. You must + furthermore take care to <i>not</i> unlock/lock when Boost.Python + is invoking iterator changes via <tt>invoke.hpp</tt>.</p> + <p> + There is a patched <tt>invoke.hpp</tt> posted on the C++-SIG + mailing list archives and you can find a real implementation of all + the machinery necessary to fully implement this in the TnFOX + project at <a href="http://sourceforge.net/projects/tnfox/"> this + SourceForge project location</a>.</p> + + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 12 March, 2006 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002-2006.</i></p> + </body> +</html> diff --git a/libs/python/doc/v2/feb2002.html b/libs/python/doc/v2/feb2002.html new file mode 100644 index 000000000..5f15aeace --- /dev/null +++ b/libs/python/doc/v2/feb2002.html @@ -0,0 +1,367 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta http-equiv="Content-Type" content= + "text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - February 2002 Progress Report</title> +<style type="text/css"> + :link { color: #0000ff } + :visited { color: #800080 } + p.c3 {font-style: italic} + h2.c2 {text-align: center} + h1.c1 {text-align: center} +</style> + + <table border="0" cellpadding="7" cellspacing="0" width= + "100%" summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 class="c1"><a href="../index.html">Boost.Python</a></h1> + + <h2 class="c2">February 2002 Progress Report</h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="index"> + <dt><a href="#Python10">Python10 Conference Report</a> + + <dt><a href="#progress">Boost.Python v2 Progress</a> + + <dd> + <dl class="index"> + <dt><a href="#documentation">Documentation</a> + + <dt><a href="#conversion">Overhaul of + <code>to_python</code>/<code>from_python</code> + conversion mechanism</a> + + <dt><a href="#miscellaneous">Miscellaneous</a> + </dl> + </dl> + + <h2><a name="Python10">Python10 Conference Report</a></h2> + I spent the first week of February at the Python10 conference + in Alexandria, VA. I'm including this experience report + for two reasons: firstly, it documents where my time was + used. Secondly, a public presence for Boost.Python and + interaction between the Python and C++ communities is + important to the future of Boost.Python, which in turn is + important to the Kull Project. + + <p>Andy Koenig, of all people, was the keynote speaker of + this year's opening plenary session. He presented his + "impressions of a polyglot outsider", which + studiously avoided any mention of C++ until the end of his + talk, when he was asked about standardization. I was + surprised to learn that the C++ community at large wanted a + few more years before beginning but when ANSI accepted + HP's request for a standard, the process was forced to + start: it was a matter of participating or having + standardization proceed without one's input. Andy managed + to highlight very effectively the balance of strengths in + Python, one of the most important being its support for + extension via libraries. In many ways that makes Python a + good analogue for C++ in the interpreted world + + <p>There were several kind mentions of the Boost.Python + library from people who found it indispensable. I was + particularly happy that Karl MacMillan, Michael Droettboom, + and Ichiro Fujinaga from Johns Hopkins is using it to do OCR + on a vast library of music notation, since in a previous life + I was an author of music notation software. These guys are + also drawing on Ullrich Koethe's VIGRA library for image + manipulation (Ullrich has been a major contributor to + Boost.Python). They also have a system for writing the + Boost.Python wrapper code in C++ comments, which allows them + to keep all of the code in one place. I've asked them to + send me some information on that. + + <p>The development of Swig has been gaining momentum again + (the basic description at + www.boost.org/libs/python/doc/comparisons.html still + applies). The talk given about it by David Beazly was very + well-attended, and they appear to have quite a few users. + Swig's strengths (coverage of many langauages) and + weaknesses (incomplete C++ language support) haven't + changed, although the C++ support seems to have improved + considerably - they now claim to have a complete model of the + C++ type system. It seems to be mostly geared at wrapping + what Walter Landry calls "C-Tran": C++ code which + traffics in built-in types with little use of abstraction. + I'm not knocking that, either: I'm sure a lot of that + code exists, so it's a valuable service. One feature Swig + has which I'd like to steal is the ability to unwrap a + single Python argument into multiple C++ arguments, for + example, by converting a Python string into a pointer and + length. When his talk was over, David approached me about a + possible joint workshop on language binding, which sounds + like a fun idea to me. + + <p>I spent some considerable time talking with Steven Knight, + the leader of the Scons build tool effort. We had a lot to + share with one another, and I gained a much better + appreciation for many of the Scons design decisions. Scons + seems to be concentrating on being the ultimate build system + substrate, and Steve seemed to think that we were on the + right track with our high-level design. We both hope that the + Boost.Build V2 high-level architecture can eventually be + ported to run on top of Scons. + + <p>They also have a highly-refined and successful development + procedure which I'd like to emulate for Boost.Build V2. + Among many other things they do, their source-control system + automatically ensures that when you check in a new test, it + is automatically run on the currently checked-in state of the + code, and is expected to fail -- a relatively obvious good + idea which I've never heard before. + + <p>Guido Van Rossum's "State of the Python + Union" address was full of questions for the community + about what should be done next, but the one idea Guido seemed + to stress was that core language stability and continuing + library development would be a good idea (sound familiar?) I + mentioned the Boost model as a counterpoint to the idea of + something like CPAN (the massive Perl library archives), and + it seemed to generate some significant interest. I've + offered to work with anyone from the Python community who + wants to set up something like Boost. + + <p>There was some discussion of "string + interpolation" (variable substitution in strings), and + Guido mentioned that he had some thoughts about the + strengths/weaknesses of Python's formatting interface. It + might be useful for those working on formatting for boost to + contact him and find out what he has to say. + + <p>Ka-Ping Yee demoed a Mailman discussion thread weaver. + This tool weaves the various messages in a discussion thread + into a single document so you can follow the entire + conversation. Since we're looking very seriously at + moving Boost to Mailman, this could be a really useful thing + for us to have. If we do this, we'll move the yahoogroups + discussions into the mailman archive so old discussions can + be easily accessed in the same fashion. + + <p>And, just because it's cool, though perhaps not + relevant: http://homepages.ulb.ac.be/~arigo/psyco/ is a + promising effort to accelerate the execution of Python code + to speeds approaching those of compiled languages. It + reminded me a lot of Todd Veldhuizen's research into + moving parts of C++ template compilation to runtime, only + coming from the opposite end of things. + + <h2><a name="progress">Boost.Python v2 Progress</a></h2> + Here's what actually got accomplished. + + <h3><a name="documentation">Documentation</a></h3> + + <p>My first priority upon returning from Python10 was to get + some documentation in place. After wasting an unfortunate + amount of time looking at automatic documentation tools which + don't quite work, I settled down to use Bill Kempf's + HTML templates designed to be a boost standard. While they + are working well, it is highly labor-intensive. + + <p>I decided to begin with the high-level reference material, + as opposed to tutorial, narrative, or nitty-gritty details of + the framework. It seemed more important to have a precise + description of the way the commonly-used components work than + to have examples in HTML (since we already have some test + modules), and since the low-level details are much + less-frequently needed by users it made sense for me to + simply respond to support requests for the time being. + + <p>After completing approximately 60% of the high-level docs + (currently checked in to libs/python/doc/v2), I found myself + ready to start documenting the mechanisms for creating + to-/from-python converters. This caused a dilemma: I had + realized during the previous week that a much simpler, + more-efficient, and easier-to-use implementation was + possible, but I hadn't planned on implementing it right + away, since what was already in place worked adequately. I + had also received my first query on the C++-sig about how to + write such a converter + + <p>Given the labor-intensive nature of documentation writing, + I decided it would be a bad idea to document the conversion + mechanism if I was just going to rewrite it. Often the best + impetus for simplifying a design is the realization that + understandably documenting its current state would be too + difficult, and this was no exception. + + <h3><a name="conversion">Overhaul of + <code>to_python</code>/<code>from_python</code> conversion + mechanism</a></h3> + + <p>There were two basic realizations involved here: + + <ol> + <li><code>to_python</code> conversion could be a one-step + process, once an appropriate conversion function is found. + This allows elimination of the separate indirect + convertibility check + + <li>There are basically two categories of from_python + conversions: those which lvalues stored within or held by + the Python object (essentially extractions), like what + happens when an instance of a C++ class exposed with class_ + is used as the target of a wrapped member function), and + those in which a new rvalue gets created, as when a Python + Float is converted to a C++ + <code>complex<double></code> or a Python tuple is + converted to a C++ <code>std::vector<></code>. From + the client side, there are two corresponding categories of + conversion: those which demand an lvalue conversion and + those which can accept an lvalue or an rvalue conversion. + </ol> + The latter realization allowed the following collapse, which + considerably simplified things: + + <blockquote> + <table border="1" summary="Conversion protocol"> + <tr> + <th>Target Type + + <th>Eligible Converters + + <tr> + <td><code>T</code> + + <td rowspan="5"><code>T</code> rvalue or lvalue + + <tr> + <td><code>T const</code> + + <tr> + <td><code>T volatile</code> + + <tr> + <td><code>T const volatile</code> + + <tr> + <td><code>T const&</code> + + <tr> + <td><code>T const*</code> + + <td rowspan="9"><code>T</code> lvalue + + <tr> + <td><code>T volatile*</code> + + <tr> + <td><code>T const volatile*</code> + + <tr> + <td><code>T&</code> + + <tr> + <td><code>T volatile&</code> + + <tr> + <td><code>T const volatile&</code> + + <tr> + <td><code>T* const&</code> + + <tr> + <td><code>T const* const&</code> + + <tr> + <td><code>T volatile*const&</code> + + <tr> + <td><code>T const volatile*const&</code> + </table> + </blockquote> + This job included the following additional enhancements: + + <ul> + <li>Elimination of virtual functions, which cause object + code bloat + + <li>Registration of a single converter function for all + lvalue conversions, two for all rvalue conversions + + <li>Killed lots of unneeded code + + <li>Increased opacity of registry interface + + <li>Eliminated all need for decorated runtime type + identifiers + + <li>Updated test modules to reflect new interface + + <li>Eliminated the need for users to worry about converter + lifetime issues Additional Builtin Conversion Enhancements + + <li>Support for complex<float>, + complex<double>, and complex<long double> + conversions + + <li>Support for bool conversions + + <li>NULL pointers representable by None in Python + + <li>Support for conversion of Python classic classes to + numeric types + </ul> + + <h3><a name="miscellaneous">Miscellaneous</a></h3> + These don't fit easily under a large heading: + + <ul> + <li>Support CallPolicies for class member functions + + <li>from_python_data.hpp: revamped type alignment + metaprogram so that it's fast enough for KCC + + <li>classfwd.hpp header forward-declares class_<T> + + <li>indirect_traits.hpp: + + <li>added is_pointer_to_reference + + <li>fixed bugs + + <li>Reduced recompilation dependencies + + <li>msvc_typeinfo works around broken MS/Intel typeid() + implementation + + <li>Many fixes and improvements to the type_traits library + in order to work around compiler bugs and suppress warnings + + <li>Eliminated the need for explicit acquisition of + converter registrations + + <li>Expanded constructor support to 6 arguments + + <li>Implemented generalized pointer lifetime support + + <li>Updated code generation for returning.hpp + + <li>Tracked down and fixed cycle GC bugs + + <li>Added comprehensive unit tests for destroy_reference, + pointer_type_id, select_from_python, complex<T>, + bool, and classic class instance conversions + </ul> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p class="c3">© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002. Distributed + under the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/doc/v2/function_doc_signature.html b/libs/python/doc/v2/function_doc_signature.html new file mode 100644 index 000000000..e439a77ac --- /dev/null +++ b/libs/python/doc/v2/function_doc_signature.html @@ -0,0 +1,216 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright Nikolay Mladenov 2007. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta http-equiv="Content-Type" content= + "text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/doobject/function_doc_signature.hpp></title> +</head> + +<body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png" border= + "0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href= + "../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/object/function_doc_signature.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#function_doc_signature_generator-spec">Class + <code>function_doc_signature_generator</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#function_doc_signature_generator-spec-synopsis">Class + <code>function_doc_signature_generator</code> synopsis</a></dt> + + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction" id= + "introduction"></a>Introduction</h2> + + <p>Boost.Python supports docstrings with automatic + appending of Pythonic and C++ signatures. This feature is implemented + by <code>class function_doc_signature_generator</code> + The class uses all of the overloads, supplied arg names and default values, as well as + the user-defined docstrings, to generate documentation for a given function.</p> + + <h2><a name="classes" id="classes"></a>Classes</h2> + + <h3><a name="function_doc_signature_generator-spec" id= + "function_doc_signature_generator-spec"></a>Class + <code>function_doc_signature_generator</code></h3> + + <p> + The class has only one public function which returns a list of strings documenting the + overloads of a function. + </p> + + <h4><a name="function_doc_signature_generator-spec-synopsis" id= + "function_doc_signature_generator-spec-synopsis"></a>Class + <code>function_doc_signature_generator</code> synopsis</h4> + <pre> +namespace boost { namespace python { namespace objects { + + class function_doc_signature_generator + { + public: + static list function_doc_signatures(function const *f); + }; + +}}} +</pre> + + + <h2><a name="examples" id="examples"></a>Examples</h2> + + <h4>Docstrings generated with <code>function_doc_signature_generator</code></h4> + <pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/class.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/raw_function.hpp> + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + + +struct X +{ + tuple f(int x = 1, double y = 4.25, char const* z = "wow") + { + return make_tuple(x, y, z); + } +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3) + +tuple raw_func(tuple args, dict kw) +{ + return make_tuple(args, kw); +} + +BOOST_PYTHON_MODULE(args_ext) +{ + def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow") + , "This is f's docstring" + ); + + def("raw", raw_function(raw_func)); + + def("f1", f, f_overloads("f1's docstring", args("x", "y", "z"))); + + + class_<X>("X", "This is X's docstring", init<>(args("self"))) + .def("f", &X::f + , "This is X.f's docstring" + , args("self","x", "y", "z")) + + ; + +} + +</pre> +Python code: + <pre> +>>> import args_ext +>>> help(args_ext) +Help on module args_ext: + +NAME + args_ext + +FILE + args_ext.pyd + +CLASSES + Boost.Python.instance(__builtin__.object) + X + + class X(Boost.Python.instance) + | This is X's docstring + | + | Method resolution order: + | X + | Boost.Python.instance + | __builtin__.object + | + | Methods defined here: + | + | __init__(...) + | __init__( (object)self) -> None : + | C++ signature: + | void __init__(struct _object *) + | + | f(...) + | f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring + | C++ signature: + | class boost::python::tuple f(struct X {lvalue},int,double,char const *) + | + | ................. + | +FUNCTIONS + f(...) + f([ (int)x=1 [, (float)y=4.25 [, (str)z='wow']]]) -> tuple : This is f's docstring + C++ signature: + class boost::python::tuple f([ int=1 [,double=4.25 [,char const *='wow']]]) + + f1(...) + f1([ (int)x [, (float)y [, (str)z]]]) -> tuple : f1's docstring + C++ signature: + class boost::python::tuple f1([ int [,double [,char const *]]]) + + raw(...) + object raw(tuple args, dict kwds) : + C++ signature: + object raw(tuple args, dict kwds) + + +</pre> + + <p><i>© Copyright <a href="mailto:nickm at sitius dot com">Nikolay Mladenov</a> 2007.</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/handle.html b/libs/python/doc/v2/handle.html new file mode 100644 index 000000000..b20d94a1f --- /dev/null +++ b/libs/python/doc/v2/handle.html @@ -0,0 +1,336 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/handle.hpp></title> + + <style type="text/css"> + p.c4 {font-style: italic} + span.c3 {color: #ff0000} + h2.c2 {text-align: center} + h1.c1 {text-align: center} + </style> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 class="c1"><a href="../index.html">Boost.Python</a></h1> + + <h2 class="c2">Header <boost/python/handle.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#handle-spec">Class template + <code>handle</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#handle-spec-synopsis">Class <code>handle</code> + synopsis</a></dt> + + <dt><a href="#handle-spec-ctors">Class <code>handle</code> + constructors and destructor</a></dt> + + <dt><a href="#handle-spec-modifiers">Class <code>handle</code> + modifier functions</a></dt> + + <dt><a href="#handle-spec-observers">Class <code>handle</code> + observer functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#borrowed-spec"><code>borrowed</code></a></dt> + + <dt><a href="#allow_null-spec"><code>allow_null</code></a></dt> + </dl> + </dd> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/handle.hpp></code> provides + <code>class template handle</code>, a smart pointer for + managing reference-counted Python objects.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="handle-spec"></a>Class template <code>handle</code></h3> + + <p><code>handle</code> is a smart pointer to a Python object type; it + holds a pointer of type <code>T*</code>, where T is its template + parameter. <code>T</code> must be either a type derived from + <code>PyObject</code> or a <a href="definitions.html#POD">POD</a> type + whose initial <code>sizeof(PyObject)</code> bytes are layout-compatible + with <code>PyObject</code>. Use <code>handle<></code> at the + boundary between the Python/'C' API and high-level code; prefer <code><a + href="object.html#object-spec">object</a></code> for a generalized + interface to Python objects.</p> + + <p><a name="upcast"></a>In this document, the term "upcast" refers to an + operation which converts a pointer <code>Y*</code> to a base class + pointer <code>T*</code> via <code>static_cast<T*></code> if + <code>Y</code> is derived from <code>T</code>, or via C-style cast + <code>(T*)</code> if it is not. However, in the latter case the "upcast" + is ill-formed if the initial <code>sizeof(PyObject)</code> bytes of + <code>Y</code> are not layout-compatible with <code>PyObject</code>.</p> + + <h4><a name="handle-spec-synopsis"></a>Class template handle + synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T> + class handle + { + typedef <i>unspecified-member-function-pointer</i> bool_type; + + public: // types + typedef T element_type; + + public: // member functions + ~handle(); + + template <class Y> + explicit handle(detail::borrowed<null_ok<Y> >* p); + + template <class Y> + explicit handle(null_ok<detail::borrowed<Y> >* p); + + template <class Y> + explicit handle(detail::borrowed<Y>* p); + + template <class Y> + explicit handle(null_ok<Y>* p); + + template <class Y> + explicit handle(Y* p); + + handle(); + + handle& operator=(handle const& r); + + template<typename Y> + handle& operator=(handle<Y> const & r); // never throws + + + template <typename Y> + handle(handle<Y> const& r); + + handle(handle const& r); + + T* operator-> () const; + T& operator* () const; + T* get() const; + void reset(); + T* release(); + + operator bool_type() const; // never throws + private: + T* m_p; + }; + + template <class T> struct null_ok; + namespace detail { template <class T> struct borrowed; } +}} +</pre> + + <h4><a name="handle-spec-ctors">Class <code>handle</code> constructors + and destructor</a></h4> +<pre> +virtual ~handle(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Py_XDECREF(</code><i>upcast</i><code><PyObject*>(m_p))</code></dt> + </dl> +<pre> +template <class Y> +explicit handle(detail::borrowed<null_ok<Y> >* p); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Py_XINCREF(</code><i>upcast</i><code><PyObject*>(p)); + m_p = </code><i>upcast</i><code><T*>(p);</code></dt> + </dl> +<pre> +template <class Y> +explicit handle(null_ok<detail::borrowed<Y> >* p); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Py_XINCREF(</code><i>upcast</i><code><PyObject*>(p)); + m_p = </code><i>upcast</i><code><T*>(p);</code></dt> + </dl> +<pre> +template <class Y> +explicit handle(detail::borrowed<Y>* p); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Py_XINCREF(</code><i>upcast</i><code><PyObject*>(p)); + m_p = </code><i>upcast</i><code><T*>(<a href= + "errors.html#expect_non_null-spec">expect_non_null</a>(p));</code></dt> + </dl> +<pre> +template <class Y> +explicit handle(null_ok<Y>* p); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>m_p = </code><i>upcast</i><code><T*>(p);</code></dt> + </dl> +<pre> +template <class Y> +explicit handle(Y* p); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>m_p = </code><i>upcast</i><code><T*>(<a href= + "errors.html#expect_non_null-spec">expect_non_null</a>(p));</code></dt> + </dl> +<pre> +handle(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> <code>m_p = 0;</code></dt> + </dl> +<pre> +template <typename Y> +handle(handle<Y> const& r); +handle(handle const& r); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>m_p = r.m_p; Py_XINCREF(</code><i>upcast</i><code><PyObject*>(m_p));</code></dt> + </dl> + + <h4><a name="handle-spec-modifiers">Class <code>handle</code> + modifiers</a></h4> +<pre> +handle& operator=(handle const& r); +template<typename Y> +handle& operator=(handle<Y> const & r); // never throws +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Py_XINCREF(</code><i>upcast</i><code><PyObject*>(r.m_p)); Py_XDECREF(</code><i> + upcast</i><code><PyObject*>(m_p)); m_p = r.m_p;</code></dt> + </dl> +<pre> +T* release(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> <code>T* x = m_p; m_p = 0;return + x;</code></dt> + </dl> +<pre> +void reset(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>*this = handle<T>();</code></dt> + </dl> + + <h4><a name="handle-spec-observers">Class <code>handle</code> + observers</a></h4> +<pre> +T* operator-> () const; +T* get() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>m_p;</code></dt> + </dl> +<pre> +T& operator* () const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>*m_p;</code></dt> + </dl> +<pre> +operator bool_type() const; // never throws +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> 0 if <code>m_p == 0</code>, a pointer + convertible to <code>true</code> otherwise.</dt> + </dl> + + <h2><a name="functions"></a>Functions</h2> + + <h3><a name="borrowed-spec"></a><code>borrowed</code></h3> +<pre> +template <class T> +detail::borrowed<T>* borrowed(T* p) +{ + return (detail::borrowed<T>*)p; +} +</pre> + + <h3><a name="allow_null-spec"></a><code>allow_null</code></h3> +<pre> +template <class T> +null_ok<T>* allow_null(T* p) +{ + return (null_ok<T>*)p; +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p class="c4">© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002 +.</p> + </body> +</html> + diff --git a/libs/python/doc/v2/has_back_reference.html b/libs/python/doc/v2/has_back_reference.html new file mode 100644 index 000000000..29b81506c --- /dev/null +++ b/libs/python/doc/v2/has_back_reference.html @@ -0,0 +1,225 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/has_back_reference.hpp></title> + + <style type="text/css"> + p.c3 {font-style: italic} + h2.c2 {text-align: center} + h1.c1 {text-align: center} + </style> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 class="c1"><a href="../index.html">Boost.Python</a></h1> + + <h2 class="c2">Header + <boost/python/has_back_reference.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#has_back_reference-spec">Class template + <code>has_back_reference</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#has_back_reference-spec-synopsis">Class template + <code>has_back_reference</code> synopsis</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + </dd> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/has_back_reference.hpp></code> defines the + predicate metafunction <code>has_back_reference<></code>, which can + be specialized by the user to indicate that a wrapped class instance + holds a <code>PyObject*</code> corresponding to a Python object.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="has_back_reference-spec"></a>Class template + <code>has_back_reference</code></h3> + + <p>A unary metafunction whose <code>value</code> is true iff its argument + is a <code>pointer_wrapper<></code>.</p> + + <h4><a name="has_back_reference-spec-synopsis"></a>Class template + <code>has_back_reference</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template<class WrappedClass> class has_back_reference + { + typedef mpl::false_ type; + }; +}} +</pre> + <p>A "<a href="../../../mpl/doc/refmanual/metafunction.html"> + metafunction</a>" that is inspected by Boost.Python to determine how + wrapped classes can be constructed.</p> + + <dl class="traits-semantics"> + <dt><code>type::value</code> is an integral constant convertible to bool + of unspecified type.</dt> + + <dt>Specializations may substitute a <code>true</code>-valued integral constant wrapper for + <code>type</code> iff for each invocation of + <code>class_<WrappedClass>::def(init<</code> + <i>type-sequence...</i><code>>())</code> and the implicitly wrapped + copy constructor (unless it is <a href="class.html#class_-spec"> + noncopyable</a>), there exists a corresponding constructor + <code>WrappedClass::WrappedClass(PyObject*, </code> + <i>type-sequence...</i><code>)</code>. If such a specialization exists, + the <code>WrappedClass</code> constructors will be called with a "back + reference" pointer to the corresponding Python object whenever they are + invoked from Python. The easiest way to provide this nested <code> +type +</code> + is to + derive the specialization from <code>mpl::true_</code>. + </dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/has_back_reference.hpp> +#include <boost/python/handle.hpp> +#include <boost/shared_ptr.hpp> + +using namespace boost::python; +using boost::shared_ptr; + +struct X +{ + X(PyObject* self) : m_self(self), m_x(0) {} + X(PyObject* self, int x) : m_self(self), m_x(x) {} + X(PyObject* self, X const& other) : m_self(self), m_x(other.m_x) {} + + handle<> self() { return handle<>(borrowed(m_self)); } + int get() { return m_x; } + void set(int x) { m_x = x; } + + PyObject* m_self; + int m_x; +}; + +// specialize has_back_reference for X +namespace boost { namespace python +{ + template <> + struct has_back_reference<X> + : mpl::true_ + {}; +}} + +struct Y +{ + Y() : m_x(0) {} + Y(int x) : m_x(x) {} + int get() { return m_x; } + void set(int x) { m_x = x; } + + int m_x; +}; + +shared_ptr<Y> +Y_self(shared_ptr<Y> self) { return self; } + +BOOST_PYTHON_MODULE(back_references) +{ + class_<X>("X") + .def(init<int>()) + .def("self", &X::self) + .def("get", &X::get) + .def("set", &X::set) + ; + + class_<Y, shared_ptr<Y> >("Y") + .def(init<int>()) + .def("get", &Y::get) + .def("set", &Y::set) + .def("self", Y_self) + ; +} +</pre> + The following Python session illustrates that <code>x.self()</code> + returns the same Python object on which it is invoked, while + <code>y.self()</code> must create a new Python object which refers to the + same Y instance. + + <h3>Python code</h3> +<pre> +>>> from back_references import * +>>> x = X(1) +>>> x2 = x.self() +>>> x2 is x +<b>1</b> +>>> (x.get(), x2.get()) +(1, 1) +>>> x.set(10) +>>> (x.get(), x2.get()) +(10, 10) +>>> +>>> +>>> y = Y(2) +>>> y2 = y.self() +>>> y2 is y +<b>0</b> +>>> (y.get(), y2.get()) +(2, 2) +>>> y.set(20) +>>> (y.get(), y2.get()) +(20, 20) +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 18 July, 2004 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p class="c3">© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002 +.</p> + </body> +</html> + diff --git a/libs/python/doc/v2/implicit.html b/libs/python/doc/v2/implicit.html new file mode 100644 index 000000000..e9d5cac58 --- /dev/null +++ b/libs/python/doc/v2/implicit.html @@ -0,0 +1,163 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/implicit.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/implicit.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#implicitly_convertible-spec">Function Template + <code>implicitly_convertible</code></a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + <code>implicitly_convertible</code> allows Boost.Python to implicitly + take advantage of a C++ implicit or explicit conversion when matching + Python objects to C++ argument types. + + <h2><a name="functions"></a>Functions</h2> + + <h3><a name="implicitly_convertible-spec"></a>Function template + <code>implicitly_convertible</code></h3> +<pre> +template <class Source, class Target> +void implicitly_convertible(); +</pre> + + <table border="1" summary="implicitly_convertible template parameters"> + <caption> + <b><code>implicitly_convertible</code> template parameters</b><br> + </caption> + + <tr> + <th>Parameter</th> + + <th>Description</th> + </tr> + + <tr> + <td><code>Source</code></td> + + <td>The source type of the implicit conversion</td> + </tr> + + <tr> + <td><code>Target</code></td> + + <td>The target type of the implicit conversion</td> + </tr> + </table> + + <dl class="function-semantics"> + <dt><b>Requires:</b> The declaration <code>Target t(s);</code>, where + <code>s</code> is of type <code>Source</code>, is valid.</dt> + + <dt><b>Effects:</b> registers an rvalue <code>from_python</code> + converter to <code>Target</code> which can succeed for any + <code>PyObject* p</code> iff there exists any registered converter + which can produce <code>Source</code> rvalues</dt> + + <dt><b>Rationale:</b> C++ users expect to be able to take advantage of + the same sort of interoperability in Python as they do in C++.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/class.hpp> +#include <boost/python/implicit.hpp> +#include <boost/python/module.hpp> + +using namespace boost::python; + +struct X +{ + X(int x) : v(x) {} + operator int() const { return v; } + int v; +}; + +int x_value(X const& x) +{ + return x.v; +} + +X make_x(int n) { return X(n); } + +BOOST_PYTHON_MODULE(implicit_ext) +{ + def("x_value", x_value); + def("make_x", make_x); + + class_<X>("X", + init<int>()) + ; + + implicitly_convertible<X,int>(); + implicitly_convertible<int,X>(); +} +</pre> + + <h3>Python code</h3> +<pre> +>>> from implicit_ext import * +>>> x_value(X(42)) +42 +>>> x_value(42) +42 +>>> x = make_x(X(42)) +>>> x_value(x) +42 +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/import.html b/libs/python/doc/v2/import.html new file mode 100644 index 000000000..15c1c68c5 --- /dev/null +++ b/libs/python/doc/v2/import.html @@ -0,0 +1,90 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/import.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/import.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#import-spec"><code>import</code></a></dt> + </dl> + </dd> + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a mechanism for importing python modules.</p> + + <h2><a name="functions"></a>Functions</h2> + + <h3><a name="import-spec"></a><code>import</code></h3> + <pre> +object import(str name); + </pre> + <dl class="function-semantics"> + <dt><b>Effects:</b> Imports the module named by <code>name</code>.</dt> + <dt><b>Returns:</b> An instance of <a href="object.html#object-spec">object</a> + which holds a reference to the imported module.</dt> + </dl> + + <h2><a name="examples"></a>Examples</h2> + + <para>The following example demonstrates the use of <function>import</function> + to access a function in python, and later call it from within C++.</para> + +<pre> +#include <iostream> +#include <string> + +using namespace boost::python; + +void print_python_version() +{ + // Load the sys module. + object sys = import("sys"); + + // Extract the python version. + std::string version = extract<std::string>(sys.attr("version")); + std::cout << version << std::endl; +} +</pre> + <p>Revised 01 November, 2005</p> + + <p><i>© Copyright Stefan Seefeld 2005.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/index.html b/libs/python/doc/v2/index.html new file mode 100644 index 000000000..92593d06e --- /dev/null +++ b/libs/python/doc/v2/index.html @@ -0,0 +1,20 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="refresh" content="0; URL=../index.html"> + + <title></title> + </head> + + <body> + Loading index page; if nothing happens, please go to <a href= + "../index.html">../index.html</a>. + </body> +</html> + diff --git a/libs/python/doc/v2/indexing.html b/libs/python/doc/v2/indexing.html new file mode 100644 index 000000000..72c999c41 --- /dev/null +++ b/libs/python/doc/v2/indexing.html @@ -0,0 +1,695 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st February 2003), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + <title> + Indexing Support + </title> + </head> + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3> + <a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border= + "0"></a> + </h3> + </td> + <td valign="top"> + <h1 align="center"> + <a href="../index.html">Boost.Python</a> + </h1> + + <h2> Headers <boost/python/indexing/indexing_suite.hpp><br> + <boost/python/indexing/vector_indexing_suite.hpp></h2> + </td> + </tr> + </table> + <hr> + <h2> + Contents + </h2> + <dl class="page-index"> + <dt> + <a href="#introduction">Introduction</a> + </dt> + <dt> + <a href="#interface">Interface</a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#indexing_suite">indexing_suite</a> + </dt> + <dt> + <a href="#indexing_suite_subclasses">indexing_suite + sub-classes</a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#vector_indexing_suite">vector_indexing_suite</a> + </dt> + </dl> + </dd> + </dl> + </dd> + </dl> + <dl> + <dt> + <a href="#indexing_suite_class">indexing_suite class</a> + </dt> + <dt> + <a href="#vector_indexing_suite_class">vector_indexing_suite + class<br> + </a><a href="#map_indexing_suite_class">map_indexing_suite class</a> </dt> + </dl> + <hr> + <h2> + <a name="introduction" id="introduction"></a>Introduction + </h2> + <p> + Indexing is a Boost Python facility for easy exportation of indexable + C++ containers to Python. Indexable containers are containers that + allow random access through the operator[] (e.g. std::vector). + </p> + <p> + While Boost Python has all the facilities needed to expose indexable + C++ containers such as the ubiquitous std::vector to Python, the + procedure is not as straightforward as we'd like it to be. Python + containers do not map easily to C++ containers. Emulating Python + containers in C++ (see Python Reference Manual, <a href= + "http://www.python.org/doc/current/ref/sequence-types.html">Emulating + container types</a>) using Boost Python is non trivial. There are a lot + of issues to consider before we can map a C++ container to Python. + These involve implementing wrapper functions for the methods + <strong>__len__</strong>, <strong>__getitem__</strong>, + <strong>__setitem__</strong>, <strong>__delitem__,</strong> + <strong>__iter__</strong> and <strong>__contains</strong>. + </p> + <p> + The goals: + </p> + <ul> + <li> + <div> + Make indexable C++ containers behave exactly as one would expect a + Python container to behave. + </div> + </li> + <li> + Provide default reference semantics for container element indexing + (<tt>__getitem__</tt>) such that <tt>c[i]</tt> can be mutable. + Require: + <div> + <pre> + val = c[i] + c[i].m() + val == c[i] + </pre> + </div>where <tt>m</tt> is a non-const (mutating) member function + (method). + </li> + <li> + Return safe references from <tt>__getitem__</tt> such that subsequent + adds and deletes to and from the container will not result in + dangling references (will not crash Python). + </li> + <li> + Support slice indexes. + </li> + <li> + Accept Python container arguments (e.g. lists, tuples) wherever + appropriate. + </li> + <li> + Allow for extensibility through re-definable policy classes. + </li> + <li> + Provide predefined support for the most common STL and STL like + indexable containers. + </li> + </ul> + <hr> + +<h2> <a name="interface"></a>The Boost.Python Indexing Interface</h2> +<h3> <a name="indexing_suite"></a>indexing_suite [ Header <boost/python/indexing/indexing_suite.hpp> + ]</h3> + <p> + The <tt>indexing_suite</tt> class is the base class for the + management of C++ containers intended to be integrated to Python. The + objective is make a C++ container look and feel and behave exactly as + we'd expect a Python container. The class automatically wraps these + special Python methods (taken from the Python reference: <a href= + "http://www.python.org/doc/current/ref/sequence-types.html">Emulating + container types</a>): + </p> + <dl> + <dd> + <dl> + <dt> + <b><a name="l2h-126"><tt class= + "method">__len__</tt></a></b>(<var>self</var>) + </dt> + <dd> + Called to implement the built-in function <tt class= + "function">len()</tt><a name="l2h-134"> </a> Should return + the length of the object, an integer <code>>=</code> 0. Also, + an object that doesn't define a <tt class= + "method">__nonzero__()</tt> method and whose <tt class= + "method">__len__()</tt> method returns zero is considered to be + false in a Boolean context. <a name="l2h-128"> </a> + </dd> + </dl> + <dl> + <dt> + <b><a name="l2h-129"><tt class= + "method">__getitem__</tt></a></b>(<var>self, key</var>) + </dt> + <dd> + Called to implement evaluation of + <code><var>self</var>[<var>key</var>]</code>. For sequence types, + the accepted keys should be integers and slice + objects.<a name="l2h-135"> </a> Note that the special + interpretation of negative indexes (if the class wishes to + emulate a sequence type) is up to the <tt class= + "method">__getitem__()</tt> method. If <var>key</var> is of + an inappropriate type, <tt class="exception">TypeError</tt> + may be raised; if of a value outside the set of indexes for + the sequence (after any special interpretation of negative + values), <tt class="exception">IndexError</tt> should be + raised. <span class="note"><b class="label">Note:</b> + <tt class="keyword">for</tt> loops expect that an <tt class= + "exception">IndexError</tt> will be raised for illegal + indexes to allow proper detection of the end of the + sequence.</span> + </dd> + </dl> + <dl> + <dt> + <b><a name="l2h-130"><tt class= + "method">__setitem__</tt></a></b>(<var>self, key, value</var>) + </dt> + <dd> + Called to implement assignment to + <code><var>self</var>[<var>key</var>]</code>. Same note as for + <tt class="method">__getitem__()</tt>. This should only be + implemented for mappings if the objects support changes to the + values for keys, or if new keys can be added, or for sequences if + elements can be replaced. The same exceptions should be raised + for improper <var>key</var> values as for the <tt class= + "method">__getitem__()</tt> method. + </dd> + </dl> + <dl> + <dt> + <b><a name="l2h-131"><tt class= + "method">__delitem__</tt></a></b>(<var>self, key</var>) + </dt> + <dd> + Called to implement deletion of + <code><var>self</var>[<var>key</var>]</code>. Same note as for + <tt class="method">__getitem__()</tt>. This should only be + implemented for mappings if the objects support removal of keys, + or for sequences if elements can be removed from the sequence. + The same exceptions should be raised for improper <var>key</var> + values as for the <tt class="method">__getitem__()</tt> method. + </dd> + </dl> + <dl> + <dt> + <b><a name="l2h-132"><tt class= + "method">__iter__</tt></a></b>(<var>self</var>) + </dt> + <dd> + This method is called when an iterator is required for a + container. This method should return a new iterator object that + can iterate over all the objects in the container. For mappings, + it should iterate over the keys of the container, and should also + be made available as the method <tt class= + "method">iterkeys()</tt>. + <p> + Iterator objects also need to implement this method; they are + required to return themselves. For more information on iterator + objects, see ``<a class="ulink" href= + "http://www.python.org/doc/current/lib/typeiter.html">Iterator + Types</a>'' in the <em class="citetitle"><a href= + "http://www.python.org/doc/current/lib/lib.html" title= + "Python Library Reference">Python Library Reference</a></em>. + </p> + </dd> + </dl> + <dl> + <dt> + <b><a name="l2h-133"><tt class= + "method">__contains__</tt></a></b>(<var>self, item</var>) + </dt> + <dd> + Called to implement membership test operators. Should return true + if <var>item</var> is in <var>self</var>, false otherwise. For + mapping objects, this should consider the keys of the mapping + rather than the values or the key-item pairs. + </dd> + </dl> + </dd> + </dl> + +<h3> <a name="indexing_suite_subclasses"></a>indexing_suite sub-classes</h3> + <p> + The <tt>indexing_suite</tt> is not meant to be used as is. A couple of + policy functions must be supplied by subclasses of + <tt>indexing_suite</tt>. However, a set of <tt>indexing_suite</tt> + subclasses for the standard indexable STL containers will be provided, + In most cases, we can simply use the available predefined suites. In + some cases, we can refine the predefined suites to suit our needs. + </p> + +<h3> <a name="vector_indexing_suite"></a>vector_indexing_suite [ Header <boost/python/indexing/vector_indexing_suite.hpp> + ] </h3> +<p> + The <tt>vector_indexing_suite</tt> class is a predefined + <tt>indexing_suite</tt> derived class designed to wrap + <tt>std::vector</tt> (and <tt>std::vector</tt> like [i.e. a class with + std::vector interface]) classes. It provides all the policies required by the + <tt>indexing_suite</tt>. + </p> + <p> + Example usage: + </p> + <pre> + class X {...}; + ... + + class_<std::vector<X> >("XVec") + .def(vector_indexing_suite<std::vector<X> >()) + ; +</pre> + <p> + <tt>XVec</tt> is now a full-fledged Python container (see the + <a href="../../test/vector_indexing_suite.cpp">example in full</a>, + along with its <a href="../../test/vector_indexing_suite.py">python + test</a>). +</p> + <h3><a name="map_indexing_suite" id="map_indexing_suite"></a>map_indexing_suite [ Header <boost/python/indexing/map_indexing_suite.hpp> ] </h3> + <p> The <tt>map_indexing_suite</tt> class is a predefined <tt>indexing_suite</tt> derived class designed to wrap <tt>std::map</tt> (and <tt>std::map</tt> like [i.e. a class with std::map interface]) classes. It provides all the policies required by the <tt>indexing_suite</tt>. </p> + <p> Example usage: </p> + <pre> + class X {...}; + ... + + class_<std::map<X> >("XMap") + .def(map_indexing_suite<std::map<X> >()) + ; +</pre> + <p> By default indexed elements are returned by proxy. This can be disabled by supplying <tt>true</tt> in the NoProxy template parameter. <tt>XMap</tt> is now a full-fledged Python container (see the <a href="../../test/map_indexing_suite.cpp">example in full</a>, along with its <a href="../../test/map_indexing_suite.py">python test</a>).</p> + <hr> + <h2> + <a name="indexing_suite_class"></a>indexing_suite class </h2> + <h2> <tt>indexing_suite<<br> + </tt><tt>class Container<br> + , class DerivedPolicies<font color="#007F00"><br> + </font></tt> <tt>, + bool NoProxy<br> + , + bool NoSlice<br> + </tt><tt>, class Data<br> + , class Index<br> + </tt><tt>, class Key</tt></h2> + <table width="100%" border="1"> + <tr> + <td> + <strong>Template Parameter</strong><br> + </td> + <td> + <strong>Requirements</strong> + </td> + <td> + <strong>Semantics</strong> + </td> + <td> + <strong>Default</strong> + </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>Container</tt></font> + </td> + <td> + A class type + </td> + <td> + The container type to be wrapped to Python. + </td> + <td> + + </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>DerivedPolicies</tt></font> + </td> + <td> + A subclass of indexing_suite + </td> + <td> + Derived classes provide the policy hooks. See <a href= + "#DerivedPolicies">DerivedPolicies</a> below. + </td> + <td> + + </td> + </tr> + <tr> + <td> <font color="#007F00"><tt>NoProxy</tt></font> </td> + <td> A boolean </td> + <td> By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying <strong>true</strong> in the <tt>NoProxy</tt> template parameter. </td> + <td> false </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>NoSlice</tt></font> + </td> + <td> + A boolean + </td> + <td> + Do not allow slicing. </td> + <td> + false + </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>Data</tt></font> + </td> + <td> + + </td> + <td> + The container's data type. + </td> + <td> + <tt>Container::value_type</tt> + </td> + </tr> + <tr> + <td> <font color="#007F00"><tt>Index</tt></font> </td> + <td> </td> + <td> The container's index type. </td> + <td> <tt>Container::size_type</tt> </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>Key</tt></font> + </td> + <td> + + </td> + <td> + The container's key type. + </td> + <td> + <tt>Container::value_type</tt> + </td> + </tr> + </table> + <pre> + template <<br> class Container + , class DerivedPolicies + , bool NoProxy = false<br> , bool NoSlice = false + , class Data = typename Container::value_type + , class Index = typename Container::size_type + , class Key = typename Container::value_type + ><br> class indexing_suite + : unspecified + { + public: + + indexing_suite(); // default constructor + } + </pre> + <h2> + <tt><a name="DerivedPolicies"></a>DerivedPolicies</tt> + </h2> + <dl> + <dd> + Derived classes provide the hooks needed by + the <tt>indexing_suite:</tt> + </dd> + </dl> + <pre> data_type& + get_item(Container& container, index_type i); + + static object + get_slice(Container& container, index_type from, index_type to); + + static void + set_item(Container& container, index_type i, data_type const& v); + + static void + set_slice( + Container& container, index_type from, + index_type to, data_type const& v + ); + + template <class Iter> + static void<br> set_slice(Container& container, index_type from, + index_type to, Iter first, Iter last + ); + + static void + delete_item(Container& container, index_type i); + + static void + delete_slice(Container& container, index_type from, index_type to); + + static size_t + size(Container& container); + + template <class T> + static bool + contains(Container& container, T const& val); + + static index_type + convert_index(Container& container, PyObject* i); + + static index_type + adjust_index(index_type current, index_type from, + index_type to, size_type len + ); +</pre> + <blockquote> + <p> + Most of these policies are self explanatory. <tt>However, + <strong>convert_index</strong></tt> and + <tt><strong>adjust_index</strong></tt> deserve some explanation. + </p> + <p> + <strong><tt>convert_index</tt></strong> converts a Python index into + a C++ index that the container can handle. For instance, negative + indexes in Python, by convention, start counting from the right(e.g. + <tt>C[-1]</tt> indexes the rightmost element in <tt>C</tt>). + <strong><tt>convert_index</tt></strong> should handle the necessary + conversion for the C++ container (e.g. convert <tt>-1</tt> to + <tt>C.size()-1</tt>). <tt><strong>convert_index</strong></tt> should + also be able to convert the type of the index (A dynamic Python type) + to the actual type that the C++ container expects. + </p> + <p> + When a container expands or contracts, held indexes to its elements + must be adjusted to follow the movement of data. For instance, if we + erase 3 elements, starting from index 0 from a 5 element vector, what + used to be at index 4 will now be at index 1: + </p> + <pre> + [a][b][c][d][e] ---> [d][e] + ^ ^ + 4 1 +</pre> + <p> + <strong><tt>adjust_index</tt></strong> takes care of the adjustment. + Given a current index, the function should return the adjusted index + when data in the container at index <tt>from</tt>..<tt>to</tt> is + replaced by <tt>len</tt> elements. + </p> + </blockquote> + <div> + <hr> + <h2> + <a name="vector_indexing_suite_class"></a>vector_indexing_suite class + </h2> + <h3> + Class template <tt><br> + vector_indexing_suite<<br> + class <font color="#007F00">Container</font><br> + , bool <font color="#007F00">NoProxy</font><br> + , class <font color="#007F00">DerivedPolicies</font>></tt> + </h3> + <table width="100%" border="1"> + <tr> + <td> + <strong>Template Parameter</strong><br> + </td> + <td> + <strong>Requirements</strong> + </td> + <td> + <strong>Semantics</strong> + </td> + <td> + <strong>Default</strong> + </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>Container</tt></font> + </td> + <td> + A class type + </td> + <td> + The container type to be wrapped to Python. + </td> + <td> + + </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>NoProxy</tt></font> + </td> + <td> + A boolean + </td> + <td> + By default indexed elements have Python reference semantics and + are returned by proxy. This can be disabled by supplying + <strong>true</strong> in the <tt>NoProxy</tt> template parameter. + </td> + <td> + false + </td> + </tr> + <tr> + <td> + <font color="#007F00"><tt>DerivedPolicies</tt></font> + </td> + <td> + A subclass of indexing_suite + </td> + <td> + The <tt>vector_indexing_suite</tt> may still be derived to + further tweak any of the predefined policies. Static polymorphism + through CRTP (James Coplien. "Curiously Recurring Template + Pattern". C++ Report, Feb. 1995) enables the base + <tt>indexing_suite</tt> class to call policy function of the most + derived class + </td> + <td> + + </td> + </tr> + </table> + <pre> + template <<br> class Container,<br> bool NoProxy = false,<br> class DerivedPolicies = unspecified_default<br> class vector_indexing_suite : unspecified_base<br> {<br> public:<br><br> typedef typename Container::value_type data_type;<br> typedef typename Container::value_type key_type;<br> typedef typename Container::size_type index_type;<br> typedef typename Container::size_type size_type;<br> typedef typename Container::difference_type difference_type;<br> <br> data_type&<br> get_item(Container& container, index_type i); + + static object + get_slice(Container& container, index_type from, index_type to); + + static void<br> set_item(Container& container, index_type i, data_type const& v); + + static void + set_slice(Container& container, index_type from, + index_type to, data_type const& v); + + template <class Iter><br> static void<br> set_slice(Container& container, index_type from,<br> index_type to, Iter first, Iter last); + + static void + delete_item(Container& container, index_type i); + + static void + delete_slice(Container& container, index_type from, index_type to);<br> + static size_t + size(Container& container); + + static bool + contains(Container& container, key_type const& key); + + static index_type + convert_index(Container& container, PyObject* i); + + static index_type + adjust_index(index_type current, index_type from, + index_type to, size_type len); + }; + +</pre> + <h2><a name="vector_indexing_suite_class"></a>map_indexing_suite class </h2> + <h3> Class template <tt><br> + map_indexing_suite<<br> + class <font color="#007F00">Container</font><br> + , bool <font color="#007F00">NoProxy</font><br> + , class <font color="#007F00">DerivedPolicies</font>></tt> </h3> + <table width="100%" border="1"> + <tr> + <td> <strong>Template Parameter</strong><br> + </td> + <td> <strong>Requirements</strong> </td> + <td> <strong>Semantics</strong> </td> + <td> <strong>Default</strong> </td> + </tr> + <tr> + <td> <font color="#007F00"><tt>Container</tt></font> </td> + <td> A class type </td> + <td> The container type to be wrapped to Python. </td> + <td> </td> + </tr> + <tr> + <td> <font color="#007F00"><tt>NoProxy</tt></font> </td> + <td> A boolean </td> + <td> By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying <strong>true</strong> in the <tt>NoProxy</tt> template parameter. </td> + <td> false </td> + </tr> + <tr> + <td> <font color="#007F00"><tt>DerivedPolicies</tt></font> </td> + <td> A subclass of indexing_suite </td> + <td> The <tt>vector_indexing_suite</tt> may still be derived to further tweak any of the predefined policies. Static polymorphism through CRTP (James Coplien. "Curiously Recurring Template Pattern". C++ Report, Feb. 1995) enables the base <tt>indexing_suite</tt> class to call policy function of the most derived class </td> + <td> </td> + </tr> + </table> + <pre> + template <<br> class Container,<br> bool NoProxy = false,<br> class DerivedPolicies = unspecified_default<br> class map_indexing_suite : unspecified_base<br> {<br> public:<br><br> typedef typename Container::value_type value_type;<br> typedef typename Container::value_type::second_type data_type;<br> typedef typename Container::key_type key_type;<br> typedef typename Container::key_type index_type;<br> typedef typename Container::size_type size_type;<br> typedef typename Container::difference_type difference_type;<br><br> static data_type&<br> get_item(Container& container, index_type i); + + static void<br> set_item(Container& container, index_type i, data_type const& v); + + static void + delete_item(Container& container, index_type i);<br> + static size_t + size(Container& container); + + static bool + contains(Container& container, key_type const& key); + + static bool<br> compare_index(Container& container, index_type a, index_type b); +<br> static index_type + convert_index(Container& container, PyObject* i); + }; + +</pre> + <hr> + © Copyright Joel de Guzman 2003. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose. + </div> + </body> +</html> diff --git a/libs/python/doc/v2/init.html b/libs/python/doc/v2/init.html new file mode 100644 index 000000000..2aacaad9f --- /dev/null +++ b/libs/python/doc/v2/init.html @@ -0,0 +1,251 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/init.hpp></title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Headers <boost/python/init.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href= + "#init-expressions"><em>init-expressions</em></a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#init-spec">Class template <code>init</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#init-spec-synopsis">Class template + <code>init</code> synopsis</a></dt> + + <dt><a href="#init-spec-ctors">Class <code>init</code> + constructors</a></dt> + + </dl> + </dd> + + <dt><a href="#optional-spec">Class template + <code>optional</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#optional-spec-synopsis">Class template + <code>optional</code> synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/init.hpp></code> defines the interface for + exposing C++ constructors to Python as extension class + <code>__init__</code> functions.</p> + + <h2><a name="init-expressions"><em>init-expressions</em></a></h2> + An <em>init-expression</em> is used to describe a family of + <code>__init__</code> methods to be generated for an extension class, and + the result has the following properties: + + <blockquote> + <dl class="properties"> + <dt><b>docstring:</b> An <a href="definitions.html#ntbs">ntbs</a> + whose value will bound to the method's <code>__doc__</code> + attribute</dt> + + <dt><b>keywords:</b> A <a href= + "args.html#keyword-expression">keyword-expression</a> which will be + used to name (a trailing subsequence of) the arguments to the + generated <code>__init__</code> function(s).</dt> + + <dt><b>call policies:</b> An instance of a model of <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>argument types:</b> An MPL sequence of C++ argument types + which will be used to construct the wrapped C++ object. An init + expression has one or more + <b>valid prefixes</b> which are given by a sequence of + prefixes of its argument types.</dt> + </dl> + </blockquote> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="init-spec"></a>Class template <code>init<T1 =</code> + <i>unspecified</i><code>, T2 =</code> + <i>unspecified</i><code>,</code>...<code>Tn</code> = + <i>unspecified</i><code>></code></h3> + + <p>A <a href="../../../mpl/doc/refmanual/forward-sequence.html">MPL sequence</a> which + can be used to specify a family of one or more <code>__init__</code> + functions. Only the last <code>T</code><i><small>i</small></i> supplied + may be an instantiation of <a href= + "#optional-spec"><code>optional</code></a><code><</code>...<code>></code>.</p> + + <h4><a name="init-spec-synopsis"></a>Class template <code>init</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <T1 = <i>unspecified</i>,...T<i>n</i> = <i>unspecified</i>> + struct init + { + init(char const* doc = 0); + template <class Keywords> init(Keywords const& kw, char const* doc = 0); + template <class Keywords> init(char const* doc, Keywords const& kw); + + template <class CallPolicies> + <em>unspecified</em> operator[](CallPolicies const& policies) const + }; +}} +</pre> + + <h4><a name="init-spec-ctors"></a>Class template <code>init</code> + constructors</h4> +<pre> +init(char const* doc = 0); +template <class Keywords> init(Keywords const& kw, char const* doc = 0); +template <class Keywords> init(char const* doc, Keywords const& kw); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> If supplied, <code>doc</code> is an <a href= + "definitions.html#ntbs">ntbs</a>. If supplied, <code>kw</code> is the + result of a <a href="args.html#keyword-expression"></a></dt> + + <dt><b>Effects:</b> The result is an <em>init-expression</em> whose + <em>docstring</em> is <code>doc</code> and whose <em>keywords</em> are + a reference to <code>kw</code>. If the first form is used, the + resulting expression's <em>keywords</em> are empty. The expression's + <em>call policies</em> are an instance of <a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a>. + If <code>T</code><i><small>n</small></i> is <a href= + "#optional-spec"><code>optional</code></a><code><U1, U2,</code>... + <code>U</code><small><i>m</i></small><code>></code>, the + expression's <em>valid prefixes</em> are given by:</dt> + + <dd> + <blockquote> + (<code>T1, T2,</code>...<code>T</code><i><small>n-1</small></i>), + (<code>T1, T2,</code>...<code>T</code><i><small>n-1</small></i> + <code>, U1</code>), + (<code>T1, T2,</code>...<code>T</code><i><small>n-1</small></i> + <code>, U1, U2</code>), + ...(<code>T1, T2,</code>...<code>T</code><i><small>n-1</small></i> + <code>, U1, U2,</code>...<code>U</code><i><small>m</small></i>). + </blockquote> + Otherwise, the expression has one <em>valid prefix</em> given by the + the template arguments the user specified. + </dd> + </dl> + + <h4><a name="init-spec-observers"></a>Class template <code>init</code> + observer functions</h4> +<pre> +template <class Policies> +<em>unspecified</em> operator[](Policies const& policies) const +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> Policies is a model of <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>Effects:</b> Returns a new <a href= + "#init-expressions"><em>init-expression</em></a> with all the same + properties as the <code>init</code> object except that its <em>call + policies</em> are replaced by a reference to + <code>policies</code>.</dt> + </dl> + + <h3><a name="optional-spec"></a>Class template <code>optional<T1 + =</code> <i>unspecified</i><code>, T2 =</code> + <i>unspecified</i><code>,</code>...<code>Tn</code> = + <i>unspecified</i><code>></code></h3> + + <p>A <a href="../../../mpl/doc/refmanual/forward-sequence.html">MPL sequence</a> which + can be used to specify the optional arguments to an <code>__init__</code> + function.</p> + + <h4><a name="optional-spec-synopsis"></a>Class template + <code>optional</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <T1 = <i>unspecified</i>,...T<i>n</i> = <i>unspecified</i>> + struct optional {}; +}} +</pre> + + <h2><a name="examples"></a>Example(s)</h2> + + <p>Given the C++ declarations:</p> +<pre> +class Y; +class X +{ + public: + X(int x, Y* y) : m_y(y) {} + X(double); + private: + Y* m_y; +}; +</pre> + A corresponding Boost.Python extension class can be created with: +<pre> +using namespace boost::python; + +class_<X>("X", "This is X's docstring.", + init<int,char const*>(args("x","y"), "X.__init__'s docstring")[ + with_custodian_and_ward<1,3>()] + ) + .def(init<double>()) + ; +</pre> + <hr> + Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/instance_holder.html b/libs/python/doc/v2/instance_holder.html new file mode 100644 index 000000000..87571d1da --- /dev/null +++ b/libs/python/doc/v2/instance_holder.html @@ -0,0 +1,219 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content= + "text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/instance_holder.hpp></title> + </head> + +<style type="text/css"> + p.c4 {font-style: italic} + span.c3 {color: #ff0000} + h2.c2 {text-align: center} + h1.c1 {text-align: center} +</style> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png" border= + "0"></a></h3> + + <td valign="top"> + <h1 class="c1"><a href="../index.html">Boost.Python</a></h1> + + <h2 class="c2">Header <boost/python/instance_holder.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a> + + <dt><a href="#classes">Classes</a> + + <dd> + <dl class="page-index"> + <dt><a href="#instance_holder-spec">Class + <code>instance_holder</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#instance_holder-spec-synopsis">Class + <code>instance_holder</code> synopsis</a> + + <dt><a href="#instance_holder-spec-ctors">Class + <code>instance_holder</code> destructor</a> + + <dt><a href="#instance_holder-spec-modifiers">Class + <code>instance_holder</code> modifier functions</a> + + <dt><a href="#instance_holder-spec-observers">Class + <code>instance_holder</code> observer functions</a> + </dl> + </dl> + + <dt><a href="#examples">Example</a> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/instance_holder.hpp></code> provides + <code>class instance_holder</code>, the base class for types + which hold C++ instances of wrapped classes. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="instance_holder-spec"></a>Class <code>instance_holder</code></h3> + + <p><code>instance_holder</code> is an abstract base class whose + concrete derived classes hold C++ class instances within their + Python object wrappers. To allow multiple inheritance in Python + from C++ class wrappers, each such Python object contains a chain + of <code>instance_holder</code>s. When an <code>__init__</code> + function for a wrapped C++ class is invoked, a new + <code>instance_holder</code> instance is created and installed in + the Python object using its <code><a + href="#instance_holder-spec-modifiers">install</a></code>() + function. Each concrete class derived from + <code>instance_holder</code> must provide a <code><a + href="#instance_holder-spec-observers">holds</a>()</code> + implementation which allows Boost.Python to query it for the + type(s) it is holding. In order to support the held type's wrapped + constructor(s), the class must also provide constructors that can + accept an initial <code>PyObject*</code> argument referring to the + owning Python object, and which forward the rest of their + arguments to the constructor of the held type. The initial + argument is needed to enable virtual function overriding in + Python, and may be ignored, depending on the specific + <code>instance_holder</code> subclass. + + <h4><a name="instance_holder-spec-synopsis"></a>Class instance_holder + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class instance_holder : <a href="../../../utility/utility.htm#Class_noncopyable">noncopyable</a> + { + public: + // destructor + virtual ~instance_holder(); + + // instance_holder modifiers + void install(PyObject* inst) throw(); + + // instance_holder observers + virtual void* holds(type_info) = 0; + }; +}} +</pre> + + <h4><a name="instance_holder-spec-ctors">Class <code>instance_holder</code> + destructor</a></h4> +<pre> +virtual ~instance_holder(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> destroys the object + </dl> + + <h4><a name="instance_holder-spec-modifiers">Class + <code>instance_holder</code> modifiers</a></h4> +<pre> +void install(PyObject* inst) throw(); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>inst</code> is a Python instance of a + wrapped C++ class type, or is a type derived from a wrapped C++ + class type. + <dt><b>Effects:</b> installs the new instance at the head of the + Python object's chain of held instances. + <dt><b>Throws:</b> nothing + </dl> + + <h4><a name="instance_holder-spec-observers">Class <code>instance_holder</code> + observers</a></h4> +<pre> +virtual void* holds(type_info x) = 0; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> A pointer to an object of the type described + by <code>x</code> if <code>*this</code> contains such an object, + 0 otherwise. + </dl> + + <h2><a name="examples"></a>Example</h2> + +The following is a simplified version of the instance holder template +used by Boost.Python to wrap classes held by smart pointers: +<pre> +template <class SmartPtr, class Value> +struct pointer_holder : instance_holder +{ + // construct from the SmartPtr type + pointer_holder(SmartPtr p) + :m_p(p) + + // Forwarding constructors for the held type + pointer_holder(PyObject*) + :m_p(new Value()) + { + } + + template<class A0> + pointer_holder(PyObject*,A0 a0) + :m_p(new Value(a0)) + { + } + + template<class A0,class A1> + pointer_holder(PyObject*,A0 a0,A1 a1) + :m_p(new Value(a0,a1)) + { + } + ... + + private: // required holder implementation + void* holds(type_info dst_t) + { + // holds an instance of the SmartPtr type... + if (dst_t == python::type_id<SmartPtr>()) + return &this->m_p; + + // ...and an instance of the SmartPtr's element_type, if the + // pointer is non-null + return python::type_id<Value>() == dst_t ? &*this->m_p : 0; + } + + private: // data members + SmartPtr m_p; +}; +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p class="c4">© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002. + + </body> +</html> diff --git a/libs/python/doc/v2/iterator.html b/libs/python/doc/v2/iterator.html new file mode 100644 index 000000000..3557ffb9a --- /dev/null +++ b/libs/python/doc/v2/iterator.html @@ -0,0 +1,398 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/iterator.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/iterator.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#iterator-spec">Class template + <code>iterator</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#iterator-spec-synopsis">Class + <code>iterator</code> synopsis</a></dt> + + <dt><a href="#iterator-spec-constructors">Class template + <code>iterator</code> constructor</a></dt> + </dl> + </dd> + </dl> + + <dl class="page-index"> + <dt><a href="#iterators-spec">Class template + <code>iterators</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#iterators-spec-synopsis">Class + <code>iterators</code> synopsis</a></dt> + + <dt><a href="#iterators-spec-types">Class template + <code>iterators</code> nested types</a></dt> + + <dt><a href="#iterators-spec-statics">Class template + <code>iterators</code> static functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#range-spec">range</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/iterator.hpp></code> provides types and + functions for creating <a href= + "http://www.python.org/doc/current/lib/typeiter.html">Python + iterators</a> from <a href= + "http://www.sgi.com/tech/stl/Container.html">C++ Containers</a> and <a + href="http://www.sgi.com/tech/stl/Iterators.html">Iterators</a>. Note + that if your <code>class_</code> supports random-access iterators, + implementing <code><a href= + "http://www.python.org/doc/current/ref/sequence-types.html#l2h-128">__getitem__</a></code> + (also known as the Sequence Protocol) may serve you better than using + this facility: Python will automatically create an iterator type for you + (see <a href= + "http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-35">iter()</a>), + and each access can be range-checked, leaving no possiblity of accessing + through an invalidated C++ iterator.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="iterator-spec"></a>Class Template <code>iterator</code></h3> + + <p>Instances of <code>iterator<C,P></code> hold a reference to a + callable Python object which, when invoked from Python, expects a single + argument <code>c</code> convertible to <code>C</code> and creates a + Python iterator that traverses [<code>c.begin()</code>, + <code>c.end()</code>). The optional <a href= + "CallPolicies.html">CallPolicies</a> <code>P</code> can be used to + control how elements are returned during iteration.</p> + + <p>In the table below, <code><b>c</b></code> is an instance of + <code>Container</code>.</p> + + <table border="1" summary="iterator template parameters"> + <tr> + <th>Template Parameter</th> + + <th>Requirements</th> + + <th>Semantics</th> + + <th>Default</th> + </tr> + + <tr> + <td><code>Container</code></td> + + <td>[c.begin(),c.end()) is a valid <a href= + "http://www.sgi.com/tech/stl/Iterators.html">Iterator range</a>.</td> + + <td>The result will convert its argument to <code>c</code> and call + <code>c.begin()</code> and <code>c.end()</code> to acquire iterators. + To invoke <code>Container</code>'s <code>const</code> + <code>begin()</code> and <code>end()</code> functions, make it + <code>const</code>.</td> + </tr> + + <tr> + <td><code>NextPolicies</code></td> + + <td>A default-constructible model of <a href= + "CallPolicies.html#CallPolicies-concept">CallPolicies</a>.</td> + + <td>Applied to the resulting iterators' <code>next()</code> + method.</td> + + <td>An unspecified model of <a href= + "CallPolicies.html#CallPolicies-concept">CallPolicies</a> which + always makes a copy of the result of deferencing the underlying C++ + iterator</td> + </tr> + </table> + + <h4><a name="iterator-spec-synopsis"></a>Class Template iterator + synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class Container + , class NextPolicies = <i>unspecified</i>> + struct iterator : <a href="object.html#object-spec">object</a> + { + iterator(); + }; +}} +</pre> + + <h4><a name="iterator-spec-constructors"></a>Class Template iterator + constructor</h4> +<pre> +iterator() +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b></dt> + + <dd> + Initializes its base class with the result of: +<pre> +range<NextPolicies>(&iterators<Container>::begin, &iterators<Container>::end) +</pre> + </dd> + + <dt><b>Postconditions:</b> <code>this->get()</code> points to a + Python callable object which creates a Python iterator as described + above.</dt> + + <dt><b>Rationale:</b> Provides an easy way to create iterators for the + common case where a C++ class being wrapped provides + <code>begin()</code> and <code>end()</code>.</dt> + </dl> + <!-- --> + + <h3><a name="iterators-spec"></a>Class Template + <code>iterators</code></h3> + + <p>A utility class template which provides a way to reliably call its + argument's <code>begin()</code> and <code>end()</code> member functions. + Note that there is no portable way to take the address of a member + function of a C++ standard library container, so + <code>iterators<></code> can be particularly helpful when wrapping + them.</p> + + <p>In the table below, <code><b>x</b></code> is an instance of + <code>C</code>.</p> + + <table border="1" summary="iterator template parameters"> + <tr> + <th>Required Valid Expression</th> + + <th>Type</th> + </tr> + + <tr> + <td><code>x.begin()</code></td> + + <td>Convertible to <code>C::const_iterator</code> if <code>C</code> + is a <code>const</code> type; convertible to <code>C::iterator</code> + otherwise.</td> + </tr> + + <tr> + <td><code>x.end()</code></td> + + <td>Convertible to <code>C::const_iterator</code> if <code>C</code> + is a <code>const</code> type; convertible to <code>C::iterator</code> + otherwise.</td> + </tr> + </table> + + <h4><a name="iterators-spec-synopsis"></a>Class Template iterators + synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class C> + struct iterators + { + typedef typename C::[const_]iterator iterator; + static iterator begin(C& x); + static iterator end(C& x); + }; +}} + +</pre> + + <h4><a name="iterators-spec-types"></a>Class Template iterators nested + types</h4> + If C is a <code>const</code> type, +<pre> +typedef typename C::const_iterator iterator; +</pre> + Otherwise: +<pre> +typedef typename C::iterator iterator; +</pre> + + <h4><a name="iterators-spec-statics"></a>Class Template iterators static + functions</h4> +<pre> +static iterator begin(C&); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>x.begin()</code></dt> + </dl> +<pre> +static iterator end(C&); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>x.end()</code></dt> + </dl> + <!-- --> + + <h2><a name="functions"></a>Functions</h2> +<pre> +<a name= +"range-spec">template</a> <class NextPolicies, class Target, class Accessor1, class Accessor2> +<a href= +"object.html#object-spec">object</a> range(Accessor1 start, Accessor2 finish); + +template <class NextPolicies, class Accessor1, class Accessor2> +<a href= +"object.html#object-spec">object</a> range(Accessor1 start, Accessor2 finish); + +template <class Accessor1, class Accessor2> +<a href= +"object.html#object-spec">object</a> range(Accessor1 start, Accessor2 finish); +</pre> + + <dl class="range-semantics"> + <dt><b>Requires:</b> <code>NextPolicies</code> is a + default-constructible model of <a href= + "CallPolicies.html#CallPolicies-concept">CallPolicies</a>.</dt> + + <dt><b>Effects:</b></dt> + + <dd> + <dl> + <dt>The first form creates a Python callable object which, when + invoked, converts its argument to a <code>Target</code> object + <code>x</code>, and creates a Python iterator which traverses + [<code><a href= + "../../../bind/bind.html">bind</a>(start,_1)(x)</code>, <code><a + href="../../../bind/bind.html">bind</a>(finish,_1)(x)</code>), + applying <code>NextPolicies</code> to the iterator's + <code>next()</code> function.</dt> + + <dt>The second form is identical to the first, except that + <code>Target</code> is deduced from <code>Accessor1</code> as + follows:</dt> + + <dd> + <ol> + <li>If <code>Accessor1</code> is a function type, + <code>Target</code> is the type of its first argument.</li> + + <li>If <code>Accessor1</code> is a data member pointer of the + form <code>R (T::*)</code>, <code>Target</code> is + identical to <code>T</code>.</li> + + <li>If <code>Accessor1</code> is a member function pointer of + the form + <code>R (T::*)(</code><i>arguments...</i><code>)</code> + <i>cv-opt</i>, where <i>cv-opt</i> is an optional + <code>cv-qualifier</code>, <code>Target</code> is identical to + <code>T</code>.</li> + </ol> + </dd> + + <dt>The third form is identical to the second, except that + <code>NextPolicies</code> is an unspecified model of <a href= + "CallPolicies.html#CallPolicies-concept">CallPolicies</a> which + always makes a copy of the result of deferencing the underlying C++ + iterator</dt> + </dl> + </dd> + + <dt><b>Rationale:</b> The use of <code><a href= + "../../../bind/bind.html">boost::bind</a>()</code> allows C++ iterators + to be accessed through functions, member functions or data member + pointers. Customization of <code>NextPolicies</code> (e.g. using + <code><a href= + "return_internal_reference.html#return_internal_reference-spec">return_internal_reference</a></code>) + is useful when it is expensive to copy sequence elements of a wrapped + class type. Customization of <code>Target</code> is useful when + <code>Accessor1</code> is a function object, or when a base class of + the intended target type would otherwise be deduced.</dt> + </dl> + + <h2><a name="examples"></a>Examples</h2> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> + +#include <vector> + +using namespace boost::python; +BOOST_PYTHON_MODULE(demo) +{ + class_<std::vector<double> >("dvec") + .def("__iter__", iterator<std::vector<double> >()) + ; +} +</pre> + A more comprehensive example can be found in: + + <dl> + <dt><code><a href= + "../../test/iterator.cpp">libs/python/test/iterator.cpp</a></code></dt> + + <dt><code><a href= + "../../test/input_iterator.cpp">libs/python/test/input_iterator.cpp</a></code></dt> + + <dt><code><a href= + "../../test/iterator.py">libs/python/test/input_iterator.py</a></code></dt> + + </dl> +<hr> + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/list.html b/libs/python/doc/v2/list.html new file mode 100644 index 000000000..e347ae461 --- /dev/null +++ b/libs/python/doc/v2/list.html @@ -0,0 +1,142 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/list.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/list.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#list-spec">Class <code>list</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#list-spec-synopsis">Class <code>list</code> + synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> for the Python + <a href= + "http://www.python.org/doc/current/lib/typesseq-mutable.html">list</a> + type.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="list-spec"></a>Class <code>list</code></h3> + + <p>Exposes the <a href= + "http://www.python.org/doc/current/lib/typesseq-mutable.html">mapping + protocol</a> of Python's built-in <code>list</code> type. The semantics + of the constructors and member functions defined below can be fully + understood by reading the <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept + definition. Since <code>list</code> is publicly derived from <code><a + href="object.html#object-spec">object</a></code>, the public object + interface applies to <code>list</code> instances as well.</p> + + <h4><a name="list-spec-synopsis"></a>Class <code>list</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class list : public object + { + public: + list(); // new list + + template <class T> + explicit list(T const& sequence); + + template <class T> + void append(T const& x); + + template <class T> + long count(T const& value) const; + + template <class T> + void extend(T const& x); + + template <class T> + long index(T const& x) const; + + template <class T> + void insert(object const& index, T const& x); // insert object before index + + object pop(); // remove and return item at index (default last) + object pop(long index); + object pop(object const& index); + + template <class T> + void remove(T const& value); + + void reverse(); // reverse *IN PLACE* + + void sort(); // sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1 + + template <class T> + void sort(T const& value); + }; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> +<pre> +using namespace boost::python; + +// Return the number of zeroes in the list +long zeroes(list l) +{ + return l.count(0); +} +</pre> + + <p>Revised 1 October, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/long.html b/libs/python/doc/v2/long.html new file mode 100644 index 000000000..08ceb3bd5 --- /dev/null +++ b/libs/python/doc/v2/long.html @@ -0,0 +1,119 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/long.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/long.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#long_-spec">Class <code>long_</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#long_-spec-synopsis">Class <code>long_</code> + synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> for the Python + <a href= + "http://www.python.org/doc/current/lib/typesnumeric.html">long</a> + integer type.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="long_-spec"></a>Class <code>long_</code></h3> + + <p>Exposes the <a href= + "http://www.python.org/doc/current/lib/typesnumeric.html">numeric type + protocol</a> of Python's built-in <code>long</code> type. The semantics + of the constructors and member functions defined below can be fully + understood by reading the <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept + definition. Since <code>long_</code> is publicly derived from <code><a + href="object.html#object-spec">object</a></code>, the public object + interface applies to <code>long_</code> instances as well.</p> + + <h4><a name="long_-spec-synopsis"></a>Class <code>long_</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class long_ : public object + { + public: + long_(); // new long_ + + template <class T> + explicit long_(T const& rhs); + + template <class T, class U> + long_(T const& rhs, U const& base); + }; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> +<pre> +namespace python = boost::python; + +// compute a factorial without overflowing +python::long_ fact(long n) +{ + if (n == 0) + return python::long_(1); + else + return n * fact(n - 1); +} +</pre> + + <p>Revised 1 October, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/lvalue_from_pytype.html b/libs/python/doc/v2/lvalue_from_pytype.html new file mode 100644 index 000000000..d27c57d0c --- /dev/null +++ b/libs/python/doc/v2/lvalue_from_pytype.html @@ -0,0 +1,301 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/lvalue_from_python.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/lvalue_from_pytype.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#lvalue_from_pytype-spec">Class Template + <code>lvalue_from_pytype</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#lvalue_from_pytype-spec-synopsis">Class Template + <code>lvalue_from_pytype</code> synopsis</a></dt> + + <dt><a href="#lvalue_from_pytype-spec-ctors">Class Template + <code>lvalue_from_pytype</code> constructor</a></dt> + </dl> + </dd> + </dl> + + <dl class="page-index"> + <dt><a href="#extract_identity-spec">Class Template + <code>extract_identity</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#extract_identity-spec-synopsis">Class Template + <code>extract_identity</code> synopsis</a></dt> + + <dt><a href="#extract_identity-spec-statics">Class Template + <code>extract_identity</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#extract_member-spec">Class Template + <code>extract_member</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#extract_member-spec-synopsis">Class Template + <code>extract_member</code> synopsis</a></dt> + + <dt><a href="#extract_member-spec-statics">Class Template + <code>extract_member</code> static functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + <code><boost/python/lvalue_from_pytype.hpp></code> supplies a + facility for extracting C++ objects from within Python instances of a + given type. This is typically useful for dealing with "traditional" + Python extension types. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="lvalue_from_pytype-spec"></a>Class template + <code>lvalue_from_pytype</code></h3> + + <p>Class template <code>lvalue_from_pytype</code> will register + from_python converters which, given an object of the given Python type, + can extract references and pointers to a particular C++ type. Its + template arguments are:</p> + + <table border="1" summary="lvalue_from_pytype template parameters"> + <caption> + <b><code>lvalue_from_pytype</code> Requirements</b><br> + In the table below, <b><code>x</code></b> denotes an object of type + <code>PythonObject&</code> + </caption> + + <tr> + <th>Parameter</th> + + <th>Requirements</th> + + <th>Semantics</th> + </tr> + + <tr> + <td><code>Extractor</code></td> + + <td>a model of <a href= + "Extractor.html#Extractor-concept">Extractor</a> whose execute + function returns a reference type.</td> + + <td>Extracts the lvalue from the Python object once its type has been + confirmed</td> + </tr> + + <tr> + <td><code>python_type</code></td> + + <td>A compile-time constant <code><a href= + "http://www.python.org/doc/2.2/ext/dnt-type-methods.html">PyTypeObject</a>*</code></td> + + <td>The Python type of instances convertible by this converter. + Python subtypes are also convertible.</td> + </tr> + </table> + + <h4><a name="lvalue_from_pytype-spec-synopsis"></a>Class template + <code>lvalue_from_pytype</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class Extractor, PyTypeObject const* python_type> + struct lvalue_from_pytype + { + lvalue_from_pytype(); + }; +}} +</pre> + + <h4><a name="lvalue_from_pytype-spec-ctors"></a>Class template + <code>lvalue_from_pytype</code> constructor</h4> +<pre> +lvalue_from_pytype(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Registers converters which can convert Python + objects of the given type to lvalues of the type returned by + <code>Extractor::execute</code>.</dt> + </dl> + + <h3><a name="extract_identity-spec"></a>Class template + <code>extract_identity</code></h3> + + <p><code>extract_identity</code> is a model of <a href= + "Extractor.html#Extractor-concept">Extractor</a> which can be used in the + common case where the C++ type to be extracted is the same as the Python + object type.</p> + + <h4><a name="extract_identity-spec-synopsis"></a>Class template + <code>extract_identity</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class InstanceType> + struct extract_identity + { + static InstanceType& execute(InstanceType& c); + }; +}} +</pre> + + <h4><a name="extract_identity-spec-statics"></a>Class template + <code>extract_identity</code> static functions</h4> +<pre> +InstanceType& execute(InstanceType& c); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>c</code></dt> + </dl> + + <h3><a name="extract_member-spec"></a>Class template + <code>extract_member</code></h3> + + <p><code>extract_member</code> is a model of <a href= + "Extractor.html#Extractor-concept">Extractor</a> which can be used in the + common case in the common case where the C++ type to be extracted is a + member of the Python object.</p> + + <h4><a name="extract_member-spec-synopsis"></a>Class template + <code>extract_member</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class InstanceType, class MemberType, MemberType (InstanceType::*member)> + struct extract_member + { + static MemberType& execute(InstanceType& c); + }; +}} +</pre> + + <h4><a name="extract_member-spec-statics"></a>Class template + <code>extract_member</code> static functions</h4> +<pre> +static MemberType& execute(InstanceType& c); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>c.*member</code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + This example presumes that someone has implemented the standard <a href= + "http://www.python.org/doc/2.2/ext/dnt-basics.html">noddy example + module</a> from the Python documentation, and we want to build a module + which manipulates <code>Noddy</code>s. Since + <code>noddy_NoddyObject</code> is so simple that it carries no + interesting information, the example is a bit contrived: it assumes you + want to keep track of one particular object for some reason. This module + would have to be dynamically linked to the module which defines + <code>noddy_NoddyType</code>. + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/python/lvalue_from_pytype.hpp> + +// definition lifted from the Python docs +typedef struct { + PyObject_HEAD +} noddy_NoddyObject; + +using namespace boost::python; +static handle<noddy_NoddyObject> cache; + +bool is_cached(noddy_NoddyObject* x) +{ + return x == cache.get(); +} + +void set_cache(noddy_NoddyObject* x) +{ + cache = handle<noddy_NoddyObject>(borrowed(x)); +} + +BOOST_PYTHON_MODULE(noddy_cache) +{ + def("is_cached", is_cached); + def("set_cache", set_cache); + + // register Noddy lvalue converter + lvalue_from_pytype<extract_identity<noddy_NoddyObject>,&noddy_NoddyType>(); +} +</pre> + + <h3>Python code</h3> +<pre> +>>> import noddy +>>> n = noddy.new_noddy() +>>> import noddy_cache +>>> noddy_cache.is_cached(n) +0 +>>> noddy_cache.set_cache(n) +>>> noddy_cache.is_cached(n) +1 +>>> noddy_cache.is_cached(noddy.new_noddy()) +0 +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 20 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/make_function.html b/libs/python/doc/v2/make_function.html new file mode 100644 index 000000000..d5a6cdb06 --- /dev/null +++ b/libs/python/doc/v2/make_function.html @@ -0,0 +1,207 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/make_function.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/make_function.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#make_function-spec">make_function</a></dt> + + <dt><a href="#make_constructor-spec">make_constructor</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><a href="#make_function-spec">make_function</a>()</code> and + <code><a href="#make_constructor-spec">make_constructor</a>()</code> are + the functions used internally by <code><a href= + "def.html#def-spec">def</a>()</code> and <code>class_<>::<a href= + "class.html#class_-spec-modifiers">def</a>()</code> to produce Python + callable objects which wrap C++ functions and member functions.</p> + + <h2><a name="functions"></a>Functions</h2> +<pre> +<a name="make_function-spec">template <class F></a> +<a href="object.html#object-spec">object</a> make_function(F f) + +template <class F, class Policies> +<a href= +"object.html#object-spec">object</a> make_function(F f, Policies const& policies) + +template <class F, class Policies, class KeywordsOrSignature> +<a href= +"object.html#object-spec">object</a> make_function(F f, Policies const& policies, KeywordsOrSignature const& ks) + +template <class F, class Policies, class Keywords, class Signature> +<a href= +"object.html#object-spec">object</a> make_function(F f, Policies const& policies, Keywords const& kw, Signature const& sig) +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>F</code> is a function pointer or member + function pointer type. If <code>policies</code> are supplied, it must + be a model of <a href="CallPolicies.html">CallPolicies</a>. If + <code>kewords</code> are supplied, it must be the result of a <a href= + "args.html#keyword-expression"><em>keyword-expression</em></a> + specifying no more arguments than the <a href= + "definitions.html#arity">arity</a> of <code>f</code>.</dt> + + <dt><b>Effects:</b> Creates a Python callable object which, when called + from Python, converts its arguments to C++ and calls <code>f</code>. If + <code>F</code> is a pointer-to-member-function type, the target + object of the function call (<code>*this</code>) will be taken + from the first Python argument, and subsequent Python arguments + will be used as the arguments + to <code>f</code>. <ul> +<li> If <code>policies</code> are supplied, it + will be applied to the function as described <a href= + "CallPolicies.html">here</a>. +<li>If <code>keywords</code> are + supplied, the keywords will be applied in order to the final + arguments of the resulting function. +<li>If <code>Signature</code> + is supplied, it should be an instance of an <a + href="../../../mpl/doc/refmanual/front-extensible-sequence.html">MPL front-extensible + sequence</a> representing the function's return type followed by + its argument types. Pass a <code>Signature</code> when wrapping + function object types whose signatures can't be deduced, or when + you wish to override the types which will be passed to the + wrapped function. +</ul></dt> + + <dt><b>Returns:</b> An instance of <a href= + "object.html#object-spec">object</a> which holds the new Python + callable object.</dt> + + <dt><b>Caveats:</b> An argument of pointer type may + be <code>0</code> if <code>None</code> is passed from Python. + An argument type which is a constant reference may refer to a + temporary which was created from the Python object for just the + duration of the call to the wrapped function, for example + a <code>std::vector</code> conjured up by the conversion process + from a Python list. Use a non-<code>const</code> reference + argument when a persistent lvalue is required. + </dl> + +<pre> +<a name="make_constructor-spec">template <class F></a> +<a href="object.html#object-spec">object</a> make_constructor(F f) + +template <class F, class Policies> +<a href= +"object.html#object-spec">object</a> make_constructor(F f, Policies const& policies) + +template <class F, class Policies, class KeywordsOrSignature> +<a href= +"object.html#object-spec">object</a> make_constructor(F f, Policies const& policies, KeywordsOrSignature const& ks) + +template <class F, class Policies, class Keywords, class Signature> +<a href= +"object.html#object-spec">object</a> make_constructor(F f, Policies const& policies, Keywords const& kw, Signature const& sig) +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>F</code> is a + function pointer type. If <code>policies</code> are supplied, it must + be a model of <a href="CallPolicies.html">CallPolicies</a>. If + <code>kewords</code> are supplied, it must be the result of a <a href= + "args.html#keyword-expression"><em>keyword-expression</em></a> + specifying no more arguments than the <a href= + "definitions.html#arity">arity</a> of <code>f</code>.</dt> + + <dt><b>Effects:</b> Creates a Python callable object which, when called + from Python, converts its arguments to C++ and calls <code>f</code>.</dt> + + <dt><b>Returns:</b> An instance of <a href= + "object.html#object-spec">object</a> which holds the new Python + callable object.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <p>C++ function exposed below returns a callable object wrapping one of + two functions.</p> +<pre> +#include <boost/python/make_function.hpp> +#include <boost/python/module.hpp> + +char const* foo() { return "foo"; } +char const* bar() { return "bar"; } + +using namespace boost::python; +object choose_function(bool selector) +{ + if (selector) + return boost::python::make_function(foo); + else + return boost::python::make_function(bar); +} + +BOOST_PYTHON_MODULE(make_function_test) +{ + def("choose_function", choose_function); +} +</pre> + It can be used this way in Python: +<pre> +>>> from make_function_test import * +>>> f = choose_function(1) +>>> g = choose_function(0) +>>> f() +'foo' +>>> g() +'bar' +</pre> + + <p> + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/manage_new_object.html b/libs/python/doc/v2/manage_new_object.html new file mode 100644 index 000000000..57efb4137 --- /dev/null +++ b/libs/python/doc/v2/manage_new_object.html @@ -0,0 +1,145 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/manage_new_object.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/manage_new_object.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#manage_new_object-spec">Class + <code>manage_new_object</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#manage_new_object-spec-synopsis">Class + <code>manage_new_object</code> synopsis</a></dt> + + <dt><a href="#manage_new_object-spec-metafunctions">Class + <code>manage_new_object</code> metafunctions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="manage_new_object-spec"></a>Class + <code>manage_new_object</code></h3> + + <p><code>manage_new_object</code> is a model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> + which can be used to wrap C++ functions which return a pointer to an + object allocated with a <i>new-expression</i>, and expect the caller to + take responsibility for deleting that object.</p> + + <h4><a name="manage_new_object-spec-synopsis"></a>Class + <code>manage_new_object</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct manage_new_object + { + template <class T> struct apply; + }; +}} +</pre> + + <h4><a name="manage_new_object-spec-metafunctions"></a>Class + <code>manage_new_object</code> metafunctions</h4> +<pre> +template <class T> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Requires:</b> <code>T</code> is <code>U*</code> for some + <code>U</code>.</dt> + + <dt><b>Returns:</b> <code>typedef <a href= + "to_python_indirect.html#to_python_indirect-spec">to_python_indirect</a><T> + type;</code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <p>In C++:</p> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/return_value_policy.hpp> + + +struct Foo { + Foo(int x) : x(x){} + int get_x() { return x; } + int x; +}; + +Foo* make_foo(int x) { return new Foo(x); } + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + def("make_foo", make_foo, return_value_policy<manage_new_object>()) + class_<Foo>("Foo") + .def("get_x", &Foo::get_x) + ; +} +</pre> + In Python: +<pre> +>>> from my_module import * +>>> f = make_foo(3) # create a Foo object +>>> f.get_x() +3 +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/module.html b/libs/python/doc/v2/module.html new file mode 100644 index 000000000..353523cb6 --- /dev/null +++ b/libs/python/doc/v2/module.html @@ -0,0 +1,110 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/module.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/module.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a> + + <dt><a href="#macros">Macros</a> + + <dd> + <dl class="page-index"> + <dt><a href= + "#BOOST_PYTHON_MODULE-spec">BOOST_PYTHON_MODULE</a> + </dl> + + <dt><a href="#examples">Example(s)</a> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>This header provides the basic facilities needed to create a + Boost.Python extension module. + + <h2><a name="macros"></a>Macros</h2> + + <p><a name= + "BOOST_PYTHON_MODULE-spec"><code>BOOST_PYTHON_MODULE(name)</code></a> + is used to declare Python <a href= + "http://www.python.org/doc/2.2/ext/methodTable.html#SECTION003400000000000000000"> + module initialization functions</a>. The <code>name</code> argument must + exactly match the name of the module to be initialized, and must conform to + Python's <a href= + "http://www.python.org/doc/2.2/ref/identifiers.html">identifier naming + rules</a>. Where you would normally write +<pre> +extern "C" void init<i>name</i>() +{ + ... +} +</pre> + Boost.Python modules should be initialized with +<pre> +BOOST_PYTHON_MODULE(<i>name</i>) +{ + ... +} +</pre> + +This macro generates two functions in the scope where it is used: +<code>extern "C" void init<i>name</i>()</code>, +and <code>void init_module_<i>name</i>()</code>, whose body must +follow the macro invocation. <code>init_<i>name</i></code> passes +<code>init_module_<i>name</i></code> to <code><a +href="errors.html#handle_exception-spec">handle_exception</a>()</code> so +that any C++ exceptions generated are safely processeed. During the +body of <code>init_<i>name</i></code>, the current <code><a +href="scope.html#scope-spec">scope</a></code> refers to the module +being initialized. + + <h2><a name="examples"></a>Example(s)</h2> + + <p>C++ module definition: +<pre> +#include <boost/python/module.hpp> + +BOOST_PYTHON_MODULE(xxx) +{ + throw "something bad happened" +} +</pre> + +Interactive Python: +<pre> +>>> import xxx +Traceback (most recent call last): + File "<stdin>", line 1, in ? +RuntimeError: Unidentifiable C++ Exception +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> Distributed + under the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/doc/v2/numeric.html b/libs/python/doc/v2/numeric.html new file mode 100644 index 000000000..eaa390af4 --- /dev/null +++ b/libs/python/doc/v2/numeric.html @@ -0,0 +1,276 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> + +<html> +<head> + <meta name="generator" content= + "HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/numeric.hpp></title> +</head> + +<body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/numeric.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#array-spec">Class <code>array</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#array-spec-synopsis">Class <code>array</code> + synopsis</a></dt> + + <dt><a href="#array-spec-observers">Class <code>array</code> + observer functions</a></dt> + + <dt><a href="#array-spec-statics">Class <code>array</code> static + functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction" id="introduction"></a>Introduction</h2> + + <p>Exposes a <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> for the Python + <a href= + "http://www.python.org/dev/doc/devel/lib/typesmapping.html">array</a> + type.</p> + + <h2><a name="classes" id="classes"></a>Classes</h2> + + <h3><a name="array-spec" id="array-spec"></a>Class <code>array</code></h3> + + <p>Provides access to the array types of <a href= + "http://www.pfdubois.com/numpy/">Numerical Python</a>'s <a href= + "http://www.pfdubois.com/numpy/#Numeric">Numeric</a> and <a href= + "http://stsdas.stsci.edu/numarray/index.html">NumArray</a> modules. With + the exception of the functions documented <a href= + "#array-spec-observers">below</a>, the semantics of the constructors and + member functions defined below can be fully understood by reading the + <a href="ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept + definition. Since <code>array</code> is publicly derived from + <code><a href="object.html#object-spec">object</a></code>, the public + object interface applies to <code>array</code> instances as well.</p> + + <p><a name="default_search" id="default_search"></a>The default behavior is + to use <code>numarray.NDArray</code> as the associated Python type if the + <code>numarray</code> module is installed in the default location. + Otherwise it falls back to use <code>Numeric.ArrayType</code>. If neither + extension module is installed, overloads of wrapped C++ functions with + <code>numeric::array</code> parameters will never be matched, and other + attempted uses of <code>numeric::array</code> will <a href= + "definitions.html#raise">raise</a> an appropriate Python exception. The + associated Python type can be set manually using the <code><a href= + "#array-spec-statics">set_module_and_type</a>(...)</code> static + function.</p> + + <h4><a name="array-spec-synopsis" id="array-spec-synopsis"></a>Class + <code>array</code> synopsis</h4> + <pre> +namespace boost { namespace python { namespace numeric +{ + class array : public object + { + public: + object astype(); + template <class Type> + object astype(Type const& type_); + + template <class Type> + array new_(Type const& type_) const; + + template <class Sequence> + void resize(Sequence const& x); + void resize(long x1); + void resize(long x1, long x2); + ... + void resize(long x1, long x2,...long x<i>n</i>); + + template <class Sequence> + void setshape(Sequence const& x); + void setshape(long x1); + void setshape(long x1, long x2); + ... + void setshape(long x1, long x2,...long x<i>n</i>); + + template <class Indices, class Values> + void put(Indices const& indices, Values const& values); + + template <class Sequence> + object take(Sequence const& sequence, long axis = 0); + + template <class File> + void tofile(File const& f) const; + + object factory(); + template <class Sequence> + object factory(Sequence const&); + template <class Sequence, class Typecode> + object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false); + template <class Sequence, class Typecode, class Type> + object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&); + template <class Sequence, class Typecode, class Type, class Shape> + object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&); + + template <class T1> + explicit array(T1 const& x1); + template <class T1, class T2> + explicit array(T1 const& x1, T2 const& x2); + ... + template <class T1, class T2,...class T<i>n</i>> + explicit array(T1 const& x1, T2 const& x2,...T<i>n</i> const& xn); + + static void set_module_and_type(); + static void set_module_and_type(char const* package_path = 0, char const* type_name = 0); + static void get_module_name(); + + object argmax(long axis=-1); + + object argmin(long axis=-1); + + object argsort(long axis=-1); + + void byteswap(); + + object copy() const; + + object diagonal(long offset = 0, long axis1 = 0, long axis2 = 1) const; + + void info() const; + + bool is_c_array() const; + bool isbyteswapped() const; + void sort(); + object trace(long offset = 0, long axis1 = 0, long axis2 = 1) const; + object type() const; + char typecode() const; + + object getflat() const; + long getrank() const; + object getshape() const; + bool isaligned() const; + bool iscontiguous() const; + long itemsize() const; + long nelements() const; + object nonzero() const; + + void ravel(); + + object repeat(object const& repeats, long axis=0); + + void setflat(object const& flat); + + void swapaxes(long axis1, long axis2); + + str tostring() const; + + void transpose(object const& axes = object()); + + object view() const; + }; +}}} +</pre> + + <h4><a name="array-spec-observers" id="array-spec-observers"></a>Class + <code>array</code> observer functions</h4> + <pre> +object factory(); +template <class Sequence> +object factory(Sequence const&); +template <class Sequence, class Typecode> +object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false); +template <class Sequence, class Typecode, class Type> +object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&); +template <class Sequence, class Typecode, class Type, class Shape> +object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&); +</pre>These functions map to the underlying array type's <code>array()</code> +function family. They are not called "<code>array</code>" because of the C++ +limitation that you can't define a member function with the same name as its +enclosing class. + <pre> +template <class Type> +array new_(Type const&) const; +</pre>This function maps to the underlying array type's <code>new()</code> +function. It is not called "<code>new</code>" because that is a keyword in +C++. + + <h4><a name="array-spec-statics" id="array-spec-statics"></a>Class + <code>array</code> static functions</h4> + <pre> +static void set_module_and_type(char const* package_path, char const* type_name); +static void set_module_and_type(); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>package_path</code> and + <code>type_name</code>, if supplied, is an <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> The first form sets the package path of the module + that supplies the type named by <code>type_name</code> to + <code>package_path</code>. The second form restores the <a href= + "#default_search">default search behavior</a>. The associated Python type + will be searched for only the first time it is needed, and thereafter the + first time it is needed after an invocation of + <code>set_module_and_type</code>.</dt> + </dl> + <pre> +static std::string get_module_name() +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Returns the name of the module containing the class + that will be held by new <code>numeric::array</code> instances.</dt> + </dl> + + <h2><a name="examples" id="examples"></a>Example</h2> + <pre> +#include <boost/python/numeric.hpp> +#include <boost/python/tuple.hpp> + +// sets the first element in a 2d numeric array +void set_first_element(numeric::array& y, double value) +{ + y[make_tuple(0,0)] = value; +} +</pre> + + <p>Revised 07 October, 2006</p> + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002-2006.</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/object.html b/libs/python/doc/v2/object.html new file mode 100644 index 000000000..8df8ef5f8 --- /dev/null +++ b/libs/python/doc/v2/object.html @@ -0,0 +1,1121 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/object.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/object.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#types">Types</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#slice_nil-spec">slice_nil</a></dt> + </dl> + </dd> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#const_attribute_policies-spec">Class + <code>const_attribute_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#const_attribute_policies-spec-synopsis">Class + <code>const_attribute_policies</code> synopsis</a></dt> + + <dt><a href="#const_attribute_policies-spec-statics">Class + <code>const_attribute_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#attribute_policies-spec">Class + <code>attribute_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#attribute_policies-spec-synopsis">Class + <code>attribute_policies</code> synopsis</a></dt> + + <dt><a href="#attribute_policies-spec-statics">Class + <code>attribute_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#const_objattribute_policies-spec">Class + <code>const_objattribute_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#const_objattribute_policies-spec-synopsis">Class + <code>const_objattribute_policies</code> synopsis</a></dt> + + <dt><a href="#const_objattribute_policies-spec-statics">Class + <code>const_objattribute_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#objattribute_policies-spec">Class + <code>objattribute_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#objattribute_policies-spec-synopsis">Class + <code>objattribute_policies</code> synopsis</a></dt> + + <dt><a href="#objattribute_policies-spec-statics">Class + <code>objattribute_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#const_item_policies-spec">Class + <code>const_item_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#const_item_policies-spec-synopsis">Class + <code>const_item_policies</code> synopsis</a></dt> + + <dt><a href="#const_item_policies-spec-statics">Class + <code>const_item_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#item_policies-spec">Class + <code>item_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#item_policies-spec-synopsis">Class + <code>item_policies</code> synopsis</a></dt> + + <dt><a href="#item_policies-spec-statics">Class + <code>item_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#const_slice_policies-spec">Class + <code>const_slice_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#const_slice_policies-spec-synopsis">Class + <code>const_slice_policies</code> synopsis</a></dt> + + <dt><a href="#const_slice_policies-spec-statics">Class + <code>const_slice_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#slice_policies-spec">Class + <code>slice_policies</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#slice_policies-spec-synopsis">Class + <code>slice_policies</code> synopsis</a></dt> + + <dt><a href="#slice_policies-spec-statics">Class + <code>slice_policies</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#object_operators-spec">Class + <code>object_operators</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#object_operators-spec-synopsis">Class + <code>object_operators</code> synopsis</a></dt> + + <dt><a href="#object_operators-spec-observers">Class + <code>object_operators</code> observer functions</a></dt> + </dl> + </dd> + + <dt><a href="#object-spec">Class <code>object</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#object-spec-synopsis">Class <code>object</code> + synopsis</a></dt> + + <dt><a href="#object-spec-ctors">Class <code>object</code> + constructors and destructor</a></dt> + + <dt><a href="#object-spec-modifiers">Class template + <code>object</code> modifier functions</a></dt> + + <dt><a href="#object-spec-observers">Class template + <code>object</code> observer functions</a></dt> + </dl> + </dd> + + <dt><a href="#proxy-spec">Class template + <code>proxy</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#proxy-spec-synopsis">Class template + <code>proxy</code> synopsis</a></dt> + + <dt><a href="#proxy-spec-modifiers">Class template + <code>proxy</code> modifier functions</a></dt> + + <dt><a href="#proxy-spec-observers">Class template + <code>proxy</code> observer functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#del-spec">del</a></dt> + + <dt><a href="#comparisons-spec">comparisons</a></dt> + + <dt><a href="#binary-spec">binary operations</a></dt> + + <dt><a href="#assignment-spec">assignment operations</a></dt> + + </dl> + + <dl class="page-index"> + <dt><a href="#object_operators-spec">operators</a></dt> + </dl> + + <dl class="page-index"> + <dt><a href="#len-spec">len()</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes the generic Python object wrapper class <code>object</code>, + and related classes. In order to avoid some potenential problems with + argument-dependent lookup and the generalized operators defined on + <code>object</code>, all these facilities are defined in + <code>namespace boost::python::api</code>, and <code>object</code> + is imported into <code>namespace boost::python</code> with a + <i>using-declaration</i>.</p> + + <h2><a name="types"></a>Types</h2> + + <p><a name="slice_nil-spec"></a></p> +<pre> +class slice_nil; +static const _ = slice_nil(); +</pre> + A type that can be used to get the effect of leaving out an index in a + Python slice expression: +<pre> +>>> x[:-1] +>>> x[::-1] +</pre> + C++ equivalent: +<pre> +x.slice(_,-1) +x[slice(_,_,-1)] +</pre> + + <h2><a name="classes"></a>Classes</h2> + <!-- begin --> + + <h3><a name="const_attribute_policies-spec"></a>Class + <code>const_attribute_policies</code></h3> + + <p>The policies which are used for proxies representing an attribute + access to a <code>const object</code>.</p> + + <h4><a name="const_attribute_policies-spec-synopsis"></a>Class + <code>const_attribute_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct const_attribute_policies + { + typedef char const* key_type; + static object get(object const& target, char const* key); + }; +}}} +</pre> + + <h4><a name="const_attribute_policies-spec-statics"></a>Class + <code>const_attribute_policies</code> static functions</h4> +<pre> +static object get(object const& target, char const* key); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>key</code> is an <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> accesses the attribute of <code>target</code> named + by <code>key</code>.</dt> + + <dt><b>Returns:</b> An <code>object</code> managing the result of the + attribute access.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + + <h3><a name="attribute_policies-spec"></a>Class + <code>attribute_policies</code></h3> + + <p>The policies which are used for proxies representing an attribute + access to a mutable <code>object</code>.</p> + + <h4><a name="attribute_policies-spec-synopsis"></a>Class + <code>attribute_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct attribute_policies : const_attribute_policies + { + static object const& set(object const& target, char const* key, object const& value); + static void del(object const&target, char const* key); + }; +}}} +</pre> + + <h4><a name="attribute_policies-spec-statics"></a>Class + <code>attribute_policies</code> static functions</h4> +<pre> +static object const& set(object const& target, char const* key, object const& value); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>key</code> is an <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> sets the attribute of <code>target</code> named by + <code>key</code> to <code>value</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> +<pre> +static void del(object const&target, char const* key); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>key</code> is an <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> deletes the attribute of <code>target</code> named + by <code>key</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + <!-- end --> + <!-- begin --> + + <h3><a name="const_objattribute_policies-spec"></a>Class + <code>const_objattribute_policies</code></h3> + + <p>The policies which are used for proxies representing an attribute + access to a <code>const object</code> when the attribute name is + given as a <code>const object</code>.</p> + + <h4><a name="const_objattribute_policies-spec-synopsis"></a>Class + <code>const_objattribute_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct const_objattribute_policies + { + typedef object const& key_type; + static object get(object const& target, object const& key); + }; +}}} +</pre> + + <h4><a name="const_objattribute_policies-spec-statics"></a>Class + <code>const_objattribute_policies</code> static functions</h4> +<pre> +static object get(object const& target, object const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>key</code> is an <code>object</code> + holding a string.</dt> + + <dt><b>Effects:</b> accesses the attribute of <code>target</code> named + by <code>key</code>.</dt> + + <dt><b>Returns:</b> An <code>object</code> managing the result of the + attribute access.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + + <h3><a name="objattribute_policies-spec"></a>Class + <code>objattribute_policies</code></h3> + + <p>The policies which are used for proxies representing an attribute + access to a mutable <code>object</code> when the attribute name is + given as a <code>const object</code>.</p> + + <h4><a name="objattribute_policies-spec-synopsis"></a>Class + <code>objattribute_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct objattribute_policies : const_objattribute_policies + { + static object const& set(object const& target, object const& key, object const& value); + static void del(object const&target, object const& key); + }; +}}} +</pre> + + <h4><a name="objattribute_policies-spec-statics"></a>Class + <code>objattribute_policies</code> static functions</h4> +<pre> +static object const& set(object const& target, object const& key, object const& value); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>key</code> is an <code>object</code> + holding a string.</dt> + + <dt><b>Effects:</b> sets the attribute of <code>target</code> named by + <code>key</code> to <code>value</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> +<pre> +static void del(object const&target, object const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>key</code> is an <code>object</code> + holding a string.</dt> + + <dt><b>Effects:</b> deletes the attribute of <code>target</code> named + by <code>key</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + <!-- end --> + <!-- begin --> + + <h3><a name="const_item_policies-spec"></a>Class + <code>const_item_policies</code></h3> + + <p>The policies which are used for proxies representing an item access + (via the Python bracket operators <code>[]</code>) to a + <code>const object</code>.</p> + + <h4><a name="const_item_policies-spec-synopsis"></a>Class + <code>const_item_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct const_item_policies + { + typedef object key_type; + static object get(object const& target, object const& key); + }; +}}} +</pre> + + <h4><a name="const_item_policies-spec-statics"></a>Class + <code>const_item_policies</code> static functions</h4> +<pre> +static object get(object const& target, object const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> accesses the item of <code>target</code> specified + by <code>key</code>.</dt> + + <dt><b>Returns:</b> An <code>object</code> managing the result of the + item access.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + + <h3><a name="item_policies-spec"></a>Class + <code>item_policies</code></h3> + + <p>The policies which are used for proxies representing an item access + (via the Python bracket operators <code>[]</code>) to a mutable + <code>object</code>.</p> + + <h4><a name="item_policies-spec-synopsis"></a>Class + <code>item_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct item_policies : const_item_policies + { + static object const& set(object const& target, object const& key, object const& value); + static void del(object const& target, object const& key); + }; +}}} +</pre> + + <h4><a name="item_policies-spec-statics"></a>Class + <code>item_policies</code> static functions</h4> +<pre> +static object const& set(object const& target, object const& key, object const& value); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> sets the item of <code>target</code> specified by + <code>key</code> to <code>value</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> +<pre> +static void del(object const& target, object const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> deletes the item of <code>target</code> specified + by <code>key</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + <!-- end --> + <!-- begin --> + + <h3><a name="const_slice_policies-spec"></a>Class + <code>const_slice_policies</code></h3> + + <p>The policies which are used for proxies representing an slice access + (via the Python slice notation + <code>[</code><i>x</i><code>:</code><i>y</i><code>]</code>) to a + <code>const object</code>.</p> + + <h4><a name="const_slice_policies-spec-synopsis"></a>Class + <code>const_slice_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct const_slice_policies + { + typedef std::pair<handle<>, handle<> > key_type; + static object get(object const& target, key_type const& key); + }; +}}} +</pre> + + <h4><a name="const_slice_policies-spec-statics"></a>Class + <code>const_slice_policies</code> static functions</h4> +<pre> +static object get(object const& target, key_type const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> accesses the slice of <code>target</code> specified + by <code>key</code>.</dt> + + <dt><b>Returns:</b> An <code>object</code> managing the result of the + slice access.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + + <h3><a name="slice_policies-spec"></a>Class + <code>slice_policies</code></h3> + + <p>The policies which are used for proxies representing an slice access + to a mutable <code>object</code>.</p> + + <h4><a name="slice_policies-spec-synopsis"></a>Class + <code>slice_policies</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + struct slice_policies : const_slice_policies + { + static object const& set(object const& target, key_type const& key, object const& value); + static void del(object const& target, key_type const& key); + }; +}}} +</pre> + + <h4><a name="slice_policies-spec-statics"></a>Class + <code>slice_policies</code> static functions</h4> +<pre> +static object const& set(object const& target, key_type const& key, object const& value); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> sets the slice of <code>target</code> specified by + <code>key</code> to <code>value</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> +<pre> +static void del(object const& target, key_type const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> deletes the slice of <code>target</code> specified + by <code>key</code>.</dt> + + <dt><b>Throws:</b> <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> if a + Python exception is raised.</dt> + </dl> + <!-- end --> + + <h3><a name="object_operators-spec"></a>Class template + <code>object_operators<U></code></h3> + + <p>This is the base class of <code>object</code> and its + <code>proxy</code> template used to supply common interface: member + functions, and operators which must be defined within the class body. Its + template parameter <code>U</code> is expected to be a class derived from + <code>object_operators<U></code>. In practice users should never + use this class directly, but it is documented here because it supplies + important interface to <code>object</code> and its proxies.</p> + + <h4><a name="object_operators-spec-synopsis"></a>Class template + <code>object_operators</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + template <class U> + class object_operators + { + public: + // function call + // + object operator()() const; + + template <class A0> + object operator()(A0 const&) const; + template <class A0, class A1> + object operator()(A0 const&, A1 const&) const; + ... + template <class A0, class A1,...class An> + object operator()(A0 const&, A1 const&,...An const&) const; + + detail::args_proxy operator* () const; + object operator()(detail::args_proxy const &args) const; + object operator()(detail::args_proxy const &args, + detail::kwds_proxy const &kwds) const; + + // truth value testing + // + typedef unspecified bool_type; + operator bool_type() const; + + // Attribute access + // + proxy<const_object_attribute> attr(char const*) const; + proxy<object_attribute> attr(char const*); + proxy<const_object_objattribute> attr(object const&) const; + proxy<object_objattribute> attr(object const&); + + // item access + // + template <class T> + proxy<const_object_item> operator[](T const& key) const; + + template <class T> + proxy<object_item> operator[](T const& key); + + // slicing + // + template <class T, class V> + proxy<const_object_slice> slice(T const& start, V const& end) const + + template <class T, class V> + proxy<object_slice> slice(T const& start, V const& end); + }; +}}} +</pre> + + <h4><a name="object_operators-spec-observers"></a>Class template + <code>object_operators</code> observer functions</h4> +<pre> +object operator()() const; +template <class A0> +object operator()(A0 const&) const; +template <class A0, class A1> +object operator()(A0 const&, A1 const&) const; +... +template <class A0, class A1,...class An> +object operator()(A0 const& a1, A1 const& a2,...An const& aN) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + call<object>(object(*static_cast<U*>(this)).ptr(), a1, + a2,...aN)</dt> + </dl> + +<pre> +object operator()(detail::args_proxy const &args) const; +</pre> +<dl class="function-semantics"> + <dt><b>Effects:</b> + call object with arguments given by the tuple <varname>args</varname></dt> +</dl> +<pre> +object operator()(detail::args_proxy const &args, + detail::kwds_proxy const &kwds) const; +</pre> +<dl class="function-semantics"> + <dt><b>Effects:</b> + call object with arguments given by the tuple <varname>args</varname>, and named + arguments given by the dictionary <varname>kwds</varname></dt> +</dl> + + +<pre> +operator bool_type() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Tests truth value of <code>*this</code>.</dt> + + <dt><b>Returns:</b> + call<object>(object(*static_cast<U*>(this)).ptr(), a1, + a2,...aN)</dt> + </dl> +<pre> +proxy<const_object_attribute> attr(char const* name) const; +proxy<object_attribute> attr(char const* name); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> name is an <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Effects:</b> accesses the named attribute of + <code>*this</code>.</dt> + + <dt><b>Returns:</b> a proxy object which binds + <code>object(*static_cast<U*>(this))</code> as its target, and + <code>name</code> as its key.</dt> + </dl> +<pre> +proxy<const_object_objattribute> attr(const object& name) const; +proxy<object_objattribute> attr(const object& name); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> name is a <code>object</code> holding a string.</dt> + + <dt><b>Effects:</b> accesses the named attribute of + <code>*this</code>.</dt> + + <dt><b>Returns:</b> a proxy object which binds + <code>object(*static_cast<U*>(this))</code> as its target, and + <code>name</code> as its key.</dt> + </dl> +<pre> +template <class T> +proxy<const_object_item> operator[](T const& key) const; +template <class T> +proxy<object_item> operator[](T const& key); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> accesses the item of <code>*this</code> indicated + by <code>key</code>.</dt> + + <dt><b>Returns:</b> a proxy object which binds + <code>object(*static_cast<U*>(this))</code> as its target, and + <code>object(key)</code> as its key.</dt> + </dl> +<pre> +template <class T, class V> +proxy<const_object_slice> slice(T const& start; start, V const& finish) const +template <class T, class V> +proxy<object_slice> slice(T const& start; start, V const& finish); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> accesses the slice of <code>*this</code> indicated + by <code>std::make_pair(object(start), object(finish))</code>.</dt> + + <dt><b>Returns:</b> a proxy object which binds + <code>object(*static_cast<U*>(this))</code> as its target, and + <code>std::make_pair(object(start), object(finish))</code> as its + key.</dt> + </dl> + <!-- --> + + <h3><a name="object-spec"></a>Class <code>object</code></h3> + + <p>The intention is that <code>object</code> acts as much like a + Python variable as possible. Thus expressions you'd expect to work + in Python should generally work in the same way from C++. Most of + <code>object</code>'s interface is provided by its base class + <code><a + href="#object_operators-spec">object_operators</a><object></code>, + and the <a href="#functions">free functions</a> defined in this + header. +</p> + + <h4><a name="object-spec-synopsis"></a>Class <code>object</code> + synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + class object : public object_operators<object> + { + public: + object(); + + object(object const&); + + template <class T> + explicit object(T const& x); + + ~object(); + + object& operator=(object const&); + + PyObject* ptr() const; + + bool is_none() const; + }; +}}} +</pre> + + <h4><a name="object-spec-ctors"></a>Class <code>object</code> + constructors and destructor</h4> +<pre> +object(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Constructs an object managing a reference to the + Python <code>None</code> object.</dt> + + <dt><b>Throws:</b> nothing.</dt> + </dl> +<pre> +template <class T> +explicit object(T const& x); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> converts <code>x</code> to python and manages a + reference to it.</dt> + + <dt><b>Throws:</b> <code>error_already_set</code> and sets a Python + <code>TypeError</code> exception if no such conversion is + possible.</dt> + </dl> +<pre> +~object(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> decrements the reference count of the + internally-held object.</dt> + </dl> + + <h4><a name="object-spec-modifiers"></a>Class <code>object</code> + modifiers</h4> +<pre> +object& operator=(object const& rhs); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> increments the reference count of the object held + by <code>rhs</code> and decrements the reference count of the object + held by <code>*this</code>.</dt> + </dl> + + <h4><a name="object-spec-observers"></a>Class <code>object</code> + observers</h4> +<pre> +PyObject* ptr() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> a pointer to the internally-held Python + object.</dt> + </dl> + +<pre> +bool is_none() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> result of (ptr() == Py_None)</dt> + </dl> + <!-- --> + + <h3><a name="proxy-spec"></a>Class template <code>proxy</code></h3> + + <p>This template is instantiated with various Policies described in this + document in order to implement attribute, item, and slice access for + <code>object</code>. It stores an object of type + <code>Policies::key_type</code>.</p> + + <h4><a name="proxy-spec-synopsis"></a>Class template <code>proxy</code> + synopsis</h4> +<pre> +namespace boost { namespace python { namespace api +{ + template <class Policies> + class proxy : public object_operators<proxy<Policies> > + { + public: + operator object() const; + + proxy const& operator=(proxy const&) const; + template <class T> + inline proxy const& operator=(T const& rhs) const; + + void del() const; + + template <class R> + proxy operator+=(R const& rhs); + template <class R> + proxy operator-=(R const& rhs); + template <class R> + proxy operator*=(R const& rhs); + template <class R> + proxy operator/=(R const& rhs); + template <class R> + proxy operator%=(R const& rhs); + template <class R> + proxy operator<<=(R const& rhs); + template <class R> + proxy operator>>=(R const& rhs); + template <class R> + proxy operator&=(R const& rhs); + template <class R> + proxy operator|=(R const& rhs); + }; +}}} +</pre> + + <h4><a name="proxy-spec-observers"></a>Class template <code>proxy</code> + observer functions</h4> +<pre> +operator object() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> applies + <code>Policies::get(</code><i>target</i><code>,</code> <i>key</i> + <code>)</code> with the proxy's target and key objects.</dt> + </dl> + + <h4><a name="proxy-spec-modifiers"></a>Class template <code>proxy</code> + modifier functions</h4> +<pre> +proxy const& operator=(proxy const& rhs) const; +template <class T> +inline proxy const& operator=(T const& rhs) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Policies::set(</code><i>target</i><code>,</code> <i>key</i> + <code>, object(rhs))</code> with the proxy's target and key + objects.</dt> + </dl> +<pre> +template <class R> +proxy operator+=(R const& rhs); +template <class R> +proxy operator-=(R const& rhs); +template <class R> +proxy operator*=(R const& rhs); +template <class R> +proxy operator/=(R const& rhs); +template <class R> +proxy operator%=(R const& rhs); +template <class R> +proxy operator<<=(R const& rhs); +template <class R> +proxy operator>>=(R const& rhs); +template <class R> +proxy operator&=(R const& rhs); +template <class R> +proxy operator|=(R const& rhs); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> for a given operator@=, + <code>object(*this) @= rhs;</code></dt> + <dt><b>Returns:</b> <code>*this</code></dt> + </dl> +<pre> +void del() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>Policies::del(</code><i>target</i><code>,</code> <i>key</i> + <code>)</code> with the proxy's target and key objects.</dt> + </dl> + <!-- --> + + <h2><a name="functions"></a>Functions</h2> +<pre> +<a name="del-spec"></a>template <class T> +void del(proxy<T> const& x); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> x.del()</dt> + </dl> +<pre> +<a name="comparisons-spec"></a> +template<class L,class R> object operator>(L const&l,R const&r); +template<class L,class R> object operator>=(L const&l,R const&r); +template<class L,class R> object operator<(L const&l,R const&r); +template<class L,class R> object operator<=(L const&l,R const&r); +template<class L,class R> object operator==(L const&l,R const&r); +template<class L,class R> object operator!=(L const&l,R const&r); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> returns the result of applying the operator to + <code>object(l)</code> and <code>object(r)</code>, respectively, in + Python.</dt> + </dl> +<pre> +<a name="binary-spec"></a> +template<class L,class R> object operator+(L const&l,R const&r); +template<class L,class R> object operator-(L const&l,R const&r); +template<class L,class R> object operator*(L const&l,R const&r); +template<class L,class R> object operator/(L const&l,R const&r); +template<class L,class R> object operator%(L const&l,R const&r); +template<class L,class R> object operator<<(L const&l,R const&r); +template<class L,class R> object operator>>(L const&l,R const&r); +template<class L,class R> object operator&(L const&l,R const&r); +template<class L,class R> object operator^(L const&l,R const&r); +template<class L,class R> object operator|(L const&l,R const&r); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> returns the result of applying the operator to + <code>object(l)</code> and <code>object(r)</code>, respectively, in + Python.</dt> + </dl> +<pre> +<a name="assignment-spec"></a> +template<class R> object& operator+=(object&l,R const&r); +template<class R> object& operator-=(object&l,R const&r); +template<class R> object& operator*=(object&l,R const&r); +template<class R> object& operator/=(object&l,R const&r); +template<class R> object& operator%=(object&l,R const&r); +template<class R> object& operator<<=(object&l,R const&r) +template<class R> object& operator>>=(object&l,R const&r); +template<class R> object& operator&=(object&l,R const&r); +template<class R> object& operator^=(object&l,R const&r); +template<class R> object& operator|=(object&l,R const&r); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> assigns to l the result of applying the + corresponding Python inplace operator to <code>l</code> and + <code>object(r)</code>, respectively.</dt> + + <dt><b>Returns:</b> <code>l</code>.</dt> + </dl> + +<pre> +inline long len(object const& obj); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> PyObject_Length(obj.ptr()) </dt> + <dt><b>Returns:</b> len() of object.</dt> + </dl> + +<h2><a name="examples"></a>Example</h2> + Python code: +<pre> +def sum_items(seq): + result = 0 + for x in seq: + result += x + return result +</pre> + C++ version: +<pre> +object sum_items(object seq) +{ + object result = object(0); + for (int i = 0; i < len(seq); ++i) + result += seq[i]; + return result; +} +</pre> + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 15 March, 2010 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2008.</i></p> + </body> +</html> diff --git a/libs/python/doc/v2/opaque.html b/libs/python/doc/v2/opaque.html new file mode 100644 index 000000000..fed1d446f --- /dev/null +++ b/libs/python/doc/v2/opaque.html @@ -0,0 +1,138 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright 2003..2006 Haufe Mediengruppe. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> + +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/opaque_pointer_converter.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/opaque_pointer_converter.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#opaque-spec">Class template + <code>opaque<Pointee></code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#opaque-spec-synopsis">Class template + <code>opaque</code> synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#macros">Macros</a></dt> + <dd> + <dl class="page-index"> + <dt><a href="#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">Macro + <code>BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</code></a></dt> + </dl> + </dd> + + <dt><a href="#see-also">See Also</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="opaque-spec"></a>Class template + <code>opaque<P></code></h3> + + <p><code>opaque<></code> registers itself as a converter from + Python objects to pointers to undefined types and vice versa.</p> + + <h4><a name="opaque-spec-synopsis"></a>Class template + <code>opaque</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template<class Pointee> + struct opaque + { + opaque(); + }; +}} +</pre> + + <h4><a name="opaque-spec-constructor"></a>Class template + <code>opaque</code> constructor</h4> +<pre> +opaque(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <ul> + <li>Registers the instance as a + <a href="lvalue_from_pytype.html#lvalue_from_pytype-spec"> <code>lvalue_from_pytype</code></a> + converter from Python objects into opaque pointers.</p> + <p>The Python Objects created are named after the type pointed to + by the opaque pointer being wrapped.</p></li> + <li>Registers the instance as a + <a href="to_python_converter.html#to_python_converter-spec"> <code>to_python_converter</code></a> + from opaque pointers to Python objects.</p></li> + </ul> + <p>If there is already an instance registered by another module, this + instance doesn't try to register again in order to avoid warnings + about multiple registrations.</p> + + <h4>Note</h4> + <p>Normally only a single instance of this class is created for every + Pointee.</p> + </dt> + </dl> + + <h2><a name="macros"></a>Macros</h2> + + <h3><a name="BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec"></a> + Macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)</h3> + <p>This macro must be used to define specializations of the + <a href="type_id.html#type_id-spec">type_id</a> function + which can't be instantiated for incomplete types.</p> + <h4>Note</h4> + <p>The macro must be invoked in every translation unit which uses the + opaque converter.</p> + + <h2><a name="see-also"></a>See Also</h2> + <p> + <a href="return_opaque_pointer.html">return_opaque_pointer</a> + </p> + + <p>Revised + 10 September, 2006 + </p> + + <p><i>© Copyright 2003..2006 Haufe Mediengruppe. All Rights + Reserved.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/operators.html b/libs/python/doc/v2/operators.html new file mode 100644 index 000000000..69740243f --- /dev/null +++ b/libs/python/doc/v2/operators.html @@ -0,0 +1,921 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/operators.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/operators.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#self_t-spec">Class + <code>self_ns::self_t</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#self_t-spec-synopsis">Class <code>self_t</code> + synopsis</a></dt> + + <dt><a href="#self_t-spec-inplace">Class <code>self_t</code> + inplace operators</a></dt> + + <dt><a href="#self_t-spec-comparisons">Class + <code>self_t</code> comparison functions</a></dt> + + <dt><a href="#self_t-spec-ops">Class <code>self_t</code> + non-member operations</a></dt> + + <dt><a href="#self_t-spec-value-unary-ops">Class + <code>self_t</code> unary operations</a></dt> + + <dt><a href="#self_t-spec-value-ops">Class + <code>self_t</code> value operations</a></dt> + </dl> + </dd> + + <dt><a href="#other-spec">Class template + <code>other</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#other-spec-synopsis">Class <code>other</code> + synopsis</a></dt> + </dl> + </dd> + + <dt><a href="#operator_-spec">Class template + <code>operator_</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#operator_-spec-synopsis">Class + <code>operator_</code> synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#objects">Objects</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#self-spec">self</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/operators.hpp></code> provides types and + functions for automatically generating Python <a href= + "http://www.python.org/doc/ref/specialnames.html">special methods</a> + from the corresponding C++ constructs. Most of these constructs are + operator expressions, hence the name. To use the facility, substitute the + <code><a href="#self-spec">self</a></code> object for an object of the + class type being wrapped in the expression to be exposed, and pass the + result to <a href= + "class.html#class_-spec-modifiers">class_<>::def()</a>. Much of + what is exposed in this header should be considered part of the + implementation, so is not documented in detail here.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="self_t-spec"></a>Class <code>self_ns::self_t</code></h3> + + <p><code>self_ns::self_t</code> is the actual type of the <a href= + "#self-spec"><code>self</code></a> object. The library isolates + <code>self_t</code> in its own namespace, <code>self_ns</code>, in order + to prevent the generalized operator templates which operate on it from + being found by argument-dependent lookup in other contexts. This should + be considered an implementation detail, since users should never have to + mention <code>self_t</code> directly.</p> + + <h4><a name="self_t-spec-synopsis"></a>Class <code>self_ns::self_t</code> + synopsis</h4> +<pre> +namespace boost { namespace python { namespace self_ns { +{ + <i>unspecified-type-declaration</i> self_t; + + // inplace operators + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator+=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator-=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator*=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator/=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator%=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator>>=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator<<=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator&=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator^=(self_t, T); + template <class T> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator|=(self_t, T); + + // comparisons + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator==(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator!=(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator<(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator>(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator<=(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator>=(L const&, R const&); + + // non-member operations + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator+(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator-(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator*(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator/(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator%(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator>>(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator<<(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator&(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator^(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator|(L const&, R const&); + template <class L, class R> <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> pow(L const&, R const&); + + // unary operations + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator-(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator+(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator~(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> operator!(self_t); + + // value operations + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> int_(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> long_(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> float_(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> complex_(self_t); + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> str(self_t); + + <a href= +"#operator_-spec">operator_</a><<i>unspecified</i>> repr(self_t); + +}}}; +</pre> + The tables below describe the methods generated when the results of the + expressions described are passed as arguments to <a href= + "class.html#class_-spec-modifiers">class_<>::def()</a>. + <code><b>x</b></code> is an object of the class type being wrapped. + + <h4><a name="self_t-spec-inplace"></a>Class <code>self_t</code> inplace + operators</h4> + In the table below, If <code><b>r</b></code> is an object of type + <code><a href="#other-spec">other</a><T></code>, + <code><b>y</b></code> is an object of type <code>T</code>; otherwise, + <code><b>y</b></code> is an object of the same type as + <code><b>r</b></code>. + + <table border="1" summary="self_t inplace operators"> + <tr> + <th>C++ Expression</th> + + <th>Python Method Name</th> + + <th>C++ Implementation</th> + </tr> + + <tr> + <td><code>self += r</code></td> + + <td><code>__iadd__</code></td> + + <td><code>x += y</code></td> + </tr> + + <tr> + <td><code>self -= r</code></td> + + <td><code>__isub__</code></td> + + <td><code>x -= y</code></td> + </tr> + + <tr> + <td><code>self *= r</code></td> + + <td><code>__imul__</code></td> + + <td><code>x *= y</code></td> + </tr> + + <tr> + <td><code>self /= r</code></td> + + <td><code>__idiv__</code></td> + + <td><code>x /= y</code></td> + </tr> + + <tr> + <td><code>self %= r</code></td> + + <td><code>__imod__</code></td> + + <td><code>x %= y</code></td> + </tr> + + <tr> + <td><code>self >>= r</code></td> + + <td><code>__irshift__</code></td> + + <td><code>x >>= y</code></td> + </tr> + + <tr> + <td><code>self <<= r</code></td> + + <td><code>__ilshift__</code></td> + + <td><code>x <<= y</code></td> + </tr> + + <tr> + <td><code>self &= r</code></td> + + <td><code>__iand__</code></td> + + <td><code>x &= y</code></td> + </tr> + + <tr> + <td><code>self ^= r</code></td> + + <td><code>__ixor__</code></td> + + <td><code>x ^= y</code></td> + </tr> + + <tr> + <td><code>self |= r</code></td> + + <td><code>__ior__</code></td> + + <td><code>x |= y</code></td> + </tr> + </table> + + <h4><a name="self_t-spec-comparisons"></a>Class <code>self_t</code> + comparison functions</h4> + In the tables below, if <code><b>r</b></code> is of type <code><a href= + "#self_t-spec">self_t</a></code>, <code><b>y</b></code> is an object of + the same type as <code>x</code>; <br> + if <code><b>l</b></code> or <code><b>r</b></code> is an object of type + <code><a href="#other-spec">other</a><T></code>, + <code><b>y</b></code> is an object of type <code>T</code>; <br> + otherwise, <code><b>y</b></code> is an object of the same type as + <code><b>l</b></code> or <code><b>r</b></code>.<br> + <code><b>l</b></code> is never of type <code><a href= + "#self_t-spec">self_t</a></code>. + + <p>The column of <b>Python Expressions</b> illustrates the expressions + that will be supported in Python for objects convertible to the types of + <code>x</code> and <code>y</code>. The secondary operation arises due to + Python's <a href= + "http://www.python.org/doc/ref/customization.html#l2h-89">reflection + rules</a> for rich comparison operators, and are only used when the + corresponding operation is not defined as a method of the <code>y</code> + object.</p> + + <table border="1" summary="self_t comparison functions"> + <tr> + <th>C++ Expression</th> + + <th>Python Method Name</th> + + <th>C++ Implementation</th> + + <th>Python Expressions<br> + (primary, secondary)</th> + </tr> + + <tr> + <td><code>self == r</code></td> + + <td><code>__eq__</code></td> + + <td><code>x == y</code></td> + + <td><code>x == y, y == x</code></td> + </tr> + + <tr> + <td><code>l == self</code></td> + + <td><code>__eq__</code></td> + + <td><code>y == x</code></td> + + <td><code>y == x, x == y</code></td> + </tr> + + <tr> + <td><code>self != r</code></td> + + <td><code>__ne__</code></td> + + <td><code>x != y</code></td> + + <td><code>x != y, y != x</code></td> + </tr> + + <tr> + <td><code>l != self</code></td> + + <td><code>__ne__</code></td> + + <td><code>y != x</code></td> + + <td><code>y != x, x != y</code></td> + </tr> + + <tr> + <td><code>self < r</code></td> + + <td><code>__lt__</code></td> + + <td><code>x < y</code></td> + + <td><code>x < y, y > x</code></td> + </tr> + + <tr> + <td><code>l < self</code></td> + + <td><code>__gt__</code></td> + + <td><code>y < x</code></td> + + <td><code>y > x, x < y</code></td> + </tr> + + <tr> + <td><code>self > r</code></td> + + <td><code>__gt__</code></td> + + <td><code>x > y</code></td> + + <td><code>x > y, y < x</code></td> + </tr> + + <tr> + <td><code>l > self</code></td> + + <td><code>__lt__</code></td> + + <td><code>y > x</code></td> + + <td><code>y < x, x > y</code></td> + </tr> + + <tr> + <td><code>self <= r</code></td> + + <td><code>__le__</code></td> + + <td><code>x <= y</code></td> + + <td><code>x <= y, y >= x</code></td> + </tr> + + <tr> + <td><code>l <= self</code></td> + + <td><code>__ge__</code></td> + + <td><code>y <= x</code></td> + + <td><code>y >= x, x <= y</code></td> + </tr> + + <tr> + <td><code>self >= r</code></td> + + <td><code>__ge__</code></td> + + <td><code>x >= y</code></td> + + <td><code>x >= y, y <= x</code></td> + </tr> + + <tr> + <td><code>l >= self</code></td> + + <td><code>__le__</code></td> + + <td><code>y >= x</code></td> + + <td><code>y <= x, x >= y</code></td> + </tr> + </table> + + <h4><a name="self_t-spec-ops"></a>Class <code>self_t</code> non-member + operations</h4> + The operations whose names begin with "<code>__r</code>" below will only + be called if the left-hand operand does not already support the given + operation, as described <a href= + "http://www.python.org/doc/current/ref/numeric-types.html#l2h-152">here</a>. + + + <table border="1" summary="self_t non-member operations"> + <tr> + <th>C++ Expression</th> + + <th>Python Method Name</th> + + <th>C++ Implementation</th> + </tr> + + <tr> + <td><code>self + r</code></td> + + <td><code>__add__</code></td> + + <td><code>x + y</code></td> + </tr> + + <tr> + <td><code>l + self</code></td> + + <td><code>__radd__</code></td> + + <td><code>y + x</code></td> + </tr> + + <tr> + <td><code>self - r</code></td> + + <td><code>__sub__</code></td> + + <td><code>x - y</code></td> + </tr> + + <tr> + <td><code>l - self</code></td> + + <td><code>__rsub__</code></td> + + <td><code>y - x</code></td> + </tr> + + <tr> + <td><code>self * r</code></td> + + <td><code>__mul__</code></td> + + <td><code>x * y</code></td> + </tr> + + <tr> + <td><code>l * self</code></td> + + <td><code>__rmul__</code></td> + + <td><code>y * x</code></td> + </tr> + + <tr> + <td><code>self / r</code></td> + + <td><code>__div__</code></td> + + <td><code>x / y</code></td> + </tr> + + <tr> + <td><code>l / self</code></td> + + <td><code>__rdiv__</code></td> + + <td><code>y / x</code></td> + </tr> + + <tr> + <td><code>self % r</code></td> + + <td><code>__mod__</code></td> + + <td><code>x % y</code></td> + </tr> + + <tr> + <td><code>l % self</code></td> + + <td><code>__rmod__</code></td> + + <td><code>y % x</code></td> + </tr> + + <tr> + <td><code>self >> r</code></td> + + <td><code>__rshift__</code></td> + + <td><code>x >> y</code></td> + </tr> + + <tr> + <td><code>l >> self</code></td> + + <td><code>__rrshift__</code></td> + + <td><code>y >> x</code></td> + </tr> + + <tr> + <td><code>self << r</code></td> + + <td><code>__lshift__</code></td> + + <td><code>x << y</code></td> + </tr> + + <tr> + <td><code>l << self</code></td> + + <td><code>__rlshift__</code></td> + + <td><code>y << x</code></td> + </tr> + + <tr> + <td><code>self & r</code></td> + + <td><code>__and__</code></td> + + <td><code>x & y</code></td> + </tr> + + <tr> + <td><code>l & self</code></td> + + <td><code>__rand__</code></td> + + <td><code>y & x</code></td> + </tr> + + <tr> + <td><code>self ^ r</code></td> + + <td><code>__xor__</code></td> + + <td><code>x ^ y</code></td> + </tr> + + <tr> + <td><code>l ^ self</code></td> + + <td><code>__rxor__</code></td> + + <td><code>y ^ x</code></td> + </tr> + + <tr> + <td><code>self | r</code></td> + + <td><code>__or__</code></td> + + <td><code>x | y</code></td> + </tr> + + <tr> + <td><code>l | self</code></td> + + <td><code>__ror__</code></td> + + <td><code>y | x</code></td> + </tr> + + <tr> + <td><code>pow(self, r)</code></td> + + <td><code>__pow__</code></td> + + <td><code>pow(x, y)</code></td> + </tr> + + <tr> + <td><code>pow(l, self)</code></td> + + <td><code>__rpow__</code></td> + + <td><code>pow(y, x)</code></td> + </tr> + </table> + + <h4><a name="self_t-spec-value-unary-ops"></a>Class <code>self_t</code> unary + operations</h4> + + <table border="1" summary="self_t unary operations"> + <tr> + <th>C++ Expression</th> + + <th>Python Method Name</th> + + <th>C++ Implementation</th> + </tr> + + <tr> + <td><code>-self</code></td> + + <td><code>__neg__</code></td> + + <td><code>-x</code></td> + </tr> + + <tr> + <td><code>+self</code></td> + + <td><code>__pos__</code></td> + + <td><code>+x</code></td> + </tr> + + <tr> + <td><code>~self</code></td> + + <td><code>__invert__</code></td> + + <td><code>~x</code></td> + </tr> + + <tr> + <td><code>not self</code><br><i>or</i><br><code>!self</code></td> + + <td><code>__nonzero__</code></td> + + <td><code>!!x</code></td> + </tr> + </table> + + <h4><a name="self_t-spec-value-ops"></a>Class <code>self_t</code> value + operations</h4> + + <table border="1" summary="self_t value operations"> + <tr> + <th>C++ Expression</th> + + <th>Python Method Name</th> + + <th>C++ Implementation</th> + </tr> + + <tr> + <td><code>int_(self)</code></td> + + <td><code>__int__</code></td> + + <td><code>long(x)</code></td> + </tr> + + <tr> + <td><code>long_</code></td> + + <td><code>__long__</code></td> + + <td><code>PyLong_FromLong(x)</code></td> + </tr> + + <tr> + <td><code>float_</code></td> + + <td><code>__float__</code></td> + + <td><code>double(x)</code></td> + </tr> + + <tr> + <td><code>complex_</code></td> + + <td><code>__complex__</code></td> + + <td><code>std::complex<double>(x)</code></td> + </tr> + + <tr> + <td><code>str</code></td> + + <td><code>__str__</code></td> + + <td><code><a href= + "../../../conversion/lexical_cast.htm#lexical_cast">lexical_cast</a><std::string>(x)</code></td> + </tr> + + <tr> + <td><code>repr</code></td> + + <td><code>__repr__</code></td> + + <td><code><a href= + "../../../conversion/lexical_cast.htm#lexical_cast">lexical_cast</a><std::string>(x)</code></td> + </tr> + </table> + + <h3><a name="other-spec"></a>Class Template <code>other</code></h3> + + <p>Instances of <code>other<T></code> can be used in operator + expressions with <a href="#self-spec">self</a>; the result is equivalent + to the same expression with a <code>T</code> object in place of + <code>other<T></code>. Use <code>other<T></code> to prevent + construction of a <code>T</code> object in case it is heavyweight, when + no constructor is available, or simply for clarity.</p> + + <h4><a name="other-spec-synopsis"></a>Class Template other synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T> + struct other + { + }; +}} +</pre> + <!-- --> + + <h3><a name="operator_-spec"></a>Class Template + <code>detail::operator_</code></h3> + + <p>Instantiations of <code>detail::operator_<></code> are used as + the return type of operator expressions involving <code><a href= + "#self-spec">self</a></code>. This should be considered an implementation + detail and is only documented here as a way of showing how the result of + <code>self</code>-expressions match calls to <a href= + "class.html#class_-spec-modifiers">class_<>::def()</a>.</p> + + <h4><a name="operator_-spec-synopsis"></a>Class Template + <code>detail::operator_</code> synopsis</h4> +<pre> +namespace boost { namespace python { namespace detail +{ + template <<i>unspecified</i>> + struct operator_ + { + }; +}}} +</pre> + + <h2><a name="objects"></a>Objects</h2> + + <p><a name="self-spec"><code>self</code></a></p> +<pre> +namespace boost { namespace python +{ + using self_ns::self; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/operators.hpp> +#include <boost/operators.hpp> + +struct number + : boost::<a href= +"../../../utility/operators.htm#grpd_oprs">integer_arithmetic</a><number> +{ + explicit number(long x_) : x(x_) {} + operator long() const { return x; } + + template <class T> + number& operator+=(T const& rhs) + { x += rhs; return *this; } + + template <class T> + number& operator-=(T const& rhs) + { x -= rhs; return *this; } + + template <class T> + number& operator*=(T const& rhs) + { x *= rhs; return *this; } + + template <class T> + number& operator/=(T const& rhs) + { x /= rhs; return *this; } + + template <class T> + number& operator%=(T const& rhs) + { x %= rhs; return *this; } + + long x; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(demo) +{ + class_<number>("number", init<long>()) + // interoperate with self + .def(self += self) + .def(self + self) + .def(self -= self) + .def(self - self) + .def(self *= self) + .def(self * self) + .def(self /= self) + .def(self / self) + .def(self %= self) + .def(self % self) + + // Convert to Python int + .def(int_(self)) + + // interoperate with long + .def(self += long()) + .def(self + long()) + .def(long() + self) + .def(self -= long()) + .def(self - long()) + .def(long() - self) + .def(self *= long()) + .def(self * long()) + .def(long() * self) + .def(self /= long()) + .def(self / long()) + .def(long() / self) + .def(self %= long()) + .def(self % long()) + .def(long() % self) + ; +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 5 October, 2004 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/overloads.html b/libs/python/doc/v2/overloads.html new file mode 100644 index 000000000..783e8e5db --- /dev/null +++ b/libs/python/doc/v2/overloads.html @@ -0,0 +1,229 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/overloads.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/overloads.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href= + "#overload-dispatch-expression"><i>overload-dispatch-expressions</i></a></dt> + + <dt><a href= "#OverloadDispatcher-concept">OverloadDispatcher</a> concept</dt> + + <dt><a href="#macros">Macros</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href= + "#BOOST_PYTHON_FUNCTION_OVERLOADS-spec">BOOST_PYTHON_FUNCTION_OVERLOADS</a></dt> + + <dt><a href= + "#BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS-spec">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Defines facilities for generating families of overloaded Python + functions and extension class methods from C++ functions and + member functions with default arguments, or from similar families + of C++ overloads</p> + + <h2><a name= + "overload-dispatch-expression"></a><i>overload-dispatch-expressions</i></h2> + + <p> + An <em>overload-dispatch-expression</em> is used to describe a + family of overloaded methods to be generated for an extension + class. It has the following properties: + + <blockquote> + <dl class="properties"> + <dt><b>docstring:</b> An <a href="definitions.html#ntbs">ntbs</a> + whose value will bound to the methods' <code>__doc__</code> + attribute</dt> + + <dt><b>keywords:</b> A <a href= + "args.html#keyword-expression">keyword-expression</a> which + will be used to name (a trailing subsequence of) the arguments + to the generated methods.</dt> + + <dt><b>call policies:</b> An instance of some type which models <a href= + "CallPolicies.html">CallPolicies</a>.</dt> + + <dt><b>minimum <a href="definitions.html#arity">arity</a></b> + The minimum number of arguments to be accepted by a generated + method overload.</dt> + + <dt><b>maximum <a href="definitions.html#arity">arity</a></b> + The maximum number of arguments to be accepted by a generated + method overload.</dt> + </dl> + </blockquote> + + <h2><a name="OverloadDispatcher-concept"></a>OverloadDispatcher Concept</h2> + + An OverloadDispatcher <code>X</code> is a class which has a + <em>minimum arity</em> and a <em>maximum arity</em>, and for which + the following following are valid <a + href="#overload-dispatch-expression"><em>overload-dispatch-expression</em></a>s, + with the same minimum and maximum arity as the OverloadDispatcher. + +<pre> +X() +X(docstring) +X(docstring, keywords) +X(keywords, docstring) +X()[policies] +X(docstring)[policies] +X(docstring, keywords)[policies] +X(keywords, docstring)[policies] +</pre> + +<ul> +<li>If <code>policies</code> are supplied, it must be an instance of a +type which models <a +href="CallPolicies.html#CallPolicies-concept">CallPolicies</a>, and +will be used as the result's call policies. Otherwise the result's +call policies will be an instance of <a +href="default_call_policies.html#default_call_policies-spec">default_call_policies</a>. + +<li>If <code>docstring</code> is supplied it must be an <a +href="definitions.html#ntbs">ntbs</a>, and will be used as the result's docstring. Otherwise the result has an empty docstring. + +<li>If <code>keywords</code> is supplied it must be the result of a <a + href= "args.html#keyword-expression">keyword-expression</a> + whose length is no greater than <code>X</code>'s maximum + arity, and will be used as the result's keywords. Otherwise + the result's keywords will be empty. +</ul> + + + + + <h2><a name="macros"></a>Macros</h2> + + <h3><a name= + "BOOST_PYTHON_FUNCTION_OVERLOADS-spec">BOOST_PYTHON_FUNCTION_OVERLOADS(name, func_id, min_args, max_args)</a></h3> + Expands to the definition of an OverloadDispatcher called + <code>name</code> in the current scope which can be used to + generate the following function invocation: +<pre> +func_id(a<small><i>1</i></small>, a<small><i>2</i></small>,...a<small><i>i</i></small>); +</pre> + + for all <code>min_args</code> <= <i>i</i> <= <code>max_args</code>. + + <h3><a name= + "BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS-spec">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(name, member_name, min_args, max_args)</a></h3> + + Expands to the definition of an OverloadDispatcher called + <code>name</code> in the current scope which can be used to + generate the following function invocation: +<pre> +x.member_name(a<small><i>1</i></small>, a<small><i>2</i></small>,...a<small><i>i</i></small>); +</pre> + + for all <code>min_args</code> <= <i>i</i> <= + <code>max_args</code>, where <code>x</code> is a reference to an + object of class type. + + <h2><a name="examples"></a>Example(s)</h2> + +<pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/class.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/return_internal_reference.hpp> + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + +struct Y {}; +struct X +{ + Y& f(int x, double y = 4.25, char const* z = "wow") + { + return inner; + } + Y inner; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(f_member_overloads, f, 1, 3) + +BOOST_PYTHON_MODULE(args_ext) +{ + def("f", f, + f_overloads( + args("x", "y", "z"), "This is f's docstring" + )); + + + class_<Y>("Y") + ; + + class_<X>("X", "This is X's docstring") + .def("f1", &X::f, + f_member_overloads( + args("x", "y", "z"), "f's docstring" + )[return_internal_reference<>()] + ) + ; +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 15 April, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/pickle.html b/libs/python/doc/v2/pickle.html new file mode 100644 index 000000000..22e198d63 --- /dev/null +++ b/libs/python/doc/v2/pickle.html @@ -0,0 +1,280 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>Boost.Python Pickle Support</title> +</head> + +<body> + <div> + <img src="../../../../boost.png" alt="boost.png (6897 bytes)" align= + "center" width="277" height="86" /> + <hr /> + + <h1>Boost.Python Pickle Support</h1>Pickle is a Python module for object + serialization, also known as persistence, marshalling, or flattening. + + <p>It is often necessary to save and restore the contents of an object to + a file. One approach to this problem is to write a pair of functions that + read and write data from a file in a special format. A powerful + alternative approach is to use Python's pickle module. Exploiting + Python's ability for introspection, the pickle module recursively + converts nearly arbitrary Python objects into a stream of bytes that can + be written to a file.</p> + + <p>The Boost Python Library supports the pickle module through the + interface as described in detail in the <a href= + "http://www.python.org/doc/current/lib/module-pickle.html">Python Library + Reference for pickle.</a> This interface involves the special methods + <tt>__getinitargs__</tt>, <tt>__getstate__</tt> and <tt>__setstate__</tt> + as described in the following. Note that Boost.Python is also fully + compatible with Python's cPickle module.</p> + <hr /> + + <h2>The Boost.Python Pickle Interface</h2>At the user level, the + Boost.Python pickle interface involves three special methods: + + <dl> + <dt><strong><tt>__getinitargs__</tt></strong></dt> + + <dd> + When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a <tt>__getinitargs__</tt> method. + This method must return a Python tuple (it is most convenient to use + a boost::python::tuple). When the instance is restored by the + unpickler, the contents of this tuple are used as the arguments for + the class constructor. + + <p>If <tt>__getinitargs__</tt> is not defined, <tt>pickle.load</tt> + will call the constructor (<tt>__init__</tt>) without arguments; + i.e., the object must be default-constructible.</p> + </dd> + + <dt><strong><tt>__getstate__</tt></strong></dt> + + <dd>When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a <tt>__getstate__</tt> method. This + method should return a Python object representing the state of the + instance.</dd> + + <dt><strong><tt>__setstate__</tt></strong></dt> + + <dd>When an instance of a Boost.Python extension class is restored by + the unpickler (<tt>pickle.load</tt>), it is first constructed using the + result of <tt>__getinitargs__</tt> as arguments (see above). + Subsequently the unpickler tests if the new instance has a + <tt>__setstate__</tt> method. If so, this method is called with the + result of <tt>__getstate__</tt> (a Python object) as the argument.</dd> + </dl>The three special methods described above may be <tt>.def()</tt>'ed + individually by the user. However, Boost.Python provides an easy to use + high-level interface via the + <strong><tt>boost::python::pickle_suite</tt></strong> class that also + enforces consistency: <tt>__getstate__</tt> and <tt>__setstate__</tt> + must be defined as pairs. Use of this interface is demonstrated by the + following examples. + <hr /> + + <h2>Examples</h2>There are three files in <tt>boost/libs/python/test</tt> + that show how to provide pickle support. + <hr /> + + <h3><a href="../../test/pickle1.cpp"><tt>pickle1.cpp</tt></a></h3>The C++ + class in this example can be fully restored by passing the appropriate + argument to the constructor. Therefore it is sufficient to define the + pickle interface method <tt>__getinitargs__</tt>. This is done in the + following way: + + <ul> + <li>1. Definition of the C++ pickle function: + <pre> + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(world const& w) + { + return boost::python::make_tuple(w.get_country()); + } + }; +</pre> + </li> + + <li>2. Establishing the Python binding: + <pre> + class_<world>("world", args<const std::string&>()) + // ... + .def_pickle(world_pickle_suite()) + // ... +</pre> + </li> + </ul> + <hr /> + + <h3><a href="../../test/pickle2.cpp"><tt>pickle2.cpp</tt></a></h3>The C++ + class in this example contains member data that cannot be restored by any + of the constructors. Therefore it is necessary to provide the + <tt>__getstate__</tt>/<tt>__setstate__</tt> pair of pickle interface + methods: + + <ul> + <li>1. Definition of the C++ pickle functions: + <pre> + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + // ... + } + + static + boost::python::tuple + getstate(const world& w) + { + // ... + } + + static + void + setstate(world& w, boost::python::tuple state) + { + // ... + } + }; +</pre> + </li> + + <li>2. Establishing the Python bindings for the entire suite: + <pre> + class_<world>("world", args<const std::string&>()) + // ... + .def_pickle(world_pickle_suite()) + // ... +</pre> + </li> + </ul> + + <p>For simplicity, the <tt>__dict__</tt> is not included in the result of + <tt>__getstate__</tt>. This is not generally recommended, but a valid + approach if it is anticipated that the object's <tt>__dict__</tt> will + always be empty. Note that the safety guard described below will catch + the cases where this assumption is violated.</p> + <hr /> + + <h3><a href="../../test/pickle3.cpp"><tt>pickle3.cpp</tt></a></h3>This + example is similar to <a href= + "../../test/pickle2.cpp"><tt>pickle2.cpp</tt></a>. However, the object's + <tt>__dict__</tt> is included in the result of <tt>__getstate__</tt>. + This requires a little more code but is unavoidable if the object's + <tt>__dict__</tt> is not always empty. + <hr /> + + <h2>Pitfall and Safety Guard</h2>The pickle protocol described above has + an important pitfall that the end user of a Boost.Python extension module + might not be aware of: + + <p><strong><tt>__getstate__</tt> is defined and the instance's + <tt>__dict__</tt> is not empty.</strong></p> + + <p>The author of a Boost.Python extension class might provide a + <tt>__getstate__</tt> method without considering the possibilities + that:</p> + + <ul> + <li>his class is used in Python as a base class. Most likely the + <tt>__dict__</tt> of instances of the derived class needs to be pickled + in order to restore the instances correctly.</li> + + <li>the user adds items to the instance's <tt>__dict__</tt> directly. + Again, the <tt>__dict__</tt> of the instance then needs to be + pickled.</li> + </ul> + + <p>To alert the user to this highly unobvious problem, a safety guard is + provided. If <tt>__getstate__</tt> is defined and the instance's + <tt>__dict__</tt> is not empty, Boost.Python tests if the class has an + attribute <tt>__getstate_manages_dict__</tt>. An exception is raised if + this attribute is not defined:</p> + <pre> + RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set) +</pre>To resolve this problem, it should first be established that the <tt> + __getstate__</tt> and <tt>__setstate__</tt> methods manage the + instances's <tt>__dict__</tt> correctly. Note that this can be done + either at the C++ or the Python level. Finally, the safety guard should + intentionally be overridden. E.g. in C++ (from <a href= + "../../test/pickle3.cpp"><tt>pickle3.cpp</tt></a>): + <pre> + struct world_pickle_suite : boost::python::pickle_suite + { + // ... + + static bool getstate_manages_dict() { return true; } + }; +</pre>Alternatively in Python: + <pre> + import your_bpl_module + class your_class(your_bpl_module.your_class): + __getstate_manages_dict__ = 1 + def __getstate__(self): + # your code here + def __setstate__(self, state): + # your code here +</pre> + <hr /> + + <h2>Practical Advice</h2> + + <ul> + <li>In Boost.Python extension modules with many extension classes, + providing complete pickle support for all classes would be a + significant overhead. In general complete pickle support should only be + implemented for extension classes that will eventually be pickled.</li> + + <li>Avoid using <tt>__getstate__</tt> if the instance can also be + reconstructed by way of <tt>__getinitargs__</tt>. This automatically + avoids the pitfall described above.</li> + + <li>If <tt>__getstate__</tt> is required, include the instance's + <tt>__dict__</tt> in the Python object that is returned.</li> + </ul> + <hr /> + + <h2>Light-weight alternative: pickle support implemented in Python</h2> + + <h3><a href="../../test/pickle4.cpp"><tt>pickle4.cpp</tt></a></h3>The + <tt>pickle4.cpp</tt> example demonstrates an alternative technique for + implementing pickle support. First we direct Boost.Python via the + <tt>class_::enable_pickling()</tt> member function to define only the + basic attributes required for pickling: + <pre> + class_<world>("world", args<const std::string&>()) + // ... + .enable_pickling() + // ... +</pre>This enables the standard Python pickle interface as described in the +Python documentation. By "injecting" a <tt>__getinitargs__</tt> method into +the definition of the wrapped class we make all instances pickleable: + <pre> + # import the wrapped world class + from pickle4_ext import world + + # definition of __getinitargs__ + def world_getinitargs(self): + return (self.get_country(),) + + # now inject __getinitargs__ (Python is a dynamic language!) + world.__getinitargs__ = world_getinitargs +</pre>See also the <a href= +"../tutorial/doc/html/python/techniques.html#python.extending_wrapped_objects_in_python"> + tutorial section</a> on injecting additional methods from Python. + <hr /> + © Copyright Ralf W. Grosse-Kunstleve 2001-2004. Distributed under the + Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + <p>Updated: Feb 2004.</p> + </div> +</body> +</html> diff --git a/libs/python/doc/v2/platforms.html b/libs/python/doc/v2/platforms.html new file mode 100644 index 000000000..ac984b43f --- /dev/null +++ b/libs/python/doc/v2/platforms.html @@ -0,0 +1,135 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Known Working Platforms and Compilers</title> + </head> + + <body link="#0000ff" vlink="#800080"> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Known Working Platforms and Compilers</h2> + </td> + </tr> + </table> + <hr> + Please see + our <a + href="http://boost.sourceforge.net/regression-logs">regression + logs</a> for up-to-date information. Note that logs not marked + otherwise reflect the CVS state, not the condition of the release. + + <p> + Earlier versions of <b>Boost.Python</b> have been successfully + tested on the following platforms and compilers. + + <dl class="page-index"> + <dt>Unix Platforms:</dt> + + <dd> + <dl> + <dt>with Python <a href="http://www.python.org/2.2">2.2</a> and <a + href="http://www.python.org/2.2.2">2.2.2b1</a>:</dt> + + <dd> + <dl> + <dt><a href="http://gcc.gnu.org">GCC</a> 2.95.3, 2.96, 3.0.4, + 3.1, and 3.2 on <a href="http://www.redhat.com">RedHat Linux 7.3</a> + for Intel x86</dt> + + <dt>Tru64 CXX 6.5.1 on OSF v. 5.1 for Dec/Compaq + Alpha</dt> + + <dt> + MIPSPro 7.3.1.2m on <a href= + "http://www.sgi.com/software/irix6.5/">IRIX 6.5</a> for SGI + mips</dt> + + <dt><a href="http://gcc.gnu.org">GCC 3.1</a> on SunOS 5.8</dt> + </dl> + </dd> + + <dt>with Python <a href= + "http://www.python.org/2.2.1">2.2.1</a></dt> + + <dd> + <dl> + <dt>KCC 3.4d on OSF v. 5.1 for Dec/Compaq Alpha</dt> + + <dt>KCC 3.4d</a> on AIX</dt> + </dl> + </dd> + </dl> + <br> + </dd> + + <dt>Microsoft Windows XP Professional with Python <a href= + "http://www.python.org/2.2">2.2</a>, <a href= + "http://www.python.org/2.2.1">2.2.1</a>, and <a href= + "http://www.python.org/2.2.2">2.2.2b1</a>:</dt> + + <dd> + <dl> + <dt><a href= + "http://msdn.microsoft.com/visualc/default.asp">Microsoft Visual + C++</a> 6, 7, and 7.1 beta</dt> + + <dt><a href= + "http://msdn.microsoft.com/visualc/default.asp">Microsoft Visual + C++ 6</a> with <a href="http://www.stlport.org">STLPort + 4.5.3</a></dt> + + <dt><a href= + "http://www.metrowerks.com/MW/Develop/Desktop/Windows/Professional/Default.htm"> + Metrowerks CodeWarrior</a> 7.2, 8.0, 8.2 and 8.3 beta</dt> + + <dt><a href= + "http://www.intel.com/software/products/compilers/c60/">Intel + C++</a> 5.0, 6.0, and 7.0 beta</dt> + + <dt><a href= + "http://www.intel.com/software/products/compilers/c60/">Intel C++ + 5.0</a> with <a href="http://www.stlport.org">STLPort + 4.5.3</a></dt> + + <dt><a href="http://www.cygwin.com">Cygwin</a> <a href= + "http://gcc.gnu.org">GCC</a> 3.0.4 and 3.2</dt> + + <dt><a href="http://www.mingw.org">MinGW-1.1</a> (<a href= + "http://gcc.gnu.org">GCC 2.95.3-5</a>)</dt> + + <dt><a href="http://www.mingw.org">MinGW-2.0</a> (<a href= + "http://gcc.gnu.org">GCC 3.2</a>)</dt> + </dl> + </dd> + </dl> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/pointee.html b/libs/python/doc/v2/pointee.html new file mode 100644 index 000000000..2dcec8c36 --- /dev/null +++ b/libs/python/doc/v2/pointee.html @@ -0,0 +1,119 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/pointee.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/pointee.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a> + + <dt><a href="#classes">Classes</a> + + <dd> + <dl class="page-index"> + <dt><a href="#pointee-spec">Class Template<code>pointee</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#pointee-spec-synopsis">Class Template + <code>pointee</code> synopsis</a> + </dl> + </dl> + + <dt><a href="#examples">Example</a> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/pointee.hpp></code> introduces a + traits <a + href="../../../mpl/doc/refmanual/metafunction.html">metafunction</a> + template <code>pointee<T></code> that can be used to extract the "pointed-to" type from the type of a pointer or smart pointer. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="pointee-spec"></a>Class Template <code>pointee<class T></code></h3> + + <p><code>pointee<T></code> is used by the <code><a + href="class.html#class_-spec">class_</a><...></code> + template to deduce the type being held when a pointer or smart + pointer type is used as its <code>HeldType</code> argument. + + <h4><a name="pointee-spec-synopsis"></a>Class Template + <code>pointee</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T> struct pointee + { + typedef T::element_type type; + }; + + // specialization for pointers + template <T> struct pointee<T*> + { + typedef T type; + }; +} +</pre> + + + <h2><a name="examples"></a>Example</h2> + +Given a 3rd-party smart pointer type +<code>smart_pointer<T></code>, one might partially specialize +<code>pointee<smart_pointer<T> ></code> so that it can be +used as the <code>HeldType</code> for a class wrapper: + +<pre> +#include <boost/python/pointee.hpp> +#include <boost/python/class.hpp> +#include <third_party_lib.hpp> + +namespace boost { namespace python +{ + template <class T> struct pointee<smart_pointer<T> > + { + typedef T type; + }; +}} + +BOOST_PYTHON_MODULE(pointee_demo) +{ + class_<third_party_class, smart_pointer<third_party_class> >("third_party_class") + .def(...) + ... + ; +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> Distributed + under the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</p> + + diff --git a/libs/python/doc/v2/progress_reports.html b/libs/python/doc/v2/progress_reports.html new file mode 100644 index 000000000..5a8b015a2 --- /dev/null +++ b/libs/python/doc/v2/progress_reports.html @@ -0,0 +1,47 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - Progress Reports</title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">Progress Reports</h2> + </td> + </tr> +</table> +<hr> + +Monthly progress reports are required as part of Boost Consulting's +contract with LLNL for Boost.Python development. These reports contain +a useful record of the project history, including the rationale for +design decisions and links to relevant discussions. + +<dl class="page-index"> + <dt><a href="feb2002.html">February 2002</a></dt> + <dt><a href="Mar2002.html">March 2002</a></dt> + <dt><a href="Apr2002.html">April 2002</a></dt> + <dt><a href="May2002.html">May 2002</a></dt> + <dt><a href="Jun2002.html">June 2002</a></dt> +</dl> +<hr> +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> diff --git a/libs/python/doc/v2/ptr.html b/libs/python/doc/v2/ptr.html new file mode 100644 index 000000000..4aca53915 --- /dev/null +++ b/libs/python/doc/v2/ptr.html @@ -0,0 +1,265 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/ptr.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/ptr.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a> + + <dt><a href="#functions">Functions</a> + <dd> + <dl class="page-index"> + <dt><a href="#ptr-spec">ptr</a> + </dl> + + <dt><a href="#classes">Classes</a> + <dd> + <dl class="page-index"> + <dt><a href="#pointer_wrapper-spec">Class template <code>pointer_wrapper</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#pointer_wrapper-spec-synopsis">Class template <code>pointer_wrapper</code> synopsis</a> + + <dt><a href="#pointer_wrapper-spec-types">Class + <code>pointer_wrapper</code> types</a> + + <dt><a href="#pointer_wrapper-spec-ctors">Class + <code>pointer_wrapper</code> constructors and destructor</a> + + <dt><a href="#pointer_wrapper-spec-observers">Class + <code>pointer_wrapper</code> observer functions</a> + + </dl> + </dl> + + <dt><a href="#metafunctions">Metafunctions</a> + <dd> + <dl class="page-index"> + <dt><a href="#is_pointer_wrapper-spec">Class template <code>is_pointer_wrapper</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#is_pointer_wrapper-spec-synopsis">Class template <code>is_pointer_wrapper</code> synopsis</a> + </dl> + + + <dt><a href="#unwrap_pointer-spec">Class template <code>unwrap_pointer</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#unwrap_pointer-spec-synopsis">Class template <code>unwrap_pointer</code> synopsis</a> + </dl> + + </dl> + + + <dt><a href="#examples">Example(s)</a> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/ptr.hpp></code> defines the + <code>ptr()</code> function template, which allows users to + specify how to convert C++ pointer values to python in the context + of implementing overridable virtual functions, invoking Python + callable objects, or explicitly converting C++ objects to + Python. Normally, when passing pointers to Python callbacks, the + pointee is copied to ensure that the Python object + never holds a dangling reference. To specify that the new Python + object should merely contain a copy of a pointer <code>p</code>, + the user can pass <code><a href="#ptr-spec">ptr</a>(p)</code> instead of passing + <code>p</code> directly. This interface is meant to mirror the use + of <a href="../../../bind/ref.html"><code>boost::ref()</code></a>, + which can be similarly used to prevent copying of referents. + + <p><code>ptr(p)</code> returns an instance of <code><a + href="#pointer_wrapper-spec">pointer_wrapper<></a></code>, which + can be detected using the <code><a + href="#is_pointer_wrapper-spec">is_pointer_wrapper<></a></code> + metafunction; <code><a + href="#unwrap_pointer-spec">unwrap_pointer<></a></code> is a + metafunction which extracts the original pointer type from a + <code>pointer_wrapper<></code>. These classes can be thought + of as implementation details. + + <h2><a name="functions"></a>Functions</h2> +<pre> + +<a name="ptr-spec">template <class T></a> +pointer_wrapper<T> ptr(T x); +</pre> + + <dl class="ptr-semantics"> + <dt><b>Requires:</b> <code>T</code> is a pointer type. + + <dt><b>Returns:</b> <code><a href="#pointer_wrapper-spec">pointer_wrapper</a><T>(x)</code> + + <dt><b>Throws:</b> nothing. + </dl> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="pointer_wrapper-spec"></a>Class template <code>pointer_wrapper</code></h3> + + <p>A "type envelope" which is returned by <a + href="#ptr-spec">ptr()</a>, used to indicate reference semantics + for pointers passed to Python callbacks. + + <h4><a name="pointer_wrapper-spec-synopsis"></a>Class + <code>pointer_wrapper</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template<class Ptr> class pointer_wrapper + { + public: + typedef Ptr type; + + explicit pointer_wrapper(Ptr x); + operator Ptr() const; + Ptr get() const; + }; +}} +</pre> + + <h4><a name="pointer_wrapper-spec-types"></a>Class template <code>pointer_wrapper</code> types</h4> +<pre> +typedef Ptr type; +</pre> +The type of the pointer being wrapped. + + <h4><a name="pointer_wrapper-spec-ctors"></a>Class template <code>pointer_wrapper</code> constructors and + destructor</h4> +<pre> +explicit pointer_wrapper(Ptr x); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>Ptr</code> is a pointer type. + + <dt><b>Effects:</b> Stores <code>x</code> in a the <code>pointer_wrapper<></code>. + <dt><b>Throws:</b> nothing. + </dl> + + <h4><a name="pointer_wrapper-spec-observers"></a>Class template <code>pointer_wrapper</code> observer + functions</h4> +<pre> +operator Ptr() const; +Ptr get() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> a copy of the stored pointer. + <dt><b>Rationale:</b> <code>pointer_wrapper</code> is intended + to be a stand-in for the actual pointer type, but sometimes it's + better to have an explicit way to retrieve the pointer. + </dl> + + <h2><a name="metafunctions"></a>Metafunctions</h2> + + <h3><a name="is_pointer_wrapper-spec"></a>Class template <code>is_pointer_wrapper</code></h3> + + <p>A unary metafunction whose <code>value</code> is true iff its + argument is a <code>pointer_wrapper<></code>. + + <h4><a name="is_pointer_wrapper-spec-synopsis"></a>Class template <code>is_pointer_wrapper</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template<class T> class is_pointer_wrapper + { + static <i>unspecified</i> value = ...; + }; +}} +</pre> + + + <dl class="metafunction-semantics"> + <dt><b>Returns:</b> <code>true</code> iff <code>T</code> is a + specialization of +<code>pointer_wrapper<></code>. +<dt><code>value</code> is an integral constant convertible to bool of +unspecified type + + </dl> + +<h3><a name="unwrap_pointer-spec"></a>Class template <code>unwrap_pointer</code></h3> + +A unary metafunction which extracts the wrapped pointer type from a +specialization of <code>pointer_wrapper<></code>. + + <h4><a name="unwrap_pointer-spec-synopsis"></a>Class template <code>unwrap_pointer</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template<class T> class unwrap_pointer + { + typedef <i>unspecified</i> type; + }; +}} +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Returns:</b> <code>T::type</code> if <code>T</code> is a + specialization of +<code>pointer_wrapper<></code>, <code>T</code> otherwise + </dl> + + + <h2><a name="examples"></a>Example(s)</h2> + +This example illustrates the use of <code>ptr()</code> to prevent an +object from being copied: +<pre> +#include <boost/python/call.hpp> +#include <boost/python/ptr.hpp> + +class expensive_to_copy +{ + ... +}; + +void pass_as_arg(expensive_to_copy* x, PyObject* f) +{ + // call the Python function f, passing a Python object built around + // which refers to *x by-pointer. + // + // *** Note: ensuring that *x outlives the argument to f() is *** + // *** up to the user! Failure to do so could result in a crash! *** + + boost::python::call<void>(f, ptr(x)); +} +... +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> Distributed + under the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/doc/v2/python.html b/libs/python/doc/v2/python.html new file mode 100644 index 000000000..9c4e27ec6 --- /dev/null +++ b/libs/python/doc/v2/python.html @@ -0,0 +1,110 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>This is a convenience header which #includes all of the public + interface headers that are part of the Boost.Python library</p> +<pre> +# include <args.hpp> +# include <args_fwd.hpp> +# include <back_reference.hpp> +# include <bases.hpp> +# include <borrowed.hpp> +# include <call.hpp> +# include <call_method.hpp> +# include <class.hpp> +# include <copy_const_reference.hpp> +# include <copy_non_const_reference.hpp> +# include <data_members.hpp> +# include <def.hpp> +# include <default_call_policies.hpp> +# include <dict.hpp> +# include <enum.hpp> +# include <errors.hpp> +# include <exception_translator.hpp> +# include <extract.hpp> +# include <handle.hpp> +# include <has_back_reference.hpp> +# include <implicit.hpp> +# include <init.hpp> +# include <instance_holder.hpp> +# include <iterator.hpp> +# include <list.hpp> +# include <long.hpp> +# include <lvalue_from_pytype.hpp> +# include <make_function.hpp> +# include <manage_new_object.hpp> +# include <module.hpp> +# include <numeric.hpp> +# include <object.hpp> +# include <object_protocol.hpp> +# include <object_protocol_core.hpp> +# include <operators.hpp> +# include <other.hpp> +# include <overloads.hpp> +# include <pointee.hpp> +# include <ptr.hpp> +# include <reference_existing_object.hpp> +# include <return_internal_reference.hpp> +# include <return_value_policy.hpp> +# include <scope.hpp> +# include <self.hpp> +# include <slice_nil.hpp> +# include <str.hpp> +# include <to_python_converter.hpp> +# include <to_python_indirect.hpp> +# include <to_python_value.hpp> +# include <tuple.hpp> +# include <type_id.hpp> +# include <with_custodian_and_ward.hpp> +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/pytype_function.html b/libs/python/doc/v2/pytype_function.html new file mode 100644 index 000000000..fcc2a7f92 --- /dev/null +++ b/libs/python/doc/v2/pytype_function.html @@ -0,0 +1,370 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright Nikolay Mladenov 2007. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta http-equiv="Content-Type" content= + "text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/doobject/pytype_function.hpp></title> +</head> + +<body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png" border= + "0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href= + "../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/converter/pytype_function.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#wrap_pytype-spec">Class + <code>wrap_pytype</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#wrap_pytype-spec-synopsis">Class + <code>wrap_pytype</code> synopsis</a></dt> + + </dl> + </dd> + </dl> + </dd> + + <dd> + <dl class="page-index"> + <dt><a href="#registered_pytype-spec">Class + <code>registered_pytype</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#registered_pytype-spec-synopsis">Class + <code>registered_pytype</code> synopsis</a></dt> + + </dl> + </dd> + </dl> + </dd> + + <dd> + <dl class="page-index"> + <dt><a href="#expected_from_python_type-spec">Class + <code>expected_from_python_type</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#expected_from_python_type-spec-synopsis">Class + <code>expected_from_python_type</code> synopsis</a></dt> + + </dl> + </dd> + </dl> + </dd> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_target_type-spec">Class + <code>to_python_target_type</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_target_type-spec-synopsis">Class + <code>to_python_target_type</code> synopsis</a></dt> + + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction" id= + "introduction"></a>Introduction</h2> + + <p>To support Pythonic signatures the converters should supply a <code>get_pytype</code> function + returning a pointer to the associated <code>PyTypeObject</code>. See for example + <a href="ResultConverter.html#ResultConverter-concept">ResultConverter</a> or + <a href="to_python_converter.html#to_python_converter-spec">to_python_converter</a>. + The classes in this header file are meant to be used when implmenting <code>get_pytype</code>. + There are also <code>_direct</code> versions of the templates of <code>class T</code> which + should be used with undecorated type parameter, expected to be in the conversion registry when the module loads. + </p> + + <h2><a name="classes" id="classes"></a>Classes</h2> + + <h3><a name="wrap_pytype-spec" id= + "wrap_pytype-spec"></a>Class + <code>wrap_pytype</code></h3> + + <p> + This template generates a static <code>get_pytype</code> member returning the template parameter. + </p> + + <h4><a name="wrap_pytype-spec-synopsis" id= + "wrap_pytype-spec-synopsis"></a>Class + <code>wrap_pytype</code> synopsis</h4> + <pre> +namespace boost { namespace python { namespace converter{ + + template < PyTypeObject const *pytype > + class wrap_pytype + { + public: + static PyTypeObject const *get_pytype(){return pytype; } + }; + +}}} +</pre> + + + <h3><a name="registered_pytype-spec" id= + "registered_pytype-spec"></a>Class + <code>registered_pytype</code></h3> + + <p> + This template should be used with template parameters which are (possibly decorated) + types exported to python using <a href="class.html"><code>class_</code></a>. + The generated a static <code>get_pytype</code> member + returns the corresponding python type. + </p> + + <h4><a name="registered_pytype-spec-synopsis" id= + "registered_pytype-spec-synopsis"></a>Class + <code>registered_pytype</code> synopsis</h4> + <pre> +namespace boost { namespace python { namespace converter{ + + template < class T > + class registered_pytype + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +</pre> + + + <h3><a name="expected_from_python_type-spec" id= + "expected_from_python_type-spec"></a>Class + <code>expected_from_python_type</code></h3> + + <p> + This template generates a static <code>get_pytype</code> member which inspects the registered + <code>from_python</code> converters for the type <code>T</code> and returns a matching python type. + </p> + + <h4><a name="expected_from_python_type-spec-synopsis" id= + "expected_from_python_type-spec-synopsis"></a>Class + <code>expected_from_python_type</code> synopsis</h4> + <pre> +namespace boost { namespace python { namespace converter{ + + template < class T > + class expected_from_python_type + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +</pre> + + + <h3><a name="to_python_target_type-spec" id= + "to_python_target_type-spec"></a>Class + <code>to_python_target_type</code></h3> + + <p> + This template generates a static <code>get_pytype</code> member returning the + python type to which T can be converted. + </p> + + <h4><a name="to_python_target_type-spec-synopsis" id= + "to_python_target_type-spec-synopsis"></a>Class + <code>to_python_target_type</code> synopsis</h4> + <pre> +namespace boost { namespace python { namespace converter{ + + template < class T > + class to_python_target_type + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +</pre> + + + <h2><a name="examples" id="examples"></a>Examples</h2> + + This example presumes that someone has implemented the standard <a href= + "http://www.python.org/doc/2.2/ext/dnt-basics.html">noddy example + module</a> from the Python documentation, and placed the corresponding + declarations in <code>"noddy.h"</code>. Because + <code>noddy_NoddyObject</code> is the ultimate trivial extension type, + the example is a bit contrived: it wraps a function for which all + information is contained in the <i>type</i> of its return value. + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/reference.hpp> +#include <boost/python/module.hpp> +#include "noddy.h" + +struct tag {}; +tag make_tag() { return tag(); } + +using namespace boost::python; + +struct tag_to_noddy +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported +: wrap_pytype<&noddy_NoddyType> //inherits get_pytype from wrap_pytype +#endif +{ + static PyObject* convert(tag const& x) + { + return PyObject_New(noddy_NoddyObject, &noddy_NoddyType); + } +}; + +BOOST_PYTHON_MODULE(to_python_converter) +{ + def("make_tag", make_tag); + to_python_converter<tag, tag_to_noddy +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + , true +#endif + >(); //"true" because tag_to_noddy has member get_pytype +} +</pre> + + +<p>The following example registers to and from python converters using the templates +<code>expected_from_python_type</code> and <code>to_pyhton_target_type</code>. +</p> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/to_python_converter.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +struct A +{ +}; + +struct B +{ + A a; + B(const A& a_):a(a_){} +}; + +// Converter from A to python int +struct BToPython +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported + : converter::to_python_target_type<A> //inherits get_pytype +#endif +{ + static PyObject* convert(const B& b) + { + return incref(object(b.a).ptr()); + } +}; + +// Conversion from python int to A +struct BFromPython +{ + BFromPython() + { + boost::python::converter::registry::push_back + ( &convertible + , &construct + , type_id< B >() +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + , &converter::expected_from_python_type<A>::get_pytype//convertible to A can be converted to B +#endif + ); + } + + static void* convertible(PyObject* obj_ptr) + { + extract<const A&> ex(obj_ptr); + if (!ex.check()) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (converter::rvalue_from_python_storage< B >*)data)-> storage.bytes; + + extract<const A&> ex(obj_ptr); + new (storage) B(ex()); + data->convertible = storage; + } +}; + + +B func(const B& b) { return b ; } + +BOOST_PYTHON_MODULE(pytype_function_ext) +{ + to_python_converter< B , BToPython +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + ,true +#endif + >(); //has get_pytype + BFromPython(); + + class_<A>("A") ; + + def("func", &func); + +} + + + +>>> from pytype_function_ext import * +>>> print func.__doc__ +func( (A)arg1) -> A : + C++ signature: + struct B func(struct B) +</pre> + + + <p><i>© Copyright <a href="mailto:nickm at sitius dot com">Nikolay Mladenov</a> 2007.</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/raw_function.html b/libs/python/doc/v2/raw_function.html new file mode 100644 index 000000000..0ad4c37c2 --- /dev/null +++ b/libs/python/doc/v2/raw_function.html @@ -0,0 +1,118 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/raw_function.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/raw_function.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#raw_function-spec">raw_function</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><a href="#raw_function-spec">raw_function</a>(...)</code> + is used to convert a function taking a <a + href="tuple.html#tuple-spec">tuple</a> and a <a + href="dict.html#dict-spec">dict</a> into a Python callable object + which accepts a variable number of arguments and arbitrary keyword + arguments. + + <h2><a name="functions"></a>Functions</h2> + <a name="raw_function-spec"></a>raw_function +<pre> +template <class F> +object raw_function(F f, std::size_t min_args = 0); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>f(tuple(), dict())</code> is + well-formed.</dt> + + <dt><b>Returns:</b> a <a href= + "http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6">callable</a> object which requires at least <code>min_args</code> arguments. When called, the actual non-keyword arguments will be passed in a <a + href="tuple.html#tuple-spec">tuple</a> as the first argument to <code>f</code>, and the keyword arguments will be passed in a <a + href="dict.html#dict-spec">dict</a> as the second argument to <code>f</code>. + + </dd> + </dl> + + <h2><a name="examples"></a>Example</h2> +C++: +<pre> +#include <boost/python/def.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/module.hpp> +#include <boost/python/raw_function.hpp> + +using namespace boost::python; + +tuple raw(tuple args, dict kw) +{ + return make_tuple(args, kw); +} + +BOOST_PYTHON_MODULE(raw_test) +{ + def("raw", raw_function(raw)); +} +</pre> + +Python: +<pre> +>>> from raw_test import * + +>>> raw(3, 4, foo = 'bar', baz = 42) +((3, 4), {'foo': 'bar', 'baz': 42}) +</pre> + <p> + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 7 March, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/reference.html b/libs/python/doc/v2/reference.html new file mode 100644 index 000000000..5ebdad105 --- /dev/null +++ b/libs/python/doc/v2/reference.html @@ -0,0 +1,1192 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - Reference</title> + + <style type="text/css"> + p.c3 {font-style: italic} + h2.c2 {text-align: center} + h1.c1 {text-align: center} + </style> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "reference"> + <tr> + <td valign="top" width="300"> + <h3><a href="http://www.boost.org"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 class="c1"><a href="../index.html">Boost.Python</a></h1> + + <h2 class="c2">Reference</h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="Reference"> + <dt><a href="#concepts">Concepts</a></dt> + + <dt><a href="#high_level">High Level Components</a></dt> + + <dt><a href="#object_wrappers">Object Wrappers</a></dt> + + <dt><a href="#invocation">Function Invocation and Creation</a></dt> + + <dd> + <dl class="index"> + <dt><a href="#models_of_call_policies">Models of + CallPolicies</a></dt> + + <dt><a href="#models_of_result_converter">Models of + ResultConverter</a></dt> + + <dt><a href="#result_converter_generators">Models of + ResultConverterGenerator</a></dt> + </dl> + </dd> + + <dt><a href="#type_conversion">To/From Python Type Conversion</a></dt> + + <dt><a href="#embedding">Embedding</a></dt> + + <dt><a href="#utility">Utility and Infrastructure</a></dt> + + <dt><a href="#topics">Topics</a></dt> + </dl> + <hr> + <!-- xxxxx --> + + <h2><a name="concepts">Concepts</a></h2> + + <dl class="index"> + <dt><a href= + "CallPolicies.html#CallPolicies-concept">CallPolicies</a></dt> + + <dt><a href= + "Dereferenceable.html#Dereferenceable-concept">Dereferenceable</a></dt> + + <dt><a href="Extractor.html#Extractor-concept">Extractor</a></dt> + + <dt><a href= + "HolderGenerator.html#HolderGenerator-concept">HolderGenerator</a></dt> + + <dt><a href= + "ResultConverter.html#ResultConverter-concept">ResultConverter</a></dt> + + <dt><a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a></dt> + + <dt><a href= + "ObjectWrapper.html#ObjectWrapper-concept">ObjectWrapper</a></dt> + + <dt><a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a></dt> + </dl> + + <h2><a name="high_level">High Level Components</a></h2> + + <dl> + <dt><a href="class.html">class.hpp/class_fwd.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="class.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="class.html#class_-spec">class_</a></dt> + + <dt><a href="class.html#bases-spec">bases</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="def.html">def.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="def.html#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="def.html#def-spec">def</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="def_visitor.html">def_visitor.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="def_visitor.html#classes">Classes</a></dt> + </dl> + </dd> + + <dt><a href="docstring_options.html">docstring_options.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="docstring_options.html#classes">Classes</a></dt> + </dl> + </dd> + + <dt><a href="enum.html">enum.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="enum.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="enum.html#enum_-spec">enum_</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="errors.html">errors.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="errors.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "errors.html#error_already_set-spec">error_already_set</a></dt> + </dl> + </dd> + + <dt><a href="errors.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "errors.html#handle_exception-spec">handle_exception</a></dt> + + <dt><a href= + "errors.html#expect_non_null-spec">expect_non_null</a></dt> + + <dt><a href= + "errors.html#throw_error_already_set-spec">throw_error_already_set</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "exception_translator.html">exception_translator.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "exception_translator.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "exception_translator.html#register_exception_translator-spec">register_exception_translator</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="init.html">init.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="init.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="init.html#init-spec">init</a></dt> + + <dt><a href="init.html#optional-spec">optional</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="iterator.html">iterator.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="iterator.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="iterator.html#iterator-spec">iterator</a></dt> + + <dt><a href="iterator.html#iterators-spec">iterators</a></dt> + </dl> + </dd> + + <dt><a href="iterator.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="iterator.html#range-spec">range</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="module.html">module.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="module.html#macros">Macros</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "module.html#BOOST_PYTHON_MODULE-spec">BOOST_PYTHON_MODULE</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="operators.html">operators.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="operators.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="operators.html#self_t-spec">self_t</a></dt> + + <dt><a href="operators.html#other-spec">other</a></dt> + + <dt><a href="operators.html#operator_-spec">operator_</a></dt> + </dl> + </dd> + + <dt><a href="operators.html#objects">Objects</a></dt> + + <dd> + <dl class="index"> + <dt><a href="operators.html#self-spec">self</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="scope.html">scope.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="scope.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="scope.html#scope-spec">scope</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="stl_iterator.html">stl_iterator.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="stl_iterator.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="stl_iterator.html#stl_input_iterator-spec">stl_input_iterator</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="wrapper.html">wrapper.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="wrapper.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="wrapper.html#override-spec">override</a></dt> + + <dt><a href="wrapper.html#wrapper-spec">wrapper</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + + <h2><a name="object_wrappers">Object Wrappers</a></h2> + + <dl class="index"> + <dt><a href="dict.html">dict.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="dict.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="dict.html#dict-spec">dict</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="list.html">list.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="list.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="list.html#list-spec">list</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="long.html">long.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="long.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="long.html#long_-spec">long_</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="numeric.html">numeric.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="numeric.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="numeric.html#array-spec">numeric::array</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="object.html">object.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="object.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="object.html#object-spec">object</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="str.html">str.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="str.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="str.html#str-spec">str</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="tuple.html">tuple.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="tuple.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="tuple.html#tuple-spec">tuple</a></dt> + </dl> + </dd> + + <dt><a href="tuple.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="tuple.html#make_tuple-spec">make_tuple</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="slice.html">slice.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="slice.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="slice.html#slice-spec">slice</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + + <h2><a name="invocation">Function Invocation and Creation</a></h2> + + <dl class="index"> + <dt><a href="args.html">args.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="args.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="args.html#args-spec">args</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="call.html">call.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="call.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="call.html#call-spec">call</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="call_method.html">call_method.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="call_method.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "call_method.html#call_method-spec">call_method</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="data_members.html">data_members.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="data_members.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "data_members.html#make_getter-spec">make_getter</a></dt> + + <dt><a href= + "data_members.html#make_setter-spec">make_setter</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="make_function.html">make_function.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="make_function.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "make_function.html#make_function-spec">make_function</a></dt> + + <dt><a href= + "make_function.html#make_constructor-spec">make_constructor</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="overloads.html">overloads.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="overloads.html#macros">macros</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec">BOOST_PYTHON_FUNCTION_OVERLOADS</a></dt> + + <dt><a href= + "overloads.html#BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS-spec">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="ptr.html">ptr.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="ptr.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="ptr.html#ptr-spec">ptr</a></dt> + </dl> + </dd> + + <dt><a href="ptr.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "ptr.html#pointer_wrapper-spec">pointer_wrapper</a></dt> + </dl> + </dd> + + <dt><a href="ptr.html#metafunctions">MetaFunctions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "ptr.html#is_pointer_wrapper-spec">is_pointer_wrapper</a></dt> + + <dt><a href= + "ptr.html#unwrap_pointer-spec">unwrap_pointer</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="raw_function.html">raw_function.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="raw_function.html#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href= + "raw_function.html#raw_function-spec">raw_function</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dd> + <a name="function_documentation"></a> + + <h3>Function documentation</h3> + + <dl class="index"> + <dt><a href= + "function_doc_signature.html">function_doc_signature.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "function_doc_signature.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "function_doc_signature.html#function_doc_signature_generator-spec">function_doc_signature_generator</a></dt> + + </dl> + </dd> + </dl> + </dd> + </dl> + <dl class="index"> + <dt><a href= + "pytype_function.html">pytype_function.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "pytype_function.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "pytype_function.html#wrap_pytype-spec">wrap_pytype</a></dt> + + </dl> + <dl class="index"> + <dt><a href= + "pytype_function.html#expected_from_python_type-spec">expected_from_python_type</a></dt> + + </dl> + <dl class="index"> + <dt><a href= + "pytype_function.html#to_python_target_type-spec">to_python_target_type</a></dt> + + </dl> + <dl class="index"> + <dt><a href= + "pytype_function.html#registered_pytype-spec">registered_pytype</a></dt> + + </dl> + </dd> + </dl> + </dd> + </dl> + </dd> + + <dd> + <a name="models_of_call_policies"></a> + + <h3>Models of CallPolicies</h3> + + <dl class="index"> + <dt><a href= + "default_call_policies.html">default_call_policies.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "default_call_policies.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a></dt> + + <dt><a href= + "default_call_policies.html#default_result_converter-spec">default_result_converter</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="return_arg.html">return_arg.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="return_arg.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_arg.html#return_arg-spec">return_arg</a></dt> + + <dt><a href= + "return_arg.html#return_self-spec">return_self</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "return_internal_reference.html">return_internal_reference.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_internal_reference.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_internal_reference.html#return_internal_reference-spec"> + return_internal_reference</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "return_value_policy.html">return_value_policy.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="return_value_policy.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_value_policy.html#return_value_policy-spec">return_value_policy</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "with_custodian_and_ward.html">with_custodian_and_ward.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "with_custodian_and_ward.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "with_custodian_and_ward.html#with_custodian_and_ward-spec"> + with_custodian_and_ward</a></dt> + + <dt><a href= + "with_custodian_and_ward.html#with_custodian_and_ward_postcall-spec"> + with_custodian_and_ward_postcall</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + <a name="models_of_result_converter"></a> + + <h3>Models of ResultConverter</h3> + + <dl class="index"> + <dt><a href= + "to_python_indirect.html">to_python_indirect.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="to_python_indirect.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "to_python_indirect.html#to_python_indirect-spec">to_python_indirect</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="to_python_value.html">to_python_value.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="to_python_value.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "to_python_value.html#to_python_value-spec">to_python_value</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + <a name="result_converter_generators"></a> + + <h3>Models of ResultConverterGenerator</h3> + + <dl class="index"> + <dt><a href= + "copy_const_reference.html">copy_const_reference.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "copy_const_reference.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "copy_const_reference.html#copy_const_reference-spec">copy_const_reference</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "copy_non_const_reference.html">copy_non_const_reference.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "copy_non_const_reference.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "copy_non_const_reference.html#copy_non_const_reference-spec"> + copy_non_const_reference</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="manage_new_object.html">manage_new_object.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="manage_new_object.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "manage_new_object.html#manage_new_object-spec">manage_new_object</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "reference_existing_object.html">reference_existing_object.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "reference_existing_object.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "reference_existing_object.html#reference_existing_object-spec"> + reference_existing_object</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="return_by_value.html">return_by_value.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="return_by_value.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_by_value.html#return_by_value-spec">return_by_value</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_opaque_pointer.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "return_opaque_pointer.html#return_opaque_pointer-spec">return_opaque_pointer</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + </dd> + </dl> + + <h2><a name="type_conversion">To/From Python Type Conversion</a></h2> + + <dl class="index"> + <dt><a href="extract.html">extract.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="extract.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="extract.html#extract-spec">extract</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="implicit.html">implicit.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="implicit.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "implicit.html#implicitly_convertible-spec">implicitly_convertible</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="lvalue_from_pytype.html">lvalue_from_pytype.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="lvalue_from_pytype.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "lvalue_from_pytype.html#lvalue_from_pytype-spec">lvalue_from_pytype</a></dt> + + <dt><a href= + "lvalue_from_pytype.html#extract_identity-spec">extract_identity</a></dt> + + <dt><a href= + "lvalue_from_pytype.html#extract_member-spec">extract_member</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "opaque.html">opaque_pointer_converter.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "opaque.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "opaque.html#opaque-spec">opaque</a></dt> + </dl> + </dd> + + <dt><a href="opaque.html#macros">Macros</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "opaque.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec"> + BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="to_python_converter.html">to_python_converter.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="to_python_converter.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "to_python_converter.html#to_python_converter-spec">to_python_converter</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href= + "register_ptr_to_python.html">register_ptr_to_python.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "register_ptr_to_python.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "register_ptr_to_python.html#register_ptr_to_python-spec">register_ptr_to_python</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + + <h2><a name="embedding">Embedding</a></h2> + + <dl class="index"> + <dt><a href="exec.html">exec.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="exec.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="exec.html#eval-spec">eval</a></dt> + <dt><a href="exec.html#exec-spec">exec</a></dt> + <dt><a href="exec.html#exec_file-spec">exec_file</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="import.html">import.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="import.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="import.html#import-spec">import</a></dt> + </dl> + </dd> + </dl> + </dd> + </dl> + + <h2><a name="utility">Utility and Infrastructure</a></h2> + + <dl> + <dt><a href="has_back_reference.html">has_back_reference.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="has_back_reference.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "has_back_reference.html#has_back_reference-spec">has_back_reference</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="instance_holder.html">instance_holder.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="instance_holder.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href= + "instance_holder.html#instance_holder-spec">instance_holder</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="pointee.html">pointee.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="pointee.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt>class template <a href= + "pointee.html#pointee-spec">pointee</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="python.html"><boost/python.hpp></a></dt> + + <dt><a href="handle.html">handle.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="handle.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="handle.html#handle-spec">handle</a></dt> + </dl> + </dd> + + <dt><a href="handle.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="handle.html#borrowed-spec">borrowed</a></dt> + + <dt><a href="handle.html#allow_null-spec">allow_null</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="type_id.html">type_id.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="type_id.html#functions">Functions</a></dt> + + <dd> + <dl class="index"> + <dt><a href="type_id.html#type_id-spec">type_id</a></dt> + </dl> + </dd> + + <dt><a href="type_id.html#classes">Classes</a></dt> + + <dd> + <dl class="index"> + <dt><a href="type_id.html#type_info-spec">type_info</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="ssize_t.html">ssize_t.hpp</a></dt> + + <dd> + <dl class="index"> + <dt><a href="ssize_t.html#typedefs">Typedefs</a></dt> + + <dt><a href="ssize_t.html#constants">Constants</a></dt> + </dl> + </dd> + </dl> + + <h2><a name="topics">Topics</a></h2> + + <dl> + <dt><a href="callbacks.html">Calling Python Functions and + Methods</a></dt> + + <dt><a href="pickle.html">Pickle Support</a><br> + <a href="indexing.html">Indexing Support</a></dt> + </dl> + <hr> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 31 October, 2004 +<!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p class="c3">© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002 +.</p> + </body> +</html> + diff --git a/libs/python/doc/v2/reference_existing_object.html b/libs/python/doc/v2/reference_existing_object.html new file mode 100644 index 000000000..12e228f50 --- /dev/null +++ b/libs/python/doc/v2/reference_existing_object.html @@ -0,0 +1,180 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/reference_existing_object.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/reference_existing_object.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#reference_existing_object-spec">Class + <code>reference_existing_object</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#reference_existing_object-spec-synopsis">Class + <code>reference_existing_object</code> synopsis</a></dt> + + <dt><a href= + "#reference_existing_object-spec-metafunctions">Class + <code>reference_existing_object</code> metafunctions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="reference_existing_object-spec"></a>Class + <code>reference_existing_object</code></h3> + + <p><code>reference_existing_object</code> is a model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> + which can be used to wrap C++ functions which return a reference or + pointer to a C++ object. When the wrapped function is called, the value + referenced by its return value is not copied. A new Python object is + created which contains a pointer to the referent, and no attempt is made + to ensure that the lifetime of the referent is at least as long as that + of the corresponding Python object. Thus, it can be <font color= + "#ff0000"><b>highly dangerous</b></font> to use + <code>reference_existing_object</code> without additional lifetime + management from such models of <a href= + "CallPolicies.html">CallPolicies</a> as <a href= + "with_custodian_and_ward.html#with_custodian_and_ward-spec">with_custodian_and_ward</a>. + This class is used in the implementation of <a href= + "return_internal_reference.html#return_internal_reference-spec">return_internal_reference</a>.</p> + + <h4><a name="reference_existing_object-spec-synopsis"></a>Class + <code>reference_existing_object</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct reference_existing_object + { + template <class T> struct apply; + }; +}} +</pre> + + <h4><a name="reference_existing_object-spec-metafunctions"></a>Class + <code>reference_existing_object</code> metafunctions</h4> +<pre> +template <class T> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Requires:</b> <code>T</code> is <code>U&</code> or + <code>U*</code>for some <code>U</code>.</dt> + + <dt><b>Returns:</b> <code>typedef <a href= + "to_python_indirect.html#to_python_indirect-spec">to_python_indirect</a><T,V> + type</code>, where <code>V</code> is a class whose + static <code>execute</code> function constructs an instance + holder containing an <i>unowned</i> + <code>U*</code> pointing to the referent of the wrapped function's + return value.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <p>In C++:</p> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/return_value_policy.hpp> +#include <utility> + +// classes to wrap +struct Singleton +{ + Singleton() : x(0) {} + + int exchange(int n) // set x and return the old value + { + std::swap(n, x); + return n; + } + + int x; +}; + +Singleton& get_it() +{ + static Singleton just_one; + return just_one; +} + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(singleton) +{ + def("get_it", get_it, + return_value_policy<reference_existing_object>()); + + class_<Singleton>("Singleton") + .def("exchange", &Singleton::exchange) + ; +} +</pre> + In Python: +<pre> +>>> import singleton +>>> s1 = singleton.get_it() +>>> s2 = singleton.get_it() +>>> id(s1) == id(s2) # s1 and s2 are not the same object +0 +>>> s1.exchange(42) # but they reference the same C++ Singleton +0 +>>> s2.exchange(99) +42 +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/register_ptr_to_python.html b/libs/python/doc/v2/register_ptr_to_python.html new file mode 100644 index 000000000..5f660e18f --- /dev/null +++ b/libs/python/doc/v2/register_ptr_to_python.html @@ -0,0 +1,162 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<link rel="stylesheet" type="text/css" href="../boost.css"> +<title>Boost.Python - <register_ptr_to_python.hpp></title> +</head> +<body link="#0000ff" vlink="#800080"> +<table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">Header <register_ptr_to_python.hpp></h2> + </td> + </tr> +</table> +<hr> +<h2>Contents</h2> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#functions">Functions</a></dt> + <dl class="page-index"> + <dt><a href="#register_ptr_to_python-spec">register_ptr_to_python</a></dt> + </dl> + + <dt><a href="#examples">Example(s)</a></dt> + +</dl> +<hr> +<h2><a name="introduction"></a>Introduction</h2> +<p> + <code><boost/python/register_ptr_to_python.hpp></code> + supplies <code>register_ptr_to_python</code>, a function template + which registers a conversion for smart pointers to Python. The + resulting Python object holds a copy of the converted smart pointer, + but behaves as though it were a wrapped copy of the pointee. If + the pointee type has virtual functions and the class representing + its dynamic (most-derived) type has been wrapped, the Python object + will be an instance of the wrapper for the most-derived type. More than + one smart pointer type for a pointee's class can be registered. +</p> +<p> + Note that in order to convert a Python <code>X</code> object to a + <code>smart_ptr<X>&</code> (non-const reference), the embedded C++ + object must be held by <code>smart_ptr<X></code>, and that when wrapped + objects are created by calling the constructor from Python, how they are held + is determined by the <code>HeldType</code> parameter to + <code>class_<...></code> instances. +</p> + +<h2><a name="functions"></a>Functions</h2> +<pre> +<a name="register_ptr_to_python-spec">template <class P> +void register_ptr_to_python() +</pre> +<dl class="function-semantics"> + <dt><b>Requires:</b> <code>P</code> is <a href="Dereferenceable.html#Dereferenceable-concept">Dereferenceable</a>. + </dt> + <dt><b>Effects:</b> Allows conversions to-python of <code>P</code> + instances. + </dt> +</dl> + +<h2><a name="examples"></a>Example(s)</h2> + +<h3>C++ Wrapper Code</h3> + +Here is an example of a module that contains a class <code>A</code> with +virtual functions and some functions that work with +<code>boost::shared_ptr<A></code>. + +<pre> +struct A +{ + virtual int f() { return 0; } +}; + +shared_ptr<A> New() { return shared_ptr<A>( new A() ); } + +int Ok( const shared_ptr<A>& a ) { return a->f(); } + +int Fail( shared_ptr<A>& a ) { return a->f(); } + +struct A_Wrapper: A +{ + A_Wrapper(PyObject* self_): self(self_) {} + int f() { return call_method<int>(self, "f"); } + int default_f() { return A::f(); } + PyObject* self; +}; + +BOOST_PYTHON_MODULE(register_ptr) +{ + class_<A, A_Wrapper>("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; + + def("New", &New); + def("Ok", &Call); + def("Fail", &Fail); + + register_ptr_to_python< shared_ptr<A> >(); +} +</pre> + +<h3>Python Code</h3> + +<pre> +>>> from register_ptr import * +>>> a = A() +>>> Ok(a) # ok, passed as shared_ptr<A> +0 +>>> Fail(a) # passed as shared_ptr<A>&, and was created in Python! +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: bad argument type for built-in operation +>>> +>>> na = New() # now "na" is actually a shared_ptr<A> +>>> Ok(a) +0 +>>> Fail(a) +0 +>>> +</pre> + +If <code>shared_ptr<A></code> is registered as follows: + +<pre> + class_<A, A_Wrapper, shared_ptr<A> >("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; +</pre> + +There will be an error when trying to convert <code>shared_ptr<A></code> to +<code>shared_ptr<A_Wrapper></code>: + +<pre> +>>> a = New() +Traceback (most recent call last): +File "<stdin>", line 1, in ? +TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<struct A> +>>> +</pre> + +<p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 24 Jun, 2003 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> +</p> +<p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> + 2002. </i></p> +</body> +</html> + + diff --git a/libs/python/doc/v2/return_arg.html b/libs/python/doc/v2/return_arg.html new file mode 100644 index 000000000..44cd58c24 --- /dev/null +++ b/libs/python/doc/v2/return_arg.html @@ -0,0 +1,224 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/return_arg.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/return_arg.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_arg-spec">Class Template + <code>return_arg</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_arg-spec-synopsis">Class Template + <code>return_arg</code> synopsis</a></dt> + + <dt><a href="#return_arg-spec-statics">Class + <code>return_arg</code> static functions</a></dt> + </dl> + </dd> + + <dt><a href="#return_self-spec">Class Template + <code>return_self</code></a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + <code>return_arg</code> and <code>return_self</code> instantiations are + models of <a href="CallPolicies.html">CallPolicies</a> which return the + specified argument parameter (usually <code>*this</code>) of a wrapped + (member) function. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="return_arg-spec"></a>Class template + <code>return_arg</code></h3> + + <table border="1" summary="return_arg template parameters"> + <caption> + <b><code>return_arg</code> template parameters</b> + </caption> + + <tr> + <th>Parameter</th> + + <th>Requirements</th> + + <th>Description</th> + + <th>Default</th> + </tr> + + <tr> + <td><code>arg_pos</code></td> + + <td>A positive compile-time constant of type + <code>std::size_t</code>.</td> + + <td>the position of the argument to be returned.</td> + + <td>1</td> + </tr> + + <tr> + <td><code>Base</code></td> + + <td>A model of <a href="CallPolicies.html">CallPolicies</a></td> + + <td>Used for policy composition. Any <code>result_converter</code> it + supplies will be overridden by <code>return_arg</code>, but its + <code>precall</code> and <code>postcall</code> policies are composed + as described here <a href= + "CallPolicies.html#composition">CallPolicies</a>.</td> + + <td><code><a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a></code></td> + </tr> + </table> + + <h4><a name="return_arg-spec-synopsis"></a>Class template + <code>return_arg</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <size_t arg_pos=1, class Base = default_call_policies> + struct return_arg : Base + { + static PyObject* postcall(PyObject*, PyObject* result); + struct result_converter{ template <class T> struct apply; }; + template <class Sig> struct extract_return_type : mpl::at_c<Sig, arg_pos>{}; + + }; +}} +</pre> + + <h4><a name="return_arg-spec-statics"></a>Class <code>return_arg</code> + static functions</h4> +<pre> +PyObject* postcall(PyObject* args, PyObject* result); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code><a href= + "http://www.python.org/doc/2.2/api/tupleObjects.html#l2h-476">PyTuple_Check</a>(args) + != 0</code> and <code>PyTuple_Size(args) != 0</code></dt> + + <dt><b>Returns:</b> <code>PyTuple_GetItem(args,arg_pos-1)</code></dt> + </dl> + + <h3><a name="return_self-spec"></a>Class template + <code>return_self</code></h3> + + <h4>Class template <code>return_self</code> synopsis:</h4> +<pre> +namespace boost { namespace python +{ + template <class Base = default_call_policies> + struct return_self + : return_arg<1,Base> + {}; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_arg.hpp> + +struct Widget +{ + Widget() :sensitive_(true){} + bool get_sensitive() const { return sensitive_; } + void set_sensitive(bool s) { this->sensitive_ = s; } + private: + bool sensitive_; +}; + +struct Label : Widget +{ + Label() {} + + std::string get_label() const { return label_; } + void set_label(const std::string &l){ label_ = l; } + + private: + std::string label_; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(return_self_ext) +{ + class_<widget>("Widget") + .def("sensitive", &Widget::get_sensitive) + .def("sensitive", &Widget::set_sensitive, return_self<>()) + ; + + class_<Label, bases<Widget> >("Label") + .def("label", &Label::get_label) + .def("label", &Label::set_label, return_self<>()) + ; +} + + +</pre> + + <h3>Python code</h3> +<pre> +>>> from return_self_ext import * +>>> l1 = Label().label("foo").sensitive(false) +>>> l2 = Label().sensitive(false).label("foo") +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 19 July, 2003 <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> and Nikolay + Mladenov 2003. </i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/return_by_value.html b/libs/python/doc/v2/return_by_value.html new file mode 100644 index 000000000..12ca3c43f --- /dev/null +++ b/libs/python/doc/v2/return_by_value.html @@ -0,0 +1,149 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/return_by_value.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/return_by_value.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_by_value-spec">Class + <code>return_by_value</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_by_value-spec-synopsis">Class + <code>return_by_value</code> synopsis</a></dt> + + <dt><a href="#return_by_value-spec-metafunctions">Class + <code>return_by_value</code> metafunctions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="return_by_value-spec"></a>Class + <code>return_by_value</code></h3> + + <p><code>return_by_value</code> is a model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> + which can be used to wrap C++ functions returning any reference or value + type such that the return value is copied into a new Python object.</p> + + <h4><a name="return_by_value-spec-synopsis"></a>Class + <code>return_by_value</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct return_by_value + { + template <class T> struct apply; + }; +}} +</pre> + + <h4><a name="return_by_value-spec-metafunctions"></a>Class + <code>return_by_value</code> metafunctions</h4> +<pre> +template <class T> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Returns:</b> <code>typedef <a href= + "to_python_value.html#to_python_value-spec">to_python_value</a><T> + type;</code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ Module Definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_by_value.hpp> +#include <boost/python/return_value_policy.hpp> + +// classes to wrap +struct Bar { }; + +Bar global_bar; + +// functions to wrap: +Bar b1(); +Bar& b2(); +Bar const& b3(); + +// Wrapper code +using namespace boost::python; +template <class R> +void def_void_function(char const* name, R (*f)()) +{ + def(name, f, return_value_policy<return_by_value>()); +} + +BOOST_PYTHON_MODULE(my_module) +{ + class_<Bar>("Bar"); + def_void_function("b1", b1); + def_void_function("b2", b2); + def_void_function("b3", b3); +} +</pre> + + <h3>Python Code</h3> +<pre> +>>> from my_module import * +>>> b = b1() # each of these calls +>>> b = b2() # creates a brand +>>> b = b3() # new Bar object +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/return_internal_reference.html b/libs/python/doc/v2/return_internal_reference.html new file mode 100644 index 000000000..87c33f855 --- /dev/null +++ b/libs/python/doc/v2/return_internal_reference.html @@ -0,0 +1,230 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/return_internal_reference.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/return_internal_reference.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_internal_reference-spec">Class Template + <code>return_internal_reference</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_internal_reference-spec-synopsis">Class + Template <code>return_internal_reference</code> + synopsis</a></dt> + + <dt><a href="#return_internal_reference-spec-statics">Class + <code>return_internal_reference</code> static + functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + <code>return_internal_reference</code> instantiations are models of <a + href="CallPolicies.html">CallPolicies</a> which allow pointers and + references to objects held internally by a free or member function + argument or from the target of a member function to be returned safely + without making a copy of the referent. The default for its first template + argument handles the common case where the containing object is the + target (<code>*this</code>) of a wrapped member function. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="return_internal_reference-spec"></a>Class template + <code>return_internal_reference</code></h3> + + <table border="1" summary= + "return_internal_reference template parameters"> + <caption> + <b><code>return_internal_reference</code> template parameters</b> + </caption> + + <tr> + <th>Parameter</th> + + <th>Requirements</th> + + <th>Description</th> + + <th>Default</th> + </tr> + + <tr> + <td><code>owner_arg</code></td> + + <td>A positive compile-time constant of type + <code>std::size_t</code>.</td> + + <td>The index of the parameter which contains the object to which the + reference or pointer is being returned. If used to wrap a member + function, parameter 1 is the target object (<code>*this</code>). Note + that if the target Python object type doesn't support weak + references, a Python <code>TypeError</code> exception will be raised + when the function being wrapped is called.</td> + + <td>1</td> + </tr> + + <tr> + <td><code>Base</code></td> + + <td>A model of <a href="CallPolicies.html">CallPolicies</a></td> + + <td>Used for policy composition. Any <code>result_converter</code> it + supplies will be overridden by + <code>return_internal_reference</code>, but its <code>precall</code> + and <code>postcall</code> policies are composed as described here <a + href="CallPolicies.html#composition">CallPolicies</a>.</td> + + <td><code><a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a></code></td> + </tr> + </table> + + <h4><a name="return_internal_reference-spec-synopsis"></a>Class template + <code>return_internal_reference</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <std::size_t owner_arg = 1, class Base = default_call_policies> + struct return_internal_reference : Base + { + static PyObject* postcall(PyObject*, PyObject* result); + typedef <a href= +"reference_existing_object.html#reference_existing_object-spec">reference_existing_object</a> result_converter; + }; +}} +</pre> + + <h4><a name="return_internal_reference-spec-statics"></a>Class + <code>return_internal_reference</code> static functions</h4> +<pre> +PyObject* postcall(PyObject* args, PyObject* result); +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code><a href= + "http://www.python.org/doc/2.2/api/tupleObjects.html#l2h-476">PyTuple_Check</a>(args) + != 0</code></dt> + + <dt><b>Returns:</b> <code><a href= + "with_custodian_and_ward.html#with_custodian_and_ward_postcall-spec-statics"> + with_custodian_and_ward_postcall::postcall(args, + result)</a></code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_internal_reference.hpp> + +class Bar +{ + public: + Bar(int x) : x(x) {} + int get_x() const { return x; } + void set_x(int x) { this->x = x; } + private: + int x; +}; + +class Foo +{ + public: + Foo(int x) : b(x) {} + + // Returns an internal reference + Bar const& get_bar() const { return b; } + + private: + Bar b; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(internal_refs) +{ + class_<Bar>("Bar", init<int>()) + .def("get_x", &Bar::get_x) + .def("set_x", &Bar::set_x) + ; + + class_<Foo>("Foo", init<int>()) + .def("get_bar", &Foo::get_bar + , return_internal_reference<>()) + ; +} +</pre> + + <h3>Python code</h3> +<pre> +>>> from internal_refs import * +>>> f = Foo(3) +>>> b1 = f.get_bar() +>>> b2 = f.get_bar() +>>> b1.get_x() +3 +>>> b2.get_x() +3 +>>> b1.set_x(42) +>>> b2.get_x() +42 +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/return_opaque_pointer.html b/libs/python/doc/v2/return_opaque_pointer.html new file mode 100644 index 000000000..52d8396e8 --- /dev/null +++ b/libs/python/doc/v2/return_opaque_pointer.html @@ -0,0 +1,192 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/return_opaque_pointer.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/return_opaque_pointer.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_opaque_pointer-spec">Class + <code>return_opaque_pointer</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_opaque_pointer-spec-synopsis">Class + <code>return_opaque_pointer</code> synopsis</a></dt> + + <dt><a href="#return_opaque_pointer-spec-metafunctions">Class + <code>return_opaque_pointer</code> metafunctions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + + <dt><a href="#see-also">See Also</a></dt> + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="return_opaque_pointer-spec"></a>Class + <code>return_opaque_pointer</code></h3> + + <p><code>return_opaque_pointer</code> is a model of + <a href="ResultConverter.html#ResultConverterGenerator-concept"> + ResultConverterGenerator</a> + which can be used to wrap C++ functions returning pointers to + undefined types such that the return value is copied into a + new Python object.</p> + <p>In addition to specifying the <code>return_opaque_pointer</code> + policy the <a href="opaque.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec"> + <code>BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</code></a> macro must be + used to define specializations for the + <a href="type_id.html#type_id-spec">type_id</a> function + on the type pointed to by returned pointer.</p> + + <h4><a name="return_opaque_pointer-spec-synopsis"></a>Class + <code>return_opaque_pointer</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + struct return_opaque_pointer + { + template <class R> struct apply; + }; +}} +</pre> + + <h4><a name="return_opaque_pointer-spec-metafunctions"></a>Class + <code>return_opaque_pointer</code> metafunctions</h4> +<pre> +template <class R> struct apply +</pre> + + <dl class="metafunction-semantics"> + <dt><b>Returns:</b> <code>typedef + detail::opaque_conversion_holder<R> + type;</code></dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ Module Definition</h3> +<pre> +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get () { return the_op; } +void use (opaque op) { + if (op != the_op) + throw std::runtime_error (std::string ("failed")); +} + +void failuse (opaque op) { + if (op == the_op) + throw std::runtime_error (std::string ("success")); +} + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(opaque_ext) +{ + bpl::def ( + "get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("use", &::use); + bpl::def ("failuse", &::failuse); +} +</pre> + + <h3>Python Code</h3> +<pre> +""" +>>> from opaque_ext import * +>>> # +>>> # Check for correct conversion +>>> use(get()) +>>> failuse(get()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> # +>>> # Check that there is no conversion from integers ... +>>> use(0) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> # +>>> # ... and from strings to opaque objects +>>> use("") +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) +</pre> + + <h2><a name="see-also"></a>See Also</h2> + <p> + <a href="opaque.html"> + opaque</a> + </p> + + <p>Revised + 28 January, 2003 + </p> + + <p><i>© Copyright 2003 Haufe Mediengruppe. All Rights + Reserved.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/return_value_policy.html b/libs/python/doc/v2/return_value_policy.html new file mode 100644 index 000000000..b02d4bc39 --- /dev/null +++ b/libs/python/doc/v2/return_value_policy.html @@ -0,0 +1,167 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/return_value_policy.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/return_value_policy.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_value_policy-spec">Class Template + <code>return_value_policy</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#return_value_policy-spec-synopsis">Class Template + <code>return_value_policy</code> synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + <code>return_value_policy</code> instantiations are simply models of <a + href="CallPolicies.html">CallPolicies</a> which are composed of a <a + href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a> + and optional <code>Base</code> <a href= + "CallPolicies.html">CallPolicies</a>. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="return_value_policy-spec"></a>Class template + <code>return_value_policy</code></h3> + + <table border="1" summary="return_value_policy template parameters"> + <caption> + <b><code>return_value_policy</code> template parameters</b> + </caption> + + <tr> + <th>Parameter</th> + + <th>Requirements</th> + + <th>Default</th> + </tr> + + <tr> + <td><a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a></td> + + <td>A model of <a href= + "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a>.</td> + </tr> + + <tr> + <td><code>Base</code></td> + + <td>A model of <a href="CallPolicies.html">CallPolicies</a></td> + + <td><code><a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a></code></td> + </tr> + </table> + + <h4><a name="return_value_policy-spec-synopsis"></a>Class template + <code>return_value_policy</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class ResultConverterGenerator, class Base = default_call_policies> + struct return_value_policy : Base + { + typedef ResultConverterGenerator result_converter; + }; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> + + <h3>C++ Module Definition</h3> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar const& get_bar() const { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_<Bar>("Bar"); + + class_<Foo>("Foo", init<int>()) + .def("get_bar", &Foo::get_bar + , return_value_policy<copy_const_reference>()) + ; +} +</pre> + + <h3>Python Code</h3> +<pre> +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/scope.html b/libs/python/doc/v2/scope.html new file mode 100644 index 000000000..54ef67e3e --- /dev/null +++ b/libs/python/doc/v2/scope.html @@ -0,0 +1,173 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/scope.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/scope.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#scope-spec">Class <code>scope</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#scope-spec-synopsis">Class <code>scope</code> + synopsis</a></dt> + + <dt><a href="#scope-spec-ctors">Class <code>scope</code> + constructors and destructor</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Defines facilities for querying and controlling the Python scope + (namespace) which will contain new wrapped classes and functions.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="scope-spec"></a>Class <code>scope</code></h3> + + <p>The <code>scope</code> class has an associated global Python + object which controls the Python namespace in which new extension + classes and wrapped functions will be defined as + attributes. Default-constructing a new <code>scope</code> object + binds it to the associated global Python object. Constructing a + <code>scope</code> object with an argument changes the associated + global Python object to the one held by the argument, until the + lifetime of the <code>scope</code> object ends, at which time the + associated global Python object reverts to what it was before the + <code>scope</code> object was constructed.</p> + + <h4><a name="scope-spec-synopsis"></a>Class <code>scope</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class scope : public <a href= +"object.html#object-spec">object</a> + { + public: + scope(scope const&); + scope(object const&); + scope(); + ~scope() + private: + void operator=(scope const&); + }; +}} +</pre> + + <h4><a name="scope-spec-ctors"></a>Class <code>scope</code> constructors + and destructor</h4> +<pre> +explicit scope(scope const& x); +explicit scope(object const& x); +</pre> + Stores a reference to the current associated scope object, and sets the + associated scope object to the one referred to by <code>x.ptr()</code>. + The <code>object</code> base class is initialized with <code>x</code>. +<pre> +scope(); +</pre> + Stores a reference to the current associated scope object. The + <code>object</code> base class is initialized with the current associated + scope object. Outside any module initialization function, the current + associated Python object is <code>None</code>. +<pre> +~scope() +</pre> + Sets the current associated Python object to the stored object. + + <h2><a name="examples"></a>Example</h2> + The following example shows how scope setting can be used to define + nested classes. + + <p>C++ Module definition:</p> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/scope.hpp> +using namespace boost::python; + +struct X +{ + void f() {} + + struct Y { int g() { return 42; } }; +}; + +BOOST_PYTHON_MODULE(nested) +{ + // add some constants to the current (module) scope + scope().attr("yes") = 1; + scope().attr("no") = 0; + + // Change the current scope + scope outer + = class_<X>("X") + .def("f", &X::f) + ; + + // Define a class Y in the current scope, X + class_<X::Y>("Y") + .def("g", &X::Y::g) + ; +} +</pre> + Interactive Python: +<pre> +>>> import nested +>>> nested.yes +1 +>>> y = nested.X.Y() +>>> y.g() +42 +</pre> + + <p>Revised 09 October, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/slice.html b/libs/python/doc/v2/slice.html new file mode 100644 index 000000000..fb6b47c7e --- /dev/null +++ b/libs/python/doc/v2/slice.html @@ -0,0 +1,246 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> + <meta name="generator" + content="HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" + content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + <title>Boost.Python - <boost/python/slice.hpp></title> +</head> +<body> +<table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tbody> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + <h2 align="center">Header <boost/python/slice.hpp></h2> + </td> + </tr> + </tbody> +</table> +<hr> +<h2>Contents</h2> +<dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + <dt><a href="#classes">Classes</a></dt> + <dd> + <dl class="page-index"> + <dt><a href="#slice-spec">Class <code>slice</code></a></dt> + <dd> + <dl class="page-index"> + <dt><a href="#slice-spec-synopsis">Class <code>slice</code> +synopsis</a></dt> + <dt><a href="#slice-spec-ctors">Class <code>slice</code> +constructors</a></dt> + <dt><a href="#slice-spec-observers">Class <code>slice</code> +observer functions</a></dt> + </dl> + </dd> + </dl> + </dd> + <dt><a href="#examples">Example(s)</a></dt> +</dl> +<hr> +<h2><a name="introduction"></a>Introduction</h2> +<p>Exposes a <a href="ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> +for the Python <a + href="http://www.python.org/doc/2.3.3/api/slice-objects.html">slice</a> +type.</p> +<h2><a name="classes"></a>Classes</h2> +<h3><a name="slice-spec"></a>Class <code>slice</code></h3> +<p>Exposes the extended slicing protocol by wrapping the built-in slice +type. The semantics of the constructors and member functions defined +below can be fully understood by reading the <a + href="ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept +definition. Since <code>slice</code> is publicly derived from <code><a + href="object.html#object-spec">object</a></code>, the public object +interface applies to <code>slice</code> instances as well.<br> +</p> +<h4><a name="slice-spec-synopsis"></a>Class <code>slice</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + class slice : public object + { + public: + slice(); // create an empty slice, equivalent to [::] + + template <typename Int1, typename Int2> + slice(Int1 start, Int2 stop); + + template <typename Int1, typename Int2, typename Int3> + slice(Int1 start, Int2 stop, Int3 step); + + // Access the parameters this slice was created with. + object start(); + object stop(); + object step(); + + // The return type of slice::get_indices() + template <typename RandomAccessIterator> + struct range + { + RandomAccessIterator start; + RandomAccessIterator stop; + int step; + }; + + template <typename RandomAccessIterator> + range<RandomAccessIterator> + get_indices( + RandomAccessIterator const& begin, + RandomAccessIterator const& end); + }; +}} +</pre> +<h4><a name="slice-spec-ctors"></a>Class <code>slice</code> +constructors<br> +</h4> +<pre>slice();<br></pre> +<dl class="function-semantics"> + <dt><b>Effects:</b> constructs a <code>slice</code> with default stop, start, and +step values. Equivalent to the slice object created as part of the Python +expression <code>base[::].</code></dt> + <dt><b>Throws:</b> nothing.</dt> +</dl> +<pre> +template <typename Int1, typename Int2> +slice(Int1 start, Int2 stop); +</pre> +<dl class="function-semantics"> + <dt><b>Requires:</b> <code>start</code>, <code>stop</code>, and <code>step</code> + are of type <code><a href="object.html#slice_nil-spec">slice_nil</a></code> + or convertible to type <code>object</code>.</dt> + <dt><b>Effects:</b> constructs a new slice with default step value +and the provided start and stop values. Equivalent to the slice +object +created by the built-in Python function <code><a + href="http://www.python.org/doc/current/lib/built-in-funcs.html#12h-62">slice(start,stop)</a></code>, +or as part of the Python expression <code>base[start:stop]</code>.</dt> + <dt><b>Throws:</b> <code>error_already_set</code> and sets a Python <code>TypeError</code> +exception if no conversion is possible from the arguments to type <code>object</code>.</dt> +</dl> +<pre> +template <typename Int1, typename Int2, typename Int3> +slice(Int1 start, Int2 stop, Int3 step); +</pre> + <dt><b>Requires:</b> <code>start</code>, <code>stop</code>, and <code>step</code> are <code>slice_nil</code> or convertible to type <code>object</code>.</dt> + <dt><b>Effects:</b> constructs a new slice with start stop and step +values. Equivalent to the slice object created +by the built-in Python function <code><a + href="http://www.python.org/doc/current/lib/built-in-funcs.html">slice(start,stop,step)</a></code>, +or as part of the Python expression <code>base[start:stop:step]</code>.</dt> + <dt><b>Throws:</b> <code>error_already_set</code> and sets a Python <code>TypeError</code> +exception if no conversion is possible from the arguments to type +object.</dt> +<h4><a name="slice-spec-observers"></a>Class <code>slice</code> +observer functions<br> +</h4> +<pre> +object slice::start() const; +object slice::stop() const; +object slice::step() const; +</pre> +<dl class="function-semantics"> + <dt><b>Effects:</b> None.</dt> + <dt><b>Throws:</b> nothing.</dt> + <dt><b>Returns:</b>the parameter that +the slice was created with. If the parameter was omitted or +slice_nil was used when the slice was created, than that parameter will +be a reference to PyNone and compare equal to a default-constructed +object. In principal, any object may be used when creating a +slice object, but in practice they are usually integers.</dt> +</dl> +<br> +<pre> +template <typename RandomAccessIterator> +slice::range<RandomAccessIterator> +slice::get_indices( + RandomAccessIterator const& begin, + RandomAccessIterator const& end) const; +</pre> +<dl class="function-semantics"> + <dt><b>Arguments:</b> A pair of STL-conforming Random Access +Iterators that form a half-open range.</dt> + <dt><b>Effects:</b> Create a RandomAccessIterator pair that defines a +fully-closed range within the [begin,end) range of its arguments. +This function translates this slice's indices while accounting for the +effects of any PyNone or negative indices, and non-singular step sizes.</dt> + <dt><b>Returns:</b> a slice::range +that has been initialized with a non-zero value of step and a pair of +RandomAccessIterators that point within the range of this functions +arguments and define a closed interval.</dt> + <dt><b>Throws:</b> <a href="definitions.html#raise">Raises</a> a Python <code>TypeError</code> exception if any of this slice's arguments +are neither references to <code>PyNone</code> nor convertible to <code>int</code>. Throws +<code>std::invalid_argument</code> if the resulting range would be empty. You +should always wrap calls to <code>slice::get_indices()</code> +within <code>try { ...; } catch (std::invalid_argument) {}</code> to +handle this case and take appropriate action.</dt> + <dt><b>Rationale</b>: closed-interval: If +an open interval were used, then for step +size other than 1, the required state for the end iterator would point +beyond the one-past-the-end position or before the beginning of the +specified range.<br> +exceptions on empty slice: It is impossible to define a closed interval +over an empty range, so some other form of error checking would have to +be used to prevent undefined behavior. In the case where the +exception is not caught, it will simply be translated to Python by the +default exception handling mechanisms. </dt> +</dl> +<h2><a name="examples"></a><b>Examples</b></h2> +<pre> +using namespace boost::python; + +// Perform an extended slice of a Python list. +// Warning: extended slicing was not supported for built-in types prior +// to Python 2.3 +list odd_elements(list l) +{ + return l[slice(_,_,2)]; +} + +// Perform a multidimensional extended slice of a Numeric.array +numeric::array even_columns(numeric::array arr) +{ + // select every other column, starting with the second, of a 2-D array. + // Equivalent to "return arr[:, 1::2]" in Python. + return arr[make_tuple( slice(), slice(1,_,2))]; +} + +// Perform a summation over a slice of a std::vector. +double partial_sum(std::vector<double> const& Foo, const slice index) +{ + slice::range<std::vector<double>::const_iterator> bounds; + try { + bounds = index.get_indices<>(Foo.begin(), Foo.end()); + } + catch (std::invalid_argument) { + return 0.0; + } + double sum = 0.0; + while (bounds.start != bounds.stop) { + sum += *bounds.start; + std::advance( bounds.start, bounds.step); + } + sum += *bounds.start; + return sum; +} +</pre> +<p>Revised 07 Febuary, 2004</p> +<p><i>© Copyright <a + href="mailto:jbrandmeyer@users.sourceforge.net">Jonathan Brandmeyer</a>, +2004. Modification, copying and redistribution of this document +is permitted under the terms and conditions of the Boost Software +License, version 1.0.<br> +</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/ssize_t.html b/libs/python/doc/v2/ssize_t.html new file mode 100644 index 000000000..cb4398bb5 --- /dev/null +++ b/libs/python/doc/v2/ssize_t.html @@ -0,0 +1,96 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> + +<html> +<head> + <meta name="generator" content= + "HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org"> + <meta http-equiv="Content-Type" content= + "text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/ssize_t.hpp></title> +</head> + +<body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png" border= + "0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href= + "../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/ssize_t.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#typdefs">Typedef</a></dt> + + <dt><a href="#macros">Constants</a></dt> + </dl> + <hr> + + <h2><a name="introduction" id= + "introduction"></a>Introduction</h2> + + <p>Python 2.5 introduces a new <tt>Py_ssize_t</tt> typedef and + two related macros (<a href= + "http://www.python.org/dev/peps/pep-0353/">PEP 353</a>). The + <tt><boost/python/ssize_t.hpp></tt> header imports these + definitions into the <tt>boost::python</tt> namespace as + <tt>ssize_t</tt>, <tt>ssize_t_max</tt>, and <tt>ssize_t_min</tt>. + Appropriate definitions are provided for backward compatibility + with previous Python versions.</p> + + <h2><a name="typedefs" id="typedefs"></a>Typedefs</h2>Imports + <tt>Py_ssize_t</tt> into the <tt>boost::python</tt> namespace if + available, or provides an appropriate typedef for backward + compatibility: + <pre> +#if PY_VERSION_HEX >= 0x02050000 +typedef Py_ssize_t ssize_t; +#else +typedef int ssize_t; +#endif +</pre> + + <h2><a name="constants" id="constants"></a>Constants</h2>Imports + <tt>PY_SSIZE_T_MAX</tt> and <tt>PY_SSIZE_T_MIN</tt> as constants + into the <tt>boost::python</tt> namespace if available, or + provides appropriate constants for backward compatibility: + <pre> +#if PY_VERSION_HEX >= 0x02050000 +ssize_t const ssize_t_max = PY_SSIZE_T_MAX; +ssize_t const ssize_t_min = PY_SSIZE_T_MIN; +#else +ssize_t const ssize_t_max = INT_MAX; +ssize_t const ssize_t_min = INT_MIN; +#endif +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 25 September, 2006 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --></p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/ralf_w_grosse_kunstleve.htm">Ralf W. + Grosse-Kunstleve</a> 2006.</i></p> +</body> +</html> diff --git a/libs/python/doc/v2/stl_iterator.html b/libs/python/doc/v2/stl_iterator.html new file mode 100644 index 000000000..ef197b0f8 --- /dev/null +++ b/libs/python/doc/v2/stl_iterator.html @@ -0,0 +1,273 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + + <title>Boost.Python - <boost/python/stl_iterator.hpp></title> + <meta name="generator" content= +"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org" > + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= +header > + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/stl_iterator.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#stl_input_iterator-spec">Class template + <code>stl_input_iterator</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#stl_input_iterator-spec-synopsis">Class + <code>stl_input_iterator</code> synopsis</a></dt> + + <dt><a href="#stl_input_iterator-spec-constructors">Class template + <code>stl_input_iterator</code> constructors</a></dt> + + <dt><a href="#stl_input_iterator-spec-modifiers">Class template + <code>stl_input_iterator</code> modifiers</a></dt> + + <dt><a href="#stl_input_iterator-spec-observers">Class template + <code>stl_input_iterator</code> observers</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Examples</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/stl_iterator.hpp></code> provides types + for creating <a href="http://www.sgi.com/tech/stl/Iterators.html">C++ + Iterators</a> from <a href="http://www.python.org/doc/current/lib/typeiter.html"> + Python iterables</a>.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="stl_input_iterator-spec"></a>Class Template + <code>stl_input_iterator</code></h3> + + <p>Instances of <code>stl_input_iterator<T></code> hold a Python + iterator and adapt it for use with STL algorithms. + <code>stl_input_iterator<T></code> satisfies the requirements for + an <a href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>. + </p> + + <table border="1" summary="stl_input_iterator template parameters"> + <tr> + <th>Template Parameter</th> + + <th>Requirements</th> + + <th>Semantics</th> + + <th>Default</th> + </tr> + + <tr> + <td><code>ValueType</code></td> + + <td><code>ValueType</code> must be CopyConstructible.</td> + + <td>Dereferencing an instance of <code>stl_input_iterator<ValueType></code> + will return an rvalue of type <code>ValueType</code>.</td> + + <td><i>None</i></td> + </tr> + </table> + + <h4><a name="stl_input_iterator-spec-synopsis"></a>Class Template stl_input_iterator + synopsis</h4> + +<pre> +namespace boost { namespace python +{ + template <class ValueType> + struct stl_input_iterator + { + typedef std::ptrdiff_t difference_type; + typedef ValueType value_type; + typedef ValueType* pointer; + typedef ValueType reference; + typedef std::input_iterator_tag iterator_category; + + stl_input_iterator(); + stl_input_iterator(<a href="object.html#object-spec">object</a> const& ob); + + stl_input_iterator& operator++(); + stl_input_iterator operator++(int); + + ValueType operator*() const; + + friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs); + friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs); + private: + <a href="object.html#object-spec">object</a> it; // For exposition only + <a href="object.html#object-spec">object</a> ob; // For exposition only + }; +}} +</pre> + + <h4> + <a name="stl_input_iterator-spec-constructors"></a>Class Template <code>stl_input_iterator</code> + constructors + </h4> + +<pre> +stl_input_iterator() +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + Creates a past-the-end input iterator, useful for signifying the end of a sequence. + </dt> + <dt><b>Postconditions:</b> <code>this</code> is past-the-end.</dt> + <dt><b>Throws:</b> Nothing.</dt> + </dl> + +<pre> +stl_input_iterator(object const& ob) +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + Calls <code>ob.attr("__iter__")()</code> and stores the resulting Python iterator + object in <code>this->it</code>. Then, calls <code>this->it.attr("next")()</code> and + stores the result in <code>this->ob</code>. If the sequence is exhausted, sets + <code>this->ob</code> to <code>object()</code>. + </dt> + + <dt><b>Postconditions:</b> <code>this</code> is a dereferenceable or past-the-end.</dt> + </dl> + + <h4> + <a name="stl_input_iterator-spec-modifiers"></a>Class Template <code>stl_input_iterator</code> + modifiers + </h4> + +<pre> +stl_input_iterator& operator++() +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + Calls <code>this->it.attr("next")()</code> and stores the result in + <code>this->ob</code>. If the sequence is exhausted, sets <code>this->ob</code> + to <code>object()</code>. + </dt> + + <dt><b>Postconditions:</b> <code>this</code> is a dereferenceable or past-the-end.</dt> + + <dt><b>Returns:</b> <code>*this</code>.</dt> + </dl> + +<pre> +stl_input_iterator operator++(int) +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + <code>stl_input_iterator tmp = *this; ++*this; return tmp;</code> + </dt> + + <dt><b>Postconditions:</b> <code>this</code> is a dereferenceable or past-the-end.</dt> + </dl> + + <h4><a name="stl_input_iterator-spec-observers"></a>Class Template<code>stl_input_iterator</code> + observers</h4> + +<pre> +ValueType operator*() const +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + Returns the current element in the sequence. + </dt> + <dt><b>Returns:</b> + <code>extract<ValueType>(this->ob);</code> + </dt> + </dl> + +<pre> +friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs) +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + Returns true if both iterators are dereferenceable or if both iterators are past-the-end, + false otherwise. + </dt> + <dt><b>Returns:</b> + <code>(lhs.ob == object()) == (rhs.ob == object())</code> + </dt> + </dl> + +<pre> +friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs) +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> + Returns false if both iterators are dereferenceable or if both iterators are past-the-end, + true otherwise. + </dt> + <dt><b>Returns:</b> + <code>!(lhs == rhs)</code> + </dt> + </dl> + + <h2><a name="examples"></a>Examples</h2> +<pre> +#include <boost/python/object.hpp> +#include <boost/python/stl_iterator.hpp> + +#include <list> + +using namespace boost::python; +std::list<int> sequence_to_int_list(object const& ob) +{ + stl_input_iterator<int> begin(ob), end; + return std::list<int>(begin, end); +} +</pre> + +<hr> + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->30 +October, 2005 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright Eric Niebler 2005.</i></p> + </body> +</html>
\ No newline at end of file diff --git a/libs/python/doc/v2/str.html b/libs/python/doc/v2/str.html new file mode 100644 index 000000000..11810d841 --- /dev/null +++ b/libs/python/doc/v2/str.html @@ -0,0 +1,237 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/str.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/str.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#str-spec">Class <code>str</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#str-spec-synopsis">Class <code>str</code> + synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> for the Python + <a href= + "http://www.python.org/dev/doc/devel/lib/string-methods.html">str</a> + type.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="str-spec"></a>Class <code>str</code></h3> + + <p>Exposes the <a href= + "http://www.python.org/dev/doc/devel/lib/string-methods.html">string + methods</a> of Python's built-in <code>str</code> type. The + semantics of the constructors and member functions defined below, + except for the two-argument constructors which construct str + objects from a range of characters, can be fully understood by + reading the <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept + definition. Since <code>str</code> is publicly derived from + <code><a href="object.html#object-spec">object</a></code>, the + public object interface applies to <code>str</code> instances as + well.</p> + + <h4><a name="str-spec-synopsis"></a>Class <code>str</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class str : public object + { + public: + str(); // new str + + str(char const* s); // new str + + str(char const* start, char const* finish); // new str + str(char const* start, std::size_t length); // new str + + template <class T> + explicit str(T const& other); + + str capitalize() const; + + template <class T> + str center(T const& width) const; + + template<class T> + long count(T const& sub) const; + template<class T1, class T2> + long count(T1 const& sub,T2 const& start) const; + template<class T1, class T2, class T3> + long count(T1 const& sub,T2 const& start, T3 const& end) const; + + object decode() const; + template<class T> + object decode(T const& encoding) const; + template<class T1, class T2> + object decode(T1 const& encoding, T2 const& errors) const; + + object encode() const; + template <class T> + object encode(T const& encoding) const; + template <class T1, class T2> + object encode(T1 const& encoding, T2 const& errors) const; + + template <class T> + bool endswith(T const& suffix) const; + template <class T1, class T2> + bool endswith(T1 const& suffix, T2 const& start) const; + template <class T1, class T2, class T3> + bool endswith(T1 const& suffix, T2 const& start, T3 const& end) const; + + str expandtabs() const; + template <class T> + str expandtabs(T const& tabsize) const; + + template <class T> + long find(T const& sub) const; + template <class T1, class T2> + long find(T1 const& sub, T2 const& start) const; + template <class T1, class T2, class T3> + long find(T1 const& sub, T2 const& start, T3 const& end) const; + + template <class T> + long index(T const& sub) const; + template <class T1, class T2> + long index(T1 const& sub, T2 const& start) const; + template <class T1, class T2, class T3> + long index(T1 const& sub, T2 const& start, T3 const& end) const; + + bool isalnum() const; + bool isalpha() const; + bool isdigit() const; + bool islower() const; + bool isspace() const; + bool istitle() const; + bool isupper() const; + + template <class T> + str join(T const& sequence) const; + + template <class T> + str ljust(T const& width) const; + + str lower() const; + str lstrip() const; + + template <class T1, class T2> + str replace(T1 const& old, T2 const& new_) const; + template <class T1, class T2, class T3> + str replace(T1 const& old, T2 const& new_, T3 const& maxsplit) const; + + template <class T> + long rfind(T const& sub) const; + template <class T1, class T2> + long rfind(T1 const& sub, T2 const& start) const; + template <class T1, class T2, class T3> + long rfind(T1 const& sub, T2 const& start, T3 const& end) const; + + template <class T> + long rindex(T const& sub) const; + template <class T1, class T2> + long rindex(T1 const& sub, T2 const& start) const; + template <class T1, class T2, class T3> + long rindex(T1 const& sub, T2 const& start, T3 const& end) const; + + template <class T> + str rjust(T const& width) const; + + str rstrip() const; + + list split() const; + template <class T> + list split(T const& sep) const; + template <class T1, class T2> + list split(T1 const& sep, T2 const& maxsplit) const; + + list splitlines() const; + template <class T> + list splitlines(T const& keepends) const; + + template <class T> + bool startswith(T const& prefix) const; + template <class T1, class T2> + bool startswidth(T1 const& prefix, T2 const& start) const; + template <class T1, class T2, class T3> + bool startswidth(T1 const& prefix, T2 const& start, T3 const& end) const; + + str strip() const; + str swapcase() const; + str title() const; + + template <class T> + str translate(T const& table) const; + template <class T1, class T2> + str translate(T1 const& table, T2 const& deletechars) const; + + str upper() const; + }; +}} +</pre> + + <h2><a name="examples"></a>Example</h2> +<pre> +using namespace boost::python; +str remove_angle_brackets(str x) +{ + return x.strip('<').strip('>'); +} +</pre> + + <p>Revised 3 October, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/to_python_converter.html b/libs/python/doc/v2/to_python_converter.html new file mode 100644 index 000000000..81b61d252 --- /dev/null +++ b/libs/python/doc/v2/to_python_converter.html @@ -0,0 +1,227 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - + <boost/python/to_python_converter.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/to_python_converter.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_converter-spec">Class Template + <code>to_python_converter</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_converter-spec-synopsis">Class Template + <code>to_python_converter</code> synopsis</a></dt> + + <dt><a href="#to_python_converter-spec-ctors">Class Template + <code>to_python_converter</code> constructor</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + <code>to_python_converter</code> registers a conversion from objects of a + given C++ type into a Python object. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="to_python_converter-spec"></a>Class template + <code>to_python_converter</code></h3> + <code>to_python_converter</code> adds a wrapper around a static member + function of its second template parameter, handling low-level details + such as insertion into the converter registry. + + <table border="1" summary="to_python_converter template parameters"> + <caption> + <b><code>to_python_converter</code> template parameters</b><br> + In the table below, <b><code>x</code></b> denotes an object of type + <code>T</code> + </caption> + + <tr> + <th>Parameter</th> + + <th>Requirements</th> + + <th>Description</th> + </tr> + + <tr> + <td><code>T</code></td> + + <td> + </td> + + <td>The C++ type of the source object in the conversion</td> + </tr> + + <tr> + <td><code>Conversion</code></td> + + <td> + <code>PyObject* p = Conversion::convert(x)</code>,<br> + if <code>p == 0</code>, <code><a href= + "http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code>.</td> + + <td>A class type whose static member function <code>convert</code> + does the real work of the conversion.</td> + </tr> + <tr> + <td><code>bool has_get_pytype = false</code></td> + + <td> + <code>PyTypeObject const * p = Conversion::get_pytype() </code>.</td> + + <td><b>Optional member</b> - if <code>Conversion</code> has <code>get_pytype</code> member supply + <code>true</code> for this parameters. + If present <code>get_pytype</code> is used to document the return type + of functions using this conversion. The <code>get_pytype</code> may be implemented + using the classes and functions + from <a href="pytype_function.html"><code>pytype_function.hpp</code></a> + <b>NOTE :</b> For backward compatibility this parameter may be passed after + checking if <code>BOOST_PYTHON_SUPPORTS_PY_SIGNATURES</code> is defined (see + <a href="pytype_function.html#examples">here</a>). + </td> + </tr> + </table> + + <h4><a name="to_python_converter-spec-synopsis"></a>Class template + <code>to_python_converter</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T, class Conversion, bool convertion_has_get_pytype_member=false> + struct to_python_converter + { + to_python_converter(); + }; +}} +</pre> + + <h4><a name="to_python_converter-spec-ctors"></a>Class template + <code>to_python_converter</code> constructor</h4> +<pre> +to_python_converter(); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Registers a to_python converter which uses + <code>Conversion::convert()</code> to do its work.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + This example presumes that someone has implemented the standard <a href= + "http://www.python.org/doc/2.2/ext/dnt-basics.html">noddy example + module</a> from the Python documentation, and placed the corresponding + declarations in <code>"noddy.h"</code>. Because + <code>noddy_NoddyObject</code> is the ultimate trivial extension type, + the example is a bit contrived: it wraps a function for which all + information is contained in the <i>type</i> of its return value. + + <h3>C++ module definition</h3> +<pre> +#include <boost/python/reference.hpp> +#include <boost/python/module.hpp> +#include "noddy.h" + +struct tag {}; +tag make_tag() { return tag(); } + +using namespace boost::python; + +struct tag_to_noddy +{ + static PyObject* convert(tag const& x) + { + return PyObject_New(noddy_NoddyObject, &noddy_NoddyType); + } + static PyTypeObject const* get_pytype() + { + return &noddy_NoddyType; + } +}; + +BOOST_PYTHON_MODULE(to_python_converter) +{ + def("make_tag", make_tag); + to_python_converter<tag, tag_to_noddy, true>(); //"true" because tag_to_noddy has member get_pytype +} +</pre> + + <h3>Python code</h3> +<pre> +>>> import to_python_converter +>>> def always_none(): +... return None +... +>>> def choose_function(x): +... if (x % 2 != 0): +... return to_python_converter.make_tag +... else: +... return always_none +... +>>> a = [ choose_function(x) for x in range(5) ] +>>> b = [ f() for f in a ] +>>> type(b[0]) +<type 'NoneType'> +>>> type(b[1]) +<type 'Noddy'> +>>> type(b[2]) +<type 'NoneType'> +>>> type(b[3]) +<type 'Noddy'> +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 11 June, 2007 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/to_python_indirect.html b/libs/python/doc/v2/to_python_indirect.html new file mode 100644 index 000000000..17e0a826c --- /dev/null +++ b/libs/python/doc/v2/to_python_indirect.html @@ -0,0 +1,196 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/to_python_indirect.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/to_python_indirect.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a> + + + <dt><a href="#classes">Classes</a> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_indirect-spec">Class Template <code>to_python_indirect</code></a> + + <dd> + <dl class="page-index"> + + <dt><a href="#to_python_indirect-spec-synopsis">Class Template + <code>to_python_indirect</code> synopsis</a> + + <dt><a href="#to_python_indirect-spec-observers">Class Template + <code>to_python_indirect</code> observer functions</a> + + <dt><a href="#to_python_indirect-spec-statics">Class Template + <code>to_python_indirect</code> static functions</a> + </dl> + </dl> + + <dt><a href="#examples">Example</a> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <code><boost/python/to_python_indirect.hpp></code> supplies + a way to construct new Python objects that hold wrapped C++ class + instances via a pointer or smart pointer. + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="to_python_indirect-spec"></a>Class template <code>to_python_indirect</code></h3> + <p>Class template <code>to_python_indirect</code> converts objects +of its first argument type to python as extension class instances, using the ownership policy provided by its 2nd argument. + + <p> + + + <table border="1" summary="to_python_indirect template parameters"> + <caption> + <b><code>to_python_indirect</code> Requirements</b><br> + + In the table below, <b><code>x</code></b> denotes an object of + type <code>T</code>, <b><code>h</code></b> denotes an + object of type + <code>boost::python::objects::instance_holder*</code>, and + <b><code>p</code></b> denotes an object of type + <code>U*</code>. + + </caption> + <tr> + <th>Parameter + + <th>Requirements + + <th>Description + + <tr> + <td><code>T</code> + + <td>Either <code>U</code> <i>cv</i><code>&</code> + (where <i>cv</i> is any optional cv-qualification) or a <a + href="Dereferenceable.html">Dereferenceable</a> type such that + <code>*x</code> is convertible to <code>U const&</code>, where + <code>U</code> is a class type. + + <td>A type deferencing a C++ class exposed to Python using + class template <code><a + href="class.html#class_-spec">class_</a></code>. + + <tr> + <td><code>MakeHolder</code> + + <td>h = MakeHolder::execute(p); + + <td>A class whose static <code>execute()</code> creates an + <code>instance_holder</code>. + + </table> + + Instantiations of <code>to_python_indirect</code> are models of <a + href="ResultConverter.html#ResultConverter-concept">ResultConverter</a>. + + + <h4><a name="to_python_indirect-spec-synopsis"></a>Class template <code>to_python_indirect</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T, class MakeHolder> + struct to_python_indirect + { + static bool convertible(); + PyObject* operator()(T ptr_or_reference) const; + private: + static PyTypeObject* type(); + }; +}} +</pre> + + <h4><a name="to_python_indirect-spec-observers"></a>Class template <code>to_python_indirect</code> observers</h4> +<pre> +PyObject* operator()(T x) const; +</pre> + + <dl class="function-semantics"> + + <dt><b>Requires:</b> <code>x</code> refers to an object (if it + is a pointer type, it is non-null). <code>convertible() == + true</code>. + + <dt><b>Effects:</b> Creates an appropriately-typed Boost.Python + extension class instance, uses <code>MakeHolder</code> to create + an <code>instance_holder</code> from <code>x</code>, installs + the <code>instance_holder</code> in the new extension class + instance, and returns a pointer to it. + + </dl> + + + <h4><a name="to_python_indirect-spec-statics"></a>Class template <code>to_python_indirect</code> statics</h4> +<pre> +bool convertible(); +</pre> + + <dt><b>Effects:</b> Returns <code>true</code> iff any module has + registered a Python type corresponding to <code>U</code>. + + <h2><a name="examples"></a>Example</h2> + +This example replicates the functionality of <a +href="reference_existing_object.html#reference_existing_object-spec">reference_existing_object</a>, +but without some of the compile-time error checking. + + +<pre> + +struct make_reference_holder +{ + typedef boost::python::objects::instance_holder* result_type; + template <class T> + static result_type execute(T* p) + { + return new boost::python::objects::pointer_holder<T*, T>(p); + } +}; + +struct reference_existing_object +{ + // metafunction returning the <a href="ResultConverter.html#ResultConverter-concept">ResultConverter</a> + template <class T> + struct apply + { + typedef boost::python::to_python_indirect<T,make_reference_holder> type; + }; +}; +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> Distributed + under the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/doc/v2/to_python_value.html b/libs/python/doc/v2/to_python_value.html new file mode 100644 index 000000000..3ba0044d1 --- /dev/null +++ b/libs/python/doc/v2/to_python_value.html @@ -0,0 +1,103 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/to_python_value.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header + <boost/python/to_python_value.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#classes">Classes</a> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_value-spec">Class + <code>to_python_value</code></a> + + <dd> + <dl class="page-index"> + <dt><a href="#to_python_value-spec-synopsis">Class template + <code>to_python_value</code> synopsis</a> + + <dt><a href="#to_python_value-spec-observers">Class template + <code>to_python_value</code> observer functions</a> + </dl> + </dl> + + </dl> + <hr> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="to_python_value-spec"></a>Class template + <code>to_python_value</code></h3> + + <p><code>to_python_value</code> is a model of <a href= + "ResultConverter.html#ResultConverter-concept">ResultConverter</a> + which copies its argument into a new Python object. + + <h4><a name="to_python_value-spec-synopsis"></a>Class + <code>to_python_value</code> synopsis</h4> +<pre> +namespace boost { namespace python +{ + template <class T> + struct to_python_value + { + typedef typename <a href="../../../type_traits/index.html#transformations">add_reference</a>< + typename <a href="../../../type_traits/index.html#transformations">add_const</a><T>::type + >::type argument_type; + + static bool convertible(); + PyObject* operator()(argument_type) const; + }; +}} +</pre> + + <h4><a name="to_python_value-spec-observers"></a>Class + <code>to_python_value</code> observers</h4> +<pre> +static bool convertible(); +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>true</code> iff a converter has been registered which can convert <code>T</code> to python by-value. + </dl> + +<pre> +PyObject* operator()(argument_type x) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>convertible() == true</code> + <dt><b>Effects:</b> converts <code>x</code> to python + <dt><b>Returns:</b> the resulting Python object iff a converter for <code>T</code> has been registered, <code>0</code> otherwise. + </dl> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> Distributed under the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/doc/v2/tuple.html b/libs/python/doc/v2/tuple.html new file mode 100644 index 000000000..e90244f3e --- /dev/null +++ b/libs/python/doc/v2/tuple.html @@ -0,0 +1,139 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/tuple.hpp></title> + </head> + + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3> + </td> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <boost/python/tuple.hpp></h2> + </td> + </tr> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#tuple-spec">Class <code>tuple</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#tuple-spec-synopsis">Class <code>tuple</code> + synopsis</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#make_tuple-spec"><code>make_tuple</code></a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>Exposes a <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> for the Python + <a href= + "http://www.python.org/doc/current/tut/node7.html#SECTION007300000000000000000"> + tuple</a> type.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="tuple-spec"></a>Class <code>tuple</code></h3> + + <p>Exposes the interface of Python's built-in <code>tuple</code> type. + The semantics of the constructors and member functions defined below can + be fully understood by reading the <a href= + "ObjectWrapper.html#TypeWrapper-concept">TypeWrapper</a> concept + definition. Since <code>tuple</code> is publicly derived from <code><a + href="object.html#object-spec">object</a></code>, the public object + interface applies to <code>tuple</code> instances as well.</p> + + <h4><a name="tuple-spec-synopsis"></a>Class <code>tuple</code> + synopsis</h4> +<pre> +namespace boost { namespace python +{ + class tuple : public object + { + // tuple() -> an empty tuple + tuple(); + + // tuple(sequence) -> tuple initialized from sequence's items + template <class T> + explicit tuple(T const& sequence) + }; +}} +</pre> + + <h2><a name="functions"></a>Functions</h2> + + <h3><a name="make_tuple-spec"></a><code>make_tuple</code></h3> +<pre> +namespace boost { namespace python +{ + tuple make_tuple(); + + template <class A0> + tuple make_tuple(A0 const& a0); + + template <class A0, class A1> + tuple make_tuple(A0 const& a0, A1 const& a1); + ... + template <class A0, class A1,...class A<i>n</i>> + tuple make_tuple(A0 const& a0, A1 const& a1,...A<i>n</i> const& a<i>n</i>); +}} +</pre> + Constructs a new tuple object composed of <code>object(a0), + object(a0),...object(a<i>n</i>)</code>. + + <h2><a name="examples"></a>Example</h2> +<pre> +using namespace boost::python; +tuple head_and_tail(object sequence) +{ + return make_tuple(sequence[0],sequence[-1]); +} +</pre> + + <p>Revised 03 October, 2002</p> + + <p><i>© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002.</i></p> + </body> +</html> + diff --git a/libs/python/doc/v2/type_id.html b/libs/python/doc/v2/type_id.html new file mode 100644 index 000000000..570846741 --- /dev/null +++ b/libs/python/doc/v2/type_id.html @@ -0,0 +1,224 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content= + "text/html; charset=iso-8859-1"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <boost/python/type_id.hpp></title> + + <style type="text/css"> + p.c4 {font-style: italic} + span.c3 {color: #ff0000} + h2.c2 {text-align: center} + h1.c1 {text-align: center} +</style> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png" border= + "0"></a></h3> + + <td valign="top"> + <h1 class="c1"><a href="../index.html">Boost.Python</a></h1> + + <h2 class="c2">Header <boost/python/type_id.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#type_info-spec">Class <code>type_info</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#type_info-spec-synopsis">Class + <code>type_info</code> synopsis</a></dt> + + <dt><a href="#type_infospec-ctors">Class <code>type_info</code> + constructor</a></dt> + + <dt><a href="#type_infospec-comparisons">Class + <code>type_info</code> comparison functions</a></dt> + + <dt><a href="#type_infospec-observers">Class + <code>type_info</code> observer functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#functions">Functions</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#type_id-spec">type_id</a></dt> + </dl> + </dd> + + <dt><a href="#examples">Example</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p><code><boost/python/type_id.hpp></code> provides types and + functions for runtime type identification like those of of + <code><typeinfo></code>. It exists mostly to work around certain + compiler bugs and platform-dependent interactions with shared + libraries.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="type_info-spec"></a>Class <code>type_info</code></h3> + + <p><code>type_info</code> instances identify a type. As + <code>std::type_info</code> is specified to (but unlike its + implementation in some compilers), <code>boost::python::type_info</code> + never represents top-level references or cv-qualification (see section + 5.2.8 in the C++ standard). Unlike <code>std::type_info</code>, + <code>boost::python::type_info</code> instances are copyable, and + comparisons always work reliably across shared library boundaries.</p> + + <h4><a name="type_info-spec-synopsis"></a>Class type_info synopsis</h4> +<pre> +namespace boost { namespace python +{ + class type_info : <a href= +"../../../utility/operators.htm#totally_ordered1">totally_ordered</a><type_info> + { + public: + // constructor + type_info(std::type_info const& = typeid(void)); + + // comparisons + bool operator<(type_info const& rhs) const; + bool operator==(type_info const& rhs) const; + + // observers + char const* name() const; + }; +}} +</pre> + + <h4><a name="type_infospec-ctors">Class <code>type_info</code> + constructor</a></h4> +<pre> +type_info(std::type_info const& = typeid(void)); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> constructs a <code>type_info</code> object which + identifies the same type as its argument.</dt> + + <dt><b>Rationale:</b> Since it is occasionally necessary to make an + array of <code>type_info</code> objects a benign default argument is + supplied. <span class="c3"><b>Note:</b></span> this constructor does + <i>not</i> correct for non-conformance of compiler + <code>typeid()</code> implementations. See <code><a href= + "#type_id-spec">type_id</a></code>, below.</dt> + </dl> + + <h4><a name="type_infospec-comparisons">Class <code>type_info</code> + comparisons</a></h4> +<pre> +bool operator<(type_info const& rhs) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> yields a total order over <code>type_info</code> + objects.</dt> + </dl> +<pre> +bool operator==(type_info const& rhs) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>true</code> iff the two values describe the + same type.</dt> + </dl> + + <dl class="function-semantics"> + <dt><b>Note:</b> The use of <code><a href= + "../../../utility/operators.htm#totally_ordered1">totally_ordered</a><type_info></code> + as a private base class supplies operators <code><=</code>, + <code>>=</code>, <code>></code>, and <code>!=</code></dt> + </dl> + + <h4><a name="type_infospec-observers">Class <code>type_info</code> + observers</a></h4> +<pre> +char const* name() const; +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> The result of calling <code>name()</code> on the + argument used to construct the object.</dt> + </dl> + + <h2><a name="functions"></a>Functions</h2> +<pre> +std::ostream& operator<<(std::ostream&s, type_info const&x); +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> Writes a description of the type described by to + <code>x</code> into <code>s</code>.</dt> + + <dt><b>Rationale:</b> Not every C++ implementation provides a truly + human-readable <code>type_info::name()</code> string, but for some we + may be able to decode the string and produce a reasonable + representation.</dt> + </dl> +<pre> +<a name="type_id-spec">template <class T> type_info type_id</a>() +</pre> + + <dl class="function-semantics"> + <dt><b>Returns:</b> <code>type_info(typeid(T))</code></dt> + + <dt><b>Note:</b> On some non-conforming C++ implementations, the code + is not actually as simple as described above; the semantics are + adjusted to work <i>as-if</i> the C++ implementation were + conforming.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> + The following example, though silly, illustrates how the + <code>type_id</code> facility might be used +<pre> +#include <boost/python/type_id.hpp> + +// Returns true iff the user passes an int argument +template <class T> +bool is_int(T x) +{ + using boost::python::type_id; + return type_id<T>() == type_id<int>(); +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + + <p class="c4">© Copyright <a href= + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a> 2002. Distributed under the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt)< + + </body> +</html> + diff --git a/libs/python/doc/v2/with_custodian_and_ward.html b/libs/python/doc/v2/with_custodian_and_ward.html new file mode 100644 index 000000000..b8e2a498d --- /dev/null +++ b/libs/python/doc/v2/with_custodian_and_ward.html @@ -0,0 +1,370 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Cygwin (vers 1st February 2003), see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + <title> + Boost.Python - <boost/python/with_custodian_and_ward.hpp> + </title> + </head> + <body> + <table border="0" cellpadding="7" cellspacing="0" width="100%" + summary="header"> + <tr> + <td valign="top" width="300"> + <h3> + <a href="../../../../index.htm"><img height="86" width="277" + alt="C++ Boost" src="../../../../boost.png" border="0"> + </a> + </h3> + </td> + <td valign="top"> + <h1 align="center"> + <a href="../index.html">Boost.Python</a> + </h1> + <h2 align="center"> + Header <boost/python/with_custodian_and_ward.hpp> + </h2> + </td> + </tr> + </table> + <hr> + <h2> + Contents + </h2> + <dl class="page-index"> + <dt> + <a href="#introduction">Introduction</a> + </dt> + <dt> + <a href="#classes">Classes</a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#with_custodian_and_ward-spec">Class Template + <code>with_custodian_and_ward</code></a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href="#with_custodian_and_ward-spec-synopsis">Class + Template <code>with_custodian_and_ward</code> synopsis</a> + </dt> + <dt> + <a href="#with_custodian_and_ward-spec-statics">Class + <code>with_custodian_and_ward</code> static functions</a> + </dt> + </dl> + </dd> + <dt> + <a href="#with_custodian_and_ward_postcall-spec">Class Template + <code>with_custodian_and_ward_postcall</code></a> + </dt> + <dd> + <dl class="page-index"> + <dt> + <a href= + "#with_custodian_and_ward_postcall-spec-synopsis">Class + Template <code>with_custodian_and_ward_postcall</code> + synopsis</a> + </dt> + <dt> + <a href= + "#with_custodian_and_ward_postcall-spec-statics">Class + <code>with_custodian_and_ward_postcall</code> static + functions</a> + </dt> + </dl> + </dd> + </dl> + </dd> + <dt> + <a href="#examples">Example</a> + </dt> + </dl> + <hr> + <h2> + <a name="introduction">Introduction</a> + </h2>This header provides facilities for establishing a lifetime + dependency between two of a function's Python argument or result objects. + The <i>ward</i> object will not be destroyed until after the custodian as + long as the <i>custodian</i> object supports <a href= + "http://www.python.org/doc/current/lib/module-weakref.html">weak + references</a> (Boost.Python extension classes all support weak + references). If the <i>custodian</i> object does not support weak + references and is not <code>None</code>, an appropriate exception will be + thrown. The two class templates <code>with_custodian_and_ward</code> and + <code>with_custodian_and_ward_postcall</code> differ in the point at + which they take effect. + <p> + In order to reduce the chance of inadvertently creating dangling + pointers, the default is to do lifetime binding <i>before</i> the + underlying C++ object is invoked. However, before invocation the result + object is not available, so + <code>with_custodian_and_ward_postcall</code> is provided to bind + lifetimes after invocation. Also, if a C++ exception is thrown after + <code>with_custodian_and_ward<>::precall</code> but before the + underlying C++ object actually stores a pointer, the lifetime of the + custodian and ward objects will be artificially bound together, so one + might choose <code>with_custodian_and_ward_postcall</code> instead, + depending on the semantics of the function being wrapped. + </p> + <p> + Please note that this is <i>not</i> the appropriate tool to use when + wrapping functions which <b>transfer ownership</b> of a raw pointer + across the function-call boundary. Please see the <a href= + "faq.html#ownership">FAQ</a> if you want to do that. + </p> + <h2> + <a name="classes"></a>Classes + </h2> + <h3> + <a name="with_custodian_and_ward-spec"></a>Class template + <code>with_custodian_and_ward</code> + </h3> + <table border="1" summary="with_custodian_and_ward template parameters"> + <caption> + <b><code>with_custodian_and_ward</code> template parameters</b> + </caption> + <tr> + <th> + Parameter + </th> + <th> + Requirements + </th> + <th> + Description + </th> + <th> + Default + </th> + </tr> + <tr> + <td> + <code>custodian</code> + </td> + <td> + A positive compile-time constant of type <code>std::size_t</code>. + </td> + <td> + The 1-based index of the parameter which is the dependency in the + lifetime relationship to be established. If used to wrap a member + function, parameter 1 is the target object (<code>*this</code>). + Note that if the target Python object type doesn't support weak + references, a Python <code>TypeError</code> exception will be + raised when the C++ object being wrapped is called. + </td> + </tr> + <tr> + <td> + <code>ward</code> + </td> + <td> + A positive compile-time constant of type <code>std::size_t</code>. + </td> + <td> + The 1-based index of the parameter which is the dependent in the + lifetime relationship to be established. If used to wrap a member + function, parameter 1 is the target object (<code>*this</code>). + </td> + </tr> + <tr> + <td> + <code>Base</code> + </td> + <td> + A model of <a href="CallPolicies.html">CallPolicies</a> + </td> + <td> + Used for <a href="CallPolicies.html#composition">policy + composition</a>. + </td> + <td> + <code><a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a></code> + </td> + </tr> + </table> + <h4> + <a name="with_custodian_and_ward-spec-synopsis"></a>Class template + <code>with_custodian_and_ward</code> synopsis + </h4> + <pre> +namespace boost { namespace python +{ + template <std::size_t custodian, std::size_t ward, class Base = default_call_policies> + struct with_custodian_and_ward : Base + { + static bool precall(PyObject* args); + }; +}} +</pre> + <h4> + <a name="with_custodian_and_ward-spec-statics"></a>Class + <code>with_custodian_and_ward</code> static functions + </h4> + <pre> +bool precall(PyObject* args); +</pre> + <dl class="function-semantics"> + <dt> + <b>Requires:</b> <code><a href= + "http://www.python.org/doc/2.2/api/tupleObjects.html#l2h-476">PyTuple_Check</a>(args) + != 0</code> + </dt> + <dt> + <b>Effects:</b> Makes the lifetime of the argument indicated by + <code>ward</code> dependent on the lifetime of the argument indicated + by <code>custodian</code>. + </dt> + <dt> + <b>Returns:</b> <code>false</code> and <code><a href= + "http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code> + upon failure, <code>true</code> otherwise. + </dt> + </dl><!-- xxxxxx --> + <h3> + <a name="with_custodian_and_ward_postcall-spec"></a>Class template + <code>with_custodian_and_ward_postcall</code> + </h3> + <table border="1" summary= + "with_custodian_and_ward_postcall template parameters"> + <caption> + <b><code>with_custodian_and_ward_postcall</code> template + parameters</b> + </caption> + <tr> + <th> + Parameter + </th> + <th> + Requirements + </th> + <th> + Description + </th> + <th> + Default + </th> + </tr> + <tr> + <td> + <code>custodian</code> + </td> + <td> + A compile-time constant of type <code>std::size_t</code>. + </td> + <td> + The index of the parameter which is the dependency in the lifetime + relationship to be established. Zero indicates the result object; 1 + indicates the first argument. If used to wrap a member function, + parameter 1 is the target object (<code>*this</code>). Note that if + the target Python object type doesn't support weak references, a + Python <code>TypeError</code> exception will be raised when the C++ + object being wrapped is called. + </td> + </tr> + <tr> + <td> + <code>ward</code> + </td> + <td> + A compile-time constant of type <code>std::size_t</code>. + </td> + <td> + The index of the parameter which is the dependent in the lifetime + relationship to be established. Zero indicates the result object; 1 + indicates the first argument. If used to wrap a member function, + parameter 1 is the target object (<code>*this</code>). + </td> + </tr> + <tr> + <td> + <code>Base</code> + </td> + <td> + A model of <a href="CallPolicies.html">CallPolicies</a> + </td> + <td> + Used for <a href="CallPolicies.html#composition">policy + composition</a>. + </td> + <td> + <code><a href= + "default_call_policies.html#default_call_policies-spec">default_call_policies</a></code> + </td> + </tr> + </table> + <h4> + <a name="with_custodian_and_ward_postcall-spec-synopsis"></a>Class + template <code>with_custodian_and_ward_postcall</code> synopsis + </h4> + <pre> +namespace boost { namespace python +{ + template <std::size_t custodian, std::size_t ward, class Base = default_call_policies> + struct with_custodian_and_ward_postcall : Base + { + static PyObject* postcall(PyObject* args, PyObject* result); + }; +}} +</pre> + <h4> + <a name="with_custodian_and_ward_postcall-spec-statics"></a>Class + <code>with_custodian_and_ward_postcall</code> static functions + </h4> + <pre> +PyObject* postcall(PyObject* args, PyObject* result); +</pre> + <dl class="function-semantics"> + <dt> + <b>Requires:</b> <code><a href= + "http://www.python.org/doc/2.2/api/tupleObjects.html#l2h-476">PyTuple_Check</a>(args) + != 0</code>, <code>result != 0</code>. + </dt> + <dt> + <b>Effects:</b> Makes the lifetime of the object indicated by + <code>ward</code> dependent on the lifetime of the object indicated + by <code>custodian</code>. + </dt> + <dt> + <b>Returns:</b> <code>0</code> and <code><a href= + "http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code> + upon failure, <code>true</code> otherwise. + </dt> + </dl> + <h2> + <a name="examples"></a>Example + </h2>The following example shows how + <code>with_custodian_and_ward_postcall</code> is used by the library to + implement <code><a href= + "return_internal_reference.html#return_internal_reference-spec">return_internal_reference</a></code> + + <pre> +template <std::size_t owner_arg = 1, class Base = default_call_policies> +struct return_internal_reference + : with_custodian_and_ward_postcall<0, owner_arg, Base> +{ + typedef <a href= +"reference_existing_object.html#reference_existing_object-spec">reference_existing_object</a> result_converter; +}; +</pre> + <p> + Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 13 November, 2002 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + </p> + <p> + <i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2002. </i> + </p> + </body> +</html> diff --git a/libs/python/doc/v2/wrapper.html b/libs/python/doc/v2/wrapper.html new file mode 100644 index 000000000..06239754a --- /dev/null +++ b/libs/python/doc/v2/wrapper.html @@ -0,0 +1,238 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <meta name="generator" content="HTML Tidy, see www.w3.org"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <link rel="stylesheet" type="text/css" href="../boost.css"> + + <title>Boost.Python - <wrapper.hpp></title> + + <table border="0" cellpadding="7" cellspacing="0" width="100%" summary= + "header"> + <tr> + <td valign="top" width="300"> + <h3><a href="../../../../index.htm"><img height="86" width="277" alt= + "C++ Boost" src="../../../../boost.png" border="0"></a></h3> + + <td valign="top"> + <h1 align="center"><a href="../index.html">Boost.Python</a></h1> + + <h2 align="center">Header <wrapper.hpp></h2> + </table> + <hr> + + <h2>Contents</h2> + + <dl class="page-index"> + <dt><a href="#introduction">Introduction</a></dt> + + <dt><a href="#classes">Classes</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#override-spec">Class template + <code>override</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#override-spec-synopsis">Class + <code>override</code> synopsis</a></dt> + + <dt><a href="#override-spec-observers">Class + <code>override</code> observer functions</a></dt> + </dl> + </dd> + + <dt><a href="#wrapper-spec">Class template + <code>wrapper</code></a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#wrapper-spec-synopsis">Class <code>wrapper</code> + synopsis</a></dt> + + <dt><a href="#wrapper-spec-observers">Class + <code>wrapper</code> observer functions</a></dt> + </dl> + </dd> + </dl> + </dd> + + <dt><a href="#examples">Example(s)</a></dt> + </dl> + <hr> + + <h2><a name="introduction"></a>Introduction</h2> + + <p>To wrap a class <code>T</code> such that its virtual functions can be + "overridden in Python"—so that the corresponding method of a Python + derived class will be called when the virtual function is invoked from + C++—you must create a C++ wrapper class derived from ``T`` that + overrides those virtual functions so that they call into Python. This + header contains classes that can be used to make that job easier.</p> + + <h2><a name="classes"></a>Classes</h2> + + <h3><a name="override-spec"></a>Class <code>override</code></h3> + + <p>Encapsulates a Python override of a C++ virtual function. An + <code>override</code> object either holds a callable Python object or + <code>None</code>.</p> + + <h4><a name="override-spec-synopsis"></a>Class <code>override</code> + synopsis</h4> +<pre> +namespace boost +{ + class override : object + { + public: + <i>unspecified</i> operator() const; + template <class A0> + <i>unspecified</i> operator(A0) const; + template <class A0, class A1> + <i>unspecified</i> operator(A0, A1) const; + ... + template <class A0, class A1, ...class A<i>n</i>> + <i>unspecified</i> operator(A0, A1, ...A<i>n</i>) const; + }; +}; +</pre> + + <h4><a name="override-spec-observers"></a>Class <code>override</code> + observer functions</h4> +<pre> +<i>unspecified</i> operator() const; +template <class A0> +<i>unspecified</i> operator(A0) const; +template <class A0, class A1> +<i>unspecified</i> operator(A0, A1) const; +... +template <class A0, class A1, ...class A<i>n</i>> +<i>unspecified</i> operator(A0, A1, ...A<i>n</i>) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Effects:</b> If <code>*this</code> holds a callable Python + object, it is invoked with the specified arguments in the manner + specified <a href="callbacks.html">here</a>. Otherwise, throws <code><a + href="errors.html#error_already_set-spec">error_already_set</a></code> + .</dt> + + <dt><b>Returns:</b> An object of unspecified type that holds the Python + result of the invocation and, when converted to a C++ type + <code>R</code>, attempts to convert that result object to + <code>R</code>. If that conversion fails, throws <code><a href= + "errors.html#error_already_set-spec">error_already_set</a></code> + .</dt> + </dl> + + <h3><a name="wrapper-spec"></a>Class template <code>wrapper</code></h3> + + <p>Deriving your wrapper class from both ``T`` <i>and</i> + ``wrapper<T> makes writing that derived class easier.</p> + + <h4><a name="wrapper-spec-synopsis"></a>Class template + <code>wrapper</code> synopsis</h4> +<pre> +namespace boost +{ + class wrapper + { + protected: + override get_override(char const* name) const; + }; +}; +</pre> + + <h4><a name="wrapper-spec-observers"></a>Class <code>wrapper</code> + observer functions</h4> +<pre> +override get_override(char const* name) const; +</pre> + + <dl class="function-semantics"> + <dt><b>Requires:</b> <code>name</code> is a <a href= + "definitions.html#ntbs">ntbs</a>.</dt> + + <dt><b>Returns:</b> If <code>*this</code> is the C++ base class + subobject of a Python derived class instance that overrides the named + function, returns an <code>override</code> object that delegates to the + Python override. Otherwise, returns an <code>override</code> object + that holds <code>None</code>.</dt> + </dl> + + <h2><a name="examples"></a>Example</h2> +<pre> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/wrapper.hpp> +#include <boost/python/call.hpp> + +using namespace boost::python; + +// Class with one pure virtual function +struct P +{ + virtual ~P(){} + virtual char const* f() = 0; + char const* g() { return "P::g()"; } +}; + +struct PCallback : P, wrapper<P> +{ + char const* f() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) // Workaround for vc6/vc7 + return call<char const*>(this->get_override("f").ptr()); +#else + return this->get_override("f")(); +#endif + } +}; + +// Class with one non-pure virtual function +struct A +{ + virtual ~A(){} + virtual char const* f() { return "A::f()"; } +}; + +struct ACallback : A, wrapper<A> +{ + char const* f() + { + if (override f = this->get_override("f")) +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) // Workaround for vc6/vc7 + return call<char const*>(f.ptr()); +#else + return f(); +#endif + + return A::f(); + } + + char const* default_f() { return this->A::f(); } +}; + +BOOST_PYTHON_MODULE_INIT(polymorphism) +{ + class_<PCallback,boost::noncopyable>("P") + .def("f", pure_virtual(&P::f)) + ; + + class_<ACallback,boost::noncopyable>("A") + .def("f", &A::f, &ACallback::default_f) + ; +} +</pre> + + <p>Revised + <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan --> + 31 October, 2004 + <!--webbot bot="Timestamp" endspan i-checksum="39359" --> + + + <p><i>© Copyright <a href="http://www.boost.org/people/dave_abrahams.htm">Dave + Abrahams</a> 2004</i> Distributed under the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt)</p> + diff --git a/libs/python/example/Jamroot b/libs/python/example/Jamroot new file mode 100644 index 000000000..0d5ad9dcb --- /dev/null +++ b/libs/python/example/Jamroot @@ -0,0 +1,40 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Specify the path to the Boost project. If you move this project, +# adjust this path to refer to the Boost root directory. +use-project boost + : ../../.. ; + +# Set up the project-wide requirements that everything uses the +# boost_python library from the project whose global ID is +# /boost/python. +project + : requirements <library>/boost/python//boost_python ; + +# Declare the three extension modules. You can specify multiple +# source files after the colon separated by spaces. +python-extension getting_started1 : getting_started1.cpp ; +python-extension getting_started2 : getting_started2.cpp ; +python-extension std_pair_ext : std_pair.cpp ; + +# A little "rule" (function) to clean up the syntax of declaring tests +# of these extension modules. +local rule run-test ( test-name : sources + ) +{ + import testing ; + testing.make-test run-pyd : $(sources) : : $(test-name) ; +} + +# Declare test targets +run-test test1 : getting_started1 test_getting_started1.py ; +run-test test2 : getting_started2 test_getting_started2.py ; +run-test test3 : std_pair_ext test_std_pair.py ; + +# A target that runs all the tests +alias test : test1 test2 test3 ; + +# Only run tests when explicitly requested +explicit test test1 test2 test3 ; + diff --git a/libs/python/example/README b/libs/python/example/README new file mode 100644 index 000000000..29a94f67d --- /dev/null +++ b/libs/python/example/README @@ -0,0 +1,16 @@ +.. Copyright David Abrahams 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +To get started with the Boost Python Library, use the examples +getting_started1.cpp and getting_started2.cpp. Invoking + + bjam --toolset=your-toolset test + +in this directory will build and run the examples. See +http://www.boost.org/more/getting_started.html for details about the +--toolset= option. + +If you move this example from its place in the Boost development tree +you'll need to edit the two lines indicated in Jamroot and +boost-build.jam. diff --git a/libs/python/example/boost-build.jam b/libs/python/example/boost-build.jam new file mode 100644 index 000000000..b7220e2c2 --- /dev/null +++ b/libs/python/example/boost-build.jam @@ -0,0 +1,7 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Edit this path to point at the tools/build/v2 subdirectory of your +# Boost installation. Absolute paths work, too. +boost-build ../../../tools/build/v2 ; diff --git a/libs/python/example/getting_started1.cpp b/libs/python/example/getting_started1.cpp new file mode 100644 index 000000000..09d681039 --- /dev/null +++ b/libs/python/example/getting_started1.cpp @@ -0,0 +1,25 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <string> + +namespace { // Avoid cluttering the global namespace. + + // A couple of simple C++ functions that we want to expose to Python. + std::string greet() { return "hello, world"; } + int square(int number) { return number * number; } +} + +namespace python = boost::python; + +// Python requires an exported function called init<module-name> in every +// extension module. This is where we build the module contents. +BOOST_PYTHON_MODULE(getting_started1) +{ + // Add regular functions to the module. + python::def("greet", greet); + python::def("square", square); +} diff --git a/libs/python/example/getting_started2.cpp b/libs/python/example/getting_started2.cpp new file mode 100644 index 000000000..ee8af32e5 --- /dev/null +++ b/libs/python/example/getting_started2.cpp @@ -0,0 +1,41 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <iostream> +#include <string> + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class hello + { + public: + hello(const std::string& country) { this->country = country; } + std::string greet() const { return "Hello from " + country; } + private: + std::string country; + }; + + // A function taking a hello object as an argument. + std::string invite(const hello& w) { + return w.greet() + "! Please come soon!"; + } +} + +BOOST_PYTHON_MODULE(getting_started2) +{ + using namespace boost::python; + class_<hello>("hello", init<std::string>()) + // Add a regular member function. + .def("greet", &hello::greet) + // Add invite() as a member of hello! + .def("invite", invite) + ; + + // Also add invite() as a regular function to the module. + def("invite", invite); +} diff --git a/libs/python/example/project.zip b/libs/python/example/project.zip Binary files differnew file mode 100644 index 000000000..d863defdb --- /dev/null +++ b/libs/python/example/project.zip diff --git a/libs/python/example/quickstart/Jamroot b/libs/python/example/quickstart/Jamroot new file mode 100644 index 000000000..569dae131 --- /dev/null +++ b/libs/python/example/quickstart/Jamroot @@ -0,0 +1,43 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Specify the path to the Boost project. If you move this project, +# adjust the path to refer to the Boost root directory. +use-project boost + : ../../../.. ; + +# Set up the project-wide requirements that everything uses the +# boost_python library defined in the project whose global ID is +# /boost/python. +project boost-python-quickstart + : requirements <library>/boost/python//boost_python + ; + +# Make the definition of the python-extension rule available +import python ; + +# Declare a Python extension called hello. +python-extension extending : extending.cpp ; + +# Declare an executable called embedding that embeds Python +exe embedding : embedding.cpp /python//python ; + +import testing ; + +# Declare a test of the extension module +testing.make-test run-pyd : extending test_extending.py : : test_ext ; + +# Declare a test of the embedding application +testing.run embedding + : # any ordinary arguments + : script.py # any arguments that should be treated as relative paths + : # requirements + : test_embed ; # name of test + +# Create a "test" target that runs all the tests +alias test : test_ext test_embed ; + +# make sure the tests don't run by default +explicit test_ext test_embed test ; + diff --git a/libs/python/example/quickstart/boost-build.jam b/libs/python/example/quickstart/boost-build.jam new file mode 100644 index 000000000..a440ea9fe --- /dev/null +++ b/libs/python/example/quickstart/boost-build.jam @@ -0,0 +1,7 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Edit this path to point at the tools/build/v2 subdirectory of your +# Boost installation. Absolute paths work, too. +boost-build ../../../../tools/build/v2 ; diff --git a/libs/python/example/quickstart/embedding.cpp b/libs/python/example/quickstart/embedding.cpp new file mode 100644 index 000000000..65bcd16a0 --- /dev/null +++ b/libs/python/example/quickstart/embedding.cpp @@ -0,0 +1,154 @@ +// Copyright Stefan Seefeld 2005. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <iostream> + +namespace python = boost::python; + +// An abstract base class +class Base : public boost::noncopyable +{ +public: + virtual ~Base() {}; + virtual std::string hello() = 0; +}; + +// C++ derived class +class CppDerived : public Base +{ +public: + virtual ~CppDerived() {} + virtual std::string hello() { return "Hello from C++!";} +}; + +// Familiar Boost.Python wrapper class for Base +struct BaseWrap : Base, python::wrapper<Base> +{ + virtual std::string hello() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + // workaround for VC++ 6.x or 7.0, see + // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions + return python::call<std::string>(this->get_override("hello").ptr()); +#else + return this->get_override("hello")(); +#endif + } +}; + +// Pack the Base class wrapper into a module +BOOST_PYTHON_MODULE(embedded_hello) +{ + python::class_<BaseWrap, boost::noncopyable> base("Base"); +} + + +void exec_test() +{ + std::cout << "registering extension module embedded_hello..." << std::endl; + + // Register the module with the interpreter + if (PyImport_AppendInittab("embedded_hello", initembedded_hello) == -1) + throw std::runtime_error("Failed to add embedded_hello to the interpreter's " + "builtin modules"); + + std::cout << "defining Python class derived from Base..." << std::endl; + + // Retrieve the main module + python::object main = python::import("__main__"); + + // Retrieve the main module's namespace + python::object global(main.attr("__dict__")); + + // Define the derived class in Python. + python::object result = python::exec( + "from embedded_hello import * \n" + "class PythonDerived(Base): \n" + " def hello(self): \n" + " return 'Hello from Python!' \n", + global, global); + + python::object PythonDerived = global["PythonDerived"]; + + // Creating and using instances of the C++ class is as easy as always. + CppDerived cpp; + BOOST_TEST(cpp.hello() == "Hello from C++!"); + + std::cout << "testing derived class from C++..." << std::endl; + + // But now creating and using instances of the Python class is almost + // as easy! + python::object py_base = PythonDerived(); + Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND; + + // Make sure the right 'hello' method is called. + BOOST_TEST(py.hello() == "Hello from Python!"); + + std::cout << "success!" << std::endl; +} + +void exec_file_test(std::string const &script) +{ + std::cout << "running file " << script << "..." << std::endl; + + // Run a python script in an empty environment. + python::dict global; + python::object result = python::exec_file(script.c_str(), global, global); + + // Extract an object the script stored in the global dictionary. + BOOST_TEST(python::extract<int>(global["number"]) == 42); + + std::cout << "success!" << std::endl; +} + +void exec_test_error() +{ + std::cout << "intentionally causing a python exception..." << std::endl; + + // Execute a statement that raises a python exception. + python::dict global; + python::object result = python::exec("print unknown \n", global, global); + + std::cout << "Oops! This statement should be skipped due to an exception" << std::endl; +} + +int main(int argc, char **argv) +{ + BOOST_TEST(argc == 2); + std::string script = argv[1]; + // Initialize the interpreter + Py_Initialize(); + + bool error_expected = false; + + if ( + python::handle_exception(exec_test) + || python::handle_exception(boost::bind(exec_file_test, script)) + || ( + (error_expected = true) + && python::handle_exception(exec_test_error) + ) + + ) + { + if (PyErr_Occurred()) + { + if (!error_expected) + BOOST_ERROR("Python Error detected"); + PyErr_Print(); + } + else + { + BOOST_ERROR("A C++ exception was thrown for which " + "there was no exception translator registered."); + } + } + + // Boost.Python doesn't support Py_Finalize yet, so don't call it! + return boost::report_errors(); +} diff --git a/libs/python/example/quickstart/extending.cpp b/libs/python/example/quickstart/extending.cpp new file mode 100644 index 000000000..a539d3b4b --- /dev/null +++ b/libs/python/example/quickstart/extending.cpp @@ -0,0 +1,41 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <iostream> +#include <string> + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class hello + { + public: + hello(const std::string& country) { this->country = country; } + std::string greet() const { return "Hello from " + country; } + private: + std::string country; + }; + + // A function taking a hello object as an argument. + std::string invite(const hello& w) { + return w.greet() + "! Please come soon!"; + } +} + +BOOST_PYTHON_MODULE(extending) +{ + using namespace boost::python; + class_<hello>("hello", init<std::string>()) + // Add a regular member function. + .def("greet", &hello::greet) + // Add invite() as a member of hello! + .def("invite", invite) + ; + + // Also add invite() as a regular function to the module. + def("invite", invite); +} diff --git a/libs/python/example/quickstart/script.py b/libs/python/example/quickstart/script.py new file mode 100644 index 000000000..5a8faf79f --- /dev/null +++ b/libs/python/example/quickstart/script.py @@ -0,0 +1,6 @@ +# Copyright Stefan Seefeld 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +print 'Hello World !' +number = 42 diff --git a/libs/python/example/quickstart/test_extending.py b/libs/python/example/quickstart/test_extending.py new file mode 100644 index 000000000..14616f7c0 --- /dev/null +++ b/libs/python/example/quickstart/test_extending.py @@ -0,0 +1,36 @@ +# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Using the doctest module here to ensure that the results are as expected. +r'''>>> from extending import * + >>> hi = hello('California') + >>> hi.greet() + 'Hello from California' + >>> invite(hi) + 'Hello from California! Please come soon!' + >>> hi.invite() + 'Hello from California! Please come soon!' + + >>> class wordy(hello): + ... def greet(self): + ... return hello.greet(self) + ', where the weather is fine' + ... + >>> hi2 = wordy('Florida') + >>> hi2.greet() + 'Hello from Florida, where the weather is fine' + >>> invite(hi2) + 'Hello from Florida! Please come soon!' +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_extending + return doctest.testmod(test_extending, verbose=True) + +if __name__ == '__main__': + import sys + sys.exit(run()[0]) + diff --git a/libs/python/example/std_pair.cpp b/libs/python/example/std_pair.cpp new file mode 100644 index 000000000..edf98dd65 --- /dev/null +++ b/libs/python/example/std_pair.cpp @@ -0,0 +1,49 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/to_python_converter.hpp> + +namespace { // Avoid cluttering the global namespace. + + // Converts a std::pair instance to a Python tuple. + template <typename T1, typename T2> + struct std_pair_to_tuple + { + static PyObject* convert(std::pair<T1, T2> const& p) + { + return boost::python::incref( + boost::python::make_tuple(p.first, p.second).ptr()); + } + static PyTypeObject const *get_pytype () {return &PyTuple_Type; } + }; + + // Helper for convenience. + template <typename T1, typename T2> + struct std_pair_to_python_converter + { + std_pair_to_python_converter() + { + boost::python::to_python_converter< + std::pair<T1, T2>, + std_pair_to_tuple<T1, T2>, + true //std_pair_to_tuple has get_pytype + >(); + } + }; + + // Example function returning a std::pair. + std::pair<int, int> + foo() { return std::pair<int, int>(3, 5); } + +} // namespace anonymous + +BOOST_PYTHON_MODULE(std_pair_ext) +{ + using namespace boost::python; + std_pair_to_python_converter<int, int>(); + def("foo", foo); +} diff --git a/libs/python/example/test_getting_started1.py b/libs/python/example/test_getting_started1.py new file mode 100644 index 000000000..32dc1f6eb --- /dev/null +++ b/libs/python/example/test_getting_started1.py @@ -0,0 +1,21 @@ +# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +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 + return doctest.testmod(test_getting_started1) + +if __name__ == '__main__': + import sys + sys.exit(run()[0]) diff --git a/libs/python/example/test_getting_started2.py b/libs/python/example/test_getting_started2.py new file mode 100644 index 000000000..ae86017b2 --- /dev/null +++ b/libs/python/example/test_getting_started2.py @@ -0,0 +1,34 @@ +# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +r'''>>> from getting_started2 import * + >>> hi = hello('California') + >>> hi.greet() + 'Hello from California' + >>> invite(hi) + 'Hello from California! Please come soon!' + >>> hi.invite() + 'Hello from California! Please come soon!' + + >>> class wordy(hello): + ... def greet(self): + ... return hello.greet(self) + ', where the weather is fine' + ... + >>> hi2 = wordy('Florida') + >>> hi2.greet() + 'Hello from Florida, where the weather is fine' + >>> invite(hi2) + 'Hello from Florida! Please come soon!' +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_getting_started2 + return doctest.testmod(test_getting_started2) + +if __name__ == '__main__': + import sys + sys.exit(run()[0]) + diff --git a/libs/python/example/test_std_pair.py b/libs/python/example/test_std_pair.py new file mode 100644 index 000000000..64f239fea --- /dev/null +++ b/libs/python/example/test_std_pair.py @@ -0,0 +1,6 @@ +# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import std_pair_ext +assert std_pair_ext.foo() == (3, 5) +print "OK" diff --git a/libs/python/example/tutorial/Jamroot b/libs/python/example/tutorial/Jamroot new file mode 100644 index 000000000..1a70cb91a --- /dev/null +++ b/libs/python/example/tutorial/Jamroot @@ -0,0 +1,48 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import python ; + +if ! [ python.configured ] +{ + ECHO "notice: no Python configured in user-config.jam" ; + ECHO "notice: will use default configuration" ; + using python ; +} + +# Specify the path to the Boost project. If you move this project, +# adjust this path to refer to the Boost root directory. +use-project boost + : ../../../.. ; + +# Set up the project-wide requirements that everything uses the +# boost_python library from the project whose global ID is +# /boost/python. +project + : requirements <library>/boost/python//boost_python ; + +# Declare the three extension modules. You can specify multiple +# source files after the colon separated by spaces. +python-extension hello_ext : hello.cpp ; + +# Put the extension and Boost.Python DLL in the current directory, so +# that running script by hand works. +install convenient_copy + : hello_ext + : <install-dependencies>on <install-type>SHARED_LIB <install-type>PYTHON_EXTENSION + <location>. + ; + +# A little "rule" (function) to clean up the syntax of declaring tests +# of these extension modules. +local rule run-test ( test-name : sources + ) +{ + import testing ; + testing.make-test run-pyd : $(sources) : : $(test-name) ; +} + +# Declare test targets +run-test hello : hello_ext hello.py ; + + diff --git a/libs/python/example/tutorial/hello.cpp b/libs/python/example/tutorial/hello.cpp new file mode 100644 index 000000000..d5114312b --- /dev/null +++ b/libs/python/example/tutorial/hello.cpp @@ -0,0 +1,20 @@ +// Copyright Joel de Guzman 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// Hello World Example from the tutorial +// [Joel de Guzman 10/9/2002] + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> + +char const* greet() +{ + return "hello, world"; +} + +BOOST_PYTHON_MODULE(hello_ext) +{ + using namespace boost::python; + def("greet", greet); +} + diff --git a/libs/python/example/tutorial/hello.py b/libs/python/example/tutorial/hello.py new file mode 100755 index 000000000..d18b1c535 --- /dev/null +++ b/libs/python/example/tutorial/hello.py @@ -0,0 +1,7 @@ +# Copyright Joel de Guzman 2002-2007. Distributed under the Boost +# Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# Hello World Example from the tutorial + +import hello_ext +print hello_ext.greet() diff --git a/libs/python/index.html b/libs/python/index.html new file mode 100644 index 000000000..9c6acc885 --- /dev/null +++ b/libs/python/index.html @@ -0,0 +1,12 @@ +<!-- Copyright David Abrahams 2006. Distributed under the Boost --> +<!-- Software License, Version 1.0. (See accompanying --> +<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> +<html> +<head> +<meta http-equiv="refresh" content="0; URL=doc/index.html"> +</head> +<body> +Automatically loading index page... if nothing happens, please go to +<a href="doc/index.html">doc/index.html</a>. +</body> +</html> diff --git a/libs/python/pyste/NEWS b/libs/python/pyste/NEWS new file mode 100644 index 000000000..31a5ceba2 --- /dev/null +++ b/libs/python/pyste/NEWS @@ -0,0 +1,212 @@ +.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +25 April 2005 +- Fixed bug where the code for wrappers of member functions were defined outside +the pyste namespace. Reported by Dan Haffey. + +9 October 2004 +- Applied a patch by Christian Hudon that fixed an issue with files +that had a tail and relative includes. + +18 July 2004 +- Applied a patch by Paul Bridger that solves some problems for wrapper +methods. +- Applied a patch by Baptiste Lepilleur that allows the user to inject +code inside the class definition. +- Applied another patch by Baptiste Lepilleur that inserts two new command-line +options that helps with writing makefiles. + +27 May 2004 +Applied patch by Paul Bridger that solves a problem on windows regarding +spaces on paths. Thanks Paul! + +Applied another patch that fixes the module name if pyste is run from +another directory of where the .pyste file is located. Patch contributted +by Paul Bridger. + +17 May 2004 +Applied a patch by Roman Yakovenko that makes the export of unnamed enums +better. Thanks Roman! + +23 October 2003 +Fixed bug where a class would appear more than one in the generated code. + +6 October 2003 +Fixed bug reported by Niall Douglas (using his patch) about UniqueInt not +appearing correctly with --multiple. + +Added precompiled header support on windows systems (using #pragma hdrstop). +Suggested by Niall Douglas. + +Fixed a bug with -I directive and AllFromHeader. Reported by Scott Snyder. + +4 October 2003 +Added return_self, thanks for Niall Douglas for pointing out that it was +missing. + +Added --file-list, where you can pass a file where the pyste files are listed +one per line. Also suggested by Niall Douglas. + +Documentation has been finally updated, after a long wait. Please let me know +if you spot any mistake! + +2 October 2003 +Scott Snyder found a typo in ClassExporter that prevented -= and *= operators +from being exported. Thanks Scott! + +20 September 2003 +Added return_by_value in the list of policies supported. Thanks to Niall +Douglas for the remainder. + +19 September 2003 +Better support for unnamed enums, plus they are by default exported to the +parent's namespace. Normal enums can have the same behaviour using the function +export_values on the Enum object. Feature requested by Niall Douglas. + +10 September 2003 +A new variable is accessible in the Pyste files: INTERFACE_FILE contains the +full path of the pyste file. + +4 September 2003 +Now it is possible to override protected and private pure virtual functions +in Python, as requested by Roman Yakovenko. + +23 August 2003 +Fixed bug where some Imports where not writing their include files. +Now whenever the declarations change, the cache files are rebuilt +automatically. + +19 August 2003 +Fixed a bug related to the generation of the bases<> template. + +17 August 2003 +Added support for insertion of user code in the generated code. + +16 August 2003 +Applied a patch by Gottfried Ganssauge that adds exception specifiers to +wrapper functions and pointer declarations. Thanks a lot Gottfried!! + +Applied a patch by Prabhu Ramachandran that fixes ae problem with the +pure virtual method generation. Thanks again Prabhu! + +10 August 2003 +Support for incremental generation of the code has been added. This changes +how --multiple works; documentation of this new feature will follow. Thanks +to Prabhu Ramachandran, that saw the need for this feature and discussed a +solution. + +Automatically convert \ to / in Windows systems before passing the paths to +gccxml. + +Fixed a bug reported by Prabhu Ramachandran, where in some classes the virtual +methods were being definied incorrectly. Thanks a lot Prabhu! + +7 July 2003 +Applied 2 patches by Prabhu Ramachandran: a fix in the new --multiple method, +and two new functions "hold_with_shared_ptr" and its counterpart for auto_ptr. +Thanks a lot Prabhu! + +Fixed a bug where the macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID was being +called multiple times for the same type. +Thanks to Gottfried Ganßauge for reporting this! + +Fixed bug where using AllFromHeader didn't use bases<> when exporting +hierarchies. + +Fixed the staticmethod bug. + +5 July 2003 +Changed how --multiple works: now it generates one cpp file for each pyste +file, makeing easier to integrate Pyste with build systems. + +4 July 2003 +Applied patch that solved a bug in ClassExporter and added a distutils install +script (install/setup.py), both contributed by Prabhu Ramachandran. +Thanks Prabhu! + +2 July 2003 +Jim Wilson found a bug where types like "char**" were being interpreted as +"char*". Thanks Jim! + +16 June 2003 +Thanks to discussions with David Abrahams and Roman Sulzhyk, some behaviours +have changed: + +- If you export a derived class without exporting its base classes, the derived + class will explicitly export the bases's methods and attributes. Before, if + you were interested in the bases's methods, you had to export the base + classes too. + +- Added a new function, no_override. When a member function is specified as + "no_override", no virtual wrappers are generated for it, improving + performance and letting the code more clean. + +- There was a bug in which the policy of virtual member functions was being + ignored (patch by Roman Sulzhyk). + +Thanks again to Roman Sulzhyk for the patches and discussion in the c++-sig. + +4 June 2003 +Major improvements in memory usage. + +3 June 2003 +Appliced a patch from Giulio Eulisse that allows unnamed enumerations to be +exported with an AllFromHeader construct. Thanks a lot Giulio! + +2 June 2003 +Added a new construct, add_method. See documentation. + +23 May 2003 +Support for global variables added. +Various bug fixes. + +08 May 2003 +Fixed bug where in a certain cases the GCCXMLParser would end up with multiple +declarations of the same class + +22 Apr 2003 +- Now shows a warning when the user tries to export a forward-declared class. + Forward-declared classes are ignored by the AllFromHeader construct. +- Fixed a bug where classes, functions and enums where being exported, even if + excluded from a AllFromHeader construct. + +16 Apr 2003 +Added a more generic (but ugly) code to declare the smart pointer converters. + +07 Apr 2003 +- Removed the warnings about forward declarations: it was not accurate enough. + Another strategy must be thought of. +- Fixed bug in the --multiple mode, where the order of the class instantiations + could end up wrong. +- Lots of fixes in the documentation, pointed out by Dirk Gerrits. Thanks Dirk! +- Fixed support for the return_opaque_pointer policy (the support macro was not + being declared). + + +06 Apr 2003 +Support for the improved static data members support of Boost.Python. + +05 Apr 2003 +New option for generating the bindings: --multiple. + +02 Apr 2003 +Forward declarations are now detected and a warning is generated. + +24 Mar 2003 +Default policy for functions/methods that return const T& is now +return_value_policy<copy_const_reference>(). + +22 Mar 2003 +Exporting virtual methods of the base classes in the derived classes too. + +21 Mar 2003 +Added manual support for boost::shared_ptr and std::auto_ptr (see doc). + +19 Mar 2003 +Added support for int, double, float and long operators acting as expected in +python. + +14 Mar 2003 +Fixed bug: Wrappers for protected and virtual methods were not being generated. diff --git a/libs/python/pyste/README b/libs/python/pyste/README new file mode 100644 index 000000000..c378f3916 --- /dev/null +++ b/libs/python/pyste/README @@ -0,0 +1,35 @@ +.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +Pyste - Python Semi-Automatic Exporter +====================================== + +Pyste is a Boost.Python code generator. The user specifies the classes and +functions to be exported using a simple interface file, which following the +Boost.Python's philosophy, is simple Python code. Pyste then uses GCCXML to +parse all the headers and extract the necessary information to automatically +generate C++ code. + +The documentation can be found in the file index.html accompaning this README. + +Enjoy! +Bruno da Silva de Oliveira (nicodemus@esss.com.br) + +Thanks +====== + +- David Abrahams, creator of Boost.Python, for tips on the syntax of the interface + file and support. +- Marcelo Camelo, for design tips, support and inspiration for this project. + Also, the name was his idea. 8) +- Brad King, creator of the excellent GCCXML (http://www.gccxml.org) +- Fredrik Lundh, creator of the elementtree library (http://effbot.org) + +Bugs +==== + +Pyste is a young tool, so please help it to get better! Send bug reports to +nicodemus@esss.com.br, accompaining the stack trace in case of exceptions. +If possible, run pyste with --debug, and send the resulting xmls too (pyste +will output a xml file with the same of each header it parsed). diff --git a/libs/python/pyste/TODO b/libs/python/pyste/TODO new file mode 100644 index 000000000..0b3c9024f --- /dev/null +++ b/libs/python/pyste/TODO @@ -0,0 +1,18 @@ +.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +- Make Pyste accept already-generated xml files + +- throw() declaration in virtual wrapper's member functions + +- Allow protected methods to be overriden in Python + +- Expose programmability to the Pyste files (listing members of a class, for + instance) + +- Virtual operators + +- args() support + +- set policies to methods with the same name diff --git a/libs/python/pyste/dist/create_build.py b/libs/python/pyste/dist/create_build.py new file mode 100644 index 000000000..a68369951 --- /dev/null +++ b/libs/python/pyste/dist/create_build.py @@ -0,0 +1,55 @@ +# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import os +import sys +import shutil +import fnmatch +from zipfile import ZipFile, ZIP_DEFLATED + +def findfiles(directory, mask): + def visit(files, dir, names): + for name in names: + if fnmatch.fnmatch(name, mask): + files.append(os.path.join(dir, name)) + files = [] + os.path.walk(directory, visit, files) + return files + + +def main(): + # test if PyXML is installed + try: + import _xmlplus.parsers.expat + pyxml = '--includes _xmlplus.parsers.expat' + except ImportError: + pyxml = '' + # create exe + status = os.system('python setup.py py2exe %s >& build.log' % pyxml) + if status != 0: + raise RuntimeError, 'Error creating EXE' + + # create distribution + import pyste + version = pyste.__VERSION__ + zip = ZipFile('pyste-%s.zip' % version, 'w', ZIP_DEFLATED) + # include the base files + dist_dir = 'dist/pyste' + for basefile in os.listdir(dist_dir): + zip.write(os.path.join(dist_dir, basefile), os.path.join('pyste', basefile)) + # include documentation + for doc_file in findfiles('../doc', '*.*'): + dest_name = os.path.join('pyste/doc', doc_file[3:]) + zip.write(doc_file, dest_name) + zip.write('../index.html', 'pyste/doc/index.html') + zip.close() + # cleanup + os.remove('build.log') + shutil.rmtree('build') + shutil.rmtree('dist') + + +if __name__ == '__main__': + sys.path.append('../src') + main() diff --git a/libs/python/pyste/dist/setup.py b/libs/python/pyste/dist/setup.py new file mode 100644 index 000000000..fc7c74e21 --- /dev/null +++ b/libs/python/pyste/dist/setup.py @@ -0,0 +1,10 @@ +# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +from distutils.core import setup +import py2exe +import sys + +sys.path.append('../src') +setup(name='pyste', scripts=['../src/pyste.py']) diff --git a/libs/python/pyste/doc/adding_new_methods.html b/libs/python/pyste/doc/adding_new_methods.html new file mode 100644 index 000000000..afa772bcc --- /dev/null +++ b/libs/python/pyste/doc/adding_new_methods.html @@ -0,0 +1,79 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Adding New Methods</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="global_variables.html"> +<link rel="next" href="inserting_code.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Adding New Methods</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="global_variables.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="inserting_code.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +Suppose that you want to add a function to a class, turning it into a member +function:</p> +<code><pre> + <span class=keyword>struct </span><span class=identifier>World + </span><span class=special>{ + </span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>; + }; + + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>(</span><span class=identifier>World</span><span class=special>& </span><span class=identifier>w</span><span class=special>) + { + </span><span class=keyword>return </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>msg</span><span class=special>; + } +</span></pre></code> +<p> +Here, we want to make <tt>greet</tt> work as a member function of the class <tt>World</tt>. We do +that using the <tt>add_method</tt> construct:</p> +<code><pre> + <span class=identifier>W </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>add_method</span><span class=special>(</span><span class=identifier>W</span><span class=special>, </span><span class=string>"greet"</span><span class=special>) +</span></pre></code> +<p> +Notice also that then you can rename it, set its policy, just like a regular +member function:</p> +<code><pre> + <span class=identifier>rename</span><span class=special>(</span><span class=identifier>W</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=literal>'Greet'</span><span class=special>) +</span></pre></code> +<p> +Now from Python:</p> +<code><pre> + <span class=special>>>> </span><span class=identifier>import </span><span class=identifier>hello + </span><span class=special>>>> </span><span class=identifier>w </span><span class=special>= </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>() + >>> </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>set</span><span class=special>(</span><span class=literal>'Ni'</span><span class=special>) + >>> </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>greet</span><span class=special>() + </span><span class=literal>'Ni' + </span><span class=special>>>> </span><span class=identifier>print </span><span class=literal>'Oh no! The knights who say Ni!' + </span><span class=identifier>Oh </span><span class=identifier>no</span><span class=special>! </span><span class=identifier>The </span><span class=identifier>knights </span><span class=identifier>who </span><span class=identifier>say </span><span class=identifier>Ni</span><span class=special>! +</span></pre></code> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="global_variables.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="inserting_code.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/exporting_an_entire_header.html b/libs/python/pyste/doc/exporting_an_entire_header.html new file mode 100644 index 000000000..db25325ca --- /dev/null +++ b/libs/python/pyste/doc/exporting_an_entire_header.html @@ -0,0 +1,85 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Exporting An Entire Header</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="wrappers.html"> +<link rel="next" href="smart_pointers.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Exporting An Entire Header</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +Pyste also supports a mechanism to export all declarations found in a header +file. Suppose again our file, <tt>hello.h</tt>:</p> +<code><pre> + <span class=keyword>struct </span><span class=identifier>World + </span><span class=special>{ + </span><span class=identifier>World</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>): </span><span class=identifier>msg</span><span class=special>(</span><span class=identifier>msg</span><span class=special>) {} + </span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>; + }; + + </span><span class=keyword>enum </span><span class=identifier>choice </span><span class=special>{ </span><span class=identifier>red</span><span class=special>, </span><span class=identifier>blue </span><span class=special>}; + + </span><span class=keyword>void </span><span class=identifier>show</span><span class=special>(</span><span class=identifier>choice </span><span class=identifier>c</span><span class=special>) { </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=string>"value: " </span><span class=special><< (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; } +</span></pre></code> +<p> +You can just use the <tt>AllFromHeader</tt> construct:</p> +<code><pre> + <span class=identifier>hello </span><span class=special>= </span><span class=identifier>AllFromHeader</span><span class=special>(</span><span class=string>"hello.h"</span><span class=special>) +</span></pre></code> +<p> +this will export all the declarations found in <tt>hello.h</tt>, which is equivalent +to write:</p> +<code><pre> + <span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"show"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) +</span></pre></code> +<p> +Note that you can still use the functions <tt>rename</tt>, <tt>set_policy</tt>, <tt>exclude</tt>, etc. Just access +the members of the header object like this:</p> +<code><pre> + <span class=identifier>rename</span><span class=special>(</span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>"Greet"</span><span class=special>) + </span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>"Set"</span><span class=special>) +</span></pre></code> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> + +<img src="theme/note.gif"></img> <b>AllFromHeader is broken</b> in some cases. Until it is fixed, +use at you own risk. + </td> + </tr> +</table> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/global_variables.html b/libs/python/pyste/doc/global_variables.html new file mode 100644 index 000000000..0efd2950b --- /dev/null +++ b/libs/python/pyste/doc/global_variables.html @@ -0,0 +1,49 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Global Variables</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="smart_pointers.html"> +<link rel="next" href="adding_new_methods.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Global Variables</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="smart_pointers.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="adding_new_methods.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +To export global variables, use the <tt>Var</tt> construct:</p> +<code><pre> + <span class=identifier>Var</span><span class=special>(</span><span class=string>"myglobal"</span><span class=special>, </span><span class=string>"foo.h"</span><span class=special>) +</span></pre></code> +<p> +Beware of non-const global variables: changes in Python won't reflect in C++! +If you really must change them in Python, you will have to write some accessor +functions, and export those.</p> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="smart_pointers.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="adding_new_methods.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/inserting_code.html b/libs/python/pyste/doc/inserting_code.html new file mode 100644 index 000000000..97eb70f38 --- /dev/null +++ b/libs/python/pyste/doc/inserting_code.html @@ -0,0 +1,72 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Inserting Code</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="adding_new_methods.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Inserting Code</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="adding_new_methods.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td> + </tr> +</table> +<p> +You can insert arbitrary code in the generated cpps, just use the functions +<tt>declaration_code</tt> and <tt>module_code</tt>. This will insert the given string in the +respective sections. Example:</p> +<code><pre> + ##<span class=identifier>file </span><span class=identifier>A</span><span class=special>.</span><span class=identifier>pyste + </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"A"</span><span class=special>, </span><span class=string>"A.h"</span><span class=special>) + </span><span class=identifier>declaration_code</span><span class=special>(</span><span class=string>"/* declaration_code() comes here */\n"</span><span class=special>) + </span><span class=identifier>module_code</span><span class=special>(</span><span class=string>"/* module_code() comes here */\n"</span><span class=special>) +</span></pre></code> +<p> +Will generate:</p> +<code><pre> + <span class=comment>// Includes ==================================================================== + </span><span class=preprocessor>#include </span><span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>python</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>> + + // </span><span class=identifier>Using </span><span class=special>======================================================================= + </span><span class=keyword>using </span><span class=keyword>namespace </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>python</span><span class=special>; + + // </span><span class=identifier>Declarations </span><span class=special>================================================================ + + /* </span><span class=identifier>declaration_code</span><span class=special>() </span><span class=identifier>comes </span><span class=identifier>here </span><span class=special>*/ + + // </span><span class=identifier>Module </span><span class=special>====================================================================== + </span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>A</span><span class=special>) + { + </span><span class=identifier>class_</span><span class=special>< </span><span class=identifier>A </span><span class=special>>(</span><span class=string>"A"</span><span class=special>, </span><span class=identifier>init</span><span class=special>< >()) + .</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>init</span><span class=special>< </span><span class=keyword>const </span><span class=identifier>A</span><span class=special>& >()) + ; + + /* </span><span class=identifier>module_code</span><span class=special>() </span><span class=identifier>comes </span><span class=identifier>here </span><span class=special>*/ + } +</span></pre></code> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="adding_new_methods.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/introduction.html b/libs/python/pyste/doc/introduction.html new file mode 100644 index 000000000..943884931 --- /dev/null +++ b/libs/python/pyste/doc/introduction.html @@ -0,0 +1,73 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Introduction</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="next" href="running_pyste.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Introduction</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td> + <td width="20"><a href="running_pyste.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<a name="what_is_pyste_"></a><h2>What is Pyste?</h2><p> +Pyste is a <a href="../../index.html"> +Boost.Python</a> code generator. The user specifies the classes and +functions to be exported using a simple <i>interface file</i>, which following the +<a href="../../index.html"> +Boost.Python</a>'s philosophy, is simple Python code. Pyste then uses <a href="http://www.gccxml.org"> +GCCXML</a> to +parse all the headers and extract the necessary information to automatically +generate C++ code.</p> +<a name="example"></a><h2>Example</h2><p> +Let's borrow the class <tt>World</tt> from the <a href="../../doc/tutorial/doc/html/python/exposing.html"> +tutorial</a>: </p> +<code><pre> + <span class=keyword>struct </span><span class=identifier>World + </span><span class=special>{ + </span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>; + }; +</span></pre></code> +<p> +Here's the interface file for it, named <tt>world.pyste</tt>:</p> +<code><pre> + <span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"world.h"</span><span class=special>) +</span></pre></code> +<p> +and that's it!</p> +<p> +The next step is invoke Pyste in the command-line:</p> +<code><pre>python pyste.py --module=hello world.pyste</pre></code><p> +this will create a file "<tt>hello.cpp</tt>" in the directory where the command was +run. </p> +<p> +Pyste supports the following features:</p> +<ul><li>Functions</li><li>Classes</li><li>Class Templates</li><li>Virtual Methods</li><li>Overloading</li><li>Attributes </li><li>Enums (both "free" enums and class enums)</li><li>Nested Classes</li><li>Support for <tt>boost::shared_ptr</tt> and <tt>std::auto_ptr</tt></li><li>Global Variables</li></ul><table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td> + <td width="20"><a href="running_pyste.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/policies.html b/libs/python/pyste/doc/policies.html new file mode 100644 index 000000000..3628093bd --- /dev/null +++ b/libs/python/pyste/doc/policies.html @@ -0,0 +1,90 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Policies</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="renaming_and_excluding.html"> +<link rel="next" href="templates.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Policies</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="renaming_and_excluding.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="templates.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +Even thought Pyste can identify various elements in the C++ code, like virtual +member functions, attributes, and so on, one thing that it can't do is to +guess the semantics of functions that return pointers or references. In this +case, the user must manually specify the policy. Policies are explained in the +<a href="../../doc/tutorial/doc/html/python/functions.html#python.call_policies"> +tutorial</a>.</p> +<p> +The policies in Pyste are named exactly as in <a href="../../index.html"> +Boost.Python</a>, only the syntax is +slightly different. For instance, this policy:</p> +<code><pre> + <span class=identifier>return_internal_reference</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=identifier>with_custodian_and_ward</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>> >() +</span></pre></code> +<p> +becomes in Pyste: </p> +<code><pre> + <span class=identifier>return_internal_reference</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=identifier>with_custodian_and_ward</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>)) +</span></pre></code> +<p> +The user can specify policies for functions and virtual member functions with +the <tt>set_policy</tt> function:</p> +<code><pre> + <span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>f</span><span class=special>, </span><span class=identifier>return_internal_reference</span><span class=special>()) + </span><span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>return_value_policy</span><span class=special>(</span><span class=identifier>manage_new_object</span><span class=special>)) +</span></pre></code> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> + +<img src="theme/note.gif"></img> <b>What if a function or member function needs a policy and +the user doesn't set one?</b><br><br> If a function needs a policy and one +was not set, Pyste will issue a error. The user should then go in the +interface file and set the policy for it, otherwise the generated cpp won't +compile. + </td> + </tr> +</table> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> + +<img src="theme/note.gif"></img> +Note that for functions that return <tt>const T&</tt>, the policy +<tt>return_value_policy<copy_const_reference>()</tt> wil be used by default, because +that's normally what you want. You can change it to something else if you need +to, though. + </td> + </tr> +</table> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="renaming_and_excluding.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="templates.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/pyste.txt b/libs/python/pyste/doc/pyste.txt new file mode 100644 index 000000000..186a31cba --- /dev/null +++ b/libs/python/pyste/doc/pyste.txt @@ -0,0 +1,664 @@ +[doc Pyste Documentation] + +[/ Copyright 2003 Bruno da Silva de Oliveira and Joel de Guzman. +Distributed under the Boost Software License, Version 1.0. (See +accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt) ] + +[def GCCXML [@http://www.gccxml.org GCCXML]] +[def Boost.Python [@../../index.html Boost.Python]] + +[page Introduction] + +[h2 What is Pyste?] + +Pyste is a Boost.Python code generator. The user specifies the classes and +functions to be exported using a simple ['interface file], which following the +Boost.Python's philosophy, is simple Python code. Pyste then uses GCCXML to +parse all the headers and extract the necessary information to automatically +generate C++ code. + +[h2 Example] + +Let's borrow the class [^World] from the [@../../doc/tutorial/doc/exposing_classes.html tutorial]: + + struct World + { + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +Here's the interface file for it, named [^world.pyste]: + + Class("World", "world.h") + +and that's it! + +The next step is invoke Pyste in the command-line: + +[pre python pyste.py --module=hello world.pyste] + +this will create a file "[^hello.cpp]" in the directory where the command was +run. + +Pyste supports the following features: + +* Functions +* Classes +* Class Templates +* Virtual Methods +* Overloading +* Attributes +* Enums (both "free" enums and class enums) +* Nested Classes +* Support for [^boost::shared_ptr] and [^std::auto_ptr] +* Global Variables + +[page Running Pyste] + +To run Pyste, you will need: + +* Python 2.2, available at [@http://www.python.org python's website]. +* The great [@http://effbot.org elementtree] library, from Fredrik Lundh. +* The excellent GCCXML, from Brad King. + +Installation for the tools is available in their respective webpages. + +[blurb +[$theme/note.gif] GCCXML must be accessible in the PATH environment variable, so +that Pyste can call it. How to do this varies from platform to platform. +] + +[h2 Ok, now what?] + +Well, now let's fire it up: + +[pre +''' +>python pyste.py + +Pyste version 0.9.26 + +Usage: + pyste [options] interface-files + +where options are: + --module=<name> The name of the module that will be generated; + defaults to the first interface filename, without + the extension. + -I <path> Add an include path + -D <symbol> Define symbol + --multiple Create various cpps, instead of only one + (useful during development) + --out=<name> Specify output filename (default: <module>.cpp) + in --multiple mode, this will be a directory + --no-using Do not declare "using namespace boost"; + use explicit declarations instead + --pyste-ns=<name> Set the namespace where new types will be declared; + default is the empty namespace + --debug Writes the xml for each file parsed in the current + directory + --cache-dir=<dir> Directory for cache files (speeds up future runs) + --only-create-cache Recreates all caches (doesn't generate code). + --generate-main Generates the _main.cpp file (in multiple mode) + --file-list A file with one pyste file per line. Use as a + substitute for passing the files in the command + line. + -h, --help Print this help and exit + -v, --version Print version information + +''' +] + +Options explained: + +The [^-I] and [^-D] are preprocessor flags, which are needed by GCCXML to parse +the header files correctly and by Pyste to find the header files declared in the +interface files. + +[^--out] names the output file (default: [^<module>.cpp]), or in multiple mode, +names a output directory for the files (default: [^<module>]). + +[^--no-using] tells Pyste to don't declare "[^using namespace boost;]" in the +generated cpp, using the namespace boost::python explicitly in all declarations. +Use only if you're having a name conflict in one of the files. + +Use [^--pyste-ns] to change the namespace where new types are declared (for +instance, the virtual wrappers). Use only if you are having any problems. By +default, Pyste uses the empty namespace. + +[^--debug] will write in the current directory a xml file as outputted by GCCXML +for each header parsed. Useful for bug reports. + +[^--file-list] names a file where each line points to a Pyste file. Use this instead +to pass the pyste files if you have a lot of them and your shell has some command line +size limit. + +The other options are explained below, in [@#multiple_mode [*Multiple Mode]] and +[@#cache [*Cache]]. + +[^-h, --help, -v, --version] are self-explaining, I believe. ;) + +So, the usage is simple enough: + +[pre >python pyste.py --module=mymodule file.pyste file2.pyste ...] + +will generate a file [^mymodule.cpp] in the same dir where the command was +executed. Now you can compile the file using the same instructions of the +[@../../doc/tutorial/doc/building_hello_world.html tutorial]. + +[h2 Wait... how do I set those I and D flags?] + +Don't worry: normally GCCXML is already configured correctly for your plataform, +so the search path to the standard libraries and the standard defines should +already be set. You only have to set the paths to other libraries that your code +needs, like Boost, for example. + +Plus, Pyste automatically uses the contents of the environment variable +[^INCLUDE] if it exists. Visual C++ users should run the [^Vcvars32.bat] file, +which for Visual C++ 6 is normally located at: + + C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat + +with that, you should have little trouble setting up the flags. + +[blurb [$theme/note.gif][*A note about Psyco][br][br] +Although you don't have to install [@http://psyco.sourceforge.net/ Psyco] to +use Pyste, if you do, Pyste will make use of it to speed up the wrapper +generation. Speed ups of 30% can be achieved, so it's highly recommended. +] + + +[h2 Multiple Mode] + +The multiple mode is useful in large projects, where the presence of multiple +classes in a single file makes the compilation unpractical (excessive memory +usage, mostly). + +The solution is make Pyste generate multiple files, more specifically one cpp +file for each Pyste file. This files will contain a function named after the +file, for instance Export_MyPysteFile, which will contain all the code to export +the classes, enums, etc. You can pass as much files as you want this way: + +[pre >python pyste.py --module=mymodule file1.pyste file2.pyste] + +This will create the files [^mymodule/file1.cpp] and [^mymodule/file2.cpp]. You +can then later do: + +[pre >python pyste.py --module=mymodule file3.pyste] + +and [^mymodule/file3.cpp] will be generated. + +But compiling and linking this files won't be sufficient to generate your +extension. You have to also generate a file named [^main.cpp]; call pyste with +[*all] the Pyste files of your extension, and use the [^--generate-main] option: + +[pre >python pyste.py --module=mymodule --generate-main file1.pyste file2.pyste file3.pyste] + +Now compile and link all this files together and your extension is ready for +use. + +[h2 Cache] + +Pyste now supports a form of cache, which is a way to speed up the code +generation. Most of the time that Pyste takes to generate the code comes from +having to execute GCCXML (since being a front-end to GCC, it has to compile the +header files) and reading back the XML generated. + +When you use the [^--cache-dir=<dir>] option, Pyste will dump in the specified +directory the generated XMLs to a file named after the Pyste file, with the +extension [^.pystec]. The next time you run with this option, Pyste will use +the cache, instead of calling GCCXML again: + +[pre >python pyste.py --module=mymodule --cache-dir=cache file1.pyste] + +Will generate [^file1.cpp] and [^cache/file1.pystec]. Next time you execute +this command, the cache file will be used. Note that Pyste doesn't do any check +to ensure that the cache is up to date, but you can configure your build system to do that for you. + +When you run Pyste with [^--only-create-cache], all the cache files will be +created again, but no code will be generated. + +[page The Interface Files] + +The interface files are the heart of Pyste. The user creates one or more +interface files declaring the classes and functions he wants to export, and then +invokes Pyste passing the interface files to it. Pyste then generates a single +cpp file with Boost.Python code, with all the classes and functions exported. + +Besides declaring the classes and functions, the user has a number of other +options, like renaming e excluding classes and member functionis. Those are +explained later on. + +[h2 Basics] + +Suppose we have a class and some functions that we want to expose to Python +declared in the header [^hello.h]: + + struct World + { + World(std::string msg): msg(msg) {} + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + + enum choice { red, blue }; + + namespace test { + + void show(choice c) { std::cout << "value: " << (int)c << std::endl; } + + } + +We create a file named [^hello.pyste] and create instances of the classes +[^Function], [^Class] and [^Enum]: + + Function("test::show", "hello.h") + Class("World", "hello.h") + Enum("choice", "hello.h") + +That will expose the class, the free function and the enum found in [^hello.h]. + +[h2 Inheritance] + +Pyste automatically generates the correct code (specifying [^bases<>] in the +[^class_] declaration) [*if] the Class() function that exports the base classes +and their children are in the same Pyste file. If that's not the case, you have +to indicate that there's a relationship between the Pyste files using the +[^Import] function specifying the other Pyste file. + +Suppose we have two classes, [^A] and [^B], and A is a base class for B. We +create two Pyste files: + +[^A.pyste]: + + Class("A", "A.h") + +[^B.pyste]: + + Import("A.pyste") + Class("B", "B.h") + +Note that we specify that [^B] needs to know about [^A] to be properly exported. + +[page:1 Renaming and Excluding] + +You can easily rename functions, classes, member functions, attributes, etc. Just use the +function [^rename], like this: + + World = Class("World", "hello.h") + rename(World, "IWorld") + show = Function("choice", "hello.h") + rename(show, "Show") + +You can rename member functions and attributes using this syntax: + + rename(World.greet, "Greet") + rename(World.set, "Set") + choice = Enum("choice", "hello.h") + rename(choice.red, "Red") + rename(choice.blue, "Blue") + +You can exclude functions, classes, member functions, attributes, etc, in the same way, +with the function [^exclude]: + + exclude(World.greet) + exclude(World.msg) + +To access the operators of a class, access the member [^operator] like this +(supposing that [^C] is a class being exported): + + exclude(C.operator['+']) + exclude(C.operator['*']) + exclude(C.operator['<<']) + +The string inside the brackets is the same as the name of the operator in C++.[br] + +[h2 Virtual Member Functions] + +Pyste automatically generates wrappers for virtual member functions, but you may +want to disable this behaviour (for performance reasons, for instance) if you do +not plan to override the functions in Python. To do this, use the function +[^final]: + + C = Class('C', 'C.h') + final(C.foo) # C::foo is a virtual member function + +No virtual wrapper code will be generated for the virtual member function +C::foo that way. + +[page:1 Policies] + +Even thought Pyste can identify various elements in the C++ code, like virtual +member functions, attributes, and so on, one thing that it can't do is to +guess the semantics of functions that return pointers or references. In this +case, the user must manually specify the policy. Policies are explained in the +[@../../doc/tutorial/doc/call_policies.html tutorial]. + +The policies in Pyste are named exactly as in Boost.Python, only the syntax is +slightly different. For instance, this policy: + + return_internal_reference<1, with_custodian_and_ward<1, 2> >() + +becomes in Pyste: + + return_internal_reference(1, with_custodian_and_ward(1, 2)) + +The user can specify policies for functions and virtual member functions with +the [^set_policy] function: + + set_policy(f, return_internal_reference()) + set_policy(C.foo, return_value_policy(manage_new_object)) + +[blurb +[$theme/note.gif] [*What if a function or member function needs a policy and +the user doesn't set one?][br][br] If a function needs a policy and one +was not set, Pyste will issue a error. The user should then go in the +interface file and set the policy for it, otherwise the generated cpp won't +compile. +] + +[blurb +[$theme/note.gif] +Note that for functions that return [^const T&], the policy +[^return_value_policy<copy_const_reference>()] wil be used by default, because +that's normally what you want. You can change it to something else if you need +to, though. +] + +[page:1 Templates] + +Template classes can easily be exported too, but you can't export the template +itself... you have to export instantiations of it! So, if you want to export a +[^std::vector], you will have to export vectors of int, doubles, etc. + +Suppose we have this code: + + template <class T> + struct Point + { + T x; + T y; + }; + +And we want to export [^Point]s of int and double: + + Point = Template("Point", "point.h") + Point("int") + Point("double") + +Pyste will assign default names for each instantiation. In this example, those +would be "[^Point_int]" and "[^Point_double]", but most of the time users will want to +rename the instantiations: + + Point("int", "IPoint") // renames the instantiation + double_inst = Point("double") // another way to do the same + rename(double_inst, "DPoint") + +Note that you can rename, exclude, set policies, etc, in the [^Template] object +like you would do with a [^Function] or a [^Class]. This changes affect all +[*future] instantiations: + + Point = Template("Point", "point.h") + Point("float", "FPoint") // will have x and y as data members + rename(Point.x, "X") + rename(Point.y, "Y") + Point("int", "IPoint") // will have X and Y as data members + Point("double", "DPoint") // also will have X and Y as data member + +If you want to change a option of a particular instantiation, you can do so: + + Point = Template("Point", "point.h") + Point("int", "IPoint") + d_inst = Point("double", "DPoint") + rename(d_inst.x, "X") // only DPoint is affect by this renames, + rename(d_inst.y, "Y") // IPoint stays intact + +[blurb [$theme/note.gif] [*What if my template accepts more than one type?] +[br][br] +When you want to instantiate a template with more than one type, you can pass +either a string with the types separated by whitespace, or a list of strings +'''("int double" or ["int", "double"]''' would both work). +] + +[page:1 Wrappers] + +Suppose you have this function: + + std::vector<std::string> names(); + +But you don't want to [@../../doc/v2/faq.html#question2 to export std::vector<std::string>], +you want this function to return a python list of strings. Boost.Python has +excellent support for things like that: + + list names_wrapper() + { + list result; + // call original function + vector<string> v = names(); + // put all the strings inside the python list + vector<string>::iterator it; + for (it = v.begin(); it != v.end(); ++it){ + result.append(*it); + } + return result; + } + + BOOST_PYTHON_MODULE(test) + { + def("names", &names_wrapper); + } + +Nice heh? Pyste supports this mechanism too. You declare the [^names_wrapper] +function in a header named "[^test_wrappers.h]" and in the interface file: + + Include("test_wrappers.h") + names = Function("names", "test.h") + set_wrapper(names, "names_wrapper") + +You can optionally declare the function in the interface file itself: + + names_wrapper = Wrapper("names_wrapper", + """ + list names_wrapper() + { + // code to call name() and convert the vector to a list... + } + """) + names = Function("names", "test.h") + set_wrapper(names, names_wrapper) + +The same mechanism can be used with member functions too. Just remember that +the first parameter of wrappers for member functions is a pointer to the +class, as in: + + struct C + { + std::vector<std::string> names(); + } + + list names_wrapper(C* c) + { + // same as before, calling c->names() and converting result to a list + } + +And then in the interface file: + + C = Class("C", "test.h") + set_wrapper(C.names, "names_wrapper") + +[blurb +[$theme/note.gif]Even though Boost.Python accepts either a pointer or a +reference to the class in wrappers for member functions as the first parameter, +Pyste expects them to be a [*pointer]. Doing otherwise will prevent your +code to compile when you set a wrapper for a virtual member function. +] + +[page:1 Exporting An Entire Header] + +Pyste also supports a mechanism to export all declarations found in a header +file. Suppose again our file, [^hello.h]: + + struct World + { + World(std::string msg): msg(msg) {} + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + + enum choice { red, blue }; + + void show(choice c) { std::cout << "value: " << (int)c << std::endl; } + +You can just use the [^AllFromHeader] construct: + + hello = AllFromHeader("hello.h") + +this will export all the declarations found in [^hello.h], which is equivalent +to write: + + Class("World", "hello.h") + Enum("choice", "hello.h") + Function("show", "hello.h") + +Note that you can still use the functions [^rename], [^set_policy], [^exclude], etc. Just access +the members of the header object like this: + + rename(hello.World.greet, "Greet") + exclude(hello.World.set, "Set") + +[blurb +[$theme/note.gif] [*AllFromHeader is broken] in some cases. Until it is fixed, +use at you own risk. +] + + +[page:1 Smart Pointers] + +Pyste for now has manual support for smart pointers. Suppose: + + struct C + { + int value; + }; + + boost::shared_ptr<C> newC(int value) + { + boost::shared_ptr<C> c( new C() ); + c->value = value; + return c; + } + + void printC(boost::shared_ptr<C> c) + { + std::cout << c->value << std::endl; + } + +To make [^newC] and [^printC] work correctly, you have to tell Pyste that a +convertor for [^boost::shared_ptr<C>] is needed. + + C = Class('C', 'C.h') + use_shared_ptr(C) + Function('newC', 'C.h') + Function('printC', 'C.h') + +For [^std::auto_ptr]'s, use the function [^use_auto_ptr]. + +This system is temporary, and in the future the converters will automatically be +exported if needed, without the need to tell Pyste about them explicitly. + +[h2 Holders] + +If only the converter for the smart pointers is not enough and you need to +specify the smart pointer as the holder for a class, use the functions +[^hold_with_shared_ptr] and [^hold_with_auto_ptr]: + + C = Class('C', 'C.h') + hold_with_shared_ptr(C) + Function('newC', 'C.h') + Function('printC', 'C.h') + +[page:1 Global Variables] + +To export global variables, use the [^Var] construct: + + Var("myglobal", "foo.h") + +Beware of non-const global variables: changes in Python won't reflect in C++! +If you really must change them in Python, you will have to write some accessor +functions, and export those. + + +[page:1 Adding New Methods] + +Suppose that you want to add a function to a class, turning it into a member +function: + + struct World + { + void set(std::string msg) { this->msg = msg; } + std::string msg; + }; + + std::string greet(World& w) + { + return w.msg; + } + +Here, we want to make [^greet] work as a member function of the class [^World]. We do +that using the [^add_method] construct: + + W = Class("World", "hello.h") + add_method(W, "greet") + +Notice also that then you can rename it, set its policy, just like a regular +member function: + + rename(W.greet, 'Greet') + +Now from Python: + + >>> import hello + >>> w = hello.World() + >>> w.set('Ni') + >>> w.greet() + 'Ni' + >>> print 'Oh no! The knights who say Ni!' + Oh no! The knights who say Ni! + + +[page:1 Inserting Code] + +You can insert arbitrary code in the generated cpps, just use the functions +[^declaration_code] and [^module_code]. This will insert the given string in the +respective sections. Example: + + # file A.pyste + Class("A", "A.h") + declaration_code("/* declaration_code() comes here */\n") + module_code("/* module_code() comes here */\n") + +Will generate: + + // Includes ==================================================================== + #include <boost/python.hpp> + + // Using ======================================================================= + using namespace boost::python; + + // Declarations ================================================================ + + /* declaration_code() comes here */ + + // Module ====================================================================== + BOOST_PYTHON_MODULE(A) + { + class_< A >("A", init< >()) + .def(init< const A& >()) + ; + + /* module_code() comes here */ + } diff --git a/libs/python/pyste/doc/renaming_and_excluding.html b/libs/python/pyste/doc/renaming_and_excluding.html new file mode 100644 index 000000000..ce6654c4a --- /dev/null +++ b/libs/python/pyste/doc/renaming_and_excluding.html @@ -0,0 +1,87 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Renaming and Excluding</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="the_interface_files.html"> +<link rel="next" href="policies.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Renaming and Excluding</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="the_interface_files.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="policies.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +You can easily rename functions, classes, member functions, attributes, etc. Just use the +function <tt>rename</tt>, like this:</p> +<code><pre> + <span class=identifier>World </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>, </span><span class=string>"IWorld"</span><span class=special>) + </span><span class=identifier>show </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>show</span><span class=special>, </span><span class=string>"Show"</span><span class=special>) +</span></pre></code> +<p> +You can rename member functions and attributes using this syntax:</p> +<code><pre> + <span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>"Greet"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>"Set"</span><span class=special>) + </span><span class=identifier>choice </span><span class=special>= </span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>red</span><span class=special>, </span><span class=string>"Red"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>blue</span><span class=special>, </span><span class=string>"Blue"</span><span class=special>) +</span></pre></code> +<p> +You can exclude functions, classes, member functions, attributes, etc, in the same way, +with the function <tt>exclude</tt>:</p> +<code><pre> + <span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>) + </span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>msg</span><span class=special>) +</span></pre></code> +<p> +To access the operators of a class, access the member <tt>operator</tt> like this +(supposing that <tt>C</tt> is a class being exported):</p> +<code><pre> + <span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'+'</span><span class=special>]) + </span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'*'</span><span class=special>]) + </span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'<<'</span><span class=special>]) +</span></pre></code> +<p> +The string inside the brackets is the same as the name of the operator in C++.<br></p> +<a name="virtual_member_functions"></a><h2>Virtual Member Functions</h2><p> +Pyste automatically generates wrappers for virtual member functions, but you may +want to disable this behaviour (for performance reasons, for instance) if you do +not plan to override the functions in Python. To do this, use the function +<tt>final</tt>:</p> +<code><pre> + <span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) + </span><span class=identifier>final</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>) </span>##<span class=identifier>C</span><span class=special>::</span><span class=identifier>foo </span><span class=identifier>is </span><span class=identifier>a </span><span class=keyword>virtual </span><span class=identifier>member </span><span class=identifier>function +</span></pre></code> +<p> +No virtual wrapper code will be generated for the virtual member function +C::foo that way.</p> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="the_interface_files.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="policies.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/running_pyste.html b/libs/python/pyste/doc/running_pyste.html new file mode 100644 index 000000000..9bd9a3aee --- /dev/null +++ b/libs/python/pyste/doc/running_pyste.html @@ -0,0 +1,200 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Running Pyste</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="introduction.html"> +<link rel="next" href="the_interface_files.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Running Pyste</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="introduction.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="the_interface_files.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +To run Pyste, you will need:</p> +<ul><li>Python 2.2, available at <a href="http://www.python.org"> +python's website</a>.</li><li>The great <a href="http://effbot.org"> +elementtree</a> library, from Fredrik Lundh.</li><li>The excellent <a href="http://www.gccxml.org"> +GCCXML</a>, from Brad King.</li></ul><p> +Installation for the tools is available in their respective webpages.</p> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> + +<img src="theme/note.gif"></img> <a href="http://www.gccxml.org"> +GCCXML</a> must be accessible in the PATH environment variable, so +that Pyste can call it. How to do this varies from platform to platform. + </td> + </tr> +</table> +<a name="ok__now_what_"></a><h2>Ok, now what?</h2><p> +Well, now let's fire it up:</p> +<code><pre> + +>python pyste.py + +Pyste version 0.9.26 + +Usage: + pyste [options] interface-files + +where options are: + --module=<name> The name of the module that will be generated; + defaults to the first interface filename, without + the extension. + -I <path> Add an include path + -D <symbol> Define symbol + --multiple Create various cpps, instead of only one + (useful during development) + --out=<name> Specify output filename (default: <module>.cpp) + in --multiple mode, this will be a directory + --no-using Do not declare "using namespace boost"; + use explicit declarations instead + --pyste-ns=<name> Set the namespace where new types will be declared; + default is the empty namespace + --debug Writes the xml for each file parsed in the current + directory + --cache-dir=<dir> Directory for cache files (speeds up future runs) + --only-create-cache Recreates all caches (doesn't generate code). + --generate-main Generates the _main.cpp file (in multiple mode) + --file-list A file with one pyste file per line. Use as a + substitute for passing the files in the command + line. + -h, --help Print this help and exit + -v, --version Print version information + + +</pre></code><p> +Options explained:</p> +<p> +The <tt>-I</tt> and <tt>-D</tt> are preprocessor flags, which are needed by <a href="http://www.gccxml.org"> +GCCXML</a> to parse +the header files correctly and by Pyste to find the header files declared in the +interface files.</p> +<p> +<tt>--out</tt> names the output file (default: <tt><module>.cpp</tt>), or in multiple mode, +names a output directory for the files (default: <tt><module></tt>).</p> +<p> +<tt>--no-using</tt> tells Pyste to don't declare "<tt>using namespace boost;</tt>" in the +generated cpp, using the namespace boost::python explicitly in all declarations. +Use only if you're having a name conflict in one of the files.</p> +<p> +Use <tt>--pyste-ns</tt> to change the namespace where new types are declared (for +instance, the virtual wrappers). Use only if you are having any problems. By +default, Pyste uses the empty namespace.</p> +<p> +<tt>--debug</tt> will write in the current directory a xml file as outputted by <a href="http://www.gccxml.org"> +GCCXML</a> +for each header parsed. Useful for bug reports.</p> +<p> +<tt>--file-list</tt> names a file where each line points to a Pyste file. Use this instead +to pass the pyste files if you have a lot of them and your shell has some command line +size limit.</p> +<p> +The other options are explained below, in <a href="#multiple_mode"> +<b>Multiple Mode</b></a> and +<a href="#cache"> +<b>Cache</b></a>.</p> +<p> +<tt>-h, --help, -v, --version</tt> are self-explaining, I believe. ;)</p> +<p> +So, the usage is simple enough:</p> +<code><pre>>python pyste.py --module=mymodule file.pyste file2.pyste ...</pre></code><p> +will generate a file <tt>mymodule.cpp</tt> in the same dir where the command was +executed. Now you can compile the file using the same instructions of the +<a href="../../doc/tutorial/doc/html/python/hello.html"> +tutorial</a>. </p> +<a name="wait____how_do_i_set_those_i_and_d_flags_"></a><h2>Wait... how do I set those I and D flags?</h2><p> +Don't worry: normally <a href="http://www.gccxml.org"> +GCCXML</a> is already configured correctly for your plataform, +so the search path to the standard libraries and the standard defines should +already be set. You only have to set the paths to other libraries that your code +needs, like Boost, for example.</p> +<p> +Plus, Pyste automatically uses the contents of the environment variable +<tt>INCLUDE</tt> if it exists. Visual C++ users should run the <tt>Vcvars32.bat</tt> file, +which for Visual C++ 6 is normally located at:</p> +<code><pre> + <span class=identifier>C</span><span class=special>:\</span><span class=identifier>Program </span><span class=identifier>Files</span><span class=special>\</span><span class=identifier>Microsoft </span><span class=identifier>Visual </span><span class=identifier>Studio</span><span class=special>\</span><span class=identifier>VC98</span><span class=special>\</span><span class=identifier>bin</span><span class=special>\</span><span class=identifier>Vcvars32</span><span class=special>.</span><span class=identifier>bat +</span></pre></code> +<p> +with that, you should have little trouble setting up the flags.</p> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> +<img src="theme/note.gif"></img><b>A note about Psyco</b><br><br> +Although you don't have to install <a href="http://psyco.sourceforge.net/"> +Psyco</a> to +use Pyste, if you do, Pyste will make use of it to speed up the wrapper +generation. Speed ups of 30% can be achieved, so it's highly recommended. + </td> + </tr> +</table> +<a name="multiple_mode"></a><h2>Multiple Mode</h2><p> +The multiple mode is useful in large projects, where the presence of multiple +classes in a single file makes the compilation unpractical (excessive memory +usage, mostly). </p> +<p> +The solution is make Pyste generate multiple files, more specifically one cpp +file for each Pyste file. This files will contain a function named after the +file, for instance Export_MyPysteFile, which will contain all the code to export +the classes, enums, etc. You can pass as much files as you want this way:</p> +<code><pre>>python pyste.py --module=mymodule file1.pyste file2.pyste</pre></code><p> +This will create the files <tt>mymodule/file1.cpp</tt> and <tt>mymodule/file2.cpp</tt>. You +can then later do:</p> +<code><pre>>python pyste.py --module=mymodule file3.pyste</pre></code><p> +and <tt>mymodule/file3.cpp</tt> will be generated.</p> +<p> +But compiling and linking this files won't be sufficient to generate your +extension. You have to also generate a file named <tt>main.cpp</tt>; call pyste with +<b>all</b> the Pyste files of your extension, and use the <tt>--generate-main</tt> option:</p> +<code><pre>>python pyste.py --module=mymodule --generate-main file1.pyste file2.pyste file3.pyste</pre></code><p> +Now compile and link all this files together and your extension is ready for +use.</p> +<a name="cache"></a><h2>Cache</h2><p> +Pyste now supports a form of cache, which is a way to speed up the code +generation. Most of the time that Pyste takes to generate the code comes from +having to execute <a href="http://www.gccxml.org"> +GCCXML</a> (since being a front-end to GCC, it has to compile the +header files) and reading back the XML generated. </p> +<p> +When you use the <tt>--cache-dir=<dir></tt> option, Pyste will dump in the specified +directory the generated XMLs to a file named after the Pyste file, with the +extension <tt>.pystec</tt>. The next time you run with this option, Pyste will use +the cache, instead of calling <a href="http://www.gccxml.org"> +GCCXML</a> again:</p> +<code><pre>>python pyste.py --module=mymodule --cache-dir=cache file1.pyste</pre></code><p> +Will generate <tt>file1.cpp</tt> and <tt>cache/file1.pystec</tt>. Next time you execute +this command, the cache file will be used. Note that Pyste doesn't do any check +to ensure that the cache is up to date, but you can configure your build system to do that for you.</p> +<p> +When you run Pyste with <tt>--only-create-cache</tt>, all the cache files will be +created again, but no code will be generated.</p> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="introduction.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="the_interface_files.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/smart_pointers.html b/libs/python/pyste/doc/smart_pointers.html new file mode 100644 index 000000000..cddc96f2f --- /dev/null +++ b/libs/python/pyste/doc/smart_pointers.html @@ -0,0 +1,84 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Smart Pointers</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="exporting_an_entire_header.html"> +<link rel="next" href="global_variables.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Smart Pointers</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="exporting_an_entire_header.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="global_variables.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +Pyste for now has manual support for smart pointers. Suppose:</p> +<code><pre> + <span class=keyword>struct </span><span class=identifier>C + </span><span class=special>{ + </span><span class=keyword>int </span><span class=identifier>value</span><span class=special>; + }; + + </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>newC</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>) + { + </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>c</span><span class=special>( </span><span class=keyword>new </span><span class=identifier>C</span><span class=special>() ); + </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special>= </span><span class=identifier>value</span><span class=special>; + </span><span class=keyword>return </span><span class=identifier>c</span><span class=special>; + } + + </span><span class=keyword>void </span><span class=identifier>printC</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>c</span><span class=special>) + { + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; + } +</span></pre></code> +<p> +To make <tt>newC</tt> and <tt>printC</tt> work correctly, you have to tell Pyste that a +convertor for <tt>boost::shared_ptr<C></tt> is needed.</p> +<code><pre> + <span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) + </span><span class=identifier>use_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>) + </span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) + </span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) +</span></pre></code> +<p> +For <tt>std::auto_ptr</tt>'s, use the function <tt>use_auto_ptr</tt>.</p> +<p> +This system is temporary, and in the future the converters will automatically be +exported if needed, without the need to tell Pyste about them explicitly.</p> +<a name="holders"></a><h2>Holders</h2><p> +If only the converter for the smart pointers is not enough and you need to +specify the smart pointer as the holder for a class, use the functions +<tt>hold_with_shared_ptr</tt> and <tt>hold_with_auto_ptr</tt>:</p> +<code><pre> + <span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) + </span><span class=identifier>hold_with_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>) + </span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) + </span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>) +</span></pre></code> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="exporting_an_entire_header.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="global_variables.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/templates.html b/libs/python/pyste/doc/templates.html new file mode 100644 index 000000000..a1c1cfefb --- /dev/null +++ b/libs/python/pyste/doc/templates.html @@ -0,0 +1,102 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Templates</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="policies.html"> +<link rel="next" href="wrappers.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Templates</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="policies.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="wrappers.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +Template classes can easily be exported too, but you can't export the template +itself... you have to export instantiations of it! So, if you want to export a +<tt>std::vector</tt>, you will have to export vectors of int, doubles, etc.</p> +<p> +Suppose we have this code:</p> +<code><pre> + <span class=keyword>template </span><span class=special><</span><span class=keyword>class </span><span class=identifier>T</span><span class=special>> + </span><span class=keyword>struct </span><span class=identifier>Point + </span><span class=special>{ + </span><span class=identifier>T </span><span class=identifier>x</span><span class=special>; + </span><span class=identifier>T </span><span class=identifier>y</span><span class=special>; + }; +</span></pre></code> +<p> +And we want to export <tt>Point</tt>s of int and double:</p> +<code><pre> + <span class=identifier>Point </span><span class=special>= </span><span class=identifier>Template</span><span class=special>(</span><span class=string>"Point"</span><span class=special>, </span><span class=string>"point.h"</span><span class=special>) + </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>) + </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>) +</span></pre></code> +<p> +Pyste will assign default names for each instantiation. In this example, those +would be "<tt>Point_int</tt>" and "<tt>Point_double</tt>", but most of the time users will want to +rename the instantiations:</p> +<code><pre> + <span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>, </span><span class=string>"IPoint"</span><span class=special>) // </span><span class=identifier>renames </span><span class=identifier>the </span><span class=identifier>instantiation + </span><span class=identifier>double_inst </span><span class=special>= </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>) // </span><span class=identifier>another </span><span class=identifier>way </span><span class=identifier>to </span><span class=keyword>do </span><span class=identifier>the </span><span class=identifier>same + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>double_inst</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>) +</span></pre></code> +<p> +Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> object +like you would do with a <tt>Function</tt> or a <tt>Class</tt>. This changes affect all +<b>future</b> instantiations:</p> +<code><pre> + <span class=identifier>Point </span><span class=special>= </span><span class=identifier>Template</span><span class=special>(</span><span class=string>"Point"</span><span class=special>, </span><span class=string>"point.h"</span><span class=special>) + </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"float"</span><span class=special>, </span><span class=string>"FPoint"</span><span class=special>) // </span><span class=identifier>will </span><span class=identifier>have </span><span class=identifier>x </span><span class=keyword>and </span><span class=identifier>y </span><span class=identifier>as </span><span class=identifier>data </span><span class=identifier>members + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>Point</span><span class=special>.</span><span class=identifier>x</span><span class=special>, </span><span class=string>"X"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>Point</span><span class=special>.</span><span class=identifier>y</span><span class=special>, </span><span class=string>"Y"</span><span class=special>) + </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>, </span><span class=string>"IPoint"</span><span class=special>) // </span><span class=identifier>will </span><span class=identifier>have </span><span class=identifier>X </span><span class=keyword>and </span><span class=identifier>Y </span><span class=identifier>as </span><span class=identifier>data </span><span class=identifier>members + </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>) // </span><span class=identifier>also </span><span class=identifier>will </span><span class=identifier>have </span><span class=identifier>X </span><span class=keyword>and </span><span class=identifier>Y </span><span class=identifier>as </span><span class=identifier>data </span><span class=identifier>member +</span></pre></code> +<p> +If you want to change a option of a particular instantiation, you can do so:</p> +<code><pre> + <span class=identifier>Point </span><span class=special>= </span><span class=identifier>Template</span><span class=special>(</span><span class=string>"Point"</span><span class=special>, </span><span class=string>"point.h"</span><span class=special>) + </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>, </span><span class=string>"IPoint"</span><span class=special>) + </span><span class=identifier>d_inst </span><span class=special>= </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>) + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>d_inst</span><span class=special>.</span><span class=identifier>x</span><span class=special>, </span><span class=string>"X"</span><span class=special>) // </span><span class=identifier>only </span><span class=identifier>DPoint </span><span class=identifier>is </span><span class=identifier>affect </span><span class=identifier>by </span><span class=keyword>this </span><span class=identifier>renames</span><span class=special>, + </span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>d_inst</span><span class=special>.</span><span class=identifier>y</span><span class=special>, </span><span class=string>"Y"</span><span class=special>) // </span><span class=identifier>IPoint </span><span class=identifier>stays </span><span class=identifier>intact +</span></pre></code> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> +<img src="theme/note.gif"></img> <b>What if my template accepts more than one type?</b> +<br><br> +When you want to instantiate a template with more than one type, you can pass +either a string with the types separated by whitespace, or a list of strings +("int double" or ["int", "double"] would both work). + </td> + </tr> +</table> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="policies.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="wrappers.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/the_interface_files.html b/libs/python/pyste/doc/the_interface_files.html new file mode 100644 index 000000000..9c0200432 --- /dev/null +++ b/libs/python/pyste/doc/the_interface_files.html @@ -0,0 +1,102 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>The Interface Files</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="running_pyste.html"> +<link rel="next" href="renaming_and_excluding.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>The Interface Files</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="running_pyste.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="renaming_and_excluding.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +The interface files are the heart of Pyste. The user creates one or more +interface files declaring the classes and functions he wants to export, and then +invokes Pyste passing the interface files to it. Pyste then generates a single +cpp file with <a href="../../index.html"> +Boost.Python</a> code, with all the classes and functions exported.</p> +<p> +Besides declaring the classes and functions, the user has a number of other +options, like renaming e excluding classes and member functionis. Those are +explained later on.</p> +<a name="basics"></a><h2>Basics</h2><p> +Suppose we have a class and some functions that we want to expose to Python +declared in the header <tt>hello.h</tt>:</p> +<code><pre> + <span class=keyword>struct </span><span class=identifier>World + </span><span class=special>{ + </span><span class=identifier>World</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>): </span><span class=identifier>msg</span><span class=special>(</span><span class=identifier>msg</span><span class=special>) {} + </span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; } + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>; + }; + + </span><span class=keyword>enum </span><span class=identifier>choice </span><span class=special>{ </span><span class=identifier>red</span><span class=special>, </span><span class=identifier>blue </span><span class=special>}; + + </span><span class=keyword>namespace </span><span class=identifier>test </span><span class=special>{ + + </span><span class=keyword>void </span><span class=identifier>show</span><span class=special>(</span><span class=identifier>choice </span><span class=identifier>c</span><span class=special>) { </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=string>"value: " </span><span class=special><< (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; } + + } +</span></pre></code> +<p> +We create a file named <tt>hello.pyste</tt> and create instances of the classes +<tt>Function</tt>, <tt>Class</tt> and <tt>Enum</tt>:</p> +<code><pre> + <span class=identifier>Function</span><span class=special>(</span><span class=string>"test::show"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) + </span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>) +</span></pre></code> +<p> +That will expose the class, the free function and the enum found in <tt>hello.h</tt>. </p> +<a name="inheritance"></a><h2>Inheritance</h2><p> +Pyste automatically generates the correct code (specifying <tt>bases<></tt> in the +<tt>class_</tt> declaration) <b>if</b> the Class() function that exports the base classes +and their children are in the same Pyste file. If that's not the case, you have +to indicate that there's a relationship between the Pyste files using the +<tt>Import</tt> function specifying the other Pyste file.</p> +<p> +Suppose we have two classes, <tt>A</tt> and <tt>B</tt>, and A is a base class for B. We +create two Pyste files:</p> +<p> +<tt>A.pyste</tt>:</p> +<code><pre> + <span class=identifier>Class</span><span class=special>(</span><span class=string>"A"</span><span class=special>, </span><span class=string>"A.h"</span><span class=special>) +</span></pre></code> +<p> +<tt>B.pyste</tt>:</p> +<code><pre> + <span class=identifier>Import</span><span class=special>(</span><span class=string>"A.pyste"</span><span class=special>) + </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"B"</span><span class=special>, </span><span class=string>"B.h"</span><span class=special>) +</span></pre></code> +<p> +Note that we specify that <tt>B</tt> needs to know about <tt>A</tt> to be properly exported.</p> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="running_pyste.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="renaming_and_excluding.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/doc/theme/alert.gif b/libs/python/pyste/doc/theme/alert.gif Binary files differnew file mode 100644 index 000000000..270764cc5 --- /dev/null +++ b/libs/python/pyste/doc/theme/alert.gif diff --git a/libs/python/pyste/doc/theme/arrow.gif b/libs/python/pyste/doc/theme/arrow.gif Binary files differnew file mode 100644 index 000000000..e33db0fb4 --- /dev/null +++ b/libs/python/pyste/doc/theme/arrow.gif diff --git a/libs/python/pyste/doc/theme/bkd.gif b/libs/python/pyste/doc/theme/bkd.gif Binary files differnew file mode 100644 index 000000000..dcabcb806 --- /dev/null +++ b/libs/python/pyste/doc/theme/bkd.gif diff --git a/libs/python/pyste/doc/theme/bkd2.gif b/libs/python/pyste/doc/theme/bkd2.gif Binary files differnew file mode 100644 index 000000000..b03d9ba97 --- /dev/null +++ b/libs/python/pyste/doc/theme/bkd2.gif diff --git a/libs/python/pyste/doc/theme/bulb.gif b/libs/python/pyste/doc/theme/bulb.gif Binary files differnew file mode 100644 index 000000000..74f3baac4 --- /dev/null +++ b/libs/python/pyste/doc/theme/bulb.gif diff --git a/libs/python/pyste/doc/theme/bullet.gif b/libs/python/pyste/doc/theme/bullet.gif Binary files differnew file mode 100644 index 000000000..da787e2ef --- /dev/null +++ b/libs/python/pyste/doc/theme/bullet.gif diff --git a/libs/python/pyste/doc/theme/l_arr.gif b/libs/python/pyste/doc/theme/l_arr.gif Binary files differnew file mode 100644 index 000000000..5b3cb1cbf --- /dev/null +++ b/libs/python/pyste/doc/theme/l_arr.gif diff --git a/libs/python/pyste/doc/theme/l_arr_disabled.gif b/libs/python/pyste/doc/theme/l_arr_disabled.gif Binary files differnew file mode 100644 index 000000000..ed58a605a --- /dev/null +++ b/libs/python/pyste/doc/theme/l_arr_disabled.gif diff --git a/libs/python/pyste/doc/theme/note.gif b/libs/python/pyste/doc/theme/note.gif Binary files differnew file mode 100644 index 000000000..bd92f0755 --- /dev/null +++ b/libs/python/pyste/doc/theme/note.gif diff --git a/libs/python/pyste/doc/theme/r_arr.gif b/libs/python/pyste/doc/theme/r_arr.gif Binary files differnew file mode 100644 index 000000000..2dcdad117 --- /dev/null +++ b/libs/python/pyste/doc/theme/r_arr.gif diff --git a/libs/python/pyste/doc/theme/r_arr_disabled.gif b/libs/python/pyste/doc/theme/r_arr_disabled.gif Binary files differnew file mode 100644 index 000000000..2100f78bf --- /dev/null +++ b/libs/python/pyste/doc/theme/r_arr_disabled.gif diff --git a/libs/python/pyste/doc/theme/smiley.gif b/libs/python/pyste/doc/theme/smiley.gif Binary files differnew file mode 100644 index 000000000..4c848f8fe --- /dev/null +++ b/libs/python/pyste/doc/theme/smiley.gif diff --git a/libs/python/pyste/doc/theme/style.css b/libs/python/pyste/doc/theme/style.css new file mode 100644 index 000000000..643df02a9 --- /dev/null +++ b/libs/python/pyste/doc/theme/style.css @@ -0,0 +1,178 @@ +/*============================================================================= + Copyright (c) 2003 Bruno da Silva de Oliveira + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +body +{ + background-image: url(bkd.gif); + background-color: #FFFFFF; + margin: 1em 2em 1em 2em; +} + +h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; } +h2 { font: 140% sans-serif; font-weight: bold; text-align: left; } +h3 { font: 120% sans-serif; font-weight: bold; text-align: left; } +h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; } +h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; } +h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; } + +pre +{ + border-top: gray 1pt solid; + border-right: gray 1pt solid; + border-left: gray 1pt solid; + border-bottom: gray 1pt solid; + + padding-top: 2pt; + padding-right: 2pt; + padding-left: 2pt; + padding-bottom: 2pt; + + display: block; + font-family: "courier new", courier, mono; + background-color: #eeeeee; font-size: small +} + +code +{ + font-family: "Courier New", Courier, mono; + font-size: small +} + +tt +{ + display: inline; + font-family: "Courier New", Courier, mono; + color: #000099; + font-size: small +} + +p +{ + text-align: justify; + font-family: Georgia, "Times New Roman", Times, serif +} + +ul +{ + list-style-image: url(bullet.gif); + font-family: Georgia, "Times New Roman", Times, serif +} + +ol +{ + font-family: Georgia, "Times New Roman", Times, serif +} + +a +{ + font-weight: bold; + color: #003366; + text-decoration: none; +} + +a:hover { color: #8080FF; } + +.literal { color: #666666; font-style: italic} +.keyword { color: #000099} +.identifier {} +.comment { font-style: italic; color: #990000} +.special { color: #800040} +.preprocessor { color: #FF0000} +.string { font-style: italic; color: #666666} +.copyright { color: #666666; font-size: small} +.white_bkd { background-color: #FFFFFF} +.dk_grey_bkd { background-color: #999999} +.quotes { color: #666666; font-style: italic; font-weight: bold} + +.note_box +{ + display: block; + + border-top: gray 1pt solid; + border-right: gray 1pt solid; + border-left: gray 1pt solid; + border-bottom: gray 1pt solid; + + padding-right: 12pt; + padding-left: 12pt; + padding-bottom: 12pt; + padding-top: 12pt; + + font-family: Arial, Helvetica, sans-serif; + background-color: #E2E9EF; + font-size: small; text-align: justify +} + +.table_title +{ + background-color: #648CCA; + + font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF; + font-weight: bold +; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px +} + +.table_cells +{ + background-color: #E2E9EF; + + font-family: Geneva, Arial, Helvetica, san-serif; + font-size: small +; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px +} + +.toc +{ + DISPLAY: block; + background-color: #E2E9EF + font-family: Arial, Helvetica, sans-serif; + + border-top: gray 1pt solid; + border-left: gray 1pt solid; + border-bottom: gray 1pt solid; + border-right: gray 1pt solid; + + padding-top: 24pt; + padding-right: 24pt; + padding-left: 24pt; + padding-bottom: 24pt; +} + +.toc_title +{ + background-color: #648CCA; + padding-top: 4px; + padding-right: 4px; + padding-bottom: 4px; + padding-left: 4px; + font-family: Geneva, Arial, Helvetica, san-serif; + color: #FFFFFF; + font-weight: bold +} + +.toc_cells +{ + background-color: #E2E9EF; + padding-top: 4px; + padding-right: 4px; + padding-bottom: 4px; + padding-left: 4px; + font-family: Geneva, Arial, Helvetica, san-serif; + font-size: small +} + +div.logo +{ + float: right; +} + +.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } +.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } diff --git a/libs/python/pyste/doc/theme/u_arr.gif b/libs/python/pyste/doc/theme/u_arr.gif Binary files differnew file mode 100644 index 000000000..ada3d6e04 --- /dev/null +++ b/libs/python/pyste/doc/theme/u_arr.gif diff --git a/libs/python/pyste/doc/wrappers.html b/libs/python/pyste/doc/wrappers.html new file mode 100644 index 000000000..534ae5529 --- /dev/null +++ b/libs/python/pyste/doc/wrappers.html @@ -0,0 +1,124 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Wrappers</title> +<link rel="stylesheet" href="theme/style.css" type="text/css"> +<link rel="prev" href="templates.html"> +<link rel="next" href="exporting_an_entire_header.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Wrappers</b></font> + </td> + </tr> +</table> +<br> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="templates.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="exporting_an_entire_header.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<p> +Suppose you have this function:</p> +<code><pre> + <span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>names</span><span class=special>(); +</span></pre></code> +<p> +But you don't want to <a href="../../doc/v2/faq.html#question2"> +to export std::vector<std::string></a>, +you want this function to return a python list of strings. <a href="../../index.html"> +Boost.Python</a> has +excellent support for things like that:</p> +<code><pre> + <span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>() + { + </span><span class=identifier>list </span><span class=identifier>result</span><span class=special>; + // </span><span class=identifier>call </span><span class=identifier>original </span><span class=identifier>function + </span><span class=identifier>vector</span><span class=special><</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>v </span><span class=special>= </span><span class=identifier>names</span><span class=special>(); + // </span><span class=identifier>put </span><span class=identifier>all </span><span class=identifier>the </span><span class=identifier>strings </span><span class=identifier>inside </span><span class=identifier>the </span><span class=identifier>python </span><span class=identifier>list + </span><span class=identifier>vector</span><span class=special><</span><span class=identifier>string</span><span class=special>>::</span><span class=identifier>iterator </span><span class=identifier>it</span><span class=special>; + </span><span class=keyword>for </span><span class=special>(</span><span class=identifier>it </span><span class=special>= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(); </span><span class=identifier>it </span><span class=special>!= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>end</span><span class=special>(); ++</span><span class=identifier>it</span><span class=special>){ + </span><span class=identifier>result</span><span class=special>.</span><span class=identifier>append</span><span class=special>(*</span><span class=identifier>it</span><span class=special>); + } + </span><span class=keyword>return </span><span class=identifier>result</span><span class=special>; + } + + </span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>test</span><span class=special>) + { + </span><span class=identifier>def</span><span class=special>(</span><span class=string>"names"</span><span class=special>, &</span><span class=identifier>names_wrapper</span><span class=special>); + } +</span></pre></code> +<p> +Nice heh? Pyste supports this mechanism too. You declare the <tt>names_wrapper</tt> +function in a header named "<tt>test_wrappers.h</tt>" and in the interface file:</p> +<code><pre> + <span class=identifier>Include</span><span class=special>(</span><span class=string>"test_wrappers.h"</span><span class=special>) + </span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>) + </span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=string>"names_wrapper"</span><span class=special>) +</span></pre></code> +<p> +You can optionally declare the function in the interface file itself:</p> +<code><pre> + <span class=identifier>names_wrapper </span><span class=special>= </span><span class=identifier>Wrapper</span><span class=special>(</span><span class=string>"names_wrapper"</span><span class=special>, + </span><span class=string>""</span><span class=string>" + list names_wrapper() + { + // code to call name() and convert the vector to a list... + } + "</span><span class=string>""</span><span class=special>) + </span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>) + </span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=identifier>names_wrapper</span><span class=special>) +</span></pre></code> +<p> +The same mechanism can be used with member functions too. Just remember that +the first parameter of wrappers for member functions is a pointer to the +class, as in:</p> +<code><pre> + <span class=keyword>struct </span><span class=identifier>C + </span><span class=special>{ + </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>names</span><span class=special>(); + } + + </span><span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>* </span><span class=identifier>c</span><span class=special>) + { + // </span><span class=identifier>same </span><span class=identifier>as </span><span class=identifier>before</span><span class=special>, </span><span class=identifier>calling </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>names</span><span class=special>() </span><span class=keyword>and </span><span class=identifier>converting </span><span class=identifier>result </span><span class=identifier>to </span><span class=identifier>a </span><span class=identifier>list + </span><span class=special>} +</span></pre></code> +<p> +And then in the interface file:</p> +<code><pre> + <span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"C"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>) + </span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>names</span><span class=special>, </span><span class=string>"names_wrapper"</span><span class=special>) +</span></pre></code> +<table width="80%" border="0" align="center"> + <tr> + <td class="note_box"> + +<img src="theme/note.gif"></img>Even though <a href="../../index.html"> +Boost.Python</a> accepts either a pointer or a +reference to the class in wrappers for member functions as the first parameter, +Pyste expects them to be a <b>pointer</b>. Doing otherwise will prevent your +code to compile when you set a wrapper for a virtual member function. + </td> + </tr> +</table> +<table border="0"> + <tr> + <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> + <td width="30"><a href="templates.html"><img src="theme/l_arr.gif" border="0"></a></td> + <td width="20"><a href="exporting_an_entire_header.html"><img src="theme/r_arr.gif" border="0"></a></td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/index.html b/libs/python/pyste/index.html new file mode 100644 index 000000000..953b37c12 --- /dev/null +++ b/libs/python/pyste/index.html @@ -0,0 +1,90 @@ +<html> +<head> +<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc --> +<title>Pyste Documentation</title> +<link rel="stylesheet" href="doc/theme/style.css" type="text/css"> +<link rel="next" href="doc/introduction.html"> +</head> +<body> +<table width="100%" height="48" border="0" cellspacing="2"> + <tr> + <td><img src="../../../boost.png"> + </td> + <td width="85%"> + <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Pyste Documentation</b></font> + </td> + </tr> +</table> +<br> +<table width="80%" border="0" align="center"> + <tr> + <td class="toc_title">Table of contents</td> + </tr> + <tr> + <td class="toc_cells_L0"> + <a href="doc/introduction.html">Introduction</a> + </td> + </tr> + <tr> + <td class="toc_cells_L0"> + <a href="doc/running_pyste.html">Running Pyste</a> + </td> + </tr> + <tr> + <td class="toc_cells_L0"> + <a href="doc/the_interface_files.html">The Interface Files</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/renaming_and_excluding.html">Renaming and Excluding</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/policies.html">Policies</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/templates.html">Templates</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/wrappers.html">Wrappers</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/exporting_an_entire_header.html">Exporting An Entire Header</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/smart_pointers.html">Smart Pointers</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/global_variables.html">Global Variables</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/adding_new_methods.html">Adding New Methods</a> + </td> + </tr> + <tr> + <td class="toc_cells_L1"> + <a href="doc/inserting_code.html">Inserting Code</a> + </td> + </tr> +</table> +<br> +<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br> +<font size="2">Distributed under + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p> +</body> +</html> diff --git a/libs/python/pyste/install/pyste.py b/libs/python/pyste/install/pyste.py new file mode 100644 index 000000000..da9262353 --- /dev/null +++ b/libs/python/pyste/install/pyste.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +from Pyste import pyste +pyste.main() diff --git a/libs/python/pyste/install/setup.py b/libs/python/pyste/install/setup.py new file mode 100644 index 000000000..c17039817 --- /dev/null +++ b/libs/python/pyste/install/setup.py @@ -0,0 +1,20 @@ +# Copyright Prabhu Ramachandran 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +from distutils.core import setup +import sys + +setup (name = "Pyste", + version = "0.9.10", + description = "Pyste - Python Semi-Automatic Exporter", + maintainer = "Bruno da Silva de Oliveira", + maintainer_email = "nicodemus@globalite.com.br", + licence = "Boost License", + long_description = "Pyste is a Boost.Python code generator", + url = "http://www.boost.org/libs/python/pyste/index.html", + platforms = ['Any'], + packages = ['Pyste'], + scripts = ['pyste.py'], + package_dir = {'Pyste': '../src/Pyste'}, + ) diff --git a/libs/python/pyste/src/Pyste/ClassExporter.py b/libs/python/pyste/src/Pyste/ClassExporter.py new file mode 100644 index 000000000..decaf628e --- /dev/null +++ b/libs/python/pyste/src/Pyste/ClassExporter.py @@ -0,0 +1,918 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import exporters +from Exporter import Exporter +from declarations import * +from settings import * +from policies import * +from SingleCodeUnit import SingleCodeUnit +from EnumExporter import EnumExporter +from utils import makeid, enumerate +import copy +import exporterutils +import re + +#============================================================================== +# ClassExporter +#============================================================================== +class ClassExporter(Exporter): + 'Generates boost.python code to export a class declaration' + + def __init__(self, info, parser_tail=None): + Exporter.__init__(self, info, parser_tail) + # sections of code + self.sections = {} + # template: each item in the list is an item into the class_<...> + # section. + self.sections['template'] = [] + # constructor: each item in the list is a parameter to the class_ + # constructor, like class_<C>(...) + self.sections['constructor'] = [] + # inside: everything within the class_<> statement + self.sections['inside'] = [] + # scope: items outside the class statement but within its scope. + # scope* s = new scope(class<>()); + # ... + # delete s; + self.sections['scope'] = [] + # declarations: outside the BOOST_PYTHON_MODULE macro + self.sections['declaration'] = [] + self.sections['declaration-outside'] = [] + self.sections['include'] = [] + # a list of Constructor instances + self.constructors = [] + # a list of code units, generated by nested declarations + self.nested_codeunits = [] + + + def ScopeName(self): + return makeid(self.class_.FullName()) + '_scope' + + + def Name(self): + return self.info.name + + + def SetDeclarations(self, declarations): + Exporter.SetDeclarations(self, declarations) + if self.declarations: + decl = self.GetDeclaration(self.info.name) + if isinstance(decl, Typedef): + self.class_ = self.GetDeclaration(decl.type.name) + if not self.info.rename: + self.info.rename = decl.name + else: + self.class_ = decl + self.class_ = copy.deepcopy(self.class_) + else: + self.class_ = None + + + def ClassBases(self): + all_bases = [] + for level in self.class_.hierarchy: + for base in level: + all_bases.append(base) + return [self.GetDeclaration(x.name) for x in all_bases] + + + def Order(self): + '''Return the TOTAL number of bases that this class has, including the + bases' bases. Do this because base classes must be instantialized + before the derived classes in the module definition. + ''' + num_bases = len(self.ClassBases()) + return num_bases, self.class_.FullName() + + + def Export(self, codeunit, exported_names): + self.InheritMethods(exported_names) + self.MakeNonVirtual() + if not self.info.exclude: + self.ExportBasics() + self.ExportBases(exported_names) + self.ExportConstructors() + self.ExportVariables() + self.ExportVirtualMethods(codeunit) + self.ExportMethods() + self.ExportOperators() + self.ExportNestedClasses(exported_names) + self.ExportNestedEnums(exported_names) + self.ExportSmartPointer() + self.ExportOpaquePointerPolicies() + self.ExportAddedCode() + self.Write(codeunit) + exported_names[self.Name()] = 1 + + + def InheritMethods(self, exported_names): + '''Go up in the class hierarchy looking for classes that were not + exported yet, and then add their public members to this classes + members, as if they were members of this class. This allows the user to + just export one type and automatically get all the members from the + base classes. + ''' + valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration) + fullnames = [x.FullName() for x in self.class_] + pointers = [x.PointerDeclaration(True) for x in self.class_ if isinstance(x, Method)] + fullnames = dict([(x, None) for x in fullnames]) + pointers = dict([(x, None) for x in pointers]) + for level in self.class_.hierarchy: + level_exported = False + for base in level: + base = self.GetDeclaration(base.name) + if base.FullName() not in exported_names: + for member in base: + if type(member) in valid_members: + member_copy = copy.deepcopy(member) + member_copy.class_ = self.class_.FullName() + if isinstance(member_copy, Method): + pointer = member_copy.PointerDeclaration(True) + if pointer not in pointers: + self.class_.AddMember(member) + pointers[pointer] = None + elif member_copy.FullName() not in fullnames: + self.class_.AddMember(member) + else: + level_exported = True + if level_exported: + break + def IsValid(member): + return isinstance(member, valid_members) and member.visibility == Scope.public + self.public_members = [x for x in self.class_ if IsValid(x)] + + + def Write(self, codeunit): + indent = self.INDENT + boost_ns = namespaces.python + pyste_ns = namespaces.pyste + code = '' + # begin a scope for this class if needed + nested_codeunits = self.nested_codeunits + needs_scope = self.sections['scope'] or nested_codeunits + if needs_scope: + scope_name = self.ScopeName() + code += indent + boost_ns + 'scope* %s = new %sscope(\n' %\ + (scope_name, boost_ns) + # export the template section + template_params = ', '.join(self.sections['template']) + code += indent + boost_ns + 'class_< %s >' % template_params + # export the constructor section + constructor_params = ', '.join(self.sections['constructor']) + code += '(%s)\n' % constructor_params + # export the inside section + in_indent = indent*2 + for line in self.sections['inside']: + code += in_indent + line + '\n' + # write the scope section and end it + if not needs_scope: + code += indent + ';\n' + else: + code += indent + ');\n' + for line in self.sections['scope']: + code += indent + line + '\n' + # write the contents of the nested classes + for nested_unit in nested_codeunits: + code += '\n' + nested_unit.Section('module') + # close the scope + code += indent + 'delete %s;\n' % scope_name + + # write the code to the module section in the codeunit + codeunit.Write('module', code + '\n') + + # write the declarations to the codeunit + declarations = '\n'.join(self.sections['declaration']) + for nested_unit in nested_codeunits: + declarations += nested_unit.Section('declaration') + if declarations: + codeunit.Write('declaration', declarations + '\n') + declarations_outside = '\n'.join(self.sections['declaration-outside']) + if declarations_outside: + codeunit.Write('declaration-outside', declarations_outside + '\n') + + # write the includes to the codeunit + includes = '\n'.join(self.sections['include']) + for nested_unit in nested_codeunits: + includes += nested_unit.Section('include') + if includes: + codeunit.Write('include', includes) + + + def Add(self, section, item): + 'Add the item into the corresponding section' + self.sections[section].append(item) + + + def ExportBasics(self): + '''Export the name of the class and its class_ statement.''' + class_name = self.class_.FullName() + self.Add('template', class_name) + name = self.info.rename or self.class_.name + self.Add('constructor', '"%s"' % name) + + + def ExportBases(self, exported_names): + 'Expose the bases of the class into the template section' + hierarchy = self.class_.hierarchy + exported = [] + for level in hierarchy: + for base in level: + if base.visibility == Scope.public and base.name in exported_names: + exported.append(base.name) + if exported: + break + if exported: + code = namespaces.python + 'bases< %s > ' % (', '.join(exported)) + self.Add('template', code) + + + def ExportConstructors(self): + '''Exports all the public contructors of the class, plus indicates if the + class is noncopyable. + ''' + py_ns = namespaces.python + indent = self.INDENT + + def init_code(cons): + 'return the init<>() code for the given contructor' + param_list = [p.FullName() for p in cons.parameters] + min_params_list = param_list[:cons.minArgs] + max_params_list = param_list[cons.minArgs:] + min_params = ', '.join(min_params_list) + max_params = ', '.join(max_params_list) + init = py_ns + 'init< ' + init += min_params + if max_params: + if min_params: + init += ', ' + init += py_ns + ('optional< %s >' % max_params) + init += ' >()' + return init + + constructors = [x for x in self.public_members if isinstance(x, Constructor)] + # don't export copy constructors if the class is abstract + # we could remove all constructors, but this will have the effect of + # inserting no_init in the declaration, which would not allow + # even subclasses to be instantiated. + self.constructors = constructors[:] + if self.class_.abstract: + for cons in constructors: + if cons.IsCopy(): + constructors.remove(cons) + break + + if not constructors: + # declare no_init + self.Add('constructor', py_ns + 'no_init') + else: + # write the constructor with less parameters to the constructor section + smaller = None + for cons in constructors: + if smaller is None or len(cons.parameters) < len(smaller.parameters): + smaller = cons + assert smaller is not None + self.Add('constructor', init_code(smaller)) + constructors.remove(smaller) + # write the rest to the inside section, using def() + for cons in constructors: + code = '.def(%s)' % init_code(cons) + self.Add('inside', code) + + # check if the class is copyable + if not self.class_.HasCopyConstructor() or self.class_.abstract: + self.Add('template', namespaces.boost + 'noncopyable') + + + def ExportVariables(self): + 'Export the variables of the class, both static and simple variables' + vars = [x for x in self.public_members if isinstance(x, Variable)] + for var in vars: + if self.info[var.name].exclude: + continue + name = self.info[var.name].rename or var.name + fullname = var.FullName() + if var.type.const: + def_ = '.def_readonly' + else: + def_ = '.def_readwrite' + code = '%s("%s", &%s)' % (def_, name, fullname) + self.Add('inside', code) + + + def OverloadName(self, method): + 'Returns the name of the overloads struct for the given method' + name = makeid(method.FullName()) + overloads = '_overloads_%i_%i' % (method.minArgs, method.maxArgs) + return name + overloads + + + def GetAddedMethods(self): + added_methods = self.info.__added__ + result = [] + if added_methods: + for name, rename in added_methods: + decl = self.GetDeclaration(name) + self.info[name].rename = rename + result.append(decl) + return result + + + def ExportMethods(self): + '''Export all the non-virtual methods of this class, plus any function + that is to be exported as a method''' + + declared = {} + def DeclareOverloads(m): + 'Declares the macro for the generation of the overloads' + if (isinstance(m, Method) and m.static) or type(m) == Function: + func = m.FullName() + macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS' + else: + func = m.name + macro = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS' + code = '%s(%s, %s, %i, %i)\n' % (macro, self.OverloadName(m), func, m.minArgs, m.maxArgs) + if code not in declared: + declared[code] = True + self.Add('declaration', code) + + + def Pointer(m): + 'returns the correct pointer declaration for the method m' + # check if this method has a wrapper set for him + wrapper = self.info[m.name].wrapper + if wrapper: + return '&' + wrapper.FullName() + else: + return m.PointerDeclaration() + + def IsExportable(m): + 'Returns true if the given method is exportable by this routine' + ignore = (Constructor, ClassOperator, Destructor) + return isinstance(m, Function) and not isinstance(m, ignore) and not m.virtual + + methods = [x for x in self.public_members if IsExportable(x)] + methods.extend(self.GetAddedMethods()) + + staticmethods = {} + + for method in methods: + method_info = self.info[method.name] + + # skip this method if it was excluded by the user + if method_info.exclude: + continue + + # rename the method if the user requested + name = method_info.rename or method.name + + # warn the user if this method needs a policy and doesn't have one + method_info.policy = exporterutils.HandlePolicy(method, method_info.policy) + + # check for policies + policy = method_info.policy or '' + if policy: + policy = ', %s%s()' % (namespaces.python, policy.Code()) + # check for overloads + overload = '' + if method.minArgs != method.maxArgs and not method_info.wrapper: + # add the overloads for this method + DeclareOverloads(method) + overload_name = self.OverloadName(method) + overload = ', %s%s()' % (namespaces.pyste, overload_name) + + # build the .def string to export the method + pointer = Pointer(method) + code = '.def("%s", %s' % (name, pointer) + code += policy + code += overload + code += ')' + self.Add('inside', code) + # static method + if isinstance(method, Method) and method.static: + staticmethods[name] = 1 + # add wrapper code if this method has one + wrapper = method_info.wrapper + if wrapper and wrapper.code: + self.Add('declaration', wrapper.code) + + # export staticmethod statements + for name in staticmethods: + code = '.staticmethod("%s")' % name + self.Add('inside', code) + + + + def MakeNonVirtual(self): + '''Make all methods that the user indicated to no_override no more virtual, delegating their + export to the ExportMethods routine''' + for member in self.class_: + if type(member) == Method and member.virtual: + member.virtual = not self.info[member.name].no_override + + + def ExportVirtualMethods(self, codeunit): + # check if this class has any virtual methods + has_virtual_methods = False + for member in self.class_: + if type(member) == Method and member.virtual: + has_virtual_methods = True + break + + holder = self.info.holder + if has_virtual_methods: + generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info, codeunit) + if holder: + self.Add('template', holder(generator.FullName())) + else: + self.Add('template', generator.FullName()) + for definition in generator.GenerateDefinitions(): + self.Add('inside', definition) + self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT)) + else: + if holder: + self.Add('template', holder(self.class_.FullName())) + + # operators natively supported by boost + BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -= '\ + '*= /= %= ^= &= |= <<= >>='.split() + # create a map for faster lookup + BOOST_SUPPORTED_OPERATORS = dict(zip(BOOST_SUPPORTED_OPERATORS, range(len(BOOST_SUPPORTED_OPERATORS)))) + + # a dict of operators that are not directly supported by boost, but can be exposed + # simply as a function with a special name + BOOST_RENAME_OPERATORS = { + '()' : '__call__', + } + + # converters which have a special name in python + # it's a map of a regular expression of the converter's result to the + # appropriate python name + SPECIAL_CONVERTERS = { + re.compile(r'(const)?\s*double$') : '__float__', + re.compile(r'(const)?\s*float$') : '__float__', + re.compile(r'(const)?\s*int$') : '__int__', + re.compile(r'(const)?\s*long$') : '__long__', + re.compile(r'(const)?\s*char\s*\*?$') : '__str__', + re.compile(r'(const)?.*::basic_string<.*>\s*(\*|\&)?$') : '__str__', + } + + + def ExportOperators(self): + 'Export all member operators and free operators related to this class' + + def GetFreeOperators(): + 'Get all the free (global) operators related to this class' + operators = [] + for decl in self.declarations: + if isinstance(decl, Operator): + # check if one of the params is this class + for param in decl.parameters: + if param.name == self.class_.FullName(): + operators.append(decl) + break + return operators + + def GetOperand(param): + 'Returns the operand of this parameter (either "self", or "other<type>")' + if param.name == self.class_.FullName(): + return namespaces.python + 'self' + else: + return namespaces.python + ('other< %s >()' % param.name) + + + def HandleSpecialOperator(operator): + # gatter information about the operator and its parameters + result_name = operator.result.name + param1_name = '' + if operator.parameters: + param1_name = operator.parameters[0].name + + # check for str + ostream = 'basic_ostream' + is_str = result_name.find(ostream) != -1 and param1_name.find(ostream) != -1 + if is_str: + namespace = namespaces.python + 'self_ns::' + self_ = namespaces.python + 'self' + return '.def(%sstr(%s))' % (namespace, self_) + + # is not a special operator + return None + + + + frees = GetFreeOperators() + members = [x for x in self.public_members if type(x) == ClassOperator] + all_operators = frees + members + operators = [x for x in all_operators if not self.info['operator'][x.name].exclude] + + for operator in operators: + # gatter information about the operator, for use later + wrapper = self.info['operator'][operator.name].wrapper + if wrapper: + pointer = '&' + wrapper.FullName() + if wrapper.code: + self.Add('declaration-outside', wrapper.code) + else: + pointer = operator.PointerDeclaration() + rename = self.info['operator'][operator.name].rename + + # check if this operator will be exported as a method + export_as_method = wrapper or rename or operator.name in self.BOOST_RENAME_OPERATORS + + # check if this operator has a special representation in boost + special_code = HandleSpecialOperator(operator) + has_special_representation = special_code is not None + + if export_as_method: + # export this operator as a normal method, renaming or using the given wrapper + if not rename: + if wrapper: + rename = wrapper.name + else: + rename = self.BOOST_RENAME_OPERATORS[operator.name] + policy = '' + policy_obj = self.info['operator'][operator.name].policy + if policy_obj: + policy = ', %s()' % policy_obj.Code() + self.Add('inside', '.def("%s", %s%s)' % (rename, pointer, policy)) + + elif has_special_representation: + self.Add('inside', special_code) + + elif operator.name in self.BOOST_SUPPORTED_OPERATORS: + # export this operator using boost's facilities + op = operator + is_unary = isinstance(op, Operator) and len(op.parameters) == 1 or\ + isinstance(op, ClassOperator) and len(op.parameters) == 0 + if is_unary: + self.Add('inside', '.def( %s%sself )' % \ + (operator.name, namespaces.python)) + else: + # binary operator + if len(operator.parameters) == 2: + left_operand = GetOperand(operator.parameters[0]) + right_operand = GetOperand(operator.parameters[1]) + else: + left_operand = namespaces.python + 'self' + right_operand = GetOperand(operator.parameters[0]) + self.Add('inside', '.def( %s %s %s )' % \ + (left_operand, operator.name, right_operand)) + + # export the converters. + # export them as simple functions with a pre-determined name + + converters = [x for x in self.public_members if type(x) == ConverterOperator] + + def ConverterMethodName(converter): + result_fullname = converter.result.FullName() + result_name = converter.result.name + for regex, method_name in self.SPECIAL_CONVERTERS.items(): + if regex.match(result_fullname): + return method_name + else: + # extract the last name from the full name + result_name = makeid(result_name) + return 'to_' + result_name + + for converter in converters: + info = self.info['operator'][converter.result.FullName()] + # check if this operator should be excluded + if info.exclude: + continue + + special_code = HandleSpecialOperator(converter) + if info.rename or not special_code: + # export as method + name = info.rename or ConverterMethodName(converter) + pointer = converter.PointerDeclaration() + policy_code = '' + if info.policy: + policy_code = ', %s()' % info.policy.Code() + self.Add('inside', '.def("%s", %s%s)' % (name, pointer, policy_code)) + + elif special_code: + self.Add('inside', special_code) + + + + def ExportNestedClasses(self, exported_names): + nested_classes = [x for x in self.public_members if isinstance(x, NestedClass)] + for nested_class in nested_classes: + nested_info = self.info[nested_class.name] + nested_info.include = self.info.include + nested_info.name = nested_class.FullName() + exporter = self.__class__(nested_info) + exporter.SetDeclarations(self.declarations) + codeunit = SingleCodeUnit(None, None) + exporter.Export(codeunit, exported_names) + self.nested_codeunits.append(codeunit) + + + def ExportNestedEnums(self, exported_names): + nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)] + for enum in nested_enums: + enum_info = self.info[enum.name] + enum_info.include = self.info.include + enum_info.name = enum.FullName() + exporter = EnumExporter(enum_info) + exporter.SetDeclarations(self.declarations) + codeunit = SingleCodeUnit(None, None) + exporter.Export(codeunit, exported_names) + self.nested_codeunits.append(codeunit) + + + def ExportSmartPointer(self): + smart_ptr = self.info.smart_ptr + if smart_ptr: + class_name = self.class_.FullName() + smart_ptr = smart_ptr % class_name + self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr)) + + + def ExportOpaquePointerPolicies(self): + # check all methods for 'return_opaque_pointer' policies + methods = [x for x in self.public_members if isinstance(x, Method)] + for method in methods: + return_opaque_policy = return_value_policy(return_opaque_pointer) + if self.info[method.name].policy == return_opaque_policy: + macro = exporterutils.EspecializeTypeID(method.result.name) + if macro: + self.Add('declaration-outside', macro) + + def ExportAddedCode(self): + if self.info.__code__: + for code in self.info.__code__: + self.Add('inside', code) + + +#============================================================================== +# Virtual Wrapper utils +#============================================================================== + +def _ParamsInfo(m, count=None): + if count is None: + count = len(m.parameters) + param_names = ['p%i' % i for i in range(count)] + param_types = [x.FullName() for x in m.parameters[:count]] + params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)] + #for i, p in enumerate(m.parameters[:count]): + # if p.default is not None: + # #params[i] += '=%s' % p.default + # params[i] += '=%s' % (p.name + '()') + params = ', '.join(params) + return params, param_names, param_types + + +class _VirtualWrapperGenerator(object): + 'Generates code to export the virtual methods of the given class' + + def __init__(self, class_, bases, info, codeunit): + self.class_ = copy.deepcopy(class_) + self.bases = bases[:] + self.info = info + self.wrapper_name = makeid(class_.FullName()) + '_Wrapper' + self.virtual_methods = None + self._method_count = {} + self.codeunit = codeunit + self.GenerateVirtualMethods() + + + SELF = 'py_self' + + + def DefaultImplementationNames(self, method): + '''Returns a list of default implementations for this method, one for each + number of default arguments. Always returns at least one name, and return from + the one with most arguments to the one with the least. + ''' + base_name = 'default_' + method.name + minArgs = method.minArgs + maxArgs = method.maxArgs + if minArgs == maxArgs: + return [base_name] + else: + return [base_name + ('_%i' % i) for i in range(minArgs, maxArgs+1)] + + + def Declaration(self, method, indent): + '''Returns a string with the declarations of the virtual wrapper and + its default implementations. This string must be put inside the Wrapper + body. + ''' + pyste = namespaces.pyste + python = namespaces.python + rename = self.info[method.name].rename or method.name + result = method.result.FullName() + return_str = 'return ' + if result == 'void': + return_str = '' + params, param_names, param_types = _ParamsInfo(method) + constantness = '' + if method.const: + constantness = ' const' + + # call_method callback + decl = indent + '%s %s(%s)%s%s {\n' % (result, method.name, params, constantness, method.Exceptions()) + param_names_str = ', '.join(param_names) + if param_names_str: + param_names_str = ', ' + param_names_str + + self_str = self.SELF + + decl += indent*2 + '%(return_str)s%(python)scall_method< %(result)s >' \ + '(%(self_str)s, "%(rename)s"%(param_names_str)s);\n' % locals() + decl += indent + '}\n' + + # default implementations (with overloading) + def DefaultImpl(method, param_names): + 'Return the body of a default implementation wrapper' + indent2 = indent * 2 + wrapper = self.info[method.name].wrapper + if not wrapper: + # return the default implementation of the class + return indent2 + '%s%s(%s);\n' % \ + (return_str, method.FullName(), ', '.join(param_names)) + else: + if wrapper.code: + self.codeunit.Write('declaration-outside', wrapper.code) + # return a call for the wrapper + params = ', '.join(['this'] + param_names) + return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params) + + if not method.abstract and method.visibility != Scope.private: + minArgs = method.minArgs + maxArgs = method.maxArgs + impl_names = self.DefaultImplementationNames(method) + for impl_name, argNum in zip(impl_names, range(minArgs, maxArgs+1)): + params, param_names, param_types = _ParamsInfo(method, argNum) + decl += '\n' + decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness) + decl += DefaultImpl(method, param_names) + decl += indent + '}\n' + return decl + + + def MethodDefinition(self, method): + '''Returns a list of lines, which should be put inside the class_ + statement to export this method.''' + # dont define abstract methods + pyste = namespaces.pyste + rename = self.info[method.name].rename or method.name + default_names = self.DefaultImplementationNames(method) + class_name = self.class_.FullName() + wrapper_name = pyste + self.wrapper_name + result = method.result.FullName() + is_method_unique = method.is_unique + constantness = '' + if method.const: + constantness = ' const' + + # create a list of default-impl pointers + minArgs = method.minArgs + maxArgs = method.maxArgs + if method.abstract: + default_pointers = [] + elif is_method_unique: + default_pointers = ['&%s::%s' % (wrapper_name, x) for x in default_names] + else: + default_pointers = [] + for impl_name, argNum in zip(default_names, range(minArgs, maxArgs+1)): + param_list = [x.FullName() for x in method.parameters[:argNum]] + params = ', '.join(param_list) + signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness) + default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name) + default_pointers.append(default_pointer) + + # get the pointer of the method + pointer = method.PointerDeclaration() + if method.abstract: + pointer = namespaces.python + ('pure_virtual(%s)' % pointer) + + # warn the user if this method needs a policy and doesn't have one + method_info = self.info[method.name] + method_info.policy = exporterutils.HandlePolicy(method, method_info.policy) + + # Add policy to overloaded methods also + policy = method_info.policy or '' + if policy: + policy = ', %s%s()' % (namespaces.python, policy.Code()) + + # generate the defs + definitions = [] + # basic def + if default_pointers: + definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy)) + for default_pointer in default_pointers[:-1]: + definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy)) + else: + definitions.append('.def("%s", %s%s)' % (rename, pointer, policy)) + return definitions + + + def FullName(self): + return namespaces.pyste + self.wrapper_name + + + def GenerateVirtualMethods(self): + '''To correctly export all virtual methods, we must also make wrappers + for the virtual methods of the bases of this class, as if the methods + were from this class itself. + This method creates the instance variable self.virtual_methods. + ''' + def IsVirtual(m): + if type(m) is Method: + pure_virtual = m.abstract and m.virtual + virtual = m.virtual and m.visibility != Scope.private + return virtual or pure_virtual + else: + return False + + # extract the virtual methods, avoiding duplications. The duplication + # must take in account the full signature without the class name, so + # that inherited members are correctly excluded if the subclass overrides + # them. + def MethodSig(method): + if method.const: + const = ' const' + else: + const = '' + if method.result: + result = method.result.FullName() + else: + result = '' + params = ', '.join([x.FullName() for x in method.parameters]) + return '%s %s(%s)%s%s' % ( + result, method.name, params, const, method.Exceptions()) + + already_added = {} + self.virtual_methods = [] + for member in self.class_: + if IsVirtual(member): + already_added[MethodSig(member)] = None + self.virtual_methods.append(member) + + for base in self.bases: + base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)] + for base_method in base_methods: + self.class_.AddMember(base_method) + + all_methods = [x for x in self.class_ if IsVirtual(x)] + + for member in all_methods: + sig = MethodSig(member) + if IsVirtual(member) and not sig in already_added: + self.virtual_methods.append(member) + already_added[sig] = 0 + + + def Constructors(self): + return self.class_.Constructors(publics_only=True) + + + def GenerateDefinitions(self): + defs = [] + for method in self.virtual_methods: + exclude = self.info[method.name].exclude + # generate definitions only for public methods and non-abstract methods + if method.visibility == Scope.public and not exclude: + defs.extend(self.MethodDefinition(method)) + return defs + + + def GenerateVirtualWrapper(self, indent): + 'Return the wrapper for this class' + + # generate the class code + class_name = self.class_.FullName() + code = 'struct %s: %s\n' % (self.wrapper_name, class_name) + code += '{\n' + # generate constructors (with the overloads for each one) + for cons in self.Constructors(): # only public constructors + minArgs = cons.minArgs + maxArgs = cons.maxArgs + # from the min number of arguments to the max number, generate + # all version of the given constructor + cons_code = '' + for argNum in range(minArgs, maxArgs+1): + params, param_names, param_types = _ParamsInfo(cons, argNum) + if params: + params = ', ' + params + cons_code += indent + '%s(PyObject* %s_%s):\n' % \ + (self.wrapper_name, self.SELF, params) + cons_code += indent*2 + '%s(%s), %s(%s_) {}\n\n' % \ + (class_name, ', '.join(param_names), self.SELF, self.SELF) + code += cons_code + # generate the body + body = [] + for method in self.virtual_methods: + if not self.info[method.name].exclude: + body.append(self.Declaration(method, indent)) + body = '\n'.join(body) + code += body + '\n' + # add the self member + code += indent + 'PyObject* %s;\n' % self.SELF + code += '};\n' + return code diff --git a/libs/python/pyste/src/Pyste/CodeExporter.py b/libs/python/pyste/src/Pyste/CodeExporter.py new file mode 100644 index 000000000..382fffbd5 --- /dev/null +++ b/libs/python/pyste/src/Pyste/CodeExporter.py @@ -0,0 +1,26 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from Exporter import Exporter + +#============================================================================== +# CodeExporter +#============================================================================== +class CodeExporter(Exporter): + + def __init__(self, info): + Exporter.__init__(self, info) + + + def Name(self): + return self.info.code + + + def Export(self, codeunit, exported_names): + codeunit.Write(self.info.section, self.info.code) + + + def WriteInclude(self, codeunit): + pass diff --git a/libs/python/pyste/src/Pyste/CppParser.py b/libs/python/pyste/src/Pyste/CppParser.py new file mode 100644 index 000000000..be68a448a --- /dev/null +++ b/libs/python/pyste/src/Pyste/CppParser.py @@ -0,0 +1,247 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from GCCXMLParser import ParseDeclarations +import tempfile +import shutil +import os +import sys +import os.path +import settings +import shutil +import shelve +from cPickle import dump, load + +#============================================================================== +# exceptions +#============================================================================== +class CppParserError(Exception): pass + +#============================================================================== +# CppParser +#============================================================================== +class CppParser: + 'Parses a header file and returns a list of declarations' + + def __init__(self, includes=None, defines=None, cache_dir=None, version=None, gccxml_path = 'gccxml'): + 'includes and defines ar the directives given to gcc' + if includes is None: + includes = [] + if defines is None: + defines = [] + self.includes = includes + self.gccxml_path = gccxml_path + self.defines = defines + self.version = version + #if cache_dir is None: + # cache_dir = tempfile.mktemp() + # self.delete_cache = True + #else: + # self.delete_cache = False + self.delete_cache = False + self.cache_dir = cache_dir + self.cache_files = [] + self.mem_cache = {} + # create the cache dir + if cache_dir: + try: + os.makedirs(cache_dir) + except OSError: pass + + + def __del__(self): + self.Close() + + + def _IncludeParams(self, filename): + includes = self.includes[:] + filedir = os.path.dirname(filename) + if not filedir: + filedir = '.' + includes.insert(0, filedir) + includes = ['-I "%s"' % self.Unixfy(x) for x in includes] + return ' '.join(includes) + + + def _DefineParams(self): + defines = ['-D "%s"' % x for x in self.defines] + return ' '.join(defines) + + + def FindHeader(self, header): + if os.path.isfile(header): + return header + for path in self.includes: + filename = os.path.join(path, header) + if os.path.isfile(filename): + return filename + else: + name = os.path.basename(header) + raise RuntimeError, 'Header file "%s" not found!' % name + + + def AppendTail(self, filename, tail): + '''Creates a temporary file, appends the text tail to it, and returns + the filename of the file. + ''' + if hasattr(tempfile, 'mkstemp'): + f_no, temp = tempfile.mkstemp('.h') + f = file(temp, 'a') + os.close(f_no) + else: + temp = tempfile.mktemp('.h') + f = file(temp, 'a') + f.write('#include "%s"\n\n' % os.path.abspath(filename)) + f.write(tail) + f.write('\n') + f.close() + return temp + + + def Unixfy(self, path): + return path.replace('\\', '/') + + + def ParseWithGCCXML(self, header, tail): + '''Parses the given header using gccxml and GCCXMLParser. + ''' + header = self.FindHeader(header) + if tail: + filename = self.AppendTail(header, tail) + else: + filename = header + xmlfile = tempfile.mktemp('.xml') + try: + # get the params + includes = self._IncludeParams(filename) + defines = self._DefineParams() + # call gccxml + cmd = '%s %s %s "%s" -fxml=%s' + filename = self.Unixfy(filename) + xmlfile = self.Unixfy(xmlfile) + status = os.system(cmd % (self.gccxml_path, includes, defines, filename, xmlfile)) + if status != 0 or not os.path.isfile(xmlfile): + raise CppParserError, 'Error executing gccxml' + # parse the resulting xml + declarations = ParseDeclarations(xmlfile) + # make the declarations' location to point to the original file + if tail: + for decl in declarations: + decl_filename = os.path.normpath(os.path.normcase(decl.location[0])) + filename = os.path.normpath(os.path.normcase(filename)) + if decl_filename == filename: + decl.location = header, decl.location[1] + # return the declarations + return declarations + finally: + if settings.DEBUG and os.path.isfile(xmlfile): + debugname = os.path.basename(header) + debugname = os.path.splitext(debugname)[0] + '.xml' + print 'DEBUG:', debugname + shutil.copy(xmlfile, debugname) + # delete the temporary files + try: + os.remove(xmlfile) + if tail: + os.remove(filename) + except OSError: pass + + + def Parse(self, header, interface, tail=None): + '''Parses the given filename related to the given interface and returns + the (declarations, headerfile). The header returned is normally the + same as the given to this method (except that it is the full path), + except if tail is not None: in this case, the header is copied to a temp + filename and the tail code is appended to it before being passed on to + gccxml. This temp filename is then returned. + ''' + if tail is None: + tail = '' + tail = tail.strip() + declarations = self.GetCache(header, interface, tail) + if declarations is None: + declarations = self.ParseWithGCCXML(header, tail) + self.CreateCache(header, interface, tail, declarations) + header_fullpath = os.path.abspath(self.FindHeader(header)) + return declarations, header_fullpath + + + def CacheFileName(self, interface): + interface_name = os.path.basename(interface) + cache_file = os.path.splitext(interface_name)[0] + '.pystec' + cache_file = os.path.join(self.cache_dir, cache_file) + return cache_file + + + def GetCache(self, header, interface, tail): + key = (header, interface, tail) + # try memory cache first + if key in self.mem_cache: + return self.mem_cache[key] + + # get the cache from the disk + if self.cache_dir is None: + return None + header = self.FindHeader(header) + cache_file = self.CacheFileName(interface) + if os.path.isfile(cache_file): + f = file(cache_file, 'rb') + try: + version = load(f) + if version != self.version: + return None + cache = load(f) + if cache.has_key(key): + self.cache_files.append(cache_file) + return cache[key] + else: + return None + finally: + f.close() + else: + return None + + + def CreateCache(self, header, interface, tail, declarations): + key = (header, interface, tail) + + # our memory cache only holds one item + self.mem_cache.clear() + self.mem_cache[key] = declarations + + # save the cache in the disk + if self.cache_dir is None: + return + header = self.FindHeader(header) + cache_file = self.CacheFileName(interface) + if os.path.isfile(cache_file): + f = file(cache_file, 'rb') + try: + version = load(f) + cache = load(f) + finally: + f.close() + else: + cache = {} + cache[key] = declarations + self.cache_files.append(cache_file) + f = file(cache_file, 'wb') + try: + dump(self.version, f, 1) + dump(cache, f, 1) + finally: + f.close() + return cache_file + + + def Close(self): + if self.delete_cache and self.cache_files: + for filename in self.cache_files: + try: + os.remove(filename) + except OSError: + pass + self.cache_files = [] + shutil.rmtree(self.cache_dir) diff --git a/libs/python/pyste/src/Pyste/EnumExporter.py b/libs/python/pyste/src/Pyste/EnumExporter.py new file mode 100644 index 000000000..0107fbee3 --- /dev/null +++ b/libs/python/pyste/src/Pyste/EnumExporter.py @@ -0,0 +1,58 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from Exporter import Exporter +from settings import * +import utils + +#============================================================================== +# EnumExporter +#============================================================================== +class EnumExporter(Exporter): + 'Exports enumerators' + + def __init__(self, info): + Exporter.__init__(self, info) + + + def SetDeclarations(self, declarations): + Exporter.SetDeclarations(self, declarations) + if self.declarations: + self.enum = self.GetDeclaration(self.info.name) + else: + self.enum = None + + def Export(self, codeunit, exported_names): + if self.info.exclude: + return + indent = self.INDENT + in_indent = self.INDENT*2 + rename = self.info.rename or self.enum.name + full_name = self.enum.FullName() + unnamed_enum = False + if rename.startswith('$_') or rename.startswith('._'): + unnamed_enum = True + code = '' + if not unnamed_enum: + code += indent + namespaces.python + code += 'enum_< %s >("%s")\n' % (full_name, rename) + for name in self.enum.values: + rename = self.info[name].rename or name + value_fullname = self.enum.ValueFullName(name) + if not unnamed_enum: + code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname) + else: + code += indent + namespaces.python + code += 'scope().attr("%s") = (int)%s;\n' % (rename, value_fullname ) + if self.info.export_values and not unnamed_enum: + code += in_indent + '.export_values()\n' + if not unnamed_enum: + code += indent + ';\n' + code += '\n' + codeunit.Write('module', code) + exported_names[self.enum.FullName()] = 1 + + def Name(self): + return self.info.name diff --git a/libs/python/pyste/src/Pyste/Exporter.py b/libs/python/pyste/src/Pyste/Exporter.py new file mode 100644 index 000000000..d87b37c58 --- /dev/null +++ b/libs/python/pyste/src/Pyste/Exporter.py @@ -0,0 +1,94 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os.path + +#============================================================================== +# Exporter +#============================================================================== +class Exporter(object): + 'Base class for objects capable to generate boost.python code.' + + INDENT = ' ' * 4 + + def __init__(self, info, parser_tail=None): + self.info = info + self.parser_tail = parser_tail + self.interface_file = None + self.declarations = [] + + + def Name(self): + raise NotImplementedError(self.__class__.__name__) + + + def Tail(self): + return self.parser_tail + + + def Parse(self, parser): + self.parser = parser + header = self.info.include + tail = self.parser_tail + declarations, parser_header = parser.parse(header, tail) + self.parser_header = parser_header + self.SetDeclarations(declarations) + + + def SetParsedHeader(self, parsed_header): + self.parser_header = parsed_header + + + def SetDeclarations(self, declarations): + self.declarations = declarations + + + def GenerateCode(self, codeunit, exported_names): + self.WriteInclude(codeunit) + self.Export(codeunit, exported_names) + + + def WriteInclude(self, codeunit): + codeunit.Write('include', '#include <%s>\n' % self.info.include) + + + def Export(self, codeunit, exported_names): + 'subclasses must override this to do the real work' + pass + + + def GetDeclarations(self, fullname): + decls = [] + for decl in self.declarations: + if decl.FullName() == fullname: + decls.append(decl) + if not decls: + raise RuntimeError, 'no %s declaration found!' % fullname + return decls + + + def GetDeclaration(self, fullname): + decls = self.GetDeclarations(fullname) + #assert len(decls) == 1 + return decls[0] + + + def Order(self): + '''Returns a string that uniquely identifies this instance. All + exporters will be sorted by Order before being exported. + ''' + return 0, self.info.name + + + def Header(self): + return self.info.include + + + def __eq__(self, other): + return type(self) is type(other) and self.Name() == other.Name() \ + and self.interface_file == other.interface_file + + def __ne__(self, other): + return not self == other diff --git a/libs/python/pyste/src/Pyste/FunctionExporter.py b/libs/python/pyste/src/Pyste/FunctionExporter.py new file mode 100644 index 000000000..5765f65e9 --- /dev/null +++ b/libs/python/pyste/src/Pyste/FunctionExporter.py @@ -0,0 +1,92 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from Exporter import Exporter +from policies import * +from declarations import * +from settings import * +import utils +import exporterutils + + +#============================================================================== +# FunctionExporter +#============================================================================== +class FunctionExporter(Exporter): + 'Generates boost.python code to export the given function.' + + def __init__(self, info, tail=None): + Exporter.__init__(self, info, tail) + + + def Export(self, codeunit, exported_names): + if not self.info.exclude: + decls = self.GetDeclarations(self.info.name) + for decl in decls: + self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy) + self.ExportDeclaration(decl, len(decls) == 1, codeunit) + self.ExportOpaquePointer(decl, codeunit) + self.GenerateOverloads(decls, codeunit) + exported_names[self.Name()] = 1 + + + def ExportDeclaration(self, decl, unique, codeunit): + name = self.info.rename or decl.name + defs = namespaces.python + 'def("%s", ' % name + wrapper = self.info.wrapper + if wrapper: + pointer = '&' + wrapper.FullName() + else: + pointer = decl.PointerDeclaration() + defs += pointer + defs += self.PolicyCode() + overload = self.OverloadName(decl) + if overload: + defs += ', %s()' % (namespaces.pyste + overload) + defs += ');' + codeunit.Write('module', self.INDENT + defs + '\n') + # add the code of the wrapper + if wrapper and wrapper.code: + codeunit.Write('declaration', wrapper.code + '\n') + + + def OverloadName(self, decl): + if decl.minArgs != decl.maxArgs: + return '%s_overloads_%i_%i' % \ + (decl.name, decl.minArgs, decl.maxArgs) + else: + return '' + + + def GenerateOverloads(self, declarations, codeunit): + codes = {} + for decl in declarations: + overload = self.OverloadName(decl) + if overload and overload not in codes: + code = 'BOOST_PYTHON_FUNCTION_OVERLOADS(%s, %s, %i, %i)' %\ + (overload, decl.FullName(), decl.minArgs, decl.maxArgs) + codeunit.Write('declaration', code + '\n') + codes[overload] = None + + + def PolicyCode(self): + policy = self.info.policy + if policy is not None: + assert isinstance(policy, Policy) + return ', %s()' % policy.Code() + else: + return '' + + + def ExportOpaquePointer(self, function, codeunit): + if self.info.policy == return_value_policy(return_opaque_pointer): + typename = function.result.name + macro = exporterutils.EspecializeTypeID(typename) + if macro: + codeunit.Write('declaration-outside', macro) + + + def Name(self): + return self.info.name diff --git a/libs/python/pyste/src/Pyste/GCCXMLParser.py b/libs/python/pyste/src/Pyste/GCCXMLParser.py new file mode 100644 index 000000000..4a1017204 --- /dev/null +++ b/libs/python/pyste/src/Pyste/GCCXMLParser.py @@ -0,0 +1,478 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from declarations import * +try: + # try to use internal elementtree + from xml.etree.cElementTree import ElementTree +except ImportError: + # try to use cElementTree if avaiable + try: + from cElementTree import ElementTree + except ImportError: + # fall back to the normal elementtree + from elementtree.ElementTree import ElementTree +from xml.parsers.expat import ExpatError +from copy import deepcopy +from utils import enumerate + + +#============================================================================== +# Exceptions +#============================================================================== +class InvalidXMLError(Exception): pass + +class ParserError(Exception): pass + +class InvalidContextError(ParserError): pass + + +#============================================================================== +# GCCXMLParser +#============================================================================== +class GCCXMLParser(object): + 'Parse a GCC_XML file and extract the top-level declarations.' + + interested_tags = {'Class':0, 'Function':0, 'Variable':0, 'Enumeration':0} + + def Parse(self, filename): + self.elements = self.GetElementsFromXML(filename) + # high level declarations + self.declarations = [] + self._names = {} + # parse the elements + for id in self.elements: + element, decl = self.elements[id] + if decl is None: + try: + self.ParseElement(id, element) + except InvalidContextError: + pass # ignore those nodes with invalid context + # (workaround gccxml bug) + + + def Declarations(self): + return self.declarations + + + def AddDecl(self, decl): + if decl.FullName() in self._names: + decl.is_unique= False + for d in self.declarations: + if d.FullName() == decl.FullName(): + d.is_unique = False + self._names[decl.FullName()] = 0 + self.declarations.append(decl) + + + def ParseElement(self, id, element): + method = 'Parse' + element.tag + if hasattr(self, method): + func = getattr(self, method) + func(id, element) + else: + self.ParseUnknown(id, element) + + + def GetElementsFromXML(self,filename): + 'Extracts a dictionary of elements from the gcc_xml file.' + + tree = ElementTree() + try: + tree.parse(filename) + except ExpatError: + raise InvalidXMLError, 'Not a XML file: %s' % filename + + root = tree.getroot() + if root.tag != 'GCC_XML': + raise InvalidXMLError, 'Not a valid GCC_XML file' + + # build a dictionary of id -> element, None + elementlist = root.getchildren() + elements = {} + for element in elementlist: + id = element.get('id') + if id: + elements[id] = element, None + return elements + + + def GetDecl(self, id): + if id not in self.elements: + if id == '_0': + raise InvalidContextError, 'Invalid context found in the xml file.' + else: + msg = 'ID not found in elements: %s' % id + raise ParserError, msg + + elem, decl = self.elements[id] + if decl is None: + self.ParseElement(id, elem) + elem, decl = self.elements[id] + if decl is None: + raise ParserError, 'Could not parse element: %s' % elem.tag + return decl + + + def GetType(self, id): + def Check(id, feature): + pos = id.find(feature) + if pos != -1: + id = id[:pos] + id[pos+1:] + return True, id + else: + return False, id + const, id = Check(id, 'c') + volatile, id = Check(id, 'v') + restricted, id = Check(id, 'r') + decl = self.GetDecl(id) + if isinstance(decl, Type): + res = deepcopy(decl) + if const: + res.const = const + if volatile: + res.volatile = volatile + if restricted: + res.restricted = restricted + else: + res = Type(decl.FullName(), const) + res.volatile = volatile + res.restricted = restricted + return res + + + def GetLocation(self, location): + file, line = location.split(':') + file = self.GetDecl(file) + return file, int(line) + + + def Update(self, id, decl): + element, _ = self.elements[id] + self.elements[id] = element, decl + + + def ParseUnknown(self, id, element): + name = '__Unknown_Element_%s' % id + decl = Unknown(name) + self.Update(id, decl) + + + def ParseNamespace(self, id, element): + namespace = element.get('name') + context = element.get('context') + if context: + outer = self.GetDecl(context) + if not outer.endswith('::'): + outer += '::' + namespace = outer + namespace + if namespace.startswith('::'): + namespace = namespace[2:] + self.Update(id, namespace) + + + def ParseFile(self, id, element): + filename = element.get('name') + self.Update(id, filename) + + + def ParseVariable(self, id, element): + # in gcc_xml, a static Field is declared as a Variable, so we check + # this and call the Field parser. + context = self.GetDecl(element.get('context')) + if isinstance(context, Class): + self.ParseField(id, element) + elem, decl = self.elements[id] + decl.static = True + else: + namespace = context + name = element.get('name') + type_ = self.GetType(element.get('type')) + location = self.GetLocation(element.get('location')) + variable = Variable(type_, name, namespace) + variable.location = location + self.AddDecl(variable) + self.Update(id, variable) + + + def GetArguments(self, element): + args = [] + for child in element: + if child.tag == 'Argument': + type = self.GetType(child.get('type')) + type.default = child.get('default') + args.append(type) + return args + + + def GetExceptions(self, exception_list): + if exception_list is None: + return None + + exceptions = [] + for t in exception_list.split(): + exceptions.append(self.GetType(t)) + + return exceptions + + + def ParseFunction(self, id, element, functionType=Function): + '''functionType is used because a Operator is identical to a normal + function, only the type of the function changes.''' + name = element.get('name') + returns = self.GetType(element.get('returns')) + namespace = self.GetDecl(element.get('context')) + location = self.GetLocation(element.get('location')) + params = self.GetArguments(element) + incomplete = bool(int(element.get('incomplete', 0))) + throws = self.GetExceptions(element.get('throw', None)) + function = functionType(name, namespace, returns, params, throws) + function.location = location + self.AddDecl(function) + self.Update(id, function) + + + def ParseOperatorFunction(self, id, element): + self.ParseFunction(id, element, Operator) + + + def GetHierarchy(self, bases): + '''Parses the string "bases" from the xml into a list of tuples of Base + instances. The first tuple is the most direct inheritance, and then it + goes up in the hierarchy. + ''' + + if bases is None: + return [] + base_names = bases.split() + this_level = [] + next_levels = [] + for base in base_names: + # get the visibility + split = base.split(':') + if len(split) == 2: + visib = split[0] + base = split[1] + else: + visib = Scope.public + decl = self.GetDecl(base) + if not isinstance(decl, Class): + # on windows, there are some classes which "bases" points to an + # "Unimplemented" tag, but we are not interested in this classes + # anyway + continue + base = Base(decl.FullName(), visib) + this_level.append(base) + # normalize with the other levels + for index, level in enumerate(decl.hierarchy): + if index < len(next_levels): + next_levels[index] = next_levels[index] + level + else: + next_levels.append(level) + hierarchy = [] + if this_level: + hierarchy.append(tuple(this_level)) + if next_levels: + hierarchy.extend(next_levels) + return hierarchy + + + def GetMembers(self, member_list): + # members must be a string with the ids of the members + if member_list is None: + return [] + members = [] + for member in member_list.split(): + decl = self.GetDecl(member) + if type(decl) in Class.ValidMemberTypes(): + members.append(decl) + return members + + + def ParseClass(self, id, element): + name = element.get('name') + abstract = bool(int(element.get('abstract', '0'))) + location = self.GetLocation(element.get('location')) + context = self.GetDecl(element.get('context')) + incomplete = bool(int(element.get('incomplete', 0))) + if isinstance(context, str): + class_ = Class(name, context, [], abstract) + else: + # a nested class + visib = element.get('access', Scope.public) + class_ = NestedClass( + name, context.FullName(), visib, [], abstract) + class_.incomplete = incomplete + # we have to add the declaration of the class before trying + # to parse its members and bases, to avoid recursion. + self.AddDecl(class_) + class_.location = location + self.Update(id, class_) + # now we can get the members and the bases + class_.hierarchy = self.GetHierarchy(element.get('bases')) + if class_.hierarchy: + class_.bases = class_.hierarchy[0] + members = self.GetMembers(element.get('members')) + for member in members: + class_.AddMember(member) + + + def ParseStruct(self, id, element): + self.ParseClass(id, element) + + + FUNDAMENTAL_RENAME = { + 'long long int' : 'boost::int64_t', + 'long long unsigned int' : 'boost::uint64_t', + } + + def ParseFundamentalType(self, id, element): + name = element.get('name') + name = self.FUNDAMENTAL_RENAME.get(name, name) + type_ = FundamentalType(name) + self.Update(id, type_) + + + def ParseArrayType(self, id, element): + type = self.GetType(element.get('type')) + min = element.get('min') + max = element.get('max') + array = ArrayType(type.name, type.const, min, max) + self.Update(id, array) + + + def ParseReferenceType(self, id, element): + type = self.GetType(element.get('type')) + expand = not isinstance(type, FunctionType) + ref = ReferenceType(type.name, type.const, None, expand, type.suffix) + self.Update(id, ref) + + + def ParsePointerType(self, id, element): + type = self.GetType(element.get('type')) + expand = not isinstance(type, FunctionType) + ref = PointerType(type.name, type.const, None, expand, type.suffix) + self.Update(id, ref) + + + def ParseFunctionType(self, id, element): + result = self.GetType(element.get('returns')) + args = self.GetArguments(element) + func = FunctionType(result, args) + self.Update(id, func) + + + def ParseMethodType(self, id, element): + class_ = self.GetDecl(element.get('basetype')).FullName() + result = self.GetType(element.get('returns')) + args = self.GetArguments(element) + method = MethodType(result, args, class_) + self.Update(id, method) + + + def ParseField(self, id, element): + name = element.get('name') + visib = element.get('access', Scope.public) + classname = self.GetDecl(element.get('context')).FullName() + type_ = self.GetType(element.get('type')) + static = bool(int(element.get('extern', '0'))) + location = self.GetLocation(element.get('location')) + var = ClassVariable(type_, name, classname, visib, static) + var.location = location + self.Update(id, var) + + + def ParseMethod(self, id, element, methodType=Method): + name = element.get('name') + result = self.GetType(element.get('returns')) + classname = self.GetDecl(element.get('context')).FullName() + visib = element.get('access', Scope.public) + static = bool(int(element.get('static', '0'))) + virtual = bool(int(element.get('virtual', '0'))) + abstract = bool(int(element.get('pure_virtual', '0'))) + const = bool(int(element.get('const', '0'))) + location = self.GetLocation(element.get('location')) + throws = self.GetExceptions(element.get('throw', None)) + params = self.GetArguments(element) + method = methodType( + name, classname, result, params, visib, virtual, abstract, static, const, throws) + method.location = location + self.Update(id, method) + + + def ParseOperatorMethod(self, id, element): + self.ParseMethod(id, element, ClassOperator) + + + def ParseConstructor(self, id, element): + name = element.get('name') + visib = element.get('access', Scope.public) + classname = self.GetDecl(element.get('context')).FullName() + location = self.GetLocation(element.get('location')) + params = self.GetArguments(element) + artificial = element.get('artificial', False) + ctor = Constructor(name, classname, params, visib) + ctor.location = location + self.Update(id, ctor) + + + def ParseDestructor(self, id, element): + name = element.get('name') + visib = element.get('access', Scope.public) + classname = self.GetDecl(element.get('context')).FullName() + virtual = bool(int(element.get('virtual', '0'))) + location = self.GetLocation(element.get('location')) + des = Destructor(name, classname, visib, virtual) + des.location = location + self.Update(id, des) + + + def ParseConverter(self, id, element): + self.ParseMethod(id, element, ConverterOperator) + + + def ParseTypedef(self, id, element): + name = element.get('name') + type = self.GetType(element.get('type')) + context = self.GetDecl(element.get('context')) + if isinstance(context, Class): + context = context.FullName() + typedef = Typedef(type, name, context) + self.Update(id, typedef) + self.AddDecl(typedef) + + + def ParseEnumeration(self, id, element): + name = element.get('name') + location = self.GetLocation(element.get('location')) + context = self.GetDecl(element.get('context')) + incomplete = bool(int(element.get('incomplete', 0))) + if isinstance(context, str): + enum = Enumeration(name, context) + else: + visib = element.get('access', Scope.public) + enum = ClassEnumeration(name, context.FullName(), visib) + self.AddDecl(enum) + enum.location = location + for child in element: + if child.tag == 'EnumValue': + name = child.get('name') + value = int(child.get('init')) + enum.values[name] = value + enum.incomplete = incomplete + self.Update(id, enum) + + + +def ParseDeclarations(filename): + 'Returns a list of the top declarations found in the gcc_xml file.' + + parser = GCCXMLParser() + parser.Parse(filename) + return parser.Declarations() + + +if __name__ == '__main__': + ParseDeclarations(r'D:\Programming\Libraries\boost-cvs\boost\libs\python\pyste\example\test.xml') diff --git a/libs/python/pyste/src/Pyste/HeaderExporter.py b/libs/python/pyste/src/Pyste/HeaderExporter.py new file mode 100644 index 000000000..47651ba70 --- /dev/null +++ b/libs/python/pyste/src/Pyste/HeaderExporter.py @@ -0,0 +1,81 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from Exporter import Exporter +from ClassExporter import ClassExporter +from FunctionExporter import FunctionExporter +from EnumExporter import EnumExporter +from VarExporter import VarExporter +from infos import * +from declarations import * +import os.path +import exporters +import MultipleCodeUnit + +#============================================================================== +# HeaderExporter +#============================================================================== +class HeaderExporter(Exporter): + 'Exports all declarations found in the given header' + + def __init__(self, info, parser_tail=None): + Exporter.__init__(self, info, parser_tail) + + + def WriteInclude(self, codeunit): + pass + + + def IsInternalName(self, name): + '''Returns true if the given name looks like a internal compiler + structure''' + return name.startswith('_') + + + def Export(self, codeunit, exported_names): + header = os.path.normpath(self.parser_header) + for decl in self.declarations: + # check if this declaration is in the header + location = os.path.abspath(decl.location[0]) + if location == header and not self.IsInternalName(decl.name): + # ok, check the type of the declaration and export it accordingly + self.HandleDeclaration(decl, codeunit, exported_names) + + + def HandleDeclaration(self, decl, codeunit, exported_names): + '''Dispatch the declaration to the appropriate method, that must create + a suitable info object for a Exporter, create a Exporter, set its + declarations and append it to the list of exporters. + ''' + dispatch_table = { + Class : ClassExporter, + Enumeration : EnumExporter, + Function : FunctionExporter, + Variable : VarExporter, + } + + exporter_class = dispatch_table.get(type(decl)) + if exporter_class is not None: + self.HandleExporter(decl, exporter_class, codeunit, exported_names) + + + def HandleExporter(self, decl, exporter_type, codeunit, exported_names): + # only export complete declarations + if not decl.incomplete: + info = self.info[decl.name] + info.name = decl.FullName() + info.include = self.info.include + exporter = exporter_type(info) + exporter.SetDeclarations(self.declarations) + exporter.SetParsedHeader(self.parser_header) + if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit): + codeunit.SetCurrent(self.interface_file, exporter.Name()) + else: + codeunit.SetCurrent(exporter.Name()) + exporter.GenerateCode(codeunit, exported_names) + + + def Name(self): + return self.info.include diff --git a/libs/python/pyste/src/Pyste/MultipleCodeUnit.py b/libs/python/pyste/src/Pyste/MultipleCodeUnit.py new file mode 100644 index 000000000..65faad45d --- /dev/null +++ b/libs/python/pyste/src/Pyste/MultipleCodeUnit.py @@ -0,0 +1,135 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from SingleCodeUnit import SingleCodeUnit +import os +import utils +from SmartFile import SmartFile + + +#============================================================================== +# MultipleCodeUnit +#============================================================================== +class MultipleCodeUnit(object): + ''' + Represents a bunch of cpp files, where each cpp file represents a header + to be exported by pyste. Another cpp, named <module>.cpp is created too. + ''' + + def __init__(self, modulename, outdir): + self.modulename = modulename + self.outdir = outdir + self.codeunits = {} # maps from a (filename, function) to a SingleCodeUnit + self.functions = [] + self._current = None + self.all = SingleCodeUnit(None, None) + + + def _FunctionName(self, interface_file): + name = os.path.splitext(interface_file)[0] + return 'Export_%s' % utils.makeid(name) + + + def _FileName(self, interface_file): + filename = os.path.basename(interface_file) + filename = '_%s.cpp' % os.path.splitext(filename)[0] + return os.path.join(self.outdir, filename) + + + def SetCurrent(self, interface_file, export_name): + 'Changes the current code unit' + if export_name is None: + self._current = None + elif export_name is '__all__': + self._current = self.all + else: + filename = self._FileName(interface_file) + function = self._FunctionName(interface_file) + try: + codeunit = self.codeunits[filename] + except KeyError: + codeunit = SingleCodeUnit(None, filename) + codeunit.module_definition = 'void %s()' % function + self.codeunits[filename] = codeunit + if function not in self.functions: + self.functions.append(function) + self._current = codeunit + + + def Current(self): + return self._current + + current = property(Current, SetCurrent) + + + def Write(self, section, code): + if self._current is not None: + self.current.Write(section, code) + + + def Section(self, section): + if self._current is not None: + return self.current.Section(section) + + + def _CreateOutputDir(self): + try: + os.mkdir(self.outdir) + except OSError: pass # already created + + + def Save(self): + # create the directory where all the files will go + self._CreateOutputDir(); + # order all code units by filename, and merge them all + codeunits = {} # filename => list of codeunits + + # While ordering all code units by file name, the first code + # unit in the list of code units is used as the main unit + # which dumps all the include, declaration and + # declaration-outside sections at the top of the file. + for filename, codeunit in self.codeunits.items(): + if filename not in codeunits: + # this codeunit is the main codeunit. + codeunits[filename] = [codeunit] + codeunit.Merge(self.all) + else: + main_unit = codeunits[filename][0] + for section in ('include', 'declaration', 'declaration-outside'): + main_unit.code[section] = main_unit.code[section] + codeunit.code[section] + codeunit.code[section] = '' + codeunits[filename].append(codeunit) + + # Now write all the codeunits appending them correctly. + for file_units in codeunits.values(): + append = False + for codeunit in file_units: + codeunit.Save(append) + if not append: + append = True + + + def GenerateMain(self, interfaces): + # generate the main cpp + filename = os.path.join(self.outdir, '_main.cpp') + fout = SmartFile(filename, 'w') + fout.write(utils.left_equals('Include')) + fout.write('#include <boost/python/module.hpp>\n\n') + fout.write(utils.left_equals('Exports')) + functions = [self._FunctionName(x) for x in interfaces] + for function in functions: + fout.write('void %s();\n' % function) + fout.write('\n') + fout.write(utils.left_equals('Module')) + fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename) + fout.write('{\n') + indent = ' ' * 4 + for function in functions: + fout.write(indent) + fout.write('%s();\n' % function) + fout.write('}\n') + + + diff --git a/libs/python/pyste/src/Pyste/SingleCodeUnit.py b/libs/python/pyste/src/Pyste/SingleCodeUnit.py new file mode 100644 index 000000000..2e59dbb80 --- /dev/null +++ b/libs/python/pyste/src/Pyste/SingleCodeUnit.py @@ -0,0 +1,121 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from settings import namespaces +import settings +from utils import remove_duplicated_lines, left_equals +from SmartFile import SmartFile + + +#============================================================================== +# SingleCodeUnit +#============================================================================== +class SingleCodeUnit: + ''' + Represents a cpp file, where other objects can write in one of the + predefined sections. + The avaiable sections are: + pchinclude - The pre-compiled header area + include - The include area of the cpp file + declaration - The part before the module definition + module - Inside the BOOST_PYTHON_MODULE macro + ''' + + def __init__(self, modulename, filename): + self.modulename = modulename + self.filename = filename + # define the avaiable sections + self.code = {} + # include section + self.code['pchinclude'] = '' + # include section + self.code['include'] = '' + # declaration section (inside namespace) + self.code['declaration'] = '' + # declaration (outside namespace) + self.code['declaration-outside'] = '' + # inside BOOST_PYTHON_MACRO + self.code['module'] = '' + # create the default module definition + self.module_definition = 'BOOST_PYTHON_MODULE(%s)' % modulename + + + def Write(self, section, code): + 'write the given code in the section of the code unit' + if section not in self.code: + raise RuntimeError, 'Invalid CodeUnit section: %s' % section + self.code[section] += code + + + def Merge(self, other): + for section in ('include', 'declaration', 'declaration-outside', 'module'): + self.code[section] = self.code[section] + other.code[section] + + + def Section(self, section): + return self.code[section] + + + def SetCurrent(self, *args): + pass + + + def Current(self): + pass + + + def Save(self, append=False): + 'Writes this code unit to the filename' + space = '\n\n' + if not append: + flag = 'w' + else: + flag = 'a' + fout = SmartFile(self.filename, flag) + fout.write('\n') + # includes + # boost.python header + if self.code['pchinclude']: + fout.write(left_equals('PCH')) + fout.write(self.code['pchinclude']+'\n') + fout.write('#ifdef _MSC_VER\n') + fout.write('#pragma hdrstop\n') + fout.write('#endif\n') + else: + fout.write(left_equals('Boost Includes')) + fout.write('#include <boost/python.hpp>\n') + # include numerical boost for int64 definitions + fout.write('#include <boost/cstdint.hpp>\n') + fout.write('\n') + # other includes + if self.code['include']: + fout.write(left_equals('Includes')) + includes = remove_duplicated_lines(self.code['include']) + fout.write(includes) + fout.write(space) + # using + if settings.USING_BOOST_NS and not append: + fout.write(left_equals('Using')) + fout.write('using namespace boost::python;\n\n') + # declarations + declaration = self.code['declaration'] + declaration_outside = self.code['declaration-outside'] + if declaration_outside or declaration: + fout.write(left_equals('Declarations')) + if declaration_outside: + fout.write(declaration_outside + '\n\n') + if declaration: + pyste_namespace = namespaces.pyste[:-2] + fout.write('namespace %s {\n\n' % pyste_namespace) + fout.write(declaration) + fout.write('\n}// namespace %s\n' % pyste_namespace) + fout.write(space) + # module + fout.write(left_equals('Module')) + fout.write(self.module_definition + '\n') + fout.write('{\n') + fout.write(self.code['module']) + fout.write('}\n\n') + fout.close() diff --git a/libs/python/pyste/src/Pyste/SmartFile.py b/libs/python/pyste/src/Pyste/SmartFile.py new file mode 100644 index 000000000..039579e3b --- /dev/null +++ b/libs/python/pyste/src/Pyste/SmartFile.py @@ -0,0 +1,60 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import md5 + +#============================================================================== +# SmartFile +#============================================================================== +class SmartFile(object): + ''' + A file-like object used for writing files. The given file will only be + actually written to disk if there's not a file with the same name, or if + the existing file is *different* from the file to be written. + ''' + + def __init__(self, filename, mode='w'): + self.filename = filename + self.mode = mode + self._contents = [] + self._closed = False + + + def __del__(self): + if not self._closed: + self.close() + + + def write(self, string): + self._contents.append(string) + + + def _dowrite(self, contents): + f = file(self.filename, self.mode) + f.write(contents) + f.close() + + + def _GetMD5(self, string): + return md5.new(string).digest() + + + def close(self): + # if the filename doesn't exist, write the file right away + this_contents = ''.join(self._contents) + if not os.path.isfile(self.filename): + self._dowrite(this_contents) + else: + # read the contents of the file already in disk + f = file(self.filename) + other_contents = f.read() + f.close() + # test the md5 for both files + this_md5 = self._GetMD5(this_contents) + other_md5 = self._GetMD5(other_contents) + if this_md5 != other_md5: + self._dowrite(this_contents) + self._closed = True diff --git a/libs/python/pyste/src/Pyste/VarExporter.py b/libs/python/pyste/src/Pyste/VarExporter.py new file mode 100644 index 000000000..d3571e751 --- /dev/null +++ b/libs/python/pyste/src/Pyste/VarExporter.py @@ -0,0 +1,40 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from Exporter import Exporter +from settings import * +import utils + +#============================================================================== +# VarExporter +#============================================================================== +class VarExporter(Exporter): + '''Exports a global variable. + ''' + + def __init__(self, info): + Exporter.__init__(self, info) + + + def Export(self, codeunit, exported_names): + if self.info.exclude: return + decl = self.GetDeclaration(self.info.name) + if not decl.type.const: + msg = '---> Warning: The global variable "%s" is non-const:\n' \ + ' changes in Python will not reflect in C++.' + print msg % self.info.name + print + rename = self.info.rename or self.info.name + code = self.INDENT + namespaces.python + code += 'scope().attr("%s") = %s;\n' % (rename, self.info.name) + codeunit.Write('module', code) + + + def Order(self): + return 0, self.info.name + + + def Name(self): + return self.info.name diff --git a/libs/python/pyste/src/Pyste/__init__.py b/libs/python/pyste/src/Pyste/__init__.py new file mode 100644 index 000000000..02eec64b7 --- /dev/null +++ b/libs/python/pyste/src/Pyste/__init__.py @@ -0,0 +1,6 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + diff --git a/libs/python/pyste/src/Pyste/declarations.py b/libs/python/pyste/src/Pyste/declarations.py new file mode 100644 index 000000000..6eff97dc5 --- /dev/null +++ b/libs/python/pyste/src/Pyste/declarations.py @@ -0,0 +1,653 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +''' +Defines classes that represent declarations found in C++ header files. + +''' + +# version indicates the version of the declarations. Whenever a declaration +# changes, this variable should be updated, so that the caches can be rebuilt +# automatically +version = '1.0' + +#============================================================================== +# Declaration +#============================================================================== +class Declaration(object): + '''Base class for all declarations. + @ivar name: The name of the declaration. + @ivar namespace: The namespace of the declaration. + ''' + + def __init__(self, name, namespace): + ''' + @type name: string + @param name: The name of this declaration + @type namespace: string + @param namespace: the full namespace where this declaration resides. + ''' + self.name = name + self.namespace = namespace + self.location = '', -1 # (filename, line) + self.incomplete = False + self.is_unique = True + + + def FullName(self): + ''' + Returns the full qualified name: "boost::inner::Test" + @rtype: string + @return: The full name of the declaration. + ''' + namespace = self.namespace or '' + if namespace and not namespace.endswith('::'): + namespace += '::' + return namespace + self.name + + + def __repr__(self): + return '<Declaration %s at %s>' % (self.FullName(), id(self)) + + + def __str__(self): + return 'Declaration of %s' % self.FullName() + + +#============================================================================== +# Class +#============================================================================== +class Class(Declaration): + ''' + Represents a C++ class or struct. Iteration through it yields its members. + + @type abstract: bool + @ivar abstract: if the class has any abstract methods. + + @type bases: tuple + @ivar bases: tuple with L{Base} instances, representing the most direct + inheritance. + + @type hierarchy: list + @ivar hierarchy: a list of tuples of L{Base} instances, representing + the entire hierarchy tree of this object. The first tuple is the parent + classes, and the other ones go up in the hierarchy. + ''' + + def __init__(self, name, namespace, members, abstract): + Declaration.__init__(self, name, namespace) + self.__members = members + self.__member_names = {} + self.abstract = abstract + self.bases = () + self.hierarchy = () + self.operator = {} + + + def __iter__(self): + '''iterates through the class' members. + ''' + return iter(self.__members) + + + def Constructors(self, publics_only=True): + '''Returns a list of the constructors for this class. + @rtype: list + ''' + constructors = [] + for member in self: + if isinstance(member, Constructor): + if publics_only and member.visibility != Scope.public: + continue + constructors.append(member) + return constructors + + + def HasCopyConstructor(self): + '''Returns true if this class has a public copy constructor. + @rtype: bool + ''' + for cons in self.Constructors(): + if cons.IsCopy(): + return True + return False + + + def HasDefaultConstructor(self): + '''Returns true if this class has a public default constructor. + @rtype: bool + ''' + for cons in self.Constructors(): + if cons.IsDefault(): + return True + return False + + + def AddMember(self, member): + if member.name in self.__member_names: + member.is_unique = False + for m in self: + if m.name == member.name: + m.is_unique = False + else: + member.is_unique = True + self.__member_names[member.name] = 1 + self.__members.append(member) + if isinstance(member, ClassOperator): + self.operator[member.name] = member + + + def ValidMemberTypes(): + return (NestedClass, Method, Constructor, Destructor, ClassVariable, + ClassOperator, ConverterOperator, ClassEnumeration) + ValidMemberTypes = staticmethod(ValidMemberTypes) + + +#============================================================================== +# NestedClass +#============================================================================== +class NestedClass(Class): + '''The declaration of a class/struct inside another class/struct. + + @type class: string + @ivar class: fullname of the class where this class is contained. + + @type visibility: L{Scope} + @ivar visibility: the visibility of this class. + ''' + + def __init__(self, name, class_, visib, members, abstract): + Class.__init__(self, name, None, members, abstract) + self.class_ = class_ + self.visibility = visib + + + def FullName(self): + '''The full name of this class, like ns::outer::inner. + @rtype: string + ''' + return '%s::%s' % (self.class_, self.name) + + +#============================================================================== +# Scope +#============================================================================== +class Scope: + '''Used to represent the visibility of various members inside a class. + @cvar public: public visibility + @cvar private: private visibility + @cvar protected: protected visibility + ''' + public = 'public' + private = 'private' + protected = 'protected' + + +#============================================================================== +# Base +#============================================================================== +class Base: + '''Represents a base class of another class. + @ivar _name: the full name of the base class. + @ivar _visibility: the visibility of the derivation. + ''' + + def __init__(self, name, visibility=Scope.public): + self.name = name + self.visibility = visibility + + +#============================================================================== +# Function +#============================================================================== +class Function(Declaration): + '''The declaration of a function. + @ivar _result: instance of L{Type} or None. + @ivar _parameters: list of L{Type} instances. + @ivar _throws: exception specifiers or None + ''' + + def __init__(self, name, namespace, result, params, throws=None): + Declaration.__init__(self, name, namespace) + # the result type: instance of Type, or None (constructors) + self.result = result + # the parameters: instances of Type + self.parameters = params + # the exception specification + self.throws = throws + + + def Exceptions(self): + if self.throws is None: + return "" + else: + return " throw(%s)" % ', '.join ([x.FullName() for x in self.throws]) + + + def PointerDeclaration(self, force=False): + '''Returns a declaration of a pointer to this function. + @param force: If True, returns a complete pointer declaration regardless + if this function is unique or not. + ''' + if self.is_unique and not force: + return '&%s' % self.FullName() + else: + result = self.result.FullName() + params = ', '.join([x.FullName() for x in self.parameters]) + return '(%s (*)(%s)%s)&%s' % (result, params, self.Exceptions(), self.FullName()) + + + def MinArgs(self): + min = 0 + for arg in self.parameters: + if arg.default is None: + min += 1 + return min + + minArgs = property(MinArgs) + + + def MaxArgs(self): + return len(self.parameters) + + maxArgs = property(MaxArgs) + + + +#============================================================================== +# Operator +#============================================================================== +class Operator(Function): + '''The declaration of a custom operator. Its name is the same as the + operator name in C++, ie, the name of the declaration "operator+(..)" is + "+". + ''' + + def FullName(self): + namespace = self.namespace or '' + if not namespace.endswith('::'): + namespace += '::' + return namespace + 'operator' + self.name + + +#============================================================================== +# Method +#============================================================================== +class Method(Function): + '''The declaration of a method. + + @ivar _visibility: the visibility of this method. + @ivar _virtual: if this method is declared as virtual. + @ivar _abstract: if this method is virtual but has no default implementation. + @ivar _static: if this method is static. + @ivar _class: the full name of the class where this method was declared. + @ivar _const: if this method is declared as const. + @ivar _throws: list of exception specificiers or None + ''' + + def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const, throws=None): + Function.__init__(self, name, None, result, params, throws) + self.visibility = visib + self.virtual = virtual + self.abstract = abstract + self.static = static + self.class_ = class_ + self.const = const + + + def FullName(self): + return self.class_ + '::' + self.name + + + def PointerDeclaration(self, force=False): + '''Returns a declaration of a pointer to this member function. + @param force: If True, returns a complete pointer declaration regardless + if this function is unique or not. + ''' + if self.static: + # static methods are like normal functions + return Function.PointerDeclaration(self, force) + if self.is_unique and not force: + return '&%s' % self.FullName() + else: + result = self.result.FullName() + params = ', '.join([x.FullName() for x in self.parameters]) + const = '' + if self.const: + const = 'const' + return '(%s (%s::*)(%s) %s%s)&%s' %\ + (result, self.class_, params, const, self.Exceptions(), self.FullName()) + + +#============================================================================== +# Constructor +#============================================================================== +class Constructor(Method): + '''A class' constructor. + ''' + + def __init__(self, name, class_, params, visib): + Method.__init__(self, name, class_, None, params, visib, False, False, False, False) + + + def IsDefault(self): + '''Returns True if this constructor is a default constructor. + ''' + return len(self.parameters) == 0 and self.visibility == Scope.public + + + def IsCopy(self): + '''Returns True if this constructor is a copy constructor. + ''' + if len(self.parameters) != 1: + return False + param = self.parameters[0] + class_as_param = self.parameters[0].name == self.class_ + param_reference = isinstance(param, ReferenceType) + is_public = self.visibility == Scope.public + return param_reference and class_as_param and param.const and is_public + + + def PointerDeclaration(self, force=False): + return '' + + +#============================================================================== +# Destructor +#============================================================================== +class Destructor(Method): + 'The destructor of a class.' + + def __init__(self, name, class_, visib, virtual): + Method.__init__(self, name, class_, None, [], visib, virtual, False, False, False) + + def FullName(self): + return self.class_ + '::~' + self.name + + + def PointerDeclaration(self, force=False): + return '' + + + +#============================================================================== +# ClassOperator +#============================================================================== +class ClassOperator(Method): + 'A custom operator in a class.' + + def FullName(self): + return self.class_ + '::operator ' + self.name + + + +#============================================================================== +# ConverterOperator +#============================================================================== +class ConverterOperator(ClassOperator): + 'An operator in the form "operator OtherClass()".' + + def FullName(self): + return self.class_ + '::operator ' + self.result.FullName() + + + +#============================================================================== +# Type +#============================================================================== +class Type(Declaration): + '''Represents the type of a variable or parameter. + @ivar _const: if the type is constant. + @ivar _default: if this type has a default value associated with it. + @ivar _volatile: if this type was declared with the keyword volatile. + @ivar _restricted: if this type was declared with the keyword restricted. + @ivar _suffix: Suffix to get the full type name. '*' for pointers, for + example. + ''' + + def __init__(self, name, const=False, default=None, suffix=''): + Declaration.__init__(self, name, None) + # whatever the type is constant or not + self.const = const + # used when the Type is a function argument + self.default = default + self.volatile = False + self.restricted = False + self.suffix = suffix + + def __repr__(self): + if self.const: + const = 'const ' + else: + const = '' + return '<Type ' + const + self.name + '>' + + + def FullName(self): + if self.const: + const = 'const ' + else: + const = '' + return const + self.name + self.suffix + + +#============================================================================== +# ArrayType +#============================================================================== +class ArrayType(Type): + '''Represents an array. + @ivar min: the lower bound of the array, usually 0. Can be None. + @ivar max: the upper bound of the array. Can be None. + ''' + + def __init__(self, name, const, min, max): + 'min and max can be None.' + Type.__init__(self, name, const) + self.min = min + self.max = max + + + +#============================================================================== +# ReferenceType +#============================================================================== +class ReferenceType(Type): + '''A reference type.''' + + def __init__(self, name, const=False, default=None, expandRef=True, suffix=''): + Type.__init__(self, name, const, default) + if expandRef: + self.suffix = suffix + '&' + + +#============================================================================== +# PointerType +#============================================================================== +class PointerType(Type): + 'A pointer type.' + + def __init__(self, name, const=False, default=None, expandPointer=False, suffix=''): + Type.__init__(self, name, const, default) + if expandPointer: + self.suffix = suffix + '*' + + +#============================================================================== +# FundamentalType +#============================================================================== +class FundamentalType(Type): + 'One of the fundamental types, like int, void, etc.' + + def __init__(self, name, const=False, default=None): + Type.__init__(self, name, const, default) + + + +#============================================================================== +# FunctionType +#============================================================================== +class FunctionType(Type): + '''A pointer to a function. + @ivar _result: the return value + @ivar _parameters: a list of Types, indicating the parameters of the function. + @ivar _name: the name of the function. + ''' + + def __init__(self, result, parameters): + Type.__init__(self, '', False) + self.result = result + self.parameters = parameters + self.name = self.FullName() + + + def FullName(self): + full = '%s (*)' % self.result.FullName() + params = [x.FullName() for x in self.parameters] + full += '(%s)' % ', '.join(params) + return full + + +#============================================================================== +# MethodType +#============================================================================== +class MethodType(FunctionType): + '''A pointer to a member function of a class. + @ivar _class: The fullname of the class that the method belongs to. + ''' + + def __init__(self, result, parameters, class_): + self.class_ = class_ + FunctionType.__init__(self, result, parameters) + + + def FullName(self): + full = '%s (%s::*)' % (self.result.FullName(), self.class_) + params = [x.FullName() for x in self.parameters] + full += '(%s)' % ', '.join(params) + return full + + +#============================================================================== +# Variable +#============================================================================== +class Variable(Declaration): + '''Represents a global variable. + + @type _type: L{Type} + @ivar _type: The type of the variable. + ''' + + def __init__(self, type, name, namespace): + Declaration.__init__(self, name, namespace) + self.type = type + + +#============================================================================== +# ClassVariable +#============================================================================== +class ClassVariable(Variable): + '''Represents a class variable. + + @type _visibility: L{Scope} + @ivar _visibility: The visibility of this variable within the class. + + @type _static: bool + @ivar _static: Indicates if the variable is static. + + @ivar _class: Full name of the class that this variable belongs to. + ''' + + def __init__(self, type, name, class_, visib, static): + Variable.__init__(self, type, name, None) + self.visibility = visib + self.static = static + self.class_ = class_ + + + def FullName(self): + return self.class_ + '::' + self.name + + +#============================================================================== +# Enumeration +#============================================================================== +class Enumeration(Declaration): + '''Represents an enum. + + @type _values: dict of str => int + @ivar _values: holds the values for this enum. + ''' + + def __init__(self, name, namespace): + Declaration.__init__(self, name, namespace) + self.values = {} # dict of str => int + + + def ValueFullName(self, name): + '''Returns the full name for a value in the enum. + ''' + assert name in self.values + namespace = self.namespace + if namespace: + namespace += '::' + return namespace + name + + +#============================================================================== +# ClassEnumeration +#============================================================================== +class ClassEnumeration(Enumeration): + '''Represents an enum inside a class. + + @ivar _class: The full name of the class where this enum belongs. + @ivar _visibility: The visibility of this enum inside his class. + ''' + + def __init__(self, name, class_, visib): + Enumeration.__init__(self, name, None) + self.class_ = class_ + self.visibility = visib + + + def FullName(self): + return '%s::%s' % (self.class_, self.name) + + + def ValueFullName(self, name): + assert name in self.values + return '%s::%s' % (self.class_, name) + + +#============================================================================== +# Typedef +#============================================================================== +class Typedef(Declaration): + '''A Typedef declaration. + + @type _type: L{Type} + @ivar _type: The type of the typedef. + + @type _visibility: L{Scope} + @ivar _visibility: The visibility of this typedef. + ''' + + def __init__(self, type, name, namespace): + Declaration.__init__(self, name, namespace) + self.type = type + self.visibility = Scope.public + + + + + +#============================================================================== +# Unknown +#============================================================================== +class Unknown(Declaration): + '''A declaration that Pyste does not know how to handle. + ''' + + def __init__(self, name): + Declaration.__init__(self, name, None) diff --git a/libs/python/pyste/src/Pyste/exporters.py b/libs/python/pyste/src/Pyste/exporters.py new file mode 100644 index 000000000..f573d01be --- /dev/null +++ b/libs/python/pyste/src/Pyste/exporters.py @@ -0,0 +1,12 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + +# a list of Exporter instances +exporters = [] + +current_interface = None # the current interface file being processed +importing = False # whetever we are now importing a pyste file. + # exporters created here shouldn't export themselves diff --git a/libs/python/pyste/src/Pyste/exporterutils.py b/libs/python/pyste/src/Pyste/exporterutils.py new file mode 100644 index 000000000..363700d2b --- /dev/null +++ b/libs/python/pyste/src/Pyste/exporterutils.py @@ -0,0 +1,87 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +''' +Various helpers for interface files. +''' + +from settings import * +from policies import * +from declarations import * + +#============================================================================== +# FunctionWrapper +#============================================================================== +class FunctionWrapper(object): + '''Holds information about a wrapper for a function or a method. It is + divided in 2 parts: the name of the Wrapper, and its code. The code is + placed in the declaration section of the module, while the name is used to + def' the function or method (with the pyste namespace prepend to it). If + code is None, the name is left unchanged. + ''' + + def __init__(self, name, code=None): + self.name = name + self.code = code + + def FullName(self): + if self.code: + return namespaces.pyste + self.name + else: + return self.name + + +_printed_warnings = {} # used to avoid double-prints of warnings + +#============================================================================== +# HandlePolicy +#============================================================================== +def HandlePolicy(function, policy): + '''Show a warning to the user if the function needs a policy and doesn't + have one. Return a policy to the function, which is the given policy itself + if it is not None, or a default policy for this method. + ''' + + def IsString(type): + 'Return True if the Type instance can be considered a string' + return type.FullName() == 'const char*' + + def IsPyObject(type): + return type.FullName() == '_object *' # internal name of PyObject + + result = function.result + # if the function returns const char*, a policy is not needed + if IsString(result) or IsPyObject(result): + return policy + # if returns a const T&, set the default policy + if policy is None and result.const and isinstance(result, ReferenceType): + policy = return_value_policy(copy_const_reference) + # basic test if the result type demands a policy + needs_policy = isinstance(result, (ReferenceType, PointerType)) + # show a warning to the user, if needed + if needs_policy and policy is None: + global _printed_warnings + warning = '---> Error: %s returns a pointer or a reference, ' \ + 'but no policy was specified.' % function.FullName() + if warning not in _printed_warnings: + print warning + print + # avoid double prints of the same warning + _printed_warnings[warning] = 1 + return policy + + +#============================================================================== +# EspecializeTypeID +#============================================================================== +_exported_type_ids = {} +def EspecializeTypeID(typename): + global _exported_type_ids + macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)\n' % typename + if macro not in _exported_type_ids: + _exported_type_ids[macro] = 1 + return macro + else: + return None diff --git a/libs/python/pyste/src/Pyste/infos.py b/libs/python/pyste/src/Pyste/infos.py new file mode 100644 index 000000000..2a4f01eaf --- /dev/null +++ b/libs/python/pyste/src/Pyste/infos.py @@ -0,0 +1,259 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os.path +import copy +import exporters +from ClassExporter import ClassExporter +from FunctionExporter import FunctionExporter +from EnumExporter import EnumExporter +from HeaderExporter import HeaderExporter +from VarExporter import VarExporter +from CodeExporter import CodeExporter +from exporterutils import FunctionWrapper +from utils import makeid +import warnings + +#============================================================================== +# DeclarationInfo +#============================================================================== +class DeclarationInfo: + + def __init__(self, otherInfo=None): + self.__infos = {} + self.__attributes = {} + if otherInfo is not None: + self.__infos = copy.deepcopy(otherInfo.__infos) + self.__attributes = copy.deepcopy(otherInfo.__attributes) + + + def __getitem__(self, name): + 'Used to access sub-infos' + if name.startswith('__'): + raise AttributeError + default = DeclarationInfo() + default._Attribute('name', name) + return self.__infos.setdefault(name, default) + + + def __getattr__(self, name): + return self[name] + + + def _Attribute(self, name, value=None): + if value is None: + # get value + return self.__attributes.get(name) + else: + # set value + self.__attributes[name] = value + + + def AddExporter(self, exporter): + # this was causing a much serious bug, as reported by Niall Douglas: + # another solution must be found! + #if not exporters.importing: + if exporter not in exporters.exporters: + exporters.exporters.append(exporter) + exporter.interface_file = exporters.current_interface + + +#============================================================================== +# FunctionInfo +#============================================================================== +class FunctionInfo(DeclarationInfo): + + def __init__(self, name, include, tail=None, otherOption=None, + exporter_class = FunctionExporter): + DeclarationInfo.__init__(self, otherOption) + self._Attribute('name', name) + self._Attribute('include', include) + self._Attribute('exclude', False) + # create a FunctionExporter + exporter = exporter_class(InfoWrapper(self), tail) + self.AddExporter(exporter) + + +#============================================================================== +# ClassInfo +#============================================================================== +class ClassInfo(DeclarationInfo): + + def __init__(self, name, include, tail=None, otherInfo=None, + exporter_class = ClassExporter): + DeclarationInfo.__init__(self, otherInfo) + self._Attribute('name', name) + self._Attribute('include', include) + self._Attribute('exclude', False) + # create a ClassExporter + exporter = exporter_class(InfoWrapper(self), tail) + self.AddExporter(exporter) + + +#============================================================================== +# templates +#============================================================================== +def GenerateName(name, type_list): + name = name.replace('::', '_') + names = [name] + type_list + return makeid('_'.join(names)) + + +class ClassTemplateInfo(DeclarationInfo): + + def __init__(self, name, include, + exporter_class = ClassExporter): + DeclarationInfo.__init__(self) + self._Attribute('name', name) + self._Attribute('include', include) + self._exporter_class = exporter_class + + + def Instantiate(self, type_list, rename=None): + if not rename: + rename = GenerateName(self._Attribute('name'), type_list) + # generate code to instantiate the template + types = ', '.join(type_list) + tail = 'typedef %s< %s > %s;\n' % (self._Attribute('name'), types, rename) + tail += 'void __instantiate_%s()\n' % rename + tail += '{ sizeof(%s); }\n\n' % rename + # create a ClassInfo + class_ = ClassInfo(rename, self._Attribute('include'), tail, self, + exporter_class = self._exporter_class) + return class_ + + + def __call__(self, types, rename=None): + if isinstance(types, str): + types = types.split() + return self.Instantiate(types, rename) + +#============================================================================== +# EnumInfo +#============================================================================== +class EnumInfo(DeclarationInfo): + + def __init__(self, name, include, exporter_class = EnumExporter): + DeclarationInfo.__init__(self) + self._Attribute('name', name) + self._Attribute('include', include) + self._Attribute('exclude', False) + self._Attribute('export_values', False) + exporter = exporter_class(InfoWrapper(self)) + self.AddExporter(exporter) + + +#============================================================================== +# HeaderInfo +#============================================================================== +class HeaderInfo(DeclarationInfo): + + def __init__(self, include, exporter_class = HeaderExporter): + warnings.warn('AllFromHeader is not working in all cases in the current version.') + DeclarationInfo.__init__(self) + self._Attribute('include', include) + exporter = exporter_class(InfoWrapper(self)) + self.AddExporter(exporter) + + +#============================================================================== +# VarInfo +#============================================================================== +class VarInfo(DeclarationInfo): + + def __init__(self, name, include, exporter_class = VarExporter): + DeclarationInfo.__init__(self) + self._Attribute('name', name) + self._Attribute('include', include) + exporter = exporter_class(InfoWrapper(self)) + self.AddExporter(exporter) + + +#============================================================================== +# CodeInfo +#============================================================================== +class CodeInfo(DeclarationInfo): + + def __init__(self, code, section, exporter_class = CodeExporter): + DeclarationInfo.__init__(self) + self._Attribute('code', code) + self._Attribute('section', section) + exporter = exporter_class(InfoWrapper(self)) + self.AddExporter(exporter) + + +#============================================================================== +# InfoWrapper +#============================================================================== +class InfoWrapper: + 'Provides a nicer interface for a info' + + def __init__(self, info): + self.__dict__['_info'] = info # so __setattr__ is not called + + def __getitem__(self, name): + return InfoWrapper(self._info[name]) + + def __getattr__(self, name): + return self._info._Attribute(name) + + def __setattr__(self, name, value): + self._info._Attribute(name, value) + + +#============================================================================== +# Functions +#============================================================================== +def exclude(info): + info._Attribute('exclude', True) + +def set_policy(info, policy): + info._Attribute('policy', policy) + +def rename(info, name): + info._Attribute('rename', name) + +def set_wrapper(info, wrapper): + if isinstance(wrapper, str): + wrapper = FunctionWrapper(wrapper) + info._Attribute('wrapper', wrapper) + +def instantiate(template, types, rename=None): + if isinstance(types, str): + types = types.split() + return template.Instantiate(types, rename) + +def use_shared_ptr(info): + info._Attribute('smart_ptr', 'boost::shared_ptr< %s >') + +def use_auto_ptr(info): + info._Attribute('smart_ptr', 'std::auto_ptr< %s >') + +def holder(info, function): + msg = "Expected a callable that accepts one string argument." + assert callable(function), msg + info._Attribute('holder', function) + +def add_method(info, name, rename=None): + added = info._Attribute('__added__') + if added is None: + info._Attribute('__added__', [(name, rename)]) + else: + added.append((name, rename)) + + +def class_code(info, code): + added = info._Attribute('__code__') + if added is None: + info._Attribute('__code__', [code]) + else: + added.append(code) + +def final(info): + info._Attribute('no_override', True) + + +def export_values(info): + info._Attribute('export_values', True) diff --git a/libs/python/pyste/src/Pyste/policies.py b/libs/python/pyste/src/Pyste/policies.py new file mode 100644 index 000000000..57ebd0dea --- /dev/null +++ b/libs/python/pyste/src/Pyste/policies.py @@ -0,0 +1,95 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + + +class Policy(object): + 'Represents one of the call policies of boost.python.' + + def __init__(self): + if type(self) is Policy: + raise RuntimeError, "Can't create an instance of the class Policy" + + + def Code(self): + 'Returns the string corresponding to a instancialization of the policy.' + pass + + + def _next(self): + if self.next is not None: + return ', %s >' % self.next.Code() + else: + return ' >' + + + def __eq__(self, other): + try: + return self.Code() == other.Code() + except AttributeError: + return False + + + +class return_internal_reference(Policy): + 'Ties the return value to one of the parameters.' + + def __init__(self, param=1, next=None): + ''' + param is the position of the parameter, or None for "self". + next indicates the next policy, or None. + ''' + self.param = param + self.next=next + + + def Code(self): + c = 'return_internal_reference< %i' % self.param + c += self._next() + return c + + + +class with_custodian_and_ward(Policy): + 'Ties lifetime of two arguments of a function.' + + def __init__(self, custodian, ward, next=None): + self.custodian = custodian + self.ward = ward + self.next = next + + def Code(self): + c = 'with_custodian_and_ward< %i, %i' % (self.custodian, self.ward) + c += self._next() + return c + + + +class return_value_policy(Policy): + 'Policy to convert return values.' + + def __init__(self, which, next=None): + self.which = which + self.next = next + + + def Code(self): + c = 'return_value_policy< %s' % self.which + c += self._next() + return c + +class return_self(Policy): + + def Code(self): + return 'return_self<>' + + +# values for return_value_policy +reference_existing_object = 'reference_existing_object' +copy_const_reference = 'copy_const_reference' +copy_non_const_reference = 'copy_non_const_reference' +manage_new_object = 'manage_new_object' +return_opaque_pointer = 'return_opaque_pointer' +return_by_value = 'return_by_value' diff --git a/libs/python/pyste/src/Pyste/pyste.py b/libs/python/pyste/src/Pyste/pyste.py new file mode 100644 index 000000000..cedffff55 --- /dev/null +++ b/libs/python/pyste/src/Pyste/pyste.py @@ -0,0 +1,424 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +""" +Pyste version %s + +Usage: + pyste [options] interface-files + +where options are: + --module=<name> The name of the module that will be generated; + defaults to the first interface filename, without + the extension. + -I <path> Add an include path + -D <symbol> Define symbol + --multiple Create various cpps, instead of only one + (useful during development) + --out=<name> Specify output filename (default: <module>.cpp) + in --multiple mode, this will be a directory + --no-using Do not declare "using namespace boost"; + use explicit declarations instead + --pyste-ns=<name> Set the namespace where new types will be declared; + default is the empty namespace + --debug Writes the xml for each file parsed in the current + directory + --cache-dir=<dir> Directory for cache files (speeds up future runs) + --only-create-cache Recreates all caches (doesn't generate code). + --generate-main Generates the _main.cpp file (in multiple mode) + --file-list A file with one pyste file per line. Use as a + substitute for passing the files in the command + line. + --gccxml-path=<path> Path to gccxml executable (default: gccxml) + --no-default-include Do not use INCLUDE environment variable for include + files to pass along gccxml. + -h, --help Print this help and exit + -v, --version Print version information +""" + +import sys +import os +import getopt +import exporters +import SingleCodeUnit +import MultipleCodeUnit +import infos +import exporterutils +import settings +import gc +import sys +from policies import * +from CppParser import CppParser, CppParserError +import time +import declarations + +__version__ = '0.9.30' + +def RecursiveIncludes(include): + 'Return a list containg the include dir and all its subdirectories' + dirs = [include] + def visit(arg, dir, names): + # ignore CVS dirs + if os.path.split(dir)[1] != 'CVS': + dirs.append(dir) + os.path.walk(include, visit, None) + return dirs + + +def GetDefaultIncludes(): + if 'INCLUDE' in os.environ: + include = os.environ['INCLUDE'] + return include.split(os.pathsep) + else: + return [] + + +def ProcessIncludes(includes): + if sys.platform == 'win32': + index = 0 + for include in includes: + includes[index] = include.replace('\\', '/') + index += 1 + + +def ReadFileList(filename): + f = file(filename) + files = [] + try: + for line in f: + line = line.strip() + if line: + files.append(line) + finally: + f.close() + return files + + +def ParseArguments(): + + def Usage(): + print __doc__ % __version__ + sys.exit(1) + + try: + options, files = getopt.getopt( + sys.argv[1:], + 'R:I:D:vh', + ['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=', + 'only-create-cache', 'version', 'generate-main', 'file-list=', 'help', + 'gccxml-path=', 'no-default-include']) + except getopt.GetoptError, e: + print + print 'ERROR:', e + Usage() + + default_includes = GetDefaultIncludes() + includes = [] + defines = [] + module = None + out = None + multiple = False + cache_dir = None + create_cache = False + generate_main = False + gccxml_path = 'gccxml' + + for opt, value in options: + if opt == '-I': + includes.append(value) + elif opt == '-D': + defines.append(value) + elif opt == '-R': + includes.extend(RecursiveIncludes(value)) + elif opt == '--module': + module = value + elif opt == '--out': + out = value + elif opt == '--no-using': + settings.namespaces.python = 'boost::python::' + settings.USING_BOOST_NS = False + elif opt == '--pyste-ns': + settings.namespaces.pyste = value + '::' + elif opt == '--debug': + settings.DEBUG = True + elif opt == '--multiple': + multiple = True + elif opt == '--cache-dir': + cache_dir = value + elif opt == '--only-create-cache': + create_cache = True + elif opt == '--file-list': + files += ReadFileList(value) + elif opt in ['-h', '--help']: + Usage() + elif opt in ['-v', '--version']: + print 'Pyste version %s' % __version__ + sys.exit(2) + elif opt == '--generate-main': + generate_main = True + elif opt == '--gccxml-path': + gccxml_path = value + elif opt == '--no-default-include': + default_includes = [] + else: + print 'Unknown option:', opt + Usage() + + includes[0:0] = default_includes + if not files: + Usage() + if not module: + module = os.path.splitext(os.path.basename(files[0]))[0] + if not out: + out = module + if not multiple: + out += '.cpp' + for file in files: + d = os.path.dirname(os.path.abspath(file)) + if d not in sys.path: + sys.path.append(d) + + if create_cache and not cache_dir: + print 'Error: Use --cache-dir to indicate where to create the cache files!' + Usage() + sys.exit(3) + + if generate_main and not multiple: + print 'Error: --generate-main only valid in multiple mode.' + Usage() + sys.exit(3) + + ProcessIncludes(includes) + return includes, defines, module, out, files, multiple, cache_dir, create_cache, \ + generate_main, gccxml_path + + +def PCHInclude(*headers): + code = '\n'.join(['#include <%s>' % x for x in headers]) + infos.CodeInfo(code, 'pchinclude') + + +def CreateContext(): + 'create the context where a interface file will be executed' + context = {} + context['Import'] = Import + # infos + context['Function'] = infos.FunctionInfo + context['Class'] = infos.ClassInfo + context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include') + context['PCHInclude'] = PCHInclude + context['Template'] = infos.ClassTemplateInfo + context['Enum'] = infos.EnumInfo + context['AllFromHeader'] = infos.HeaderInfo + context['Var'] = infos.VarInfo + # functions + context['rename'] = infos.rename + context['set_policy'] = infos.set_policy + context['exclude'] = infos.exclude + context['set_wrapper'] = infos.set_wrapper + context['use_shared_ptr'] = infos.use_shared_ptr + context['use_auto_ptr'] = infos.use_auto_ptr + context['holder'] = infos.holder + context['add_method'] = infos.add_method + context['final'] = infos.final + context['export_values'] = infos.export_values + # policies + context['return_internal_reference'] = return_internal_reference + context['with_custodian_and_ward'] = with_custodian_and_ward + context['return_value_policy'] = return_value_policy + context['reference_existing_object'] = reference_existing_object + context['copy_const_reference'] = copy_const_reference + context['copy_non_const_reference'] = copy_non_const_reference + context['return_opaque_pointer'] = return_opaque_pointer + context['manage_new_object'] = manage_new_object + context['return_by_value'] = return_by_value + context['return_self'] = return_self + # utils + context['Wrapper'] = exporterutils.FunctionWrapper + context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside') + context['module_code'] = lambda code: infos.CodeInfo(code, 'module') + context['class_code'] = infos.class_code + return context + + +def Begin(): + # parse arguments + includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main, gccxml_path = ParseArguments() + # run pyste scripts + for interface in interfaces: + ExecuteInterface(interface) + # create the parser + parser = CppParser(includes, defines, cache_dir, declarations.version, gccxml_path) + try: + if not create_cache: + if not generate_main: + return GenerateCode(parser, module, out, interfaces, multiple) + else: + return GenerateMain(module, out, OrderInterfaces(interfaces)) + else: + return CreateCaches(parser) + finally: + parser.Close() + + +def CreateCaches(parser): + # There is one cache file per interface so we organize the headers + # by interfaces. For each interface collect the tails from the + # exporters sharing the same header. + tails = JoinTails(exporters.exporters) + + # now for each interface file take each header, and using the tail + # get the declarations and cache them. + for interface, header in tails: + tail = tails[(interface, header)] + declarations = parser.ParseWithGCCXML(header, tail) + cachefile = parser.CreateCache(header, interface, tail, declarations) + print 'Cached', cachefile + + return 0 + + +_imported_count = {} # interface => count + +def ExecuteInterface(interface): + old_interface = exporters.current_interface + if not os.path.exists(interface): + if old_interface and os.path.exists(old_interface): + d = os.path.dirname(old_interface) + interface = os.path.join(d, interface) + if not os.path.exists(interface): + raise IOError, "Cannot find interface file %s."%interface + + _imported_count[interface] = _imported_count.get(interface, 0) + 1 + exporters.current_interface = interface + context = CreateContext() + context['INTERFACE_FILE'] = os.path.abspath(interface) + execfile(interface, context) + exporters.current_interface = old_interface + + +def Import(interface): + exporters.importing = True + ExecuteInterface(interface) + exporters.importing = False + + +def JoinTails(exports): + '''Returns a dict of {(interface, header): tail}, where tail is the + joining of all tails of all exports for the header. + ''' + tails = {} + for export in exports: + interface = export.interface_file + header = export.Header() + tail = export.Tail() or '' + if (interface, header) in tails: + all_tails = tails[(interface,header)] + all_tails += '\n' + tail + tails[(interface, header)] = all_tails + else: + tails[(interface, header)] = tail + + return tails + + + +def OrderInterfaces(interfaces): + interfaces_order = [(_imported_count[x], x) for x in interfaces] + interfaces_order.sort() + interfaces_order.reverse() + return [x for _, x in interfaces_order] + + + +def GenerateMain(module, out, interfaces): + codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out) + codeunit.GenerateMain(interfaces) + return 0 + + +def GenerateCode(parser, module, out, interfaces, multiple): + # prepare to generate the wrapper code + if multiple: + codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out) + else: + codeunit = SingleCodeUnit.SingleCodeUnit(module, out) + # stop referencing the exporters here + exports = exporters.exporters + exporters.exporters = None + exported_names = dict([(x.Name(), None) for x in exports]) + + # order the exports + order = {} + for export in exports: + if export.interface_file in order: + order[export.interface_file].append(export) + else: + order[export.interface_file] = [export] + exports = [] + interfaces_order = OrderInterfaces(interfaces) + for interface in interfaces_order: + exports.extend(order[interface]) + del order + del interfaces_order + + # now generate the code in the correct order + #print exported_names + tails = JoinTails(exports) + for i in xrange(len(exports)): + export = exports[i] + interface = export.interface_file + header = export.Header() + if header: + tail = tails[(interface, header)] + declarations, parsed_header = parser.Parse(header, interface, tail) + else: + declarations = [] + parsed_header = None + ExpandTypedefs(declarations, exported_names) + export.SetDeclarations(declarations) + export.SetParsedHeader(parsed_header) + if multiple: + codeunit.SetCurrent(export.interface_file, export.Name()) + export.GenerateCode(codeunit, exported_names) + # force collect of cyclic references + exports[i] = None + del declarations + del export + gc.collect() + # finally save the code unit + codeunit.Save() + if not multiple: + print 'Module %s generated' % module + return 0 + + +def ExpandTypedefs(decls, exported_names): + '''Check if the names in exported_names are a typedef, and add the real class + name in the dict. + ''' + for name in exported_names.keys(): + for decl in decls: + if isinstance(decl, declarations.Typedef): + exported_names[decl.type.FullName()] = None + +def UsePsyco(): + 'Tries to use psyco if possible' + try: + import psyco + psyco.profile() + except: pass + + +def main(): + start = time.clock() + UsePsyco() + status = Begin() + print '%0.2f seconds' % (time.clock()-start) + sys.exit(status) + + +if __name__ == '__main__': + main() diff --git a/libs/python/pyste/src/Pyste/settings.py b/libs/python/pyste/src/Pyste/settings.py new file mode 100644 index 000000000..ba613b234 --- /dev/null +++ b/libs/python/pyste/src/Pyste/settings.py @@ -0,0 +1,21 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + +#============================================================================== +# Global information +#============================================================================== + +DEBUG = False +USING_BOOST_NS = True + +class namespaces: + boost = 'boost::' + pyste = '' + python = '' # default is to not use boost::python namespace explicitly, so + # use the "using namespace" statement instead + +import sys +msvc = sys.platform == 'win32' diff --git a/libs/python/pyste/src/Pyste/utils.py b/libs/python/pyste/src/Pyste/utils.py new file mode 100644 index 000000000..a8843e3f6 --- /dev/null +++ b/libs/python/pyste/src/Pyste/utils.py @@ -0,0 +1,78 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from __future__ import generators +import string +import sys + +#============================================================================== +# enumerate +#============================================================================== +def enumerate(seq): + i = 0 + for x in seq: + yield i, x + i += 1 + + +#============================================================================== +# makeid +#============================================================================== +_valid_chars = string.ascii_letters + string.digits + '_' +_valid_chars = dict(zip(_valid_chars, _valid_chars)) + +def makeid(name): + 'Returns the name as a valid identifier' + if type(name) != str: + print type(name), name + newname = [] + for char in name: + if char not in _valid_chars: + char = '_' + newname.append(char) + newname = ''.join(newname) + # avoid duplications of '_' chars + names = [x for x in newname.split('_') if x] + return '_'.join(names) + + +#============================================================================== +# remove_duplicated_lines +#============================================================================== +def remove_duplicated_lines(text): + includes = text.splitlines() + d = dict([(include, 0) for include in includes]) + includes = d.keys() + includes.sort() + return '\n'.join(includes) + + +#============================================================================== +# left_equals +#============================================================================== +def left_equals(s): + s = '// %s ' % s + return s + ('='*(80-len(s))) + '\n' + + +#============================================================================== +# post_mortem +#============================================================================== +def post_mortem(): + + def info(type, value, tb): + if hasattr(sys, 'ps1') or not sys.stderr.isatty(): + # we are in interactive mode or we don't have a tty-like + # device, so we call the default hook + sys.__excepthook__(type, value, tb) + else: + import traceback, pdb + # we are NOT in interactive mode, print the exception... + traceback.print_exception(type, value, tb) + print + # ...then start the debugger in post-mortem mode. + pdb.pm() + + sys.excepthook = info diff --git a/libs/python/pyste/tests/GCCXMLParserUT.py b/libs/python/pyste/tests/GCCXMLParserUT.py new file mode 100644 index 000000000..7175c9c68 --- /dev/null +++ b/libs/python/pyste/tests/GCCXMLParserUT.py @@ -0,0 +1,341 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import sys +sys.path.append('../src') +import unittest +import tempfile +import os.path +from Pyste import GCCXMLParser +from Pyste.declarations import * + + +class Tester(unittest.TestCase): + + def TestConstructor(self, class_, method, visib): + self.assert_(isinstance(method, Constructor)) + self.assertEqual(method.FullName(), class_.FullName() + '::' + method.name) + self.assertEqual(method.result, None) + self.assertEqual(method.visibility, visib) + self.assert_(not method.virtual) + self.assert_(not method.abstract) + self.assert_(not method.static) + + def TestDefaultConstructor(self, class_, method, visib): + self.TestConstructor(class_, method, visib) + self.assert_(method.IsDefault()) + + def TestCopyConstructor(self, class_, method, visib): + self.TestConstructor(class_, method, visib) + self.assertEqual(len(method.parameters), 1) + param = method.parameters[0] + self.TestType( + param, + ReferenceType, + class_.FullName(), + 'const %s&' % class_.FullName(), + True) + self.assert_(method.IsCopy()) + + + def TestType(self, type_, classtype_, name, fullname, const): + self.assert_(isinstance(type_, classtype_)) + self.assertEqual(type_.name, name) + self.assertEqual(type_.namespace, None) + self.assertEqual(type_.FullName(), fullname) + self.assertEqual(type_.const, const) + + +class ClassBaseTest(Tester): + + def setUp(self): + self.base = GetDecl('Base') + + def testClass(self): + 'test the properties of the class Base' + self.assert_(isinstance(self.base, Class)) + self.assert_(self.base.abstract) + + + def testFoo(self): + 'test function foo in class Base' + foo = GetMember(self.base, 'foo') + self.assert_(isinstance(foo, Method)) + self.assertEqual(foo.visibility, Scope.public) + self.assert_(foo.virtual) + self.assert_(foo.abstract) + self.failIf(foo.static) + self.assertEqual(foo.class_, 'test::Base') + self.failIf(foo.const) + self.assertEqual(foo.FullName(), 'test::Base::foo') + self.assertEqual(foo.result.name, 'void') + self.assertEqual(len(foo.parameters), 1) + param = foo.parameters[0] + self.TestType(param, FundamentalType, 'int', 'int', False) + self.assertEqual(foo.namespace, None) + self.assertEqual( + foo.PointerDeclaration(1), '(void (test::Base::*)(int) )&test::Base::foo') + + def testX(self): + 'test the member x in class Base' + x = GetMember(self.base, 'x') + self.assertEqual(x.class_, 'test::Base') + self.assertEqual(x.FullName(), 'test::Base::x') + self.assertEqual(x.namespace, None) + self.assertEqual(x.visibility, Scope.private) + self.TestType(x.type, FundamentalType, 'int', 'int', False) + self.assertEqual(x.static, False) + + def testConstructors(self): + 'test constructors in class Base' + constructors = GetMembers(self.base, 'Base') + for cons in constructors: + if len(cons.parameters) == 0: + self.TestDefaultConstructor(self.base, cons, Scope.public) + elif len(cons.parameters) == 1: # copy constructor + self.TestCopyConstructor(self.base, cons, Scope.public) + elif len(cons.parameters) == 2: # other constructor + intp, floatp = cons.parameters + self.TestType(intp, FundamentalType, 'int', 'int', False) + self.TestType(floatp, FundamentalType, 'float', 'float', False) + + def testSimple(self): + 'test function simple in class Base' + simple = GetMember(self.base, 'simple') + self.assert_(isinstance(simple, Method)) + self.assertEqual(simple.visibility, Scope.protected) + self.assertEqual(simple.FullName(), 'test::Base::simple') + self.assertEqual(len(simple.parameters), 1) + param = simple.parameters[0] + self.TestType(param, ReferenceType, 'std::string', 'const std::string&', True) + self.TestType(simple.result, FundamentalType, 'bool', 'bool', False) + self.assertEqual( + simple.PointerDeclaration(1), + '(bool (test::Base::*)(const std::string&) )&test::Base::simple') + + + def testZ(self): + z = GetMember(self.base, 'z') + self.assert_(isinstance(z, Variable)) + self.assertEqual(z.visibility, Scope.public) + self.assertEqual(z.FullName(), 'test::Base::z') + self.assertEqual(z.type.name, 'int') + self.assertEqual(z.type.const, False) + self.assert_(z.static) + + +class ClassTemplateTest(Tester): + + def setUp(self): + self.template = GetDecl('Template<int>') + + def testClass(self): + 'test the properties of the Template<int> class' + self.assert_(isinstance(self.template, Class)) + self.assert_(not self.template.abstract) + self.assertEqual(self.template.FullName(), 'Template<int>') + self.assertEqual(self.template.namespace, '') + self.assertEqual(self.template.name, 'Template<int>') + + def testConstructors(self): + 'test the automatic constructors of the class Template<int>' + constructors = GetMembers(self.template, 'Template') + for cons in constructors: + if len(cons.parameters) == 0: + self.TestDefaultConstructor(self.template, cons, Scope.public) + elif len(cons.parameters) == 1: + self.TestCopyConstructor(self.template, cons, Scope.public) + + + def testValue(self): + 'test the class variable value' + value = GetMember(self.template, 'value') + self.assert_(isinstance(value, ClassVariable)) + self.assert_(value.name, 'value') + self.TestType(value.type, FundamentalType, 'int', 'int', False) + self.assert_(not value.static) + self.assertEqual(value.visibility, Scope.public) + self.assertEqual(value.class_, 'Template<int>') + self.assertEqual(value.FullName(), 'Template<int>::value') + + def testBase(self): + 'test the superclasses of Template<int>' + bases = self.template.bases + self.assertEqual(len(bases), 1) + base = bases[0] + self.assert_(isinstance(base, Base)) + self.assertEqual(base.name, 'test::Base') + self.assertEqual(base.visibility, Scope.protected) + + + +class FreeFuncTest(Tester): + + def setUp(self): + self.func = GetDecl('FreeFunc') + + def testFunc(self): + 'test attributes of FreeFunc' + self.assert_(isinstance(self.func, Function)) + self.assertEqual(self.func.name, 'FreeFunc') + self.assertEqual(self.func.FullName(), 'test::FreeFunc') + self.assertEqual(self.func.namespace, 'test') + self.assertEqual( + self.func.PointerDeclaration(1), + '(const test::Base& (*)(const std::string&, int))&test::FreeFunc') + + + def testResult(self): + 'test the return value of FreeFunc' + res = self.func.result + self.TestType(res, ReferenceType, 'test::Base', 'const test::Base&', True) + + def testParameters(self): + 'test the parameters of FreeFunc' + self.assertEqual(len(self.func.parameters), 2) + strp, intp = self.func.parameters + self.TestType(strp, ReferenceType, 'std::string', 'const std::string&', True) + self.assertEqual(strp.default, None) + self.TestType(intp, FundamentalType, 'int', 'int', False) + self.assertEqual(intp.default, '10') + + + +class testFunctionPointers(Tester): + + def testMethodPointer(self): + 'test declaration of a pointer-to-method' + meth = GetDecl('MethodTester') + param = meth.parameters[0] + fullname = 'void (test::Base::*)(int)' + self.TestType(param, PointerType, fullname, fullname, False) + + def testFunctionPointer(self): + 'test declaration of a pointer-to-function' + func = GetDecl('FunctionTester') + param = func.parameters[0] + fullname = 'void (*)(int)' + self.TestType(param, PointerType, fullname, fullname, False) + + + +# ============================================================================= +# Support routines +# ============================================================================= + +cppcode = ''' +namespace std { + class string; +} +namespace test { +class Base +{ +public: + Base(); + Base(const Base&); + Base(int, float); + + virtual void foo(int = 0.0) = 0; + static int z; +protected: + bool simple(const std::string&); +private: + int x; +}; + +void MethodTester( void (Base::*)(int) ); +void FunctionTester( void (*)(int) ); + + +const Base & FreeFunc(const std::string&, int=10); + +} + +template <class T> +struct Template: protected test::Base +{ + T value; + virtual void foo(int); +}; + +Template<int> __aTemplateInt; +''' + +def GetXMLFile(): + '''Generates an gccxml file using the code from the global cppcode. + Returns the xml's filename.''' + # write the code to a header file + tmpfile = tempfile.mktemp() + '.h' + f = file(tmpfile, 'w') + f.write(cppcode) + f.close() + # run gccxml + outfile = tmpfile + '.xml' + if os.system('gccxml "%s" "-fxml=%s"' % (tmpfile, outfile)) != 0: + raise RuntimeError, 'Error executing GCCXML.' + # read the output file into the xmlcode + f = file(outfile) + xmlcode = f.read() + #print xmlcode + f.close() + # remove the header + os.remove(tmpfile) + return outfile + + + +def GetDeclarations(): + 'Uses the GCCXMLParser module to get the declarations.' + xmlfile = GetXMLFile() + declarations = GCCXMLParser.ParseDeclarations(xmlfile) + os.remove(xmlfile) + return declarations + +# the declarations to be analysed +declarations = GetDeclarations() + + +def GetDecl(name): + 'returns one of the top declarations given its name' + for decl in declarations: + if decl.name == name: + return decl + else: + raise RuntimeError, 'Declaration not found: %s' % name + + +def GetMember(class_, name): + 'gets the member of the given class by its name' + + res = None + multipleFound = False + for member in class_: + if member.name == name: + if res is not None: + multipleFound = True + break + res = member + if res is None or multipleFound: + raise RuntimeError, \ + 'No member or more than one member found in class %s: %s' \ + % (class_.name, name) + return res + + +def GetMembers(class_, name): + 'gets the members of the given class by its name' + res = [] + for member in class_: + if member.name == name: + res.append(member) + if len(res) in (0, 1): + raise RuntimeError, \ + 'GetMembers: 0 or 1 members found in class %s: %s' \ + % (class_.name, name) + return res + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/SmartFileUT.py b/libs/python/pyste/tests/SmartFileUT.py new file mode 100644 index 000000000..9e4e99883 --- /dev/null +++ b/libs/python/pyste/tests/SmartFileUT.py @@ -0,0 +1,84 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import sys +sys.path.append('../src') +from SmartFile import * +import unittest +import tempfile +import os +import time + + +class SmartFileTest(unittest.TestCase): + + FILENAME = tempfile.mktemp() + + def setUp(self): + self._Clean() + + def tearDown(self): + self._Clean() + + def _Clean(self): + try: + os.remove(self.FILENAME) + except OSError: pass + + + def testNonExistant(self): + "Must override the file, as there's no file in the disk yet" + self.assert_(not os.path.isfile(self.FILENAME)) + f = SmartFile(self.FILENAME, 'w') + f.write('Testing 123\nTesting again.') + f.close() + self.assert_(os.path.isfile(self.FILENAME)) + + + def testOverride(self): + "Must override the file, because the contents are different" + contents = 'Contents!\nContents!' + # create the file normally first + f = file(self.FILENAME, 'w') + f.write(contents) + f.close() + file_time = os.path.getmtime(self.FILENAME) + self.assert_(os.path.isfile(self.FILENAME)) + time.sleep(2) + f = SmartFile(self.FILENAME, 'w') + f.write(contents + '_') + f.close() + new_file_time = os.path.getmtime(self.FILENAME) + self.assert_(new_file_time != file_time) + + + def testNoOverride(self): + "Must not override the file, because the contents are the same" + contents = 'Contents!\nContents!' + # create the file normally first + f = file(self.FILENAME, 'w') + f.write(contents) + f.close() + file_time = os.path.getmtime(self.FILENAME) + self.assert_(os.path.isfile(self.FILENAME)) + time.sleep(2) + f = SmartFile(self.FILENAME, 'w') + f.write(contents) + f.close() + new_file_time = os.path.getmtime(self.FILENAME) + self.assert_(new_file_time == file_time) + + + def testAutoClose(self): + "Must be closed when garbage-collected" + def foo(): + f = SmartFile(self.FILENAME) + f.write('testing') + self.assert_(not os.path.isfile(self.FILENAME)) + foo() + self.assert_(os.path.isfile(self.FILENAME)) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/abstract_test.h b/libs/python/pyste/tests/abstract_test.h new file mode 100644 index 000000000..e0fba2b24 --- /dev/null +++ b/libs/python/pyste/tests/abstract_test.h @@ -0,0 +1,22 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#include <vector> +#include <string> + +namespace abstract { + +struct A { + virtual ~A() {} + virtual std::string f()=0; +}; + +struct B: A { + std::string f() { return "B::f"; } +}; + +std::string call(A* a) { return a->f(); } + +} diff --git a/libs/python/pyste/tests/abstract_test.pyste b/libs/python/pyste/tests/abstract_test.pyste new file mode 100644 index 000000000..c65bb3ad6 --- /dev/null +++ b/libs/python/pyste/tests/abstract_test.pyste @@ -0,0 +1,3 @@ +Class('abstract::A', 'abstract_test.h') +Class('abstract::B', 'abstract_test.h') +Function('abstract::call', 'abstract_test.h') diff --git a/libs/python/pyste/tests/abstract_testUT.py b/libs/python/pyste/tests/abstract_testUT.py new file mode 100644 index 000000000..4dc61a262 --- /dev/null +++ b/libs/python/pyste/tests/abstract_testUT.py @@ -0,0 +1,26 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _abstract_test import * + +class AbstractTest(unittest.TestCase): + + def testIt(self): + class C(A): + def f(self): + return 'C::f' + + a = A() + b = B() + c = C() + self.assertRaises(RuntimeError, a.f) + self.assertEqual(b.f(), 'B::f') + self.assertEqual(call(b), 'B::f') + self.assertEqual(c.f(), 'C::f') + self.assertEqual(call(c), 'C::f') + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/add_test.h b/libs/python/pyste/tests/add_test.h new file mode 100644 index 000000000..447e8814c --- /dev/null +++ b/libs/python/pyste/tests/add_test.h @@ -0,0 +1,18 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +namespace add_test { + +struct C +{ + int x; +}; + +const int get_x(C& c) +{ + return c.x; +} + +} diff --git a/libs/python/pyste/tests/add_test.pyste b/libs/python/pyste/tests/add_test.pyste new file mode 100644 index 000000000..cc7faa9ed --- /dev/null +++ b/libs/python/pyste/tests/add_test.pyste @@ -0,0 +1,2 @@ +C = Class('add_test::C', 'add_test.h') +add_method(C, 'add_test::get_x') diff --git a/libs/python/pyste/tests/add_testUT.py b/libs/python/pyste/tests/add_testUT.py new file mode 100644 index 000000000..16f57a320 --- /dev/null +++ b/libs/python/pyste/tests/add_testUT.py @@ -0,0 +1,16 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _add_test import * + +class AddMethodTest(unittest.TestCase): + + def testIt(self): + c = C() + c.x = 10 + self.assertEqual(c.get_x(), 10) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/basic.cpp b/libs/python/pyste/tests/basic.cpp new file mode 100644 index 000000000..d07b6da62 --- /dev/null +++ b/libs/python/pyste/tests/basic.cpp @@ -0,0 +1,13 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#include "basic.h" + +namespace basic { + + int C::static_value = 3; + const int C::const_static_value = 100; + +} diff --git a/libs/python/pyste/tests/basic.h b/libs/python/pyste/tests/basic.h new file mode 100644 index 000000000..690fed2d3 --- /dev/null +++ b/libs/python/pyste/tests/basic.h @@ -0,0 +1,69 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef BASIC_H +#define BASIC_H + + +#include <string> + +namespace basic { + +struct C +{ + // test virtuallity + C(): value(1), const_value(0) {} + virtual int f(int x = 10) + { + return x*2; + } + + int foo(int x=1){ + return x+1; + } + + const std::string& get_name() { return name; } + void set_name(const std::string& name) { this->name = name; } +private: + std::string name; + +public: + // test data members + static int static_value; + static const int const_static_value; + + int value; + const int const_value; + + // test static functions + static int mul(int x, int y) { return x*y; } + static double mul(double x, double y) { return x*y; } + + static int square(int x=2) { return x*x; } +}; + +inline int call_f(C& c) +{ + return c.f(); +} + +inline int call_f(C& c, int x) +{ + return c.f(x); +} + +inline int get_static() +{ + return C::static_value; +} + +inline int get_value(C& c) +{ + return c.value; +} + +} + +#endif diff --git a/libs/python/pyste/tests/basic.pyste b/libs/python/pyste/tests/basic.pyste new file mode 100644 index 000000000..4fe0b5b31 --- /dev/null +++ b/libs/python/pyste/tests/basic.pyste @@ -0,0 +1,5 @@ +Class('basic::C', 'basic.h') +Function('basic::call_f', 'basic.h') +Function('basic::get_static', 'basic.h') +Function('basic::get_value', 'basic.h') + diff --git a/libs/python/pyste/tests/basicUT.py b/libs/python/pyste/tests/basicUT.py new file mode 100644 index 000000000..9a18bcbf3 --- /dev/null +++ b/libs/python/pyste/tests/basicUT.py @@ -0,0 +1,73 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _basic import * + +class BasicExampleTest(unittest.TestCase): + + def testIt(self): + + # test virtual functions + class D(C): + def f(self, x=10): + return x+1 + + d = D() + c = C() + + self.assertEqual(c.f(), 20) + self.assertEqual(c.f(3), 6) + self.assertEqual(d.f(), 11) + self.assertEqual(d.f(3), 4) + self.assertEqual(call_f(c), 20) + self.assertEqual(call_f(c, 4), 8) + self.assertEqual(call_f(d), 11) + self.assertEqual(call_f(d, 3), 4) + + # test data members + def testValue(value): + self.assertEqual(c.value, value) + self.assertEqual(d.value, value) + self.assertEqual(get_value(c), value) + self.assertEqual(get_value(d), value) + testValue(1) + c.value = 30 + d.value = 30 + testValue(30) + self.assertEqual(c.const_value, 0) + self.assertEqual(d.const_value, 0) + def set_const_value(): + c.const_value = 12 + self.assertRaises(AttributeError, set_const_value) + + # test static data-members + def testStatic(value): + self.assertEqual(C.static_value, value) + self.assertEqual(c.static_value, value) + self.assertEqual(D.static_value, value) + self.assertEqual(d.static_value, value) + self.assertEqual(get_static(), value) + testStatic(3) + C.static_value = 10 + testStatic(10) + self.assertEqual(C.const_static_value, 100) + def set_const_static(): + C.const_static_value = 1 + self.assertRaises(AttributeError, set_const_static) + + # test static function + def test_mul(result, *args): + self.assertEqual(C.mul(*args), result) + self.assertEqual(c.mul(*args), result) + test_mul(16, 8, 2) + test_mul(6.0, 2.0, 3.0) + self.assertEqual(C.square(), 4) + self.assertEqual(c.square(), 4) + self.assertEqual(C.square(3), 9) + self.assertEqual(c.square(3), 9) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/code_test.h b/libs/python/pyste/tests/code_test.h new file mode 100644 index 000000000..0a31205a3 --- /dev/null +++ b/libs/python/pyste/tests/code_test.h @@ -0,0 +1,8 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +struct A { + int x; +}; diff --git a/libs/python/pyste/tests/code_test.pyste b/libs/python/pyste/tests/code_test.pyste new file mode 100644 index 000000000..467996fdb --- /dev/null +++ b/libs/python/pyste/tests/code_test.pyste @@ -0,0 +1,9 @@ +Class('A', 'code_test.h') +Include('string') +declaration_code(''' +int get(A& a) { return a.x; } + +std::string foo() { return "Hello!"; } +''') +module_code(' def("get", &get);\n') +module_code(' def("foo", &foo);\n') diff --git a/libs/python/pyste/tests/code_testUT.py b/libs/python/pyste/tests/code_testUT.py new file mode 100644 index 000000000..1059570aa --- /dev/null +++ b/libs/python/pyste/tests/code_testUT.py @@ -0,0 +1,18 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _code_test import * + +class CodeTest(unittest.TestCase): + + def testIt(self): + a = A() + a.x = 12 + self.assertEqual(get(a), 12) + self.assertEqual(foo(), "Hello!") + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/enums.h b/libs/python/pyste/tests/enums.h new file mode 100644 index 000000000..afe33ca48 --- /dev/null +++ b/libs/python/pyste/tests/enums.h @@ -0,0 +1,34 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef ENUMS_H +#define ENUMS_H + +namespace enums { + +enum color { red, blue }; + +struct X +{ + enum choices + { + good = 1, + bad = 2 + }; + + int set(choices c) + { + return (int)c; + } +}; + +enum { + x = 0, + y = 1 +}; + +} + +#endif diff --git a/libs/python/pyste/tests/enums.pyste b/libs/python/pyste/tests/enums.pyste new file mode 100644 index 000000000..c18a1244f --- /dev/null +++ b/libs/python/pyste/tests/enums.pyste @@ -0,0 +1,8 @@ +h = AllFromHeader('enums.h') +rename(h.color.red, 'Red') +rename(h.color.blue, 'Blue') +export_values(h.color) +rename(h.X.choices.bad, 'Bad') +rename(h.X.choices.good, 'Good') +rename(h.X.choices, 'Choices') + diff --git a/libs/python/pyste/tests/enumsUT.py b/libs/python/pyste/tests/enumsUT.py new file mode 100644 index 000000000..7c7720dcb --- /dev/null +++ b/libs/python/pyste/tests/enumsUT.py @@ -0,0 +1,24 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _enums import * + +class EnumsTest(unittest.TestCase): + + def testIt(self): + self.assertEqual(int(Red), 0) + self.assertEqual(int(Blue), 1) + + self.assertEqual(int(X.Choices.Good), 1) + self.assertEqual(int(X.Choices.Bad), 2) + a = X() + self.assertEqual(a.set(a.Choices.Good), 1) + self.assertEqual(a.set(a.Choices.Bad), 2) + self.assertEqual(x, 0) + self.assertEqual(y, 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/header_test.h b/libs/python/pyste/tests/header_test.h new file mode 100644 index 000000000..030d0d26c --- /dev/null +++ b/libs/python/pyste/tests/header_test.h @@ -0,0 +1,43 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef HEADER_TEST_H +#define HEADER_TEST_H + +#include <map> +#include <string> + +namespace header_test { + +enum choice { red, blue }; + +inline std::string choice_str(choice c) +{ + std::map<choice, std::string> choice_map; + choice_map[red] = "red"; + choice_map[blue] = "blue"; + return choice_map[c]; +} + +struct C +{ + choice c; + + std::string get() + { + return choice_str(c); + } +}; + +// test the exclusion of the following + +struct ForwardDeclared; // should be excluded automatically +struct A {}; +void foo(); +enum bar { value }; + +} + +#endif diff --git a/libs/python/pyste/tests/header_test.pyste b/libs/python/pyste/tests/header_test.pyste new file mode 100644 index 000000000..3bd55501c --- /dev/null +++ b/libs/python/pyste/tests/header_test.pyste @@ -0,0 +1,4 @@ +h = AllFromHeader('header_test.h') +exclude(h.A) +exclude(h.foo) +exclude(h.bar) diff --git a/libs/python/pyste/tests/header_testUT.py b/libs/python/pyste/tests/header_testUT.py new file mode 100644 index 000000000..aa0d4a16f --- /dev/null +++ b/libs/python/pyste/tests/header_testUT.py @@ -0,0 +1,27 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _header_test import * + +class HeaderTest(unittest.TestCase): + + def testIt(self): + self.assertEqual(choice.red, 0) + self.assertEqual(choice.blue, 1) + self.assertEqual(choice_str(choice.blue), 'blue') + self.assertEqual(choice_str(choice.red), 'red') + c = C() + c.c = choice.blue + self.assertEqual(c.get(), 'blue') + c.c = choice.red + self.assertEqual(c.get(), 'red') + # the following classes/functions should not have being exported + self.assertRaises(NameError, lambda: A()) + self.assertRaises(NameError, lambda: foo()) + self.assertRaises(NameError, lambda: bar.value) + self.assertRaises(NameError, lambda: ForwardDeclared()) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/infosUT.py b/libs/python/pyste/tests/infosUT.py new file mode 100644 index 000000000..93769f34e --- /dev/null +++ b/libs/python/pyste/tests/infosUT.py @@ -0,0 +1,55 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import sys +from Pyste.infos import * +from Pyste.policies import * +from Pyste.exporterutils import * +import unittest + +#================================================================================ +# InfosTest +#================================================================================ +class InfosTest(unittest.TestCase): + + def testFunctionInfo(self): + info = FunctionInfo('test::foo', 'foo.h') + rename(info, 'hello') + set_policy(info, return_internal_reference()) + set_wrapper(info, FunctionWrapper('foo_wrapper')) + + info = InfoWrapper(info) + + self.assertEqual(info.rename, 'hello') + self.assertEqual(info.policy.Code(), 'return_internal_reference< 1 >') + self.assertEqual(info.wrapper.name, 'foo_wrapper') + + + def testClassInfo(self): + info = ClassInfo('test::IFoo', 'foo.h') + rename(info.name, 'Name') + rename(info.exclude, 'Exclude') + rename(info, 'Foo') + rename(info.Bar, 'bar') + set_policy(info.Baz, return_internal_reference()) + rename(info.operator['>>'], 'from_string') + exclude(info.Bar) + set_wrapper(info.Baz, FunctionWrapper('baz_wrapper')) + + info = InfoWrapper(info) + + self.assertEqual(info.rename, 'Foo') + self.assertEqual(info['Bar'].rename, 'bar') + self.assertEqual(info['name'].rename, 'Name') + self.assertEqual(info['exclude'].rename, 'Exclude') + self.assertEqual(info['Bar'].exclude, True) + self.assertEqual(info['Baz'].policy.Code(), 'return_internal_reference< 1 >') + self.assertEqual(info['Baz'].wrapper.name, 'baz_wrapper') + self.assertEqual(info['operator']['>>'].rename, 'from_string') + + + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/inherit.cpp b/libs/python/pyste/tests/inherit.cpp new file mode 100644 index 000000000..a75e83891 --- /dev/null +++ b/libs/python/pyste/tests/inherit.cpp @@ -0,0 +1,8 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#include "inherit.h" + +int inherit::C::s = 1; diff --git a/libs/python/pyste/tests/inherit.h b/libs/python/pyste/tests/inherit.h new file mode 100644 index 000000000..8f903f4fd --- /dev/null +++ b/libs/python/pyste/tests/inherit.h @@ -0,0 +1,43 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +namespace inherit { + +template<typename T> +class A +{ +public: + void set(T v) { mData = v; } + + T get() const { return mData; } + +private: + T mData; +}; + + +class B : public A<int> +{ +public: + int go() { return get(); } +}; + +struct C : B +{ + enum ab { a = 1, b = 2 }; + int f1() { return 1; } + int x; + static int s; +}; + +struct D : C +{ + int f2() { return 2; } + int y; +}; + +struct X {}; +struct E: X, D {}; +} diff --git a/libs/python/pyste/tests/inherit.pyste b/libs/python/pyste/tests/inherit.pyste new file mode 100644 index 000000000..0dc029989 --- /dev/null +++ b/libs/python/pyste/tests/inherit.pyste @@ -0,0 +1,8 @@ +A = Template('inherit::A', 'inherit.h') +A_int = A('int', 'A_int') + +Class('inherit::B', 'inherit.h') +Class('inherit::D', 'inherit.h') +E = Class('inherit::E', 'inherit.h') +exclude(E.s) +exclude(E.ab) diff --git a/libs/python/pyste/tests/inherit2.h b/libs/python/pyste/tests/inherit2.h new file mode 100644 index 000000000..af9387bd0 --- /dev/null +++ b/libs/python/pyste/tests/inherit2.h @@ -0,0 +1,35 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +namespace inherit2 { + +struct A +{ + int x; + int getx() { return x; } + int foo() { return 0; } + int foo(int x) { return x; } +}; + +struct B : A +{ + int y; + int gety() { return y; } + int foo() { return 1; } +}; + +struct C : B +{ + int z; + int getz() { return z; } +}; + +struct D : C +{ + int w; + int getw() { return w; } +}; + +} diff --git a/libs/python/pyste/tests/inherit2.pyste b/libs/python/pyste/tests/inherit2.pyste new file mode 100644 index 000000000..380821398 --- /dev/null +++ b/libs/python/pyste/tests/inherit2.pyste @@ -0,0 +1,2 @@ +Class('inherit2::B', 'inherit2.h') +Class('inherit2::D', 'inherit2.h') diff --git a/libs/python/pyste/tests/inherit2UT.py b/libs/python/pyste/tests/inherit2UT.py new file mode 100644 index 000000000..85afce617 --- /dev/null +++ b/libs/python/pyste/tests/inherit2UT.py @@ -0,0 +1,31 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _inherit2 import * + +class InheritExampleTest(unittest.TestCase): + + def testIt(self): + b = B() + d = D() + + self.assert_(issubclass(D, B)) + b.x, b.y = 10, 5 + self.assertEqual(b.getx(), 10) + self.assertEqual(b.gety(), 5) + d.x, d.y, d.z, d.w = 20, 15, 10, 5 + self.assertEqual(d.getx(), 20) + self.assertEqual(d.gety(), 15) + self.assertEqual(d.getz(), 10) + self.assertEqual(d.getw(), 5) + self.assertEqual(b.foo(), 1) + self.assertEqual(b.foo(3), 3) + + def wrong(): + return b.getw() + self.assertRaises(AttributeError, wrong) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/inherit3.h b/libs/python/pyste/tests/inherit3.h new file mode 100644 index 000000000..1945fb514 --- /dev/null +++ b/libs/python/pyste/tests/inherit3.h @@ -0,0 +1,46 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ + +namespace inherit3 { + +struct A +{ + A() { x = 0; } + struct X { int y; }; + int x; + virtual int foo() { return 0; } + virtual int foo(int x) { return x; } + A operator+(A o) const + { + A r; + r.x = o.x + x; + return r; + } + enum E { i, j }; + +}; + +struct B: A +{ + B() { x = 0; } + struct X { int y; }; + int x; + int foo() { return 1; } + A operator+(A o) const + { + A r; + r.x = o.x + x; + return r; + } + enum E { i, j }; + +}; + +struct C: A +{ +}; + +} diff --git a/libs/python/pyste/tests/inherit3.pyste b/libs/python/pyste/tests/inherit3.pyste new file mode 100644 index 000000000..f95c06054 --- /dev/null +++ b/libs/python/pyste/tests/inherit3.pyste @@ -0,0 +1,2 @@ +Class('inherit3::B', 'inherit3.h') +Class('inherit3::C', 'inherit3.h') diff --git a/libs/python/pyste/tests/inherit3UT.py b/libs/python/pyste/tests/inherit3UT.py new file mode 100644 index 000000000..b7dba1e93 --- /dev/null +++ b/libs/python/pyste/tests/inherit3UT.py @@ -0,0 +1,27 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _inherit3 import * + +class testInherit3(unittest.TestCase): + + def testIt(self): + def testInst(c): + self.assertEqual(c.x, 0) + self.assertEqual(c.foo(3), 3) + x = c.X() + self.assertEqual(x.y, 0) + self.assertEqual(c.E.i, 0) + self.assertEqual(c.E.j, 1) + b = B() + c = C() + testInst(b) + testInst(c) + self.assertEqual(b.foo(), 1) + self.assertEqual(c.foo(), 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/inherit4.h b/libs/python/pyste/tests/inherit4.h new file mode 100644 index 000000000..a1cecfbc8 --- /dev/null +++ b/libs/python/pyste/tests/inherit4.h @@ -0,0 +1,23 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +namespace inherit4 { + +struct A +{ + int x; +}; + +struct B: A +{ + int y; +}; + +struct C: B +{ + int z; +}; + +} diff --git a/libs/python/pyste/tests/inherit4.pyste b/libs/python/pyste/tests/inherit4.pyste new file mode 100644 index 000000000..4809e022f --- /dev/null +++ b/libs/python/pyste/tests/inherit4.pyste @@ -0,0 +1,3 @@ +Class('inherit4::A', 'inherit4.h') +Class('inherit4::B', 'inherit4.h') +Class('inherit4::C', 'inherit4.h') diff --git a/libs/python/pyste/tests/inherit4UT.py b/libs/python/pyste/tests/inherit4UT.py new file mode 100644 index 000000000..f2c75c553 --- /dev/null +++ b/libs/python/pyste/tests/inherit4UT.py @@ -0,0 +1,31 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _inherit4 import * + +class TestInherit4(unittest.TestCase): + + def testIt(self): + self.assert_(issubclass(B, A)) + self.assert_(issubclass(C, A)) + self.assert_(issubclass(C, B)) + a = A() + a.x = 1 + b = B() + b.x = 10 + b.y = 20 + c = C() + c.x = 100 + c.y = 200 + c.z = 300 + self.assertEqual(a.x, 1) + self.assertEqual(b.x, 10) + self.assertEqual(b.y, 20) + self.assertEqual(c.x, 100) + self.assertEqual(c.y, 200) + self.assertEqual(c.z, 300) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/inheritUT.py b/libs/python/pyste/tests/inheritUT.py new file mode 100644 index 000000000..f3e7b4062 --- /dev/null +++ b/libs/python/pyste/tests/inheritUT.py @@ -0,0 +1,33 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _inherit import * + +class InheritExampleTest(unittest.TestCase): + + def testIt(self): + a = A_int() + b = B() + self.assert_(isinstance(b, A_int)) + self.assert_(issubclass(B, A_int)) + a.set(10) + self.assertEqual(a.get(), 10) + b.set(1) + self.assertEqual(b.go(), 1) + self.assertEqual(b.get(), 1) + + d = D() + self.assert_(issubclass(D, B)) + self.assertEqual(d.x, 0) + self.assertEqual(d.y, 0) + self.assertEqual(d.s, 1) + self.assertEqual(D.s, 1) + self.assertEqual(d.f1(), 1) + self.assertEqual(d.f2(), 2) + + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/nested.cpp b/libs/python/pyste/tests/nested.cpp new file mode 100644 index 000000000..6e167ab06 --- /dev/null +++ b/libs/python/pyste/tests/nested.cpp @@ -0,0 +1,9 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#include "nested.h" + +int nested::X::staticXValue = 10; +int nested::X::Y::staticYValue = 20; diff --git a/libs/python/pyste/tests/nested.h b/libs/python/pyste/tests/nested.h new file mode 100644 index 000000000..13ed60856 --- /dev/null +++ b/libs/python/pyste/tests/nested.h @@ -0,0 +1,32 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ + +#ifndef NESTED_H +#define NESTED_H + +namespace nested { + +struct X +{ + struct Y + { + int valueY; + static int staticYValue; + struct Z + { + int valueZ; + }; + }; + + static int staticXValue; + int valueX; +}; + +typedef X Root; + +} + +#endif diff --git a/libs/python/pyste/tests/nested.pyste b/libs/python/pyste/tests/nested.pyste new file mode 100644 index 000000000..48bb26b55 --- /dev/null +++ b/libs/python/pyste/tests/nested.pyste @@ -0,0 +1 @@ +Class('nested::Root', 'nested.h') diff --git a/libs/python/pyste/tests/nestedUT.py b/libs/python/pyste/tests/nestedUT.py new file mode 100644 index 000000000..06c1c7beb --- /dev/null +++ b/libs/python/pyste/tests/nestedUT.py @@ -0,0 +1,19 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _nested import * + +class NestedTest(unittest.TestCase): + + def testIt(self): + self.assertEqual(Root.staticXValue, 10) + self.assertEqual(Root.Y.staticYValue, 20) + z = Root.Y.Z() + z.valueZ = 3 + self.assertEqual(z.valueZ, 3) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/opaque.h b/libs/python/pyste/tests/opaque.h new file mode 100644 index 000000000..1947830ea --- /dev/null +++ b/libs/python/pyste/tests/opaque.h @@ -0,0 +1,57 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef OPAQUE_H +#define OPAQUE_H + +#include <iostream> + +namespace opaque { + + +struct C { + C(int v): value(v) {} + int value; +}; + + +inline C* new_C() +{ + return new C(10); +} + +inline C* new_C_zero() +{ + return new C(0); +} + +inline int get(C* c) +{ + return c->value; +} + +struct D { + D(double v): value(v) {} + double value; +}; + +struct A +{ + D* new_handle() + { + return new D(3.0); + } + + double get(D* d) + { + return d->value; + } + + int f(int x=0) { return x; } +}; + +} + +#endif diff --git a/libs/python/pyste/tests/opaque.pyste b/libs/python/pyste/tests/opaque.pyste new file mode 100644 index 000000000..8180d251c --- /dev/null +++ b/libs/python/pyste/tests/opaque.pyste @@ -0,0 +1,7 @@ +foo = Function('opaque::new_C', 'opaque.h') +set_policy(foo, return_value_policy(return_opaque_pointer)) +foo = Function('opaque::new_C_zero', 'opaque.h') +set_policy(foo, return_value_policy(return_opaque_pointer)) +Function('opaque::get', 'opaque.h' ) +A = Class('opaque::A', 'opaque.h') +set_policy(A.new_handle, return_value_policy(return_opaque_pointer)) diff --git a/libs/python/pyste/tests/opaqueUT.py b/libs/python/pyste/tests/opaqueUT.py new file mode 100644 index 000000000..0f3e1e073 --- /dev/null +++ b/libs/python/pyste/tests/opaqueUT.py @@ -0,0 +1,24 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _opaque import * + +class OpaqueTest(unittest.TestCase): + + def testIt(self): + + c = new_C() + self.assertEqual(get(c), 10) + c = new_C_zero() + self.assertEqual(get(c), 0) + a = A() + d = a.new_handle() + self.assertEqual(a.get(d), 3.0) + self.assertEqual(a.f(), 0) + self.assertEqual(a.f(3), 3) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/operators.cpp b/libs/python/pyste/tests/operators.cpp new file mode 100644 index 000000000..cecdaca0d --- /dev/null +++ b/libs/python/pyste/tests/operators.cpp @@ -0,0 +1,8 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#include "operators.h" + +double operators::C::x = 10; diff --git a/libs/python/pyste/tests/operators.h b/libs/python/pyste/tests/operators.h new file mode 100644 index 000000000..5d3944216 --- /dev/null +++ b/libs/python/pyste/tests/operators.h @@ -0,0 +1,52 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef OPERATORS_H +#define OPERATORS_H + + +namespace operators { + +struct C +{ + static double x; + double value; + + const C operator+(const C other) const + { + C c; + c.value = value + other.value; + return c; + } + operator int() const + { + return (int)value; + } + + double operator()() + { + return C::x; + } + + double operator()(double other) + { + return C::x + other; + } + + operator const char*() { return "C"; } +}; + +inline const C operator*(const C& lhs, const C& rhs) +{ + C c; + c.value = lhs.value * rhs.value; + return c; +} + + +} + + +#endif diff --git a/libs/python/pyste/tests/operators.pyste b/libs/python/pyste/tests/operators.pyste new file mode 100644 index 000000000..4ab7a3709 --- /dev/null +++ b/libs/python/pyste/tests/operators.pyste @@ -0,0 +1,2 @@ +C = Class('operators::C', 'operators.h') +#exclude(C.operator['+']) diff --git a/libs/python/pyste/tests/operatorsUT.py b/libs/python/pyste/tests/operatorsUT.py new file mode 100644 index 000000000..beb193173 --- /dev/null +++ b/libs/python/pyste/tests/operatorsUT.py @@ -0,0 +1,30 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _operators import * + +class OperatorTest(unittest.TestCase): + + def testIt(self): + c = C() + c.value = 3.0 + d = C() + d.value = 2.0 + self.assertEqual(c.x, 10) + self.assertEqual(C.x, 10) + self.assertEqual(C.x, 10) + self.assertEqual((c * d).value, 6.0) + self.assertEqual((c + d).value, 5.0) + self.assertEqual(int(c), 3) + self.assertEqual(int(d), 2) + self.assertEqual(c(), 10) + self.assertEqual(d(), 10) + self.assertEqual(c(3.0), 13.0) + self.assertEqual(d(6.0), 16.0) + self.assertEqual(str(c), "C") + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/policiesUT.py b/libs/python/pyste/tests/policiesUT.py new file mode 100644 index 000000000..7255baeb4 --- /dev/null +++ b/libs/python/pyste/tests/policiesUT.py @@ -0,0 +1,67 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import sys +import unittest +from Pyste.policies import * + + +#================================================================================ +# PolicicesTest +#================================================================================ +class PoliciesTest(unittest.TestCase): + + def testReturnInternal(self): + 'tests the code from a simple internal_reference' + + x = return_internal_reference(1) + self.assertEqual(x.Code(), 'return_internal_reference< 1 >') + x = return_internal_reference(3) + self.assertEqual(x.Code(), 'return_internal_reference< 3 >') + + + def testCustodian(self): + 'tests the code from a simple custodian_and_ward' + + x = with_custodian_and_ward(1,2) + self.assertEqual(x.Code(), 'with_custodian_and_ward< 1, 2 >') + x = with_custodian_and_ward(3,4) + self.assertEqual(x.Code(), 'with_custodian_and_ward< 3, 4 >') + + + def testReturnPolicies(self): + 'tests all the return_value_policies' + + ret = 'return_value_policy< %s >' + x = return_value_policy(reference_existing_object) + self.assertEqual(x.Code(), ret % 'reference_existing_object') + x = return_value_policy(copy_const_reference) + self.assertEqual(x.Code(), ret % 'copy_const_reference') + x = return_value_policy(copy_non_const_reference) + self.assertEqual(x.Code(), ret % 'copy_non_const_reference') + x = return_value_policy(manage_new_object) + self.assertEqual(x.Code(), ret % 'manage_new_object') + x = return_value_policy(return_opaque_pointer) + self.assertEqual(x.Code(), ret % 'return_opaque_pointer') + + def testReturnWithCustodiam(self): + 'test the mix of return_internal with custodian' + + x = return_internal_reference(1, with_custodian_and_ward(3,2)) + self.assertEqual( + x.Code(), + 'return_internal_reference< 1, with_custodian_and_ward< 3, 2 > >') + + + def testReturnPoliciesWithInternal(self): + 'test the mix of return_internal with return_policy' + + x = return_internal_reference(1, return_value_policy(manage_new_object)) + self.assertEqual( + x.Code(), + 'return_internal_reference< 1, return_value_policy< manage_new_object > >') + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/runtests.py b/libs/python/pyste/tests/runtests.py new file mode 100644 index 000000000..4bf83b345 --- /dev/null +++ b/libs/python/pyste/tests/runtests.py @@ -0,0 +1,21 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +#!/usr/bin/python + +import sys +sys.path.append('../src/Pyste') +import unittest +import os.path +from glob import glob + +if __name__ == '__main__': + loader = unittest.defaultTestLoader + tests = [] + for name in glob('*UT.py'): + module = __import__(os.path.splitext(name)[0]) + tests.append(loader.loadTestsFromModule(module)) + runner = unittest.TextTestRunner() + result = runner.run(unittest.TestSuite(tests)) + sys.exit(not result.wasSuccessful()) diff --git a/libs/python/pyste/tests/smart_ptr.h b/libs/python/pyste/tests/smart_ptr.h new file mode 100644 index 000000000..b230b9179 --- /dev/null +++ b/libs/python/pyste/tests/smart_ptr.h @@ -0,0 +1,50 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ + +#ifndef SMART_PTR_H +#define SMART_PTR_H + + +#include <memory> +#include <boost/shared_ptr.hpp> + +namespace smart_ptr { + +struct C +{ + int value; +}; + +inline boost::shared_ptr<C> NewC() { return boost::shared_ptr<C>( new C() ); } + +struct D +{ + boost::shared_ptr<C> Get() { return ptr; } + void Set( boost::shared_ptr<C> c ) { ptr = c; } +private: + boost::shared_ptr<C> ptr; +}; + +inline std::auto_ptr<D> NewD() { return std::auto_ptr<D>( new D() ); } + + +// test an abstract class +struct A +{ + virtual int f() = 0; +}; + +struct B: A +{ + virtual int f(){ return 1; } +}; + +inline boost::shared_ptr<A> NewA() { return boost::shared_ptr<A>(new B()); } +inline int GetA(boost::shared_ptr<A> a) { return a->f(); } + +} + +#endif diff --git a/libs/python/pyste/tests/smart_ptr.pyste b/libs/python/pyste/tests/smart_ptr.pyste new file mode 100644 index 000000000..cfbdd81ae --- /dev/null +++ b/libs/python/pyste/tests/smart_ptr.pyste @@ -0,0 +1,13 @@ +C = Class('smart_ptr::C', 'smart_ptr.h') +use_shared_ptr(C) + +D = Class('smart_ptr::D', 'smart_ptr.h') +use_auto_ptr(D) + +A = Class('smart_ptr::A', 'smart_ptr.h') +use_shared_ptr(A) + +Function('smart_ptr::NewC', 'smart_ptr.h') +Function('smart_ptr::NewD', 'smart_ptr.h') +Function('smart_ptr::NewA', 'smart_ptr.h') +Function('smart_ptr::GetA', 'smart_ptr.h') diff --git a/libs/python/pyste/tests/smart_ptrUT.py b/libs/python/pyste/tests/smart_ptrUT.py new file mode 100644 index 000000000..9d81f08dd --- /dev/null +++ b/libs/python/pyste/tests/smart_ptrUT.py @@ -0,0 +1,22 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _smart_ptr import * + +class BasicExampleTest(unittest.TestCase): + + def testIt(self): + c = NewC() + d = NewD() + c.value = 3 + d.Set(c) + c1 = d.Get() + c1.value = 6 + self.assertEqual(c.value, 6) + a = NewA() + self.assertEqual(GetA(a), 1) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/templates.h b/libs/python/pyste/tests/templates.h new file mode 100644 index 000000000..7258e91c7 --- /dev/null +++ b/libs/python/pyste/tests/templates.h @@ -0,0 +1,15 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +namespace templates { + +template <class T> +struct Point +{ + T x; + T y; +}; + +} diff --git a/libs/python/pyste/tests/templates.pyste b/libs/python/pyste/tests/templates.pyste new file mode 100644 index 000000000..77eaceaa3 --- /dev/null +++ b/libs/python/pyste/tests/templates.pyste @@ -0,0 +1,8 @@ +Point = Template('templates::Point', 'templates.h') +rename(Point.x, 'i') +rename(Point.y, 'j') +IPoint = Point('int') +FPoint = Point('double', 'FPoint') +rename(IPoint, 'IPoint') +rename(IPoint.x, 'x') +rename(IPoint.y, 'y') diff --git a/libs/python/pyste/tests/templatesUT.py b/libs/python/pyste/tests/templatesUT.py new file mode 100644 index 000000000..0c4b08b50 --- /dev/null +++ b/libs/python/pyste/tests/templatesUT.py @@ -0,0 +1,30 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _templates import * + +class TemplatesTest(unittest.TestCase): + + def testIt(self): + fp = FPoint() + fp.i = 3.0 + fp.j = 4.0 + ip = IPoint() + ip.x = 10 + ip.y = 3 + + self.assertEqual(fp.i, 3.0) + self.assertEqual(fp.j, 4.0) + self.assertEqual(ip.x, 10) + self.assertEqual(ip.y, 3) + self.assertEqual(type(fp.i), float) + self.assertEqual(type(fp.j), float) + self.assertEqual(type(ip.x), int) + self.assertEqual(type(ip.y), int) + + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/test_all.py b/libs/python/pyste/tests/test_all.py new file mode 100644 index 000000000..ba3c54dee --- /dev/null +++ b/libs/python/pyste/tests/test_all.py @@ -0,0 +1,140 @@ +#!/usr/bin/python +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import glob +import shutil +import sys +import time + +#============================================================================= +# win32 configuration +#============================================================================= +if sys.platform == 'win32': + + includes = '-ID:/programming/libraries/boost-cvs/boost -ID:/Bin/Python/include' + build_pyste_cmd = 'python ../src/Pyste/pyste.py --pyste-ns=pyste --cache-dir=cache %s ' % includes + compile_single_cmd = 'cl /nologo /GR /GX -c %s -I. ' % includes + link_single_cmd = 'link /nologo /DLL '\ + '/libpath:D:/programming/libraries/boost-cvs/lib /libpath:D:/Bin/Python/libs '\ + 'boost_python.lib python24.lib /out:_%s.dll ' + obj_ext = 'obj' + +#============================================================================= +# linux configuration +#============================================================================= +elif sys.platform == 'linux2': + + build_pyste_cmd = 'python ../src/Pyste/pyste.py -I. ' + compile_single_cmd = 'g++ -shared -c -I. -I/usr/include/python2.4 ' + link_single_cmd = 'g++ -shared -o _%s.so -lboost_python ' + obj_ext = 'o' + + + +def build_pyste(multiple, module): + rest = '%s --module=_%s %s.pyste' % (multiple, module, module) + execute(build_pyste_cmd + rest) + + +def compile_single(module): + module_obj = '' + if os.path.isfile(module+'.cpp'): + execute(compile_single_cmd + module+'.cpp') + module_obj = module + '.' + obj_ext + execute(compile_single_cmd + ('_%s.cpp' % module)) + link = link_single_cmd % module + execute(link + ('_%s.%s ' % (module, obj_ext)) + module_obj) + + +def compile_multiple(module): + module_obj = '' + if os.path.isfile(module+'.cpp'): + execute(compile_single_cmd + module+'.cpp') + module_obj = module + '.' + obj_ext + files = glob.glob('_%s/*.cpp' % module) + for f in files: + execute(compile_single_cmd + f) + def basename(name): + return os.path.basename(os.path.splitext(name)[0]) + objs = [basename(x) + '.' + obj_ext for x in files] + objs.append(module_obj) + execute((link_single_cmd % module) + ' '.join(objs)) + + +def execute(cmd): + os.system(cmd) + + +def run_tests(): + if os.system('python runtests.py') != 0: + raise RuntimeError, 'tests failed' + + +def cleanup(): + modules = get_modules() + extensions = '*.dll *.pyc *.obj *.exp *.lib *.o *.so' + files = [] + for module in modules: + files.append('_' + module + '.cpp') + for ext in extensions.split(): + files += glob.glob(ext) + files.append('build.log') + for file in files: + try: + os.remove(file) + except OSError: pass + + for module in modules: + try: + shutil.rmtree('_' + module) + except OSError: pass + + +def main(multiple, module=None): + if module is None: + modules = get_modules() + else: + modules = [module] + + start = time.clock() + for module in modules: + build_pyste(multiple, module) + print '-'*50 + print 'Building pyste files: %0.2f seconds' % (time.clock()-start) + print + + start = time.clock() + for module in modules: + if multiple: + compile_multiple(module) + else: + compile_single(module) + print '-'*50 + print 'Compiling files: %0.2f seconds' % (time.clock()-start) + print + if len(modules) == 1: + os.system('python %sUT.py' % modules[0]) + else: + run_tests() + #cleanup() + + +def get_modules(): + def getname(file): + return os.path.splitext(os.path.basename(file))[0] + return [getname(x) for x in glob.glob('*.pyste')] + +if __name__ == '__main__': + if len(sys.argv) > 1: + module = sys.argv[1] + else: + module = None + try: +# main('--multiple', module) + main('', module) + except RuntimeError, e: + print e diff --git a/libs/python/pyste/tests/vars.cpp b/libs/python/pyste/tests/vars.cpp new file mode 100644 index 000000000..e2abcd332 --- /dev/null +++ b/libs/python/pyste/tests/vars.cpp @@ -0,0 +1,12 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#include "vars.h" + +const Color black = Color(0, 0, 0); +const Color red = Color(255, 0, 0); +const Color green = Color(0, 255, 0); +const Color blue = Color(0, 0, 255); +Color in_use = black; diff --git a/libs/python/pyste/tests/vars.h b/libs/python/pyste/tests/vars.h new file mode 100644 index 000000000..24e87d802 --- /dev/null +++ b/libs/python/pyste/tests/vars.h @@ -0,0 +1,24 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ + +struct Color +{ + Color(int r_ = 0, int g_ = 0, int b_ = 0): + r(r_), g(g_), b(b_) + {} + Color( const Color &c): + r(c.r), g(c.g), b(c.b) + {} + int r; + int g; + int b; +}; + +extern const Color black; +extern const Color red; +extern const Color green; +extern const Color blue; +extern Color in_use; diff --git a/libs/python/pyste/tests/vars.pyste b/libs/python/pyste/tests/vars.pyste new file mode 100644 index 000000000..3fd9d689d --- /dev/null +++ b/libs/python/pyste/tests/vars.pyste @@ -0,0 +1 @@ +AllFromHeader('vars.h') diff --git a/libs/python/pyste/tests/varsUT.py b/libs/python/pyste/tests/varsUT.py new file mode 100644 index 000000000..4c32cbb2f --- /dev/null +++ b/libs/python/pyste/tests/varsUT.py @@ -0,0 +1,22 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +import _vars + + +class VarsTest(unittest.TestCase): + + def testIt(self): + def testColor(c, r, g, b): + self.assertEqual(c.r, r) + self.assertEqual(c.g, g) + self.assertEqual(c.b, b) + testColor(_vars.black, 0, 0, 0) + testColor(_vars.red, 255, 0, 0) + testColor(_vars.green, 0, 255, 0) + testColor(_vars.blue, 0, 0, 255) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/virtual.cpp b/libs/python/pyste/tests/virtual.cpp new file mode 100644 index 000000000..070d9d346 --- /dev/null +++ b/libs/python/pyste/tests/virtual.cpp @@ -0,0 +1,75 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ + +// Includes ==================================================================== +#include <boost/python.hpp> +#include <virtual.h> + +// Using ======================================================================= +using namespace boost::python; + +// Declarations ================================================================ + + +namespace { + + +struct virtual_C_Wrapper: virtual_::C +{ + virtual_C_Wrapper(PyObject* self_, const virtual_::C & p0): + virtual_::C(p0), self(self_) {} + + virtual_C_Wrapper(PyObject* self_): + virtual_::C(), self(self_) {} + + int f() { + return call_method< int >(self, "f"); + } + + int default_f() { + return virtual_::C::f(); + } + + void bar(int p0) { + call_method< void >(self, "bar", p0); + } + + void default_bar(int p0) { + virtual_::C::bar(p0); + } + + void bar(char * p0) { + call_method< void >(self, "bar", p0); + } + + void default_bar(char * p0) { + virtual_::C::bar(p0); + } + + int f_abs() { + return call_method< int >(self, "f_abs"); + } + + PyObject* self; +}; + + + +}// namespace + + +// Module ====================================================================== +BOOST_PYTHON_MODULE(virtual) +{ + class_< virtual_::C, boost::noncopyable, virtual_C_Wrapper >("C", init< >()) + .def("get_name", &virtual_::C::get_name) + .def("f", &virtual_::C::f, &virtual_C_Wrapper::default_f) + .def("bar", (void (virtual_::C::*)(int) )&virtual_::C::bar, (void (virtual_C_Wrapper::*)(int))&virtual_C_Wrapper::default_bar) + .def("bar", (void (virtual_::C::*)(char *) )&virtual_::C::bar, (void (virtual_C_Wrapper::*)(char *))&virtual_C_Wrapper::default_bar) + ; + + def("call_f", &virtual_::call_f); +} diff --git a/libs/python/pyste/tests/virtual.h b/libs/python/pyste/tests/virtual.h new file mode 100644 index 000000000..d0bb194a1 --- /dev/null +++ b/libs/python/pyste/tests/virtual.h @@ -0,0 +1,41 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +namespace virtual_ { + +struct C +{ +public: + virtual int f() + { + return f_abs(); + } + + virtual void bar(int) {} + virtual void bar(char*) {} + + const char* get_name() + { + return name(); + } + virtual int dummy() { return 0; } + +protected: + virtual int f_abs() = 0; + +private: + virtual const char* name() { return "C"; } +}; + +struct D +{ + virtual int dummy() { return 0; } +}; + +inline int call_f(C& c) { return c.f(); } +inline int call_dummy(C* c) { return c->dummy(); } +inline int call_dummy(D* d) { return d->dummy(); } + +} diff --git a/libs/python/pyste/tests/virtual.pyste b/libs/python/pyste/tests/virtual.pyste new file mode 100644 index 000000000..ef9664124 --- /dev/null +++ b/libs/python/pyste/tests/virtual.pyste @@ -0,0 +1,6 @@ +C = Class('virtual_::C', 'virtual.h') +final(C.dummy) +D = Class('virtual_::D', 'virtual.h') +final(D.dummy) +Function('virtual_::call_f', 'virtual.h') +Function('virtual_::call_dummy', 'virtual.h') diff --git a/libs/python/pyste/tests/virtual2.h b/libs/python/pyste/tests/virtual2.h new file mode 100644 index 000000000..a6677ad16 --- /dev/null +++ b/libs/python/pyste/tests/virtual2.h @@ -0,0 +1,34 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ + +namespace virtual2 { + +struct A +{ + virtual int f() { return 0; } + virtual int f1() { return 10; } + virtual A* make_new() { return new A; } +}; + +struct B: A +{ + virtual int f() { return 1; } + virtual int f2() { return 20; } + virtual A* make_new() { return new B; } +}; + +inline int call_fs(A*a) +{ + int r = a->f1(); + B* b = dynamic_cast<B*>(a); + return r + b->f2(); +} + +inline int call_f(A* a) +{ + return a->f(); +} +} diff --git a/libs/python/pyste/tests/virtual2.pyste b/libs/python/pyste/tests/virtual2.pyste new file mode 100644 index 000000000..785b819c8 --- /dev/null +++ b/libs/python/pyste/tests/virtual2.pyste @@ -0,0 +1,6 @@ +A = Class('virtual2::A', 'virtual2.h') +set_policy(A.make_new, return_value_policy(manage_new_object)) +B = Class('virtual2::B', 'virtual2.h') +set_policy(B.make_new, return_value_policy(manage_new_object)) +Function('virtual2::call_fs', 'virtual2.h') +Function('virtual2::call_f', 'virtual2.h') diff --git a/libs/python/pyste/tests/virtual2UT.py b/libs/python/pyste/tests/virtual2UT.py new file mode 100644 index 000000000..312277d26 --- /dev/null +++ b/libs/python/pyste/tests/virtual2UT.py @@ -0,0 +1,40 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import unittest +from _virtual2 import * + +class Virtual2Test(unittest.TestCase): + + def testIt(self): + a = A() + self.assertEqual(a.f1(), 10) + b = B() + self.assertEqual(b.f1(), 10) + self.assertEqual(b.f2(), 20) + self.assertEqual(call_fs(b), 30) + self.assertEqual(call_f(a), 0) + self.assertEqual(call_f(b), 1) + nb = b.make_new() + na = a.make_new() + self.assertEqual(na.f1(), 10) + self.assertEqual(nb.f1(), 10) + self.assertEqual(nb.f2(), 20) + self.assertEqual(call_fs(nb), 30) + self.assertEqual(call_f(na), 0) + self.assertEqual(call_f(nb), 1) + class C(B): + def f1(self): return 1 + def f2(self): return 2 + def f(self): return 100 + + c = C() + self.assertEqual(call_fs(c), 3) + self.assertEqual(call_fs(c), 3) + self.assertEqual(call_f(c), 100) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/virtualUT.py b/libs/python/pyste/tests/virtualUT.py new file mode 100644 index 000000000..deff68189 --- /dev/null +++ b/libs/python/pyste/tests/virtualUT.py @@ -0,0 +1,55 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _virtual import * + +class VirtualTest(unittest.TestCase): + + def testIt(self): + + class E(C): + def f_abs(self): + return 3 + def dummy(self): + # override should not work + return 100 + + class F(C): + def f(self): + return 10 + def name(self): + return 'F' + + class G(D): + def dummy(self): + # override should not work + return 100 + + e = E() + f = F() + + self.assertEqual(e.f(), 3) + self.assertEqual(call_f(e), 3) + self.assertEqual(f.f(), 10) + self.assertEqual(call_f(f), 10) + self.assertEqual(e.get_name(), 'C') + #self.assertEqual(e.get_name(), 'E') check this later + + c = C() + c.bar(1) # ok + c.bar('a') # ok + self.assertRaises(TypeError, c.bar, 1.0) + + # test no_overrides + d = G() + self.assertEqual(e.dummy(), 100) + self.assertEqual(call_dummy(e), 0) + self.assertEqual(d.dummy(), 100) + self.assertEqual(call_dummy(d), 0) + + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/wrappertest.h b/libs/python/pyste/tests/wrappertest.h new file mode 100644 index 000000000..2304fd843 --- /dev/null +++ b/libs/python/pyste/tests/wrappertest.h @@ -0,0 +1,51 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef WRAPPER_TEST +#define WRAPPER_TEST + + +#include <vector> + +namespace wrappertest { + +inline std::vector<int> Range(int count) +{ + std::vector<int> v; + v.reserve(count); + for (int i = 0; i < count; ++i){ + v.push_back(i); + } + return v; +} + + +struct C +{ + C() {} + + std::vector<int> Mul(int value) + { + std::vector<int> res; + res.reserve(value); + std::vector<int>::const_iterator it; + std::vector<int> v(Range(value)); + for (it = v.begin(); it != v.end(); ++it){ + res.push_back(*it * value); + } + return res; + } +}; + + +struct A +{ + virtual int f() { return 1; }; +}; + +inline int call_foo(A* a){ return a->f(); } +} +#endif + diff --git a/libs/python/pyste/tests/wrappertest.pyste b/libs/python/pyste/tests/wrappertest.pyste new file mode 100644 index 000000000..12ba47b6b --- /dev/null +++ b/libs/python/pyste/tests/wrappertest.pyste @@ -0,0 +1,21 @@ +Include('wrappertest_wrappers.h') + +f = Function('wrappertest::Range', 'wrappertest.h') +set_wrapper(f, 'RangeWrapper') + +mul = Wrapper('MulWrapper', +''' +list MulWrapper(wrappertest::C& c, int value){ + return VectorToList(c.Mul(value)); +} +''' +) + +C = Class('wrappertest::C', 'wrappertest.h') +set_wrapper(C.Mul, mul) + + +A = Class('wrappertest::A', 'wrappertest.h') +set_wrapper(A.f, 'f_wrapper') + +Function('wrappertest::call_foo', 'wrappertest.h') diff --git a/libs/python/pyste/tests/wrappertestUT.py b/libs/python/pyste/tests/wrappertestUT.py new file mode 100644 index 000000000..d770408b7 --- /dev/null +++ b/libs/python/pyste/tests/wrappertestUT.py @@ -0,0 +1,24 @@ +# Copyright Bruno da Silva de Oliveira 2003. Use, modification and +# distribution is subject to the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +import unittest +from _wrappertest import * + +class WrapperTest(unittest.TestCase): + + def testIt(self): + self.assertEqual(Range(10), range(10)) + self.assertEqual(C().Mul(10), [x*10 for x in range(10)]) + + a = A() + self.assertEqual(a.f(), 10) + self.assertEqual(call_foo(a), 10) + class D(A): + def f(self): return 2 + d = D() + self.assertEqual(d.f(), 2) + self.assertEqual(call_foo(d), 2) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/wrappertest_wrappers.h b/libs/python/pyste/tests/wrappertest_wrappers.h new file mode 100644 index 000000000..31570a051 --- /dev/null +++ b/libs/python/pyste/tests/wrappertest_wrappers.h @@ -0,0 +1,33 @@ +/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and + distribution is subject to the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef WRAPPER_TEST_WRAPPERS +#define WRAPPER_TEST_WRAPPERS + +#include <vector> +#include <boost/python.hpp> +#include "wrappertest.h" + +using namespace boost::python; + +template <class T> +list VectorToList(const std::vector<T> & v) +{ + list res; + typename std::vector<T>::const_iterator it; + for(it = v.begin(); it != v.end(); ++it){ + res.append(*it); + } + Py_XINCREF(res.ptr()); + return res; +} + +inline list RangeWrapper(int count){ + return VectorToList(wrappertest::Range(count)); +} + +inline int f_wrapper(wrappertest::A*) { return 10; } + +#endif diff --git a/libs/python/release_notes.txt b/libs/python/release_notes.txt new file mode 100644 index 000000000..1fd0f1b14 --- /dev/null +++ b/libs/python/release_notes.txt @@ -0,0 +1,223 @@ +.. Copyright David Abrahams 2006. Distributed under the Boost +.. Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +These are old release notes for Boost.Python v1 + +2000-11-22 10:00 + Ullrich fixed bug in operator_dispatcher<op_long>. + +2000-11-21 10:00 + Changed all class and function names into lower_case. + + Ullrich updated documentation for operator wrapping. + +2000-11-20 10:00 + Ullrich renamed ExtensionClass:register_coerce() into + ExtensionClass:def_standard_coerce() and made it public + + Ullrich improved shared_pod_manager. + +2000-11-17 15:04 + Changed allocation strategy of shared_pod_manager to make it portable. + + Added pickling support + tests thanks to "Ralf W. Grosse-Kunstleve" + <rwgk@cci.lbl.gov> + + Added a specialization of Callback<const char*> to prevent unsafe usage. + + Fixed Ullrich's operator_dispatcher refcount bug + + Removed const char* return values from virtual functions in tests; that + usage was unsafe. + + Ullrich changed Module::add() so that it steals a reference (fix of refcount bug) + + Ullrich added operator_dispatcher::create() optimization + + Ullrich changed design and implementation of TypeObjectBase::enable() (to eliminate low-level + code) and added shared_pod_manager optimization. + + +2000-11-15 12:01 + Fixed refcount bugs in operator calls. + + Added callback_adjust_refcount(PyObject*, Type<T>) to account for different ownership + semantics of Callback's return types and Caller's arguments (which both use from_python()) + This bug caused refcount errors during operator calls. + + Moved operator_dispatcher into extclass.cpp + Gave it shared ownership of the objects it wraps + + Introduced sequence points in extension_class_coerce for exception-safety + + UPPER_CASE_MACRO_NAMES + + MixedCase template type argument names + + Changed internal error reporting to use Python exceptions so we don't force the + user to link in iostreams code + + Changed error return value of call_cmp to -1 + + Moved unwrap_* functions out of operator_dispatcher. This was transitional: when + I realized they didn't need to be declared in extclass.h I moved them out, but + now that operator_dispatcher itself is in extclass.cpp they could go back in. + + Numerous formatting tweaks + + Updated the BoundFunction::create() optimization and enabled it so it could actually be used! + +2000-11-15 00:26 + + Made Ullrich's operators support work with MSVC + + Cleaned up operators.h such that invalid define_operator<0> is no longer needed. + + Ullrich created operators.h to support wrapping of C++ operators (including the "__r*__" forms). + He added several auxiliary classes to extclass.h and extclass.cpp (most importantly, + py::detail::operator_dispatcher and py::operators) + +2000-11-13 22:29 + + removed obsolete ExtensionClassFromPython for good. + + removed unused class ExtensionType forward declaration + +2000-11-12 13:08 + + Added enum_as_int_converters for easier enum wrapping + + Introduced new conversion namespace macros: + PY_BEGIN_CONVERSION_NAMESPACE, + PY_END_CONVERSION_NAMESPACE, + PY_CONVERSION + + callback.h, gen_callback.py: + Added call() function so that a regular python function (as opposed to + method or other function-as-attribute) can be called. + + Added newlines for readability. + + class_wrapper.h: + Fixed a bug in add(), which allows non-method class attributes + + Ullrich has added def_raw for simple varargs and keyword support. + + Fixed version number check for __MWERKS__ + + Added tests for enums and non-method class attributes + + objects.h/objects.cpp: + Added py::String operator*= and operator* for repetition + + Change Dict::items(), keys(), and values() to return a List + + Added template versions of set_item, etc., methods so that users can optionally + use C++ types that have to_python() functions as parameters. + + Changed various Ptr by-value parameters to const Ptr& + + +======= Release ======= +2000-11-06 0:22 + Lots of documentation updates + + added 4-argument template constructor to py::Tuple + + added "add" member function to ClassWrapper<> to allow arbitrary Python + objects to be added to an extension class. + + gen_all.py now generates support for n argument member functions and n+1 + argument member functions at the suggestion of "Ralf W. Grosse-Kunstleve" + <rwgk@cci.lbl.gov> + + Added regression tests and re-ordered declare_base calls to verify that the + phantom base class issue is resolved. + +2000-11-04 17:35 + + Integrated Ullrich Koethe's brilliant from_python_experiment for better + error-reporting in many cases. + + extclass.h, gen_extclass.py: + removed special-case MSVC code + added much commentary + removed unused py_copy_to_new_value_holder + + init_function.h, gen_init_function.py: + added missing 'template' keyword on type-dependent template member usage + removed special-case MSVC code + added much commentary + +2000-11-04 0:36 + + Removed the need for the phantom base class that screwed up inheritance + hierarchies, introduced error-prone ordering dependencies, and complexified + logic in many places! + + extclass.h: Added some explanatory comments, removed wasteful m_self member + of HeldInstance + + extclass_demo.cpp: Added #pragmas which allow compilation in ansi strict + mode under Metrowerks + + functions.h: Added virtual_function as part of phantom base class removal; + expanded commentary + + pyptr.h: Added some missing 'typename's and a GCC workaround fix + + subclass.cpp: Added missing string literal const_cast<>s. + +2000-11-03 10:58 + + Fix friend function instantiation bug caught by Metrowerks (thanks + Metrowerks!) + + Add proof-of-concept for one technique of wrapping function that return a + pointer + + Worked around MSVC optimizer bug by writing to_python(double) and + to_python(float) out-of-line + +2000-11-02 23:25 + + Add /Zm200 option to vc6_prj to deal with MSVC resource limitations + + Remove conflicting /Ot option from vc6_prj release build + +======= Release ======= +2000-11-02 17:42 + + Added a fix for interactions between default virtual function + implementations and declare_base(). You still need to write your + declare_base() /after/ all member functions have been def()d for the two + classes concerned. Many, many thanks to Ullrich Koethe + <koethe@informatik.uni-hamburg.de> for all his work on this. + + Added missing conversions: + to_python(float) + from_python(const char* const&) + from_python(const double&) + from_python(const float&) + + Added a Regression test for a reference-counting bug thanks to Mark Evans + (<mark.evans@clarisay.com>) + + const-ify ClassBase::getattr() + + Add repr() function to Class<T> + + Add to_python/from_python conversions for PyPtr<T> + + Standardize set_item/get_item interfaces (instead of proxies) for Dict and List + + Add Reprable<> template to newtypes.h + + Fix a bug wherein the __module__ attribute would be lost for classes that have a + default virtual function implementation. + + Remove extra ';' in module.cpp thanks to "Ralf W. Grosse-Kunstleve" + <rwgk@cci.lbl.gov> + + Fix a bug in the code of example1.html diff --git a/libs/python/src/converter/arg_to_python_base.cpp b/libs/python/src/converter/arg_to_python_base.cpp new file mode 100644 index 000000000..d872314a7 --- /dev/null +++ b/libs/python/src/converter/arg_to_python_base.cpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/converter/arg_to_python_base.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/refcount.hpp> + +namespace boost { namespace python { namespace converter { + +namespace detail +{ + arg_to_python_base::arg_to_python_base( + void const volatile* source, registration const& converters) +# if !defined(BOOST_MSVC) || BOOST_MSVC <= 1300 || _MSC_FULL_VER > 13102179 + : handle<> +# else + : m_ptr +# endif + (converters.to_python(source)) + { + } +} + +}}} // namespace boost::python::converter diff --git a/libs/python/src/converter/builtin_converters.cpp b/libs/python/src/converter/builtin_converters.cpp new file mode 100644 index 000000000..9900602b7 --- /dev/null +++ b/libs/python/src/converter/builtin_converters.cpp @@ -0,0 +1,570 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/handle.hpp> +#include <boost/python/type_id.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/refcount.hpp> + +#include <boost/python/detail/config.hpp> +#include <boost/python/detail/wrap_python.hpp> + +#include <boost/python/converter/builtin_converters.hpp> +#include <boost/python/converter/rvalue_from_python_data.hpp> +#include <boost/python/converter/registry.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/converter/shared_ptr_deleter.hpp> +#include <boost/python/converter/pytype_function.hpp> + +#include <boost/cast.hpp> +#include <string> +#include <complex> + +namespace boost { namespace python { namespace converter { + +shared_ptr_deleter::shared_ptr_deleter(handle<> owner) + : owner(owner) +{} + +shared_ptr_deleter::~shared_ptr_deleter() {} + +void shared_ptr_deleter::operator()(void const*) +{ + owner.reset(); +} + +namespace +{ + + // An lvalue conversion function which extracts a char const* from a + // Python String. +#if PY_VERSION_HEX < 0x03000000 + void* convert_to_cstring(PyObject* obj) + { + return PyString_Check(obj) ? PyString_AsString(obj) : 0; + } +#else + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0; + } +#endif + + // Given a target type and a SlotPolicy describing how to perform a + // given conversion, registers from_python converters which use the + // SlotPolicy to extract the type. + template <class T, class SlotPolicy> + struct slot_rvalue_from_python + { + public: + slot_rvalue_from_python() + { + registry::insert( + &slot_rvalue_from_python<T,SlotPolicy>::convertible + , &slot_rvalue_from_python<T,SlotPolicy>::construct + , type_id<T>() + , &SlotPolicy::get_pytype + ); + } + + private: + static void* convertible(PyObject* obj) + { + unaryfunc* slot = SlotPolicy::get_slot(obj); + return slot && *slot ? slot : 0; + } + + static void construct(PyObject* obj, rvalue_from_python_stage1_data* data) + { + // Get the (intermediate) source object + unaryfunc creator = *static_cast<unaryfunc*>(data->convertible); + handle<> intermediate(creator(obj)); + + // Get the location in which to construct + void* storage = ((rvalue_from_python_storage<T>*)data)->storage.bytes; +# ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4244) +# endif + new (storage) T( SlotPolicy::extract(intermediate.get()) ); + +# ifdef _MSC_VER +# pragma warning(pop) +# endif + // record successful construction + data->convertible = storage; + } + }; + + // identity_unaryfunc/py_object_identity -- manufacture a unaryfunc + // "slot" which just returns its argument. + extern "C" PyObject* identity_unaryfunc(PyObject* x) + { + Py_INCREF(x); + return x; + } + unaryfunc py_object_identity = identity_unaryfunc; + +#if PY_VERSION_HEX >= 0x03000000 + // As in Python 3 there is only one integer type, we can have much + // simplified logic. + // XXX(bhy) maybe the code will work with 2.6 or even 2.5? + struct int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + return PyLong_Check(obj) ? &py_object_identity : 0; + } + static PyTypeObject const* get_pytype() {return &PyLong_Type;} + }; + + template <class T> + struct signed_int_rvalue_from_python : int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + long x = PyLong_AsLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(x); + } + }; + + template <class T> + struct unsigned_int_rvalue_from_python : int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + unsigned long x = PyLong_AsUnsignedLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(x); + } + }; +#else // PY_VERSION_HEX >= 0x03000000 + // A SlotPolicy for extracting signed integer types from Python objects + struct signed_int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + return ( +#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) + !PyBool_Check(obj) && +#endif + (PyInt_Check(obj) || PyLong_Check(obj))) + + ? &number_methods->nb_int : 0; + } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} + }; + + template <class T> + struct signed_int_rvalue_from_python : signed_int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + long x = PyInt_AsLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(x); + } + }; + + // A SlotPolicy for extracting unsigned integer types from Python objects + struct unsigned_int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + return ( +#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) + !PyBool_Check(obj) && +#endif + (PyInt_Check(obj) || PyLong_Check(obj))) + ? &py_object_identity : 0; + } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} + }; + + template <class T> + struct unsigned_int_rvalue_from_python : unsigned_int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + if (PyLong_Check(intermediate)) { + // PyLong_AsUnsignedLong() checks for negative overflow, so no + // need to check it here. + unsigned long result = PyLong_AsUnsignedLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast<T>(result); + } else { + // None of PyInt_AsUnsigned*() functions check for negative + // overflow, so use PyInt_AS_LONG instead and check if number is + // negative, issuing the exception appropriately. + long result = PyInt_AS_LONG(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + if (result < 0) { + PyErr_SetString(PyExc_OverflowError, "can't convert negative" + " value to unsigned"); + throw_error_already_set(); + } + return numeric_cast<T>(result); + } + } + }; +#endif // PY_VERSION_HEX >= 0x03000000 + +// Checking Python's macro instead of Boost's - we don't seem to get +// the config right all the time. Furthermore, Python's is defined +// when long long is absent but __int64 is present. + +#ifdef HAVE_LONG_LONG + // A SlotPolicy for extracting long long types from Python objects + + struct long_long_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Check(obj) ? &py_object_identity : 0; +#else + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + // Return the identity conversion slot to avoid creating a + // new object. We'll handle that in the extract function + if (PyInt_Check(obj)) + return &number_methods->nb_int; + else if (PyLong_Check(obj)) + return &number_methods->nb_long; + else + return 0; +#endif + } + static PyTypeObject const* get_pytype() { return &PyLong_Type;} + }; + + struct long_long_rvalue_from_python : long_long_rvalue_from_python_base + { + static BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate) + { +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(intermediate)) + { + return PyInt_AS_LONG(intermediate); + } + else +#endif + { + BOOST_PYTHON_LONG_LONG result = PyLong_AsLongLong(intermediate); + + if (PyErr_Occurred()) + throw_error_already_set(); + + return result; + } + } + }; + + struct unsigned_long_long_rvalue_from_python : long_long_rvalue_from_python_base + { + static unsigned BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate) + { +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(intermediate)) + { + return numeric_cast<unsigned BOOST_PYTHON_LONG_LONG>(PyInt_AS_LONG(intermediate)); + } + else +#endif + { + unsigned BOOST_PYTHON_LONG_LONG result = PyLong_AsUnsignedLongLong(intermediate); + + if (PyErr_Occurred()) + throw_error_already_set(); + + return result; + } + } + }; +#endif + + // A SlotPolicy for extracting bool from a Python object + struct bool_rvalue_from_python + { + static unaryfunc* get_slot(PyObject* obj) + { +#if PY_VERSION_HEX >= 0x03000000 + return obj == Py_None || PyLong_Check(obj) ? &py_object_identity : 0; +#elif PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) + return obj == Py_None || PyBool_Check(obj) ? &py_object_identity : 0; +#else + return obj == Py_None || PyInt_Check(obj) ? &py_object_identity : 0; +#endif + } + + static bool extract(PyObject* intermediate) + { + return PyObject_IsTrue(intermediate); + } + + static PyTypeObject const* get_pytype() + { +#if PY_VERSION_HEX >= 0x02030000 + return &PyBool_Type; +#else + return &PyInt_Type; +#endif + } + }; + + // A SlotPolicy for extracting floating types from Python objects. + struct float_rvalue_from_python + { + static unaryfunc* get_slot(PyObject* obj) + { + PyNumberMethods* number_methods = obj->ob_type->tp_as_number; + if (number_methods == 0) + return 0; + + // For integer types, return the tp_int conversion slot to avoid + // creating a new object. We'll handle that below +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(obj)) + return &number_methods->nb_int; +#endif + + return (PyLong_Check(obj) || PyFloat_Check(obj)) + ? &number_methods->nb_float : 0; + } + + static double extract(PyObject* intermediate) + { +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(intermediate)) + { + return PyInt_AS_LONG(intermediate); + } + else +#endif + { + return PyFloat_AS_DOUBLE(intermediate); + } + } + static PyTypeObject const* get_pytype() { return &PyFloat_Type;} + }; + +#if PY_VERSION_HEX >= 0x03000000 + unaryfunc py_unicode_as_string_unaryfunc = PyUnicode_AsUTF8String; +#endif + + // A SlotPolicy for extracting C++ strings from Python objects. + struct string_rvalue_from_python + { + // If the underlying object is "string-able" this will succeed + static unaryfunc* get_slot(PyObject* obj) + { +#if PY_VERSION_HEX >= 0x03000000 + return (PyUnicode_Check(obj)) ? &py_unicode_as_string_unaryfunc : + PyBytes_Check(obj) ? &py_object_identity : 0; +#else + return (PyString_Check(obj)) ? &obj->ob_type->tp_str : 0; + +#endif + }; + + // Remember that this will be used to construct the result object +#if PY_VERSION_HEX >= 0x03000000 + static std::string extract(PyObject* intermediate) + { + return std::string(PyBytes_AsString(intermediate),PyBytes_Size(intermediate)); + } + static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} +#else + static std::string extract(PyObject* intermediate) + { + return std::string(PyString_AsString(intermediate),PyString_Size(intermediate)); + } + static PyTypeObject const* get_pytype() { return &PyString_Type;} +#endif + }; + +#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) + // encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc + // "slot" which encodes a Python string using the default encoding + extern "C" PyObject* encode_string_unaryfunc(PyObject* x) + { + return PyUnicode_FromEncodedObject( x, 0, 0 ); + } + unaryfunc py_encode_string = encode_string_unaryfunc; + + // A SlotPolicy for extracting C++ strings from Python objects. + struct wstring_rvalue_from_python + { + // If the underlying object is "string-able" this will succeed + static unaryfunc* get_slot(PyObject* obj) + { + return PyUnicode_Check(obj) + ? &py_object_identity +#if PY_VERSION_HEX >= 0x03000000 + : PyBytes_Check(obj) +#else + : PyString_Check(obj) +#endif + ? &py_encode_string + : 0; + }; + + // Remember that this will be used to construct the result object + static std::wstring extract(PyObject* intermediate) + { + std::wstring result(::PyObject_Length(intermediate), L' '); + if (!result.empty()) + { + int err = PyUnicode_AsWideChar( +#if PY_VERSION_HEX < 0x03020000 + (PyUnicodeObject *) +#endif + intermediate + , &result[0] + , result.size()); + + if (err == -1) + throw_error_already_set(); + } + return result; + } + static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} + }; +#endif + + struct complex_rvalue_from_python + { + static unaryfunc* get_slot(PyObject* obj) + { + if (PyComplex_Check(obj)) + return &py_object_identity; + else + return float_rvalue_from_python::get_slot(obj); + } + + static std::complex<double> extract(PyObject* intermediate) + { + if (PyComplex_Check(intermediate)) + { + return std::complex<double>( + PyComplex_RealAsDouble(intermediate) + , PyComplex_ImagAsDouble(intermediate)); + } +#if PY_VERSION_HEX < 0x03000000 + else if (PyInt_Check(intermediate)) + { + return PyInt_AS_LONG(intermediate); + } +#endif + else + { + return PyFloat_AS_DOUBLE(intermediate); + } + } + static PyTypeObject const* get_pytype() { return &PyComplex_Type;} + }; +} + +BOOST_PYTHON_DECL PyObject* do_return_to_python(char x) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromStringAndSize(&x, 1); +#else + return PyString_FromStringAndSize(&x, 1); +#endif +} + +BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x) +{ +#if PY_VERSION_HEX >= 0x03000000 + return x ? PyUnicode_FromString(x) : boost::python::detail::none(); +#else + return x ? PyString_FromString(x) : boost::python::detail::none(); +#endif +} + +BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x) +{ + return x ? x : boost::python::detail::none(); +} + +BOOST_PYTHON_DECL PyObject* do_arg_to_python(PyObject* x) +{ + if (x == 0) + return boost::python::detail::none(); + + Py_INCREF(x); + return x; +} + +#define REGISTER_INT_CONVERTERS(signedness, U) \ + slot_rvalue_from_python< \ + signedness U \ + ,signedness##_int_rvalue_from_python<signedness U> \ + >() + +#define REGISTER_INT_CONVERTERS2(U) \ + REGISTER_INT_CONVERTERS(signed, U); \ + REGISTER_INT_CONVERTERS(unsigned, U) + +void initialize_builtin_converters() +{ + // booleans + slot_rvalue_from_python<bool,bool_rvalue_from_python>(); + + // integer types + REGISTER_INT_CONVERTERS2(char); + REGISTER_INT_CONVERTERS2(short); + REGISTER_INT_CONVERTERS2(int); + REGISTER_INT_CONVERTERS2(long); + +// using Python's macro instead of Boost's - we don't seem to get the +// config right all the time. +# ifdef HAVE_LONG_LONG + slot_rvalue_from_python<signed BOOST_PYTHON_LONG_LONG,long_long_rvalue_from_python>(); + slot_rvalue_from_python<unsigned BOOST_PYTHON_LONG_LONG,unsigned_long_long_rvalue_from_python>(); +# endif + + // floating types + slot_rvalue_from_python<float,float_rvalue_from_python>(); + slot_rvalue_from_python<double,float_rvalue_from_python>(); + slot_rvalue_from_python<long double,float_rvalue_from_python>(); + + slot_rvalue_from_python<std::complex<float>,complex_rvalue_from_python>(); + slot_rvalue_from_python<std::complex<double>,complex_rvalue_from_python>(); + slot_rvalue_from_python<std::complex<long double>,complex_rvalue_from_python>(); + + // Add an lvalue converter for char which gets us char const* +#if PY_VERSION_HEX < 0x03000000 + registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyString_Type>::get_pytype); +#else + registry::insert(convert_to_cstring,type_id<char>(),&converter::wrap_pytype<&PyUnicode_Type>::get_pytype); +#endif + + // Register by-value converters to std::string, std::wstring +#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) + slot_rvalue_from_python<std::wstring, wstring_rvalue_from_python>(); +# endif + slot_rvalue_from_python<std::string, string_rvalue_from_python>(); + +} + +}}} // namespace boost::python::converter diff --git a/libs/python/src/converter/from_python.cpp b/libs/python/src/converter/from_python.cpp new file mode 100644 index 000000000..9678be1cb --- /dev/null +++ b/libs/python/src/converter/from_python.cpp @@ -0,0 +1,303 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/converter/from_python.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/converter/rvalue_from_python_data.hpp> + +#include <boost/python/object/find_instance.hpp> + +#include <boost/python/handle.hpp> +#include <boost/python/detail/raw_pyobject.hpp> +#include <boost/python/cast.hpp> + +#include <vector> +#include <algorithm> + +namespace boost { namespace python { namespace converter { + +// rvalue_from_python_stage1 -- do the first stage of a conversion +// from a Python object to a C++ rvalue. +// +// source - the Python object to be converted +// converters - the registry entry for the target type T +// +// Postcondition: where x is the result, one of: +// +// 1. x.convertible == 0, indicating failure +// +// 2. x.construct == 0, x.convertible is the address of an object of +// type T. Indicates a successful lvalue conversion +// +// 3. where y is of type rvalue_from_python_data<T>, +// x.construct(source, y) constructs an object of type T +// in y.storage.bytes and then sets y.convertible == y.storage.bytes, +// or else throws an exception and has no effect. +BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( + PyObject* source + , registration const& converters) +{ + rvalue_from_python_stage1_data data; + + // First check to see if it's embedded in an extension class + // instance, as a special case. + data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr); + data.construct = 0; + if (!data.convertible) + { + for (rvalue_from_python_chain const* chain = converters.rvalue_chain; + chain != 0; + chain = chain->next) + { + void* r = chain->convertible(source); + if (r != 0) + { + data.convertible = r; + data.construct = chain->construct; + break; + } + } + } + return data; +} + +// rvalue_result_from_python -- return the address of a C++ object which +// can be used as the result of calling a Python function. +// +// src - the Python object to be converted +// +// data - a reference to the base part of a +// rvalue_from_python_data<T> object, where T is the +// target type of the conversion. +// +// Requires: data.convertible == ®istered<T>::converters +// +BOOST_PYTHON_DECL void* rvalue_result_from_python( + PyObject* src, rvalue_from_python_stage1_data& data) +{ + // Retrieve the registration + // Cast in two steps for less-capable compilers + void const* converters_ = data.convertible; + registration const& converters = *static_cast<registration const*>(converters_); + + // Look for an eligible converter + data = rvalue_from_python_stage1(src, converters); + return rvalue_from_python_stage2(src, data, converters); +} + +BOOST_PYTHON_DECL void* rvalue_from_python_stage2( + PyObject* source, rvalue_from_python_stage1_data& data, registration const& converters) +{ + if (!data.convertible) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s" + , converters.target_type.name() + , source->ob_type->tp_name + )); + + PyErr_SetObject(PyExc_TypeError, msg.get()); + throw_error_already_set(); + } + + // If a construct function was registered (i.e. we found an + // rvalue conversion), call it now. + if (data.construct != 0) + data.construct(source, &data); + + // Return the address of the resulting C++ object + return data.convertible; +} + +BOOST_PYTHON_DECL void* get_lvalue_from_python( + PyObject* source + , registration const& converters) +{ + // Check to see if it's embedded in a class instance + void* x = objects::find_instance_impl(source, converters.target_type); + if (x) + return x; + + lvalue_from_python_chain const* chain = converters.lvalue_chain; + for (;chain != 0; chain = chain->next) + { + void* r = chain->convert(source); + if (r != 0) + return r; + } + return 0; +} + +namespace +{ + // Prevent looping in implicit conversions. This could/should be + // much more efficient, but will work for now. + typedef std::vector<rvalue_from_python_chain const*> visited_t; + static visited_t visited; + + inline bool visit(rvalue_from_python_chain const* chain) + { + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); + if (p != visited.end() && *p == chain) + return false; + visited.insert(p, chain); + return true; + } + + // RAII class for managing global visited marks. + struct unvisit + { + unvisit(rvalue_from_python_chain const* chain) + : chain(chain) {} + + ~unvisit() + { + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); + assert(p != visited.end()); + visited.erase(p); + } + private: + rvalue_from_python_chain const* chain; + }; +} + + +BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python( + PyObject* source + , registration const& converters) +{ + if (objects::find_instance_impl(source, converters.target_type)) + return true; + + rvalue_from_python_chain const* chain = converters.rvalue_chain; + + if (!visit(chain)) + return false; + + unvisit protect(chain); + + for (;chain != 0; chain = chain->next) + { + if (chain->convertible(source)) + return true; + } + + return false; +} + +namespace +{ + void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "No registered converter was able to extract a C++ %s to type %s" + " from this Python object of type %s" + , ref_type + , converters.target_type.name() + , source->ob_type->tp_name + )); + + PyErr_SetObject(PyExc_TypeError, msg.get()); + + throw_error_already_set(); + } + + void* lvalue_result_from_python( + PyObject* source + , registration const& converters + , char const* ref_type) + { + handle<> holder(source); + if (source->ob_refcnt <= 1) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x3000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "Attempt to return dangling %s to object of type: %s" + , ref_type + , converters.target_type.name())); + + PyErr_SetObject(PyExc_ReferenceError, msg.get()); + + throw_error_already_set(); + } + + void* result = get_lvalue_from_python(source, converters); + if (!result) + (throw_no_lvalue_from_python)(source, converters, ref_type); + return result; + } + +} + +BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject* source, registration const& converters) +{ + (throw_no_lvalue_from_python)(source, converters, "pointer"); +} + +BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject* source, registration const& converters) +{ + (throw_no_lvalue_from_python)(source, converters, "reference"); +} + +BOOST_PYTHON_DECL void* reference_result_from_python( + PyObject* source + , registration const& converters) +{ + return (lvalue_result_from_python)(source, converters, "reference"); +} + +BOOST_PYTHON_DECL void* pointer_result_from_python( + PyObject* source + , registration const& converters) +{ + if (source == Py_None) + { + Py_DECREF(source); + return 0; + } + return (lvalue_result_from_python)(source, converters, "pointer"); +} + +BOOST_PYTHON_DECL void void_result_from_python(PyObject* o) +{ + Py_DECREF(expect_non_null(o)); +} + +} // namespace boost::python::converter + +BOOST_PYTHON_DECL PyObject* +pytype_check(PyTypeObject* type_, PyObject* source) +{ + if (!PyObject_IsInstance(source, python::upcast<PyObject>(type_))) + { + ::PyErr_Format( + PyExc_TypeError + , "Expecting an object of type %s; got an object of type %s instead" + , type_->tp_name + , source->ob_type->tp_name + ); + throw_error_already_set(); + } + return source; +} + +}} // namespace boost::python diff --git a/libs/python/src/converter/registry.cpp b/libs/python/src/converter/registry.cpp new file mode 100644 index 000000000..aa20c3f68 --- /dev/null +++ b/libs/python/src/converter/registry.cpp @@ -0,0 +1,306 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/converter/registry.hpp> +#include <boost/python/converter/registrations.hpp> +#include <boost/python/converter/builtin_converters.hpp> + +#include <set> +#include <stdexcept> + +#if defined(__APPLE__) && defined(__MACH__) && defined(__GNUC__) \ + && __GNUC__ == 3 && __GNUC_MINOR__ <= 4 && !defined(__APPLE_CC__) +# define BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND +#endif + +#if defined(BOOST_PYTHON_TRACE_REGISTRY) \ + || defined(BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND) +# include <iostream> +#endif + +namespace boost { namespace python { namespace converter { +BOOST_PYTHON_DECL PyTypeObject const* registration::expected_from_python_type() const +{ + if (this->m_class_object != 0) + return this->m_class_object; + + std::set<PyTypeObject const*> pool; + + for(rvalue_from_python_chain* r = rvalue_chain; r ; r=r->next) + if(r->expected_pytype) + pool.insert(r->expected_pytype()); + + //for now I skip the search for common base + if (pool.size()==1) + return *pool.begin(); + + return 0; + +} + +BOOST_PYTHON_DECL PyTypeObject const* registration::to_python_target_type() const +{ + if (this->m_class_object != 0) + return this->m_class_object; + + if (this->m_to_python_target_type != 0) + return this->m_to_python_target_type(); + + return 0; +} + +BOOST_PYTHON_DECL PyTypeObject* registration::get_class_object() const +{ + if (this->m_class_object == 0) + { + ::PyErr_Format( + PyExc_TypeError + , const_cast<char*>("No Python class registered for C++ class %s") + , this->target_type.name()); + + throw_error_already_set(); + } + + return this->m_class_object; +} + +BOOST_PYTHON_DECL PyObject* registration::to_python(void const volatile* source) const +{ + if (this->m_to_python == 0) + { + handle<> msg( +#if PY_VERSION_HEX >= 0x3000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( + "No to_python (by-value) converter found for C++ type: %s" + , this->target_type.name() + ) + ); + + PyErr_SetObject(PyExc_TypeError, msg.get()); + + throw_error_already_set(); + } + + return source == 0 + ? incref(Py_None) + : this->m_to_python(const_cast<void*>(source)); +} + +namespace +{ + template< typename T > + void delete_node( T* node ) + { + if( !!node && !!node->next ) + delete_node( node->next ); + delete node; + } +} + +registration::~registration() +{ + delete_node(lvalue_chain); + delete_node(rvalue_chain); +} + + +namespace // <unnamed> +{ + typedef registration entry; + + typedef std::set<entry> registry_t; + +#ifndef BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND + registry_t& entries() + { + static registry_t registry; + +# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION + static bool builtin_converters_initialized = false; + if (!builtin_converters_initialized) + { + // Make this true early because registering the builtin + // converters will cause recursion. + builtin_converters_initialized = true; + + initialize_builtin_converters(); + } +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "registry: "; + for (registry_t::iterator p = registry.begin(); p != registry.end(); ++p) + { + std::cout << p->target_type << "; "; + } + std::cout << '\n'; +# endif +# endif + return registry; + } +#else + registry_t& static_registry() + { + static registry_t result; + return result; + } + + bool static_builtin_converters_initialized() + { + static bool result = false; + if (result == false) { + result = true; + std::cout << std::flush; + return false; + } + return true; + } + + registry_t& entries() + { +# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION + if (!static_builtin_converters_initialized()) + { + initialize_builtin_converters(); + } +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "registry: "; + for (registry_t::iterator p = static_registry().begin(); p != static_registry().end(); ++p) + { + std::cout << p->target_type << "; "; + } + std::cout << '\n'; +# endif +# endif + return static_registry(); + } +#endif // BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND + + entry* get(type_info type, bool is_shared_ptr = false) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + registry_t::iterator p = entries().find(entry(type)); + + std::cout << "looking up " << type << ": " + << (p == entries().end() || p->target_type != type + ? "...NOT found\n" : "...found\n"); +# endif + std::pair<registry_t::const_iterator,bool> pos_ins + = entries().insert(entry(type,is_shared_ptr)); + +# if __MWERKS__ >= 0x3000 + // do a little invariant checking if a change was made + if ( pos_ins.second ) + assert(entries().invariants()); +# endif + return const_cast<entry*>(&*pos_ins.first); + } +} // namespace <unnamed> + +namespace registry +{ + void insert(to_python_function_t f, type_info source_t, PyTypeObject const* (*to_python_target_type)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "inserting to_python " << source_t << "\n"; +# endif + entry* slot = get(source_t); + + assert(slot->m_to_python == 0); // we have a problem otherwise + if (slot->m_to_python != 0) + { + std::string msg = ( + std::string("to-Python converter for ") + + source_t.name() + + " already registered; second conversion method ignored." + ); + + if ( ::PyErr_Warn( NULL, const_cast<char*>(msg.c_str()) ) ) + { + throw_error_already_set(); + } + } + slot->m_to_python = f; + slot->m_to_python_target_type = to_python_target_type; + } + + // Insert an lvalue from_python converter + void insert(convertible_function convert, type_info key, PyTypeObject const* (*exp_pytype)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "inserting lvalue from_python " << key << "\n"; +# endif + entry* found = get(key); + lvalue_from_python_chain *registration = new lvalue_from_python_chain; + registration->convert = convert; + registration->next = found->lvalue_chain; + found->lvalue_chain = registration; + + insert(convert, 0, key,exp_pytype); + } + + // Insert an rvalue from_python converter + void insert(convertible_function convertible + , constructor_function construct + , type_info key + , PyTypeObject const* (*exp_pytype)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "inserting rvalue from_python " << key << "\n"; +# endif + entry* found = get(key); + rvalue_from_python_chain *registration = new rvalue_from_python_chain; + registration->convertible = convertible; + registration->construct = construct; + registration->expected_pytype = exp_pytype; + registration->next = found->rvalue_chain; + found->rvalue_chain = registration; + } + + // Insert an rvalue from_python converter + void push_back(convertible_function convertible + , constructor_function construct + , type_info key + , PyTypeObject const* (*exp_pytype)()) + { +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "push_back rvalue from_python " << key << "\n"; +# endif + rvalue_from_python_chain** found = &get(key)->rvalue_chain; + while (*found != 0) + found = &(*found)->next; + + rvalue_from_python_chain *registration = new rvalue_from_python_chain; + registration->convertible = convertible; + registration->construct = construct; + registration->expected_pytype = exp_pytype; + registration->next = 0; + *found = registration; + } + + registration const& lookup(type_info key) + { + return *get(key); + } + + registration const& lookup_shared_ptr(type_info key) + { + return *get(key, true); + } + + registration const* query(type_info type) + { + registry_t::iterator p = entries().find(entry(type)); +# ifdef BOOST_PYTHON_TRACE_REGISTRY + std::cout << "querying " << type + << (p == entries().end() || p->target_type != type + ? "...NOT found\n" : "...found\n"); +# endif + return (p == entries().end() || p->target_type != type) ? 0 : &*p; + } +} // namespace registry + +}}} // namespace boost::python::converter diff --git a/libs/python/src/converter/type_id.cpp b/libs/python/src/converter/type_id.cpp new file mode 100644 index 000000000..c6a8bf7a0 --- /dev/null +++ b/libs/python/src/converter/type_id.cpp @@ -0,0 +1,212 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/type_id.hpp> +#include <boost/python/detail/decorated_type_id.hpp> +#include <utility> +#include <vector> +#include <algorithm> +#include <memory> +#include <cstdlib> +#include <cstring> + +#if defined(__QNXNTO__) +# include <ostream> +#else /* defined(__QNXNTO__) */ + +#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT || __EDG_VERSION__ +# include <ostream> +#else +# include <ostream.h> +#endif + +# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE +# if defined(__GNUC__) && __GNUC__ >= 3 + +// http://lists.debian.org/debian-gcc/2003/09/msg00055.html notes +// that, in cxxabi.h of gcc-3.x for x < 4, this type is used before it +// is declared. +# if __GNUC__ == 3 && __GNUC_MINOR__ < 4 +class __class_type_info; +# endif + +# include <cxxabi.h> +# endif +# endif +#endif /* defined(__QNXNTO__) */ + +namespace boost { namespace python { + +# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE + +# if defined(__QNXNTO__) +namespace cxxabi { +extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*); +} +# else /* defined(__QNXNTO__) */ + +# ifdef __GNUC__ +# if __GNUC__ < 3 + +namespace cxxabi = :: ; +extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*); +# else + +namespace cxxabi = ::abi; // GCC 3.1 and later + +# if __GNUC__ == 3 && __GNUC_MINOR__ == 0 +namespace abi +{ + extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*); +} +# endif /* __GNUC__ == 3 && __GNUC_MINOR__ == 0 */ +# endif /* __GNUC__ < 3 */ +# endif /* __GNUC__ */ +# endif /* defined(__QNXNTO__) */ + +namespace +{ + struct compare_first_cstring + { + template <class T> + bool operator()(T const& x, T const& y) + { + return std::strcmp(x.first,y.first) < 0; + } + }; + + struct free_mem + { + free_mem(char*p) + : p(p) {} + + ~free_mem() + { + std::free(p); + } + char* p; + }; +} + +bool cxxabi_cxa_demangle_is_broken() +{ + static bool was_tested = false; + static bool is_broken = false; + if (!was_tested) { + int status; + free_mem keeper(cxxabi::__cxa_demangle("b", 0, 0, &status)); + was_tested = true; + if (status == -2 || strcmp(keeper.p, "bool") != 0) { + is_broken = true; + } + } + return is_broken; +} + +namespace detail +{ + BOOST_PYTHON_DECL char const* gcc_demangle(char const* mangled) + { + typedef std::vector< + std::pair<char const*, char const*> + > mangling_map; + + static mangling_map demangler; + mangling_map::iterator p + = std::lower_bound( + demangler.begin(), demangler.end() + , std::make_pair(mangled, (char const*)0) + , compare_first_cstring()); + + if (p == demangler.end() || strcmp(p->first, mangled)) + { + int status; + free_mem keeper( + cxxabi::__cxa_demangle(mangled, 0, 0, &status) + ); + + assert(status != -3); // invalid argument error + + if (status == -1) + { + throw std::bad_alloc(); + } + else + { + char const* demangled + = status == -2 + // Invalid mangled name. Best we can do is to + // return it intact. + ? mangled + : keeper.p; + + // Ult Mundane, 2005 Aug 17 + // Contributed under the Boost Software License, Version 1.0. + // (See accompanying file LICENSE_1_0.txt or copy at + // http://www.boost.org/LICENSE_1_0.txt) + // The __cxa_demangle function is supposed to translate + // builtin types from their one-character mangled names, + // but it doesn't in gcc 3.3.5 and gcc 3.4.x. + if (cxxabi_cxa_demangle_is_broken() + && status == -2 && strlen(mangled) == 1) + { + // list from + // http://www.codesourcery.com/cxx-abi/abi.html + switch (mangled[0]) + { + case 'v': demangled = "void"; break; + case 'w': demangled = "wchar_t"; break; + case 'b': demangled = "bool"; break; + case 'c': demangled = "char"; break; + case 'a': demangled = "signed char"; break; + case 'h': demangled = "unsigned char"; break; + case 's': demangled = "short"; break; + case 't': demangled = "unsigned short"; break; + case 'i': demangled = "int"; break; + case 'j': demangled = "unsigned int"; break; + case 'l': demangled = "long"; break; + case 'm': demangled = "unsigned long"; break; + case 'x': demangled = "long long"; break; + case 'y': demangled = "unsigned long long"; break; + case 'n': demangled = "__int128"; break; + case 'o': demangled = "unsigned __int128"; break; + case 'f': demangled = "float"; break; + case 'd': demangled = "double"; break; + case 'e': demangled = "long double"; break; + case 'g': demangled = "__float128"; break; + case 'z': demangled = "..."; break; + } + } + + p = demangler.insert(p, std::make_pair(mangled, demangled)); + keeper.p = 0; + } + } + + return p->second; + } +} +# endif + +BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, type_info const& x) +{ + return os << x.name(); +} + +namespace detail +{ + BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, detail::decorated_type_info const& x) + { + os << x.m_base_type; + if (x.m_decoration & decorated_type_info::const_) + os << " const"; + if (x.m_decoration & decorated_type_info::volatile_) + os << " volatile"; + if (x.m_decoration & decorated_type_info::reference) + os << "&"; + return os; + } +} +}} // namespace boost::python::converter diff --git a/libs/python/src/dict.cpp b/libs/python/src/dict.cpp new file mode 100644 index 000000000..77d840d45 --- /dev/null +++ b/libs/python/src/dict.cpp @@ -0,0 +1,184 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/dict.hpp> +#include <boost/python/extract.hpp> + +namespace boost { namespace python { namespace detail { +namespace +{ + // When returning list objects from methods, it may turn out that the + // derived class is returning something else, perhaps something not + // even derived from list. Since it is generally harmless for a + // Boost.Python wrapper object to hold an object of a different + // type, and because calling list() with an object may in fact + // perform a conversion, the least-bad alternative is to assume that + // we have a Python list object and stuff it into the list result. + list assume_list(object const& o) + { + return list(detail::borrowed_reference(o.ptr())); + } + + // No PyDict_CheckExact; roll our own. + inline bool check_exact(dict_base const* p) + { + return p->ptr()->ob_type == &PyDict_Type; + } +} + +detail::new_reference dict_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyDict_Type, const_cast<char*>("(O)"), + arg_.ptr()); +} + +dict_base::dict_base() + : object(detail::new_reference(PyDict_New())) +{} + +dict_base::dict_base(object_cref data) + : object(call(data)) +{} + +void dict_base::clear() +{ + if (check_exact(this)) + PyDict_Clear(this->ptr()); + else + this->attr("clear")(); +} + +dict dict_base::copy() +{ + if (check_exact(this)) + { + return dict(detail::new_reference( + PyDict_Copy(this->ptr()))); + } + else + { + return dict(detail::borrowed_reference( + this->attr("copy")().ptr() + )); + } +} + +object dict_base::get(object_cref k) const +{ + if (check_exact(this)) + { + PyObject* result = PyDict_GetItem(this->ptr(),k.ptr()); + return object(detail::borrowed_reference(result ? result : Py_None)); + } + else + { + return this->attr("get")(k); + } +} + +object dict_base::get(object_cref k, object_cref d) const +{ + return this->attr("get")(k,d); +} + +bool dict_base::has_key(object_cref k) const +{ + return extract<bool>(this->contains(k)); +} + +list dict_base::items() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Items(this->ptr()))); + } + else + { + return assume_list(this->attr("items")()); + } +} + +object dict_base::iteritems() const +{ + return this->attr("iteritems")(); +} + +object dict_base::iterkeys() const +{ + return this->attr("iterkeys")(); +} + +object dict_base::itervalues() const +{ + return this->attr("itervalues")(); +} + +list dict_base::keys() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Keys(this->ptr()))); + } + else + { + return assume_list(this->attr("keys")()); + } +} + +tuple dict_base::popitem() +{ + return tuple(detail::borrowed_reference( + this->attr("popitem")().ptr() + )); +} + +object dict_base::setdefault(object_cref k) +{ + return this->attr("setdefault")(k); +} + +object dict_base::setdefault(object_cref k, object_cref d) +{ + return this->attr("setdefault")(k,d); +} + +void dict_base::update(object_cref other) +{ + if (check_exact(this)) + { + if (PyDict_Update(this->ptr(),other.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("update")(other); + } +} + +list dict_base::values() const +{ + if (check_exact(this)) + { + return list(detail::new_reference( + PyDict_Values(this->ptr()))); + } + else + { + return assume_list(this->attr("values")()); + } +} + +static struct register_dict_pytype_ptr +{ + register_dict_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::dict>()) + ).m_class_object = &PyDict_Type; + } +}register_dict_pytype_ptr_; + +}}} // namespace boost::python diff --git a/libs/python/src/errors.cpp b/libs/python/src/errors.cpp new file mode 100644 index 000000000..34ea22f43 --- /dev/null +++ b/libs/python/src/errors.cpp @@ -0,0 +1,105 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PYTHON_SOURCE +# define BOOST_PYTHON_SOURCE +#endif + +#include <boost/python/errors.hpp> +#include <boost/cast.hpp> +#include <boost/python/detail/exception_handler.hpp> + +namespace boost { namespace python { + +error_already_set::~error_already_set() {} + +// IMPORTANT: this function may only be called from within a catch block! +BOOST_PYTHON_DECL bool handle_exception_impl(function0<void> f) +{ + try + { + if (detail::exception_handler::chain) + return detail::exception_handler::chain->handle(f); + f(); + return false; + } + catch(const boost::python::error_already_set&) + { + // The python error reporting has already been handled. + } + catch(const std::bad_alloc&) + { + PyErr_NoMemory(); + } + catch(const bad_numeric_cast& x) + { + PyErr_SetString(PyExc_OverflowError, x.what()); + } + catch(const std::out_of_range& x) + { + PyErr_SetString(PyExc_IndexError, x.what()); + } + catch(const std::invalid_argument& x) + { + PyErr_SetString(PyExc_ValueError, x.what()); + } + catch(const std::exception& x) + { + PyErr_SetString(PyExc_RuntimeError, x.what()); + } + catch(...) + { + PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception"); + } + return true; +} + +void BOOST_PYTHON_DECL throw_error_already_set() +{ + throw error_already_set(); +} + +namespace detail { + +bool exception_handler::operator()(function0<void> const& f) const +{ + if (m_next) + { + return m_next->handle(f); + } + else + { + f(); + return false; + } +} + +exception_handler::exception_handler(handler_function const& impl) + : m_impl(impl) + , m_next(0) +{ + if (chain != 0) + tail->m_next = this; + else + chain = this; + tail = this; +} + +exception_handler* exception_handler::chain; +exception_handler* exception_handler::tail; + +BOOST_PYTHON_DECL void register_exception_handler(handler_function const& f) +{ + // the constructor links the new object into a handler chain, so + // this object isn't actaully leaked (until, of course, the + // interpreter exits). + new exception_handler(f); +} + +} // namespace boost::python::detail + +}} // namespace boost::python + + diff --git a/libs/python/src/exec.cpp b/libs/python/src/exec.cpp new file mode 100644 index 000000000..9fe1b23b7 --- /dev/null +++ b/libs/python/src/exec.cpp @@ -0,0 +1,108 @@ +// Copyright Stefan Seefeld 2005. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/exec.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/handle.hpp> + +namespace boost +{ +namespace python +{ + +object BOOST_PYTHON_DECL eval(str string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = python::extract<char *>(string); + PyObject* result = PyRun_String(s, Py_eval_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +object BOOST_PYTHON_DECL exec(str string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = python::extract<char *>(string); + PyObject* result = PyRun_String(s, Py_file_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *s = python::extract<char *>(string); + PyObject* result = PyRun_String(s, Py_single_input, global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +// Execute python source code from file filename. +// global and local are the global and local scopes respectively, +// used during execution. +object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) +{ + // Set suitable default values for global and local dicts. + if (global.is_none()) + { + if (PyObject *g = PyEval_GetGlobals()) + global = object(detail::borrowed_reference(g)); + else + global = dict(); + } + if (local.is_none()) local = global; + // should be 'char const *' but older python versions don't use 'const' yet. + char *f = python::extract<char *>(filename); +#if PY_VERSION_HEX >= 0x03000000 + // TODO(bhy) temporary workaround for Python 3. + // should figure out a way to avoid binary incompatibilities as the Python 2 + // version did. + FILE *fs = fopen(f, "r"); +#else + // Let python open the file to avoid potential binary incompatibilities. + PyObject *pyfile = PyFile_FromString(f, const_cast<char*>("r")); + if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file"); + python::handle<> file(pyfile); + FILE *fs = PyFile_AsFile(file.get()); +#endif + PyObject* result = PyRun_File(fs, + f, + Py_file_input, + global.ptr(), local.ptr()); + if (!result) throw_error_already_set(); + return object(detail::new_reference(result)); +} + +} // namespace boost::python +} // namespace boost diff --git a/libs/python/src/import.cpp b/libs/python/src/import.cpp new file mode 100644 index 000000000..0add79eea --- /dev/null +++ b/libs/python/src/import.cpp @@ -0,0 +1,25 @@ +// Copyright Stefan Seefeld 2005. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/import.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/handle.hpp> + +namespace boost +{ +namespace python +{ + +object BOOST_PYTHON_DECL import(str name) +{ + // should be 'char const *' but older python versions don't use 'const' yet. + char *n = python::extract<char *>(name); + python::handle<> module(PyImport_ImportModule(n)); + return python::object(module); +} + +} // namespace boost::python +} // namespace boost diff --git a/libs/python/src/list.cpp b/libs/python/src/list.cpp new file mode 100644 index 000000000..77e616881 --- /dev/null +++ b/libs/python/src/list.cpp @@ -0,0 +1,170 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/list.hpp> +#include <boost/python/ssize_t.hpp> + +namespace boost { namespace python { namespace detail { + + +detail::new_non_null_reference list_base::call(object const& arg_) +{ + return (detail::new_non_null_reference) + (expect_non_null)( + PyObject_CallFunction( + (PyObject*)&PyList_Type, const_cast<char*>("(O)"), + arg_.ptr())); +} + +list_base::list_base() + : object(detail::new_reference(PyList_New(0))) +{} + +list_base::list_base(object_cref sequence) + : object(list_base::call(sequence)) +{} + +void list_base::append(object_cref x) +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Append(this->ptr(), x.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("append")(x); + } +} + +//long list_base::count(object_cref value) const; + +void list_base::extend(object_cref sequence) +{ + this->attr("extend")(sequence); +} + +long list_base::index(object_cref value) const +{ + object result_obj(this->attr("index")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else + long result = PyInt_AsLong(result_obj.ptr()); +#endif + if (result == -1) + throw_error_already_set(); + return result; +} + +void list_base::insert(ssize_t index, object_cref item) +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Insert(this->ptr(), index, item.ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("insert")(index, item); + } +} + +void list_base::insert(object const& index, object_cref x) +{ +#if PY_VERSION_HEX >= 0x03000000 + ssize_t index_ = PyLong_AsSsize_t(index.ptr()); +#else + long index_ = PyInt_AsLong(index.ptr()); +#endif + if (index_ == -1 && PyErr_Occurred()) + throw_error_already_set(); + this->insert(index_, x); +} + +object list_base::pop() +{ + return this->attr("pop")(); +} + +object list_base::pop(ssize_t index) +{ + return this->pop(object(index)); +} + +object list_base::pop(object const& index) +{ + return this->attr("pop")(index); +} + +void list_base::remove(object_cref value) +{ + this->attr("remove")(value); +} + +void list_base::reverse() +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Reverse(this->ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("reverse")(); + } +} + +void list_base::sort() +{ + if (PyList_CheckExact(this->ptr())) + { + if (PyList_Sort(this->ptr()) == -1) + throw_error_already_set(); + } + else + { + this->attr("sort")(); + } +} + +#if PY_VERSION_HEX >= 0x03000000 +void list_base::sort(args_proxy const &args, + kwds_proxy const &kwds) +{ + this->attr("sort")(args, kwds); +} +#else +void list_base::sort(object_cref cmpfunc) +{ + this->attr("sort")(cmpfunc); +} +#endif + +// For some reason, moving this to the end of the TU suppresses an ICE +// with vc6. +ssize_t list_base::count(object_cref value) const +{ + object result_obj(this->attr("count")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else + long result = PyInt_AsLong(result_obj.ptr()); +#endif + if (result == -1) + throw_error_already_set(); + return result; +} + +static struct register_list_pytype_ptr +{ + register_list_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::list>()) + ).m_class_object = &PyList_Type; + } +}register_list_pytype_ptr_; + +}}} // namespace boost::python diff --git a/libs/python/src/long.cpp b/libs/python/src/long.cpp new file mode 100644 index 000000000..1ec8ebc01 --- /dev/null +++ b/libs/python/src/long.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/long.hpp> + +namespace boost { namespace python { namespace detail { + +new_non_null_reference long_base::call(object const& arg_) +{ + return (detail::new_non_null_reference)PyObject_CallFunction( + (PyObject*)&PyLong_Type, const_cast<char*>("(O)"), + arg_.ptr()); +} + +new_non_null_reference long_base::call(object const& arg_, object const& base) +{ + return (detail::new_non_null_reference)PyObject_CallFunction( + (PyObject*)&PyLong_Type, const_cast<char*>("(OO)"), + arg_.ptr(), base.ptr()); +} + +long_base::long_base() + : object( + detail::new_reference( + PyObject_CallFunction((PyObject*)&PyLong_Type, const_cast<char*>("()"))) + ) +{} + +long_base::long_base(object_cref arg) + : object(long_base::call(arg)) +{} + +long_base::long_base(object_cref arg, object_cref base) + : object(long_base::call(arg, base)) +{} + + +}}} // namespace boost::python diff --git a/libs/python/src/module.cpp b/libs/python/src/module.cpp new file mode 100644 index 000000000..962848199 --- /dev/null +++ b/libs/python/src/module.cpp @@ -0,0 +1,73 @@ +// (C) Copyright David Abrahams 2000. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include <boost/python/scope.hpp> +#include <boost/python/object/add_to_namespace.hpp> + +namespace boost { namespace python { namespace detail { + +namespace +{ + PyObject* init_module_in_scope(PyObject* m, void(*init_function)()) + { + if (m != 0) + { + // Create the current module scope + object m_obj(((borrowed_reference_t*)m)); + scope current_module(m_obj); + + handle_exception(init_function); + } + + return m; + } +} + +BOOST_PYTHON_DECL void scope_setattr_doc(char const* name, object const& x, char const* doc) +{ + // Use function::add_to_namespace to achieve overloading if + // appropriate. + scope current; + objects::add_to_namespace(current, name, x, doc); +} + +#if PY_VERSION_HEX >= 0x03000000 + +BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, void(*init_function)()) +{ + return init_module_in_scope( + PyModule_Create(&moduledef), + init_function); +} + +#else + +namespace +{ + PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; +} + +BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*init_function)()) +{ + return init_module_in_scope( + Py_InitModule(const_cast<char*>(name), initial_methods), + init_function); +} + +#endif + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +namespace detail +{ + BOOST_PYTHON_DECL PyObject* current_scope = 0; +} + +}} diff --git a/libs/python/src/numeric.cpp b/libs/python/src/numeric.cpp new file mode 100644 index 000000000..c8a5f071d --- /dev/null +++ b/libs/python/src/numeric.cpp @@ -0,0 +1,325 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/numeric.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/detail/raw_pyobject.hpp> +#include <boost/python/extract.hpp> + +namespace boost { namespace python { namespace numeric { + +namespace +{ + enum state_t { failed = -1, unknown, succeeded }; + state_t state = unknown; + std::string module_name; + std::string type_name; + + handle<> array_module; + handle<> array_type; + handle<> array_function; + + void throw_load_failure() + { + PyErr_Format( + PyExc_ImportError + , "No module named '%s' or its type '%s' did not follow the NumPy protocol" + , module_name.c_str(), type_name.c_str()); + throw_error_already_set(); + + } + + bool load(bool throw_on_error) + { + if (!state) + { + if (module_name.size() == 0) + { + module_name = "numarray"; + type_name = "NDArray"; + if (load(false)) + return true; + module_name = "Numeric"; + type_name = "ArrayType"; + } + + state = failed; + PyObject* module = ::PyImport_Import(object(module_name).ptr()); + if (module) + { + PyObject* type = ::PyObject_GetAttrString(module, const_cast<char*>(type_name.c_str())); + + if (type && PyType_Check(type)) + { + array_type = handle<>(type); + PyObject* function = ::PyObject_GetAttrString(module, const_cast<char*>("array")); + + if (function && PyCallable_Check(function)) + { + array_function = handle<>(function); + state = succeeded; + } + } + } + } + + if (state == succeeded) + return true; + + if (throw_on_error) + throw_load_failure(); + + PyErr_Clear(); + return false; + } + + object demand_array_function() + { + load(true); + return object(array_function); + } +} + +void array::set_module_and_type(char const* package_name, char const* type_attribute_name) +{ + state = unknown; + module_name = package_name ? package_name : "" ; + type_name = type_attribute_name ? type_attribute_name : "" ; +} + +std::string array::get_module_name() +{ + load(false); + return module_name; +} + +namespace aux +{ + bool array_object_manager_traits::check(PyObject* obj) + { + if (!load(false)) + return false; + return ::PyObject_IsInstance(obj, array_type.get()); + } + + python::detail::new_non_null_reference + array_object_manager_traits::adopt(PyObject* obj) + { + load(true); + return detail::new_non_null_reference( + pytype_check(downcast<PyTypeObject>(array_type.get()), obj)); + } + + PyTypeObject const* array_object_manager_traits::get_pytype() + { + load(false); + if(!array_type) return 0; + return downcast<PyTypeObject>(array_type.get()); + } + +# define BOOST_PYTHON_AS_OBJECT(z, n, _) object(x##n) +# define BOOST_PP_LOCAL_MACRO(n) \ + array_base::array_base(BOOST_PP_ENUM_PARAMS(n, object const& x)) \ + : object(demand_array_function()(BOOST_PP_ENUM_PARAMS(n, x))) \ + {} +# define BOOST_PP_LOCAL_LIMITS (1, 6) +# include BOOST_PP_LOCAL_ITERATE() +# undef BOOST_PYTHON_AS_OBJECT + + array_base::array_base(BOOST_PP_ENUM_PARAMS(7, object const& x)) + : object(demand_array_function()(BOOST_PP_ENUM_PARAMS(7, x))) + {} + + object array_base::argmax(long axis) + { + return attr("argmax")(axis); + } + + object array_base::argmin(long axis) + { + return attr("argmin")(axis); + } + + object array_base::argsort(long axis) + { + return attr("argsort")(axis); + } + + object array_base::astype(object const& type) + { + return attr("astype")(type); + } + + void array_base::byteswap() + { + attr("byteswap")(); + } + + object array_base::copy() const + { + return attr("copy")(); + } + + object array_base::diagonal(long offset, long axis1, long axis2) const + { + return attr("diagonal")(offset, axis1, axis2); + } + + void array_base::info() const + { + attr("info")(); + } + + bool array_base::is_c_array() const + { + return extract<bool>(attr("is_c_array")()); + } + + bool array_base::isbyteswapped() const + { + return extract<bool>(attr("isbyteswapped")()); + } + + array array_base::new_(object type) const + { + return extract<array>(attr("new")(type))(); + } + + void array_base::sort() + { + attr("sort")(); + } + + object array_base::trace(long offset, long axis1, long axis2) const + { + return attr("trace")(offset, axis1, axis2); + } + + object array_base::type() const + { + return attr("type")(); + } + + char array_base::typecode() const + { + return extract<char>(attr("typecode")()); + } + + object array_base::factory( + object const& sequence + , object const& typecode + , bool copy + , bool savespace + , object type + , object shape + ) + { + return attr("factory")(sequence, typecode, copy, savespace, type, shape); + } + + object array_base::getflat() const + { + return attr("getflat")(); + } + + long array_base::getrank() const + { + return extract<long>(attr("getrank")()); + } + + object array_base::getshape() const + { + return attr("getshape")(); + } + + bool array_base::isaligned() const + { + return extract<bool>(attr("isaligned")()); + } + + bool array_base::iscontiguous() const + { + return extract<bool>(attr("iscontiguous")()); + } + + long array_base::itemsize() const + { + return extract<long>(attr("itemsize")()); + } + + long array_base::nelements() const + { + return extract<long>(attr("nelements")()); + } + + object array_base::nonzero() const + { + return attr("nonzero")(); + } + + void array_base::put(object const& indices, object const& values) + { + attr("put")(indices, values); + } + + void array_base::ravel() + { + attr("ravel")(); + } + + object array_base::repeat(object const& repeats, long axis) + { + return attr("repeat")(repeats, axis); + } + + void array_base::resize(object const& shape) + { + attr("resize")(shape); + } + + void array_base::setflat(object const& flat) + { + attr("setflat")(flat); + } + + void array_base::setshape(object const& shape) + { + attr("setshape")(shape); + } + + void array_base::swapaxes(long axis1, long axis2) + { + attr("swapaxes")(axis1, axis2); + } + + object array_base::take(object const& sequence, long axis) const + { + return attr("take")(sequence, axis); + } + + void array_base::tofile(object const& file) const + { + attr("tofile")(file); + } + + str array_base::tostring() const + { + return str(attr("tostring")()); + } + + void array_base::transpose(object const& axes) + { + attr("transpose")(axes); + } + + object array_base::view() const + { + return attr("view")(); + } +} + +}}} // namespace boost::python::numeric diff --git a/libs/python/src/object/class.cpp b/libs/python/src/object/class.cpp new file mode 100644 index 000000000..aeef688e2 --- /dev/null +++ b/libs/python/src/object/class.cpp @@ -0,0 +1,764 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/detail/prefix.hpp> +#include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround + +#include <boost/python/object/class.hpp> +#include <boost/python/object/instance.hpp> +#include <boost/python/object/class_detail.hpp> +#include <boost/python/scope.hpp> +#include <boost/python/converter/registry.hpp> +#include <boost/python/object/find_instance.hpp> +#include <boost/python/object/pickle_support.hpp> +#include <boost/python/detail/map_entry.hpp> +#include <boost/python/object.hpp> +#include <boost/python/object_protocol.hpp> +#include <boost/detail/binary_search.hpp> +#include <boost/python/self.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/str.hpp> +#include <boost/python/ssize_t.hpp> +#include <functional> +#include <vector> +#include <cstddef> +#include <new> +#include <structmember.h> + +namespace boost { namespace python { + +# ifdef BOOST_PYTHON_SELF_IS_CLASS +namespace self_ns +{ + self_t self; +} +# endif + +instance_holder::instance_holder() + : m_next(0) +{ +} + +instance_holder::~instance_holder() +{ +} + +extern "C" +{ + // This is copied from typeobject.c in the Python sources. Even though + // class_metatype_object doesn't set Py_TPFLAGS_HAVE_GC, that bit gets + // filled in by the base class initialization process in + // PyType_Ready(). However, tp_is_gc is *not* copied from the base + // type, making it assume that classes are GC-able even if (like + // class_type_object) they're statically allocated. + static int + type_is_gc(PyTypeObject *python_type) + { + return python_type->tp_flags & Py_TPFLAGS_HEAPTYPE; + } + + // This is also copied from the Python sources. We can't implement + // static_data as a subclass property effectively without it. + typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; + int getter_doc; + } propertyobject; + + // Copied from Python source and removed the part for setting docstring, + // since we don't have a setter for __doc__ and trying to set it will + // cause the init fail. + static int property_init(PyObject *self, PyObject *args, PyObject *kwds) + { + PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; + static const char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; + propertyobject *prop = (propertyobject *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", + const_cast<char **>(kwlist), &get, &set, &del, &doc)) + return -1; + + if (get == Py_None) + get = NULL; + if (set == Py_None) + set = NULL; + if (del == Py_None) + del = NULL; + + Py_XINCREF(get); + Py_XINCREF(set); + Py_XINCREF(del); + Py_XINCREF(doc); + + prop->prop_get = get; + prop->prop_set = set; + prop->prop_del = del; + prop->prop_doc = doc; + prop->getter_doc = 0; + + return 0; + } + + + static PyObject * + static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/) + { + propertyobject *gs = (propertyobject *)self; + + return PyObject_CallFunction(gs->prop_get, const_cast<char*>("()")); + } + + static int + static_data_descr_set(PyObject *self, PyObject * /*obj*/, PyObject *value) + { + propertyobject *gs = (propertyobject *)self; + PyObject *func, *res; + + if (value == NULL) + func = gs->prop_del; + else + func = gs->prop_set; + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, + value == NULL ? + "can't delete attribute" : + "can't set attribute"); + return -1; + } + if (value == NULL) + res = PyObject_CallFunction(func, const_cast<char*>("()")); + else + res = PyObject_CallFunction(func, const_cast<char*>("(O)"), value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; + } +} + +static PyTypeObject static_data_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.StaticProperty"), + sizeof(propertyobject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyProperty_Type, /* tp_base */ + 0, /* tp_dict */ + static_data_descr_get, /* tp_descr_get */ + static_data_descr_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + property_init, /* tp_init */ + 0, /* tp_alloc */ + 0, // filled in with type_new /* tp_new */ + 0, // filled in with __PyObject_GC_Del /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +namespace objects +{ +#if PY_VERSION_HEX < 0x03000000 + // XXX Not sure why this run into compiling error in Python 3 + extern "C" + { + // This declaration needed due to broken Python 2.2 headers + extern DL_IMPORT(PyTypeObject) PyProperty_Type; + } +#endif + + BOOST_PYTHON_DECL PyObject* static_data() + { + if (static_data_object.tp_dict == 0) + { + Py_TYPE(&static_data_object) = &PyType_Type; + static_data_object.tp_base = &PyProperty_Type; + if (PyType_Ready(&static_data_object)) + return 0; + } + return upcast<PyObject>(&static_data_object); + } +} + +extern "C" +{ + // Ordinarily, descriptors have a certain assymetry: you can use + // them to read attributes off the class object they adorn, but + // writing the same attribute on the class object always replaces + // the descriptor in the class __dict__. In order to properly + // represent C++ static data members, we need to allow them to be + // written through the class instance. This function of the + // metaclass makes it possible. + static int + class_setattro(PyObject *obj, PyObject *name, PyObject* value) + { + // Must use "private" Python implementation detail + // _PyType_Lookup instead of PyObject_GetAttr because the + // latter will always end up calling the descr_get function on + // any descriptor it finds; we need the unadulterated + // descriptor here. + PyObject* a = _PyType_Lookup(downcast<PyTypeObject>(obj), name); + + // a is a borrowed reference or 0 + + // If we found a static data descriptor, call it directly to + // force it to set the static data member + if (a != 0 && PyObject_IsInstance(a, objects::static_data())) + return Py_TYPE(a)->tp_descr_set(a, obj, value); + else + return PyType_Type.tp_setattro(obj, name, value); + } +} + +static PyTypeObject class_metatype_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.class"), + PyType_Type.tp_basicsize, + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + class_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyType_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, // filled in with type_new /* tp_new */ + 0, // filled in with __PyObject_GC_Del /* tp_free */ + (inquiry)type_is_gc, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Install the instance data for a C++ object into a Python instance +// object. +void instance_holder::install(PyObject* self) throw() +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self)), &class_metatype_object)); + m_next = ((objects::instance<>*)self)->objects; + ((objects::instance<>*)self)->objects = this; +} + + +namespace objects +{ +// Get the metatype object for all extension classes. + BOOST_PYTHON_DECL type_handle class_metatype() + { + if (class_metatype_object.tp_dict == 0) + { + Py_TYPE(&class_metatype_object) = &PyType_Type; + class_metatype_object.tp_base = &PyType_Type; + if (PyType_Ready(&class_metatype_object)) + return type_handle(); + } + return type_handle(borrowed(&class_metatype_object)); + } + extern "C" + { + static void instance_dealloc(PyObject* inst) + { + instance<>* kill_me = (instance<>*)inst; + + for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) + { + next = p->next(); + p->~instance_holder(); + instance_holder::deallocate(inst, dynamic_cast<void*>(p)); + } + + // Python 2.2.1 won't add weak references automatically when + // tp_itemsize > 0, so we need to manage that + // ourselves. Accordingly, we also have to clean up the + // weakrefs ourselves. + if (kill_me->weakrefs != NULL) + PyObject_ClearWeakRefs(inst); + + Py_XDECREF(kill_me->dict); + + Py_TYPE(inst)->tp_free(inst); + } + + static PyObject * + instance_new(PyTypeObject* type_, PyObject* /*args*/, PyObject* /*kw*/) + { + // Attempt to find the __instance_size__ attribute. If not present, no problem. + PyObject* d = type_->tp_dict; + PyObject* instance_size_obj = PyObject_GetAttrString(d, const_cast<char*>("__instance_size__")); + + ssize_t instance_size = instance_size_obj ? +#if PY_VERSION_HEX >= 0x03000000 + PyLong_AsSsize_t(instance_size_obj) : 0; +#else + PyInt_AsLong(instance_size_obj) : 0; +#endif + + if (instance_size < 0) + instance_size = 0; + + PyErr_Clear(); // Clear any errors that may have occurred. + + instance<>* result = (instance<>*)type_->tp_alloc(type_, instance_size); + if (result) + { + // Guido says we can use ob_size for any purpose we + // like, so we'll store the total size of the object + // there. A negative number indicates that the extra + // instance memory is not yet allocated to any holders. +#if PY_VERSION_HEX >= 0x02060000 + Py_SIZE(result) = +#else + result->ob_size = +#endif + -(static_cast<int>(offsetof(instance<>,storage) + instance_size)); + } + return (PyObject*)result; + } + + static PyObject* instance_get_dict(PyObject* op, void*) + { + instance<>* inst = downcast<instance<> >(op); + if (inst->dict == 0) + inst->dict = PyDict_New(); + return python::xincref(inst->dict); + } + + static int instance_set_dict(PyObject* op, PyObject* dict, void*) + { + instance<>* inst = downcast<instance<> >(op); + python::xdecref(inst->dict); + inst->dict = python::incref(dict); + return 0; + } + + } + + + static PyGetSetDef instance_getsets[] = { + {const_cast<char*>("__dict__"), instance_get_dict, instance_set_dict, NULL, 0}, + {0, 0, 0, 0, 0} + }; + + + static PyMemberDef instance_members[] = { + {const_cast<char*>("__weakref__"), T_OBJECT, offsetof(instance<>, weakrefs), 0, 0}, + {0, 0, 0, 0, 0} + }; + + static PyTypeObject class_type_object = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.instance"), + offsetof(instance<>,storage), /* tp_basicsize */ + 1, /* tp_itemsize */ + instance_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT // | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(instance<>,weakrefs), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + instance_members, /* tp_members */ + instance_getsets, /* tp_getset */ + 0, //&PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(instance<>,dict), /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + instance_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif + }; + + BOOST_PYTHON_DECL type_handle class_type() + { + if (class_type_object.tp_dict == 0) + { + Py_TYPE(&class_type_object) = incref(class_metatype().get()); + class_type_object.tp_base = &PyBaseObject_Type; + if (PyType_Ready(&class_type_object)) + return type_handle(); +// class_type_object.tp_setattro = class_setattro; + } + return type_handle(borrowed(&class_type_object)); + } + + BOOST_PYTHON_DECL void* + find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only) + { + if (!Py_TYPE(Py_TYPE(inst)) || + !PyType_IsSubtype(Py_TYPE(Py_TYPE(inst)), &class_metatype_object)) + return 0; + + instance<>* self = reinterpret_cast<instance<>*>(inst); + + for (instance_holder* match = self->objects; match != 0; match = match->next()) + { + void* const found = match->holds(type, null_shared_ptr_only); + if (found) + return found; + } + return 0; + } + + object module_prefix() + { + return object( + PyObject_IsInstance(scope().ptr(), upcast<PyObject>(&PyModule_Type)) + ? object(scope().attr("__name__")) + : api::getattr(scope(), "__module__", str()) + ); + } + + namespace + { + // Find a registered class object corresponding to id. Return a + // null handle if no such class is registered. + inline type_handle query_class(type_info id) + { + converter::registration const* p = converter::registry::query(id); + return type_handle( + python::borrowed( + python::allow_null(p ? p->m_class_object : 0)) + ); + } + + // Find a registered class corresponding to id. If not found, + // throw an appropriate exception. + type_handle get_class(type_info id) + { + type_handle result(query_class(id)); + + if (result.get() == 0) + { + object report("extension class wrapper for base class "); + report = report + id.name() + " has not been created yet"; + PyErr_SetObject(PyExc_RuntimeError, report.ptr()); + throw_error_already_set(); + } + return result; + } + + // class_base constructor + // + // name - the name of the new Python class + // + // num_types - one more than the number of declared bases + // + // types - array of python::type_info, the first item + // corresponding to the class being created, and the + // rest corresponding to its declared bases. + // + inline object + new_class(char const* name, std::size_t num_types, type_info const* const types, char const* doc) + { + assert(num_types >= 1); + + // Build a tuple of the base Python type objects. If no bases + // were declared, we'll use our class_type() as the single base + // class. + ssize_t const num_bases = (std::max)(num_types - 1, static_cast<std::size_t>(1)); + handle<> bases(PyTuple_New(num_bases)); + + for (ssize_t i = 1; i <= num_bases; ++i) + { + type_handle c = (i >= static_cast<ssize_t>(num_types)) ? class_type() : get_class(types[i]); + // PyTuple_SET_ITEM steals this reference + PyTuple_SET_ITEM(bases.get(), static_cast<ssize_t>(i - 1), upcast<PyObject>(c.release())); + } + + // Call the class metatype to create a new class + dict d; + + object m = module_prefix(); + if (m) d["__module__"] = m; + + if (doc != 0) + d["__doc__"] = doc; + + object result = object(class_metatype())(name, bases, d); + assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type)); + + if (scope().ptr() != Py_None) + scope().attr(name) = result; + + // For pickle. Will lead to informative error messages if pickling + // is not enabled. + result.attr("__reduce__") = object(make_instance_reduce_function()); + + return result; + } + } + + class_base::class_base( + char const* name, std::size_t num_types, type_info const* const types, char const* doc) + : object(new_class(name, num_types, types, doc)) + { + // Insert the new class object in the registry + converter::registration& converters = const_cast<converter::registration&>( + converter::registry::lookup(types[0])); + + // Class object is leaked, for now + converters.m_class_object = (PyTypeObject*)incref(this->ptr()); + } + + BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst) + { + converter::registration& dst_converters + = const_cast<converter::registration&>(converter::registry::lookup(dst)); + + converter::registration const& src_converters = converter::registry::lookup(src); + + dst_converters.m_class_object = src_converters.m_class_object; + } + + void class_base::set_instance_size(std::size_t instance_size) + { + this->attr("__instance_size__") = instance_size; + } + + void class_base::add_property( + char const* name, object const& fget, char const* docstr) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("Osss"), fget.ptr(), 0, 0, docstr)); + + this->setattr(name, property); + } + + void class_base::add_property( + char const* name, object const& fget, object const& fset, char const* docstr) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("OOss"), fget.ptr(), fset.ptr(), 0, docstr)); + + this->setattr(name, property); + } + + void class_base::add_static_property(char const* name, object const& fget) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast<char*>("O"), fget.ptr()) + ); + + this->setattr(name, property); + } + + void class_base::add_static_property(char const* name, object const& fget, object const& fset) + { + object property( + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast<char*>("OO"), fget.ptr(), fset.ptr())); + + this->setattr(name, property); + } + + void class_base::setattr(char const* name, object const& x) + { + if (PyObject_SetAttrString(this->ptr(), const_cast<char*>(name), x.ptr()) < 0) + throw_error_already_set(); + } + + namespace + { + extern "C" PyObject* no_init(PyObject*, PyObject*) + { + ::PyErr_SetString(::PyExc_RuntimeError, const_cast<char*>("This class cannot be instantiated from Python")); + return NULL; + } + static ::PyMethodDef no_init_def = { + const_cast<char*>("__init__"), no_init, METH_VARARGS, + const_cast<char*>("Raises an exception\n" + "This class cannot be instantiated from Python\n") + }; + } + + void class_base::def_no_init() + { + handle<> f(::PyCFunction_New(&no_init_def, 0)); + this->setattr("__init__", object(f)); + } + + void class_base::enable_pickling_(bool getstate_manages_dict) + { + setattr("__safe_for_unpickling__", object(true)); + + if (getstate_manages_dict) + { + setattr("__getstate_manages_dict__", object(true)); + } + } + + namespace + { + PyObject* callable_check(PyObject* callable) + { + if (PyCallable_Check(expect_non_null(callable))) + return callable; + + ::PyErr_Format( + PyExc_TypeError + , const_cast<char*>("staticmethod expects callable object; got an object of type %s, which is not callable") + , Py_TYPE(callable)->tp_name + ); + + throw_error_already_set(); + return 0; + } + } + + void class_base::make_method_static(const char * method_name) + { + PyTypeObject* self = downcast<PyTypeObject>(this->ptr()); + dict d((handle<>(borrowed(self->tp_dict)))); + + object method(d[method_name]); + + this->attr(method_name) = object( + handle<>( + PyStaticMethod_New((callable_check)(method.ptr()) ) + )); + } + + BOOST_PYTHON_DECL type_handle registered_class_object(type_info id) + { + return query_class(id); + } +} // namespace objects + + +void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); + objects::instance<>* self = (objects::instance<>*)self_; + + int total_size_needed = holder_offset + holder_size; + + if (-Py_SIZE(self) >= total_size_needed) + { + // holder_offset should at least point into the variable-sized part + assert(holder_offset >= offsetof(objects::instance<>,storage)); + + // Record the fact that the storage is occupied, noting where it starts + Py_SIZE(self) = holder_offset; + return (char*)self + holder_offset; + } + else + { + void* const result = PyMem_Malloc(holder_size); + if (result == 0) + throw std::bad_alloc(); + return result; + } +} + +void instance_holder::deallocate(PyObject* self_, void* storage) throw() +{ + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); + objects::instance<>* self = (objects::instance<>*)self_; + if (storage != (char*)self + Py_SIZE(self)) + { + PyMem_Free(storage); + } +} + +}} // namespace boost::python diff --git a/libs/python/src/object/enum.cpp b/libs/python/src/object/enum.cpp new file mode 100644 index 000000000..3063320cb --- /dev/null +++ b/libs/python/src/object/enum.cpp @@ -0,0 +1,246 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/object/enum_base.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/scope.hpp> +#include <boost/python/object.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/str.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/object_protocol.hpp> +#include <structmember.h> + +namespace boost { namespace python { namespace objects { + +struct enum_object +{ +#if PY_VERSION_HEX >= 0x03000000 + PyLongObject base_object; +#else + PyIntObject base_object; +#endif + PyObject* name; +}; + +static PyMemberDef enum_members[] = { + {const_cast<char*>("name"), T_OBJECT_EX, offsetof(enum_object,name),READONLY, 0}, + {0, 0, 0, 0, 0} +}; + + +extern "C" +{ + static PyObject* enum_repr(PyObject* self_) + { + // XXX(bhy) Potentional memory leak here since PyObject_GetAttrString returns a new reference + // const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast<char*>("__module__"))); + PyObject *mod = PyObject_GetAttrString( self_, "__module__"); + enum_object* self = downcast<enum_object>(self_); + if (!self->name) + { + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_)); +#else + PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_)); +#endif + } + else + { + PyObject* name = self->name; + if (name == 0) + return 0; + + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name); +#else + PyString_FromFormat("%s.%s.%s", + PyString_AsString(mod), self_->ob_type->tp_name, PyString_AsString(name)); +#endif + } + } + + static PyObject* enum_str(PyObject* self_) + { + enum_object* self = downcast<enum_object>(self_); + if (!self->name) + { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Type.tp_str(self_); +#else + return PyInt_Type.tp_str(self_); +#endif + } + else + { + return incref(self->name); + } + } +} + +static PyTypeObject enum_type_object = { + PyVarObject_HEAD_INIT(NULL, 0) // &PyType_Type + const_cast<char*>("Boost.Python.enum"), + sizeof(enum_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + enum_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + enum_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX < 0x03000000 + | Py_TPFLAGS_CHECKTYPES +#endif + | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + enum_members, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object module_prefix(); + +namespace +{ + object new_enum_type(char const* name, char const *doc) + { + if (enum_type_object.tp_dict == 0) + { + Py_TYPE(&enum_type_object) = incref(&PyType_Type); +#if PY_VERSION_HEX >= 0x03000000 + enum_type_object.tp_base = &PyLong_Type; +#else + enum_type_object.tp_base = &PyInt_Type; +#endif + if (PyType_Ready(&enum_type_object)) + throw_error_already_set(); + } + + type_handle metatype(borrowed(&PyType_Type)); + type_handle base(borrowed(&enum_type_object)); + + // suppress the instance __dict__ in these enum objects. There + // may be a slicker way, but this'll do for now. + dict d; + d["__slots__"] = tuple(); + d["values"] = dict(); + d["names"] = dict(); + + object module_name = module_prefix(); + if (module_name) + d["__module__"] = module_name; + if (doc) + d["__doc__"] = doc; + + object result = (object(metatype))(name, make_tuple(base), d); + + scope().attr(name) = result; + + return result; + } +} + +enum_base::enum_base( + char const* name + , converter::to_python_function_t to_python + , converter::convertible_function convertible + , converter::constructor_function construct + , type_info id + , char const *doc + ) + : object(new_enum_type(name, doc)) +{ + converter::registration& converters + = const_cast<converter::registration&>( + converter::registry::lookup(id)); + + converters.m_class_object = downcast<PyTypeObject>(this->ptr()); + converter::registry::insert(to_python, id); + converter::registry::insert(convertible, construct, id); +} + +void enum_base::add_value(char const* name_, long value) +{ + // Convert name to Python string + object name(name_); + + // Create a new enum instance by calling the class with a value + object x = (*this)(value); + + // Store the object in the enum class + (*this).attr(name_) = x; + + dict d = extract<dict>(this->attr("values"))(); + d[value] = x; + + // Set the name field in the new enum instanec + enum_object* p = downcast<enum_object>(x.ptr()); + Py_XDECREF(p->name); + p->name = incref(name.ptr()); + + dict names_dict = extract<dict>(this->attr("names"))(); + names_dict[x.attr("name")] = x; +} + +void enum_base::export_values() +{ + dict d = extract<dict>(this->attr("names"))(); + list items = d.items(); + scope current; + + for (unsigned i = 0, max = len(items); i < max; ++i) + api::setattr(current, items[i][0], items[i][1]); + } + +PyObject* enum_base::to_python(PyTypeObject* type_, long x) +{ + object type((type_handle(borrowed(type_)))); + + dict d = extract<dict>(type.attr("values"))(); + object v = d.get(x, object()); + return incref( + (v == object() ? type(x) : v).ptr()); +} + +}}} // namespace boost::python::object diff --git a/libs/python/src/object/function.cpp b/libs/python/src/object/function.cpp new file mode 100644 index 000000000..5c59cc779 --- /dev/null +++ b/libs/python/src/object/function.cpp @@ -0,0 +1,793 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/docstring_options.hpp> +#include <boost/python/object/function_object.hpp> +#include <boost/python/object/function_handle.hpp> +#include <boost/python/object/function_doc_signature.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/str.hpp> +#include <boost/python/object_attributes.hpp> +#include <boost/python/args.hpp> +#include <boost/python/refcount.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/ssize_t.hpp> + +#include <boost/python/detail/signature.hpp> +#include <boost/python/detail/none.hpp> +#include <boost/mpl/vector/vector10.hpp> + +#include <boost/bind.hpp> + +#include <algorithm> +#include <cstring> + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES +# include <cstdio> +#endif + +namespace boost { namespace python { + volatile bool docstring_options::show_user_defined_ = true; + volatile bool docstring_options::show_cpp_signatures_ = true; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + volatile bool docstring_options::show_py_signatures_ = true; +#else + volatile bool docstring_options::show_py_signatures_ = false; +#endif +}} + +namespace boost { namespace python { namespace objects { + +py_function_impl_base::~py_function_impl_base() +{ +} + +unsigned py_function_impl_base::max_arity() const +{ + return this->min_arity(); +} + +extern PyTypeObject function_type; + +function::function( + py_function const& implementation +#if BOOST_WORKAROUND(__EDG_VERSION__, == 245) + , python::detail::keyword const* names_and_defaults +#else + , python::detail::keyword const* const names_and_defaults +#endif + , unsigned num_keywords + ) + : m_fn(implementation) + , m_nkeyword_values(0) +{ + if (names_and_defaults != 0) + { + unsigned int max_arity = m_fn.max_arity(); + unsigned int keyword_offset + = max_arity > num_keywords ? max_arity - num_keywords : 0; + + + ssize_t tuple_size = num_keywords ? max_arity : 0; + m_arg_names = object(handle<>(PyTuple_New(tuple_size))); + + if (num_keywords != 0) + { + for (unsigned j = 0; j < keyword_offset; ++j) + PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); + } + + for (unsigned i = 0; i < num_keywords; ++i) + { + tuple kv; + + python::detail::keyword const* const p = names_and_defaults + i; + if (p->default_value) + { + kv = make_tuple(p->name, p->default_value); + ++m_nkeyword_values; + } + else + { + kv = make_tuple(p->name); + } + + PyTuple_SET_ITEM( + m_arg_names.ptr() + , i + keyword_offset + , incref(kv.ptr()) + ); + } + } + + PyObject* p = this; + if (Py_TYPE(&function_type) == 0) + { + Py_TYPE(&function_type) = &PyType_Type; + ::PyType_Ready(&function_type); + } + + (void)( // warning suppression for GCC + PyObject_INIT(p, &function_type) + ); +} + +function::~function() +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args); + std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0; + std::size_t n_actual = n_unnamed_actual + n_keyword_actual; + + function const* f = this; + + // Try overloads looking for a match + do + { + // Check for a plausible number of arguments + unsigned min_arity = f->m_fn.min_arity(); + unsigned max_arity = f->m_fn.max_arity(); + + if (n_actual + f->m_nkeyword_values >= min_arity + && n_actual <= max_arity) + { + // This will be the args that actually get passed + handle<>inner_args(allow_null(borrowed(args))); + + if (n_keyword_actual > 0 // Keyword arguments were supplied + || n_actual < min_arity) // or default keyword values are needed + { + if (f->m_arg_names.is_none()) + { + // this overload doesn't accept keywords + inner_args = handle<>(); + } + else + { + // "all keywords are none" is a special case + // indicating we will accept any number of keyword + // arguments + if (PyTuple_Size(f->m_arg_names.ptr()) == 0) + { + // no argument preprocessing + } + else if (n_actual > max_arity) + { + // too many arguments + inner_args = handle<>(); + } + else + { + // build a new arg tuple, will adjust its size later + assert(max_arity <= static_cast<std::size_t>(ssize_t_max)); + inner_args = handle<>( + PyTuple_New(static_cast<ssize_t>(max_arity))); + + // Fill in the positional arguments + for (std::size_t i = 0; i < n_unnamed_actual; ++i) + PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i))); + + // Grab remaining arguments by name from the keyword dictionary + std::size_t n_actual_processed = n_unnamed_actual; + + for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos) + { + // Get the keyword[, value pair] corresponding + PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos); + + // If there were any keyword arguments, + // look up the one we need for this + // argument position + PyObject* value = n_keyword_actual + ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0)) + : 0; + + if (!value) + { + // Not found; check if there's a default value + if (PyTuple_GET_SIZE(kv) > 1) + value = PyTuple_GET_ITEM(kv, 1); + + if (!value) + { + // still not found; matching fails + PyErr_Clear(); + inner_args = handle<>(); + break; + } + } + else + { + ++n_actual_processed; + } + + PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value)); + } + + if (inner_args.get()) + { + //check if we proccessed all the arguments + if(n_actual_processed < n_actual) + inner_args = handle<>(); + } + } + } + } + + // Call the function. Pass keywords in case it's a + // function accepting any number of keywords + PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0; + + // If the result is NULL but no error was set, m_fn failed + // the argument-matching test. + + // This assumes that all other error-reporters are + // well-behaved and never return NULL to python without + // setting an error. + if (result != 0 || PyErr_Occurred()) + return result; + } + f = f->m_overloads.get(); + } + while (f); + // None of the overloads matched; time to generate the error message + argument_error(args, keywords); + return 0; +} + +object function::signature(bool show_return_type) const +{ + py_function const& impl = m_fn; + + python::detail::signature_element const* return_type = impl.signature(); + python::detail::signature_element const* s = return_type + 1; + + list formal_params; + if (impl.max_arity() == 0) + formal_params.append("void"); + + for (unsigned n = 0; n < impl.max_arity(); ++n) + { + if (s[n].basename == 0) + { + formal_params.append("..."); + break; + } + + str param(s[n].basename); + if (s[n].lvalue) + param += " {lvalue}"; + + if (m_arg_names) // None or empty tuple will test false + { + object kv(m_arg_names[n]); + if (kv) + { + char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s"; + param += fmt % kv; + } + } + + formal_params.append(param); + } + + if (show_return_type) + return "%s(%s) -> %s" % make_tuple( + m_name, str(", ").join(formal_params), return_type->basename); + return "%s(%s)" % make_tuple( + m_name, str(", ").join(formal_params)); +} + +object function::signatures(bool show_return_type) const +{ + list result; + for (function const* f = this; f; f = f->m_overloads.get()) { + result.append(f->signature(show_return_type)); + } + return result; +} + +void function::argument_error(PyObject* args, PyObject* /*keywords*/) const +{ + static handle<> exception( + PyErr_NewException(const_cast<char*>("Boost.Python.ArgumentError"), PyExc_TypeError, 0)); + + object message = "Python argument types in\n %s.%s(" + % make_tuple(this->m_namespace, this->m_name); + + list actual_args; + for (ssize_t i = 0; i < PyTuple_Size(args); ++i) + { + char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; + actual_args.append(str(name)); + } + message += str(", ").join(actual_args); + message += ")\ndid not match C++ signature:\n "; + message += str("\n ").join(signatures()); + +#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES + std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)()); +#endif + PyErr_SetObject(exception.get(), message.ptr()); + throw_error_already_set(); +} + +void function::add_overload(handle<function> const& overload_) +{ + function* parent = this; + + while (parent->m_overloads) + parent = parent->m_overloads.get(); + + parent->m_overloads = overload_; + + // If we have no documentation, get the docs from the overload + if (!m_doc) + m_doc = overload_->m_doc; +} + +namespace +{ + char const* const binary_operator_names[] = + { + "add__", + "and__", + "div__", + "divmod__", + "eq__", + "floordiv__", + "ge__", + "gt__", + "le__", + "lshift__", + "lt__", + "mod__", + "mul__", + "ne__", + "or__", + "pow__", + "radd__", + "rand__", + "rdiv__", + "rdivmod__", + "rfloordiv__", + "rlshift__", + "rmod__", + "rmul__", + "ror__", + "rpow__", + "rrshift__", + "rshift__", + "rsub__", + "rtruediv__", + "rxor__", + "sub__", + "truediv__", + "xor__" + }; + + struct less_cstring + { + bool operator()(char const* x, char const* y) const + { + return BOOST_CSTD_::strcmp(x,y) < 0; + } + }; + + inline bool is_binary_operator(char const* name) + { + return name[0] == '_' + && name[1] == '_' + && std::binary_search( + &binary_operator_names[0] + , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names) + , name + 2 + , less_cstring() + ); + } + + // Something for the end of the chain of binary operators + PyObject* not_implemented(PyObject*, PyObject*) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + handle<function> not_implemented_function() + { + + static object keeper( + function_object( + py_function(¬_implemented, mpl::vector1<void>(), 2) + , python::detail::keyword_range()) + ); + return handle<function>(borrowed(downcast<function>(keeper.ptr()))); + } +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute) +{ + add_to_namespace(name_space, name_, attribute, 0); +} + +namespace detail +{ + extern char py_signature_tag[]; + extern char cpp_signature_tag[]; +} + +void function::add_to_namespace( + object const& name_space, char const* name_, object const& attribute, char const* doc) +{ + str const name(name_); + PyObject* const ns = name_space.ptr(); + + if (attribute.ptr()->ob_type == &function_type) + { + function* new_func = downcast<function>(attribute.ptr()); + handle<> dict; + +#if PY_VERSION_HEX < 0x03000000 + // Old-style class gone in Python 3 + if (PyClass_Check(ns)) + dict = handle<>(borrowed(((PyClassObject*)ns)->cl_dict)); + else +#endif + if (PyType_Check(ns)) + dict = handle<>(borrowed(((PyTypeObject*)ns)->tp_dict)); + else + dict = handle<>(PyObject_GetAttrString(ns, const_cast<char*>("__dict__"))); + + if (dict == 0) + throw_error_already_set(); + + handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr()))); + + if (existing) + { + if (existing->ob_type == &function_type) + { + new_func->add_overload( + handle<function>( + borrowed( + downcast<function>(existing.get()) + ) + ) + ); + } + else if (existing->ob_type == &PyStaticMethod_Type) + { + char const* name_space_name = extract<char const*>(name_space.attr("__name__")); + + ::PyErr_Format( + PyExc_RuntimeError + , "Boost.Python - All overloads must be exported " + "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'" + , name_space_name + , name_ + ); + throw_error_already_set(); + } + } + else if (is_binary_operator(name_)) + { + // Binary operators need an additional overload which + // returns NotImplemented, so that Python will try the + // __rxxx__ functions on the other operand. We add this + // when no overloads for the operator already exist. + new_func->add_overload(not_implemented_function()); + } + + // A function is named the first time it is added to a namespace. + if (new_func->name().is_none()) + new_func->m_name = name; + + handle<> name_space_name( + allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast<char*>("__name__")))); + + if (name_space_name) + new_func->m_namespace = object(name_space_name); + } + + // The PyObject_GetAttrString() or PyObject_GetItem calls above may + // have left an active error + PyErr_Clear(); + if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) + throw_error_already_set(); + + object mutable_attribute(attribute); +/* + if (doc != 0 && docstring_options::show_user_defined_) + { + // Accumulate documentation + + if ( + PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) + { + mutable_attribute.attr("__doc__") += "\n\n"; + mutable_attribute.attr("__doc__") += doc; + } + else { + mutable_attribute.attr("__doc__") = doc; + } + } + + if (docstring_options::show_signatures_) + { + if ( PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__") + && mutable_attribute.attr("__doc__")) { + mutable_attribute.attr("__doc__") += ( + mutable_attribute.attr("__doc__")[-1] != "\n" ? "\n\n" : "\n"); + } + else { + mutable_attribute.attr("__doc__") = ""; + } + function* f = downcast<function>(attribute.ptr()); + mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple( + "C++ signature:", f->signature(true))); + } + */ + str _doc; + + if (docstring_options::show_py_signatures_) + { + _doc += str(const_cast<const char*>(detail::py_signature_tag)); + } + if (doc != 0 && docstring_options::show_user_defined_) + _doc += doc; + + if (docstring_options::show_cpp_signatures_) + { + _doc += str(const_cast<const char*>(detail::cpp_signature_tag)); + } + if(_doc) + { + object mutable_attribute(attribute); + mutable_attribute.attr("__doc__")= _doc; + } +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute) +{ + function::add_to_namespace(name_space, name, attribute, 0); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc) +{ + function::add_to_namespace(name_space, name, attribute, doc); +} + + +namespace +{ + struct bind_return + { + bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords) + : m_result(result) + , m_f(f) + , m_args(args) + , m_keywords(keywords) + {} + + void operator()() const + { + m_result = m_f->call(m_args, m_keywords); + } + + private: + PyObject*& m_result; + function const* m_f; + PyObject* m_args; + PyObject* m_keywords; + }; +} + +extern "C" +{ + // Stolen from Python's funcobject.c + static PyObject * + function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) + { +#if PY_VERSION_HEX >= 0x03000000 + // The implement is different in Python 3 because of the removal of unbound method + if (obj == Py_None || obj == NULL) { + Py_INCREF(func); + return func; + } + return PyMethod_New(func, obj); +#else + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type_); +#endif + } + + static void + function_dealloc(PyObject* p) + { + delete static_cast<function*>(p); + } + + static PyObject * + function_call(PyObject *func, PyObject *args, PyObject *kw) + { + PyObject* result = 0; + handle_exception(bind_return(result, static_cast<function*>(func), args, kw)); + return result; + } + + // + // Here we're using the function's tp_getset rather than its + // tp_members to set up __doc__ and __name__, because tp_members + // really depends on having a POD object type (it relies on + // offsets). It might make sense to reformulate function as a POD + // at some point, but this is much more expedient. + // + static PyObject* function_get_doc(PyObject* op, void*) + { + function* f = downcast<function>(op); + list signatures = function_doc_signature_generator::function_doc_signatures(f); + if(!signatures) return python::detail::none(); + signatures.reverse(); + return python::incref( str("\n").join(signatures).ptr()); + } + + static int function_set_doc(PyObject* op, PyObject* doc, void*) + { + function* f = downcast<function>(op); + f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object()); + return 0; + } + + static PyObject* function_get_name(PyObject* op, void*) + { + function* f = downcast<function>(op); + if (f->name().is_none()) +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString("<unnamed Boost.Python function>"); +#else + return PyString_InternFromString("<unnamed Boost.Python function>"); +#endif + else + return python::incref(f->name().ptr()); + } + + // We add a dummy __class__ attribute in order to fool PyDoc into + // treating these as built-in functions and scanning their + // documentation + static PyObject* function_get_class(PyObject* /*op*/, void*) + { + return python::incref(upcast<PyObject>(&PyCFunction_Type)); + } + + static PyObject* function_get_module(PyObject* op, void*) + { + function* f = downcast<function>(op); + object const& ns = f->get_namespace(); + if (!ns.is_none()) { + return python::incref(ns.ptr()); + } + PyErr_SetString( + PyExc_AttributeError, const_cast<char*>( + "Boost.Python function __module__ unknown.")); + return 0; + } +} + +static PyGetSetDef function_getsetlist[] = { + {const_cast<char*>("__name__"), (getter)function_get_name, 0, 0, 0 }, + {const_cast<char*>("func_name"), (getter)function_get_name, 0, 0, 0 }, + {const_cast<char*>("__module__"), (getter)function_get_module, 0, 0, 0 }, + {const_cast<char*>("func_module"), (getter)function_get_module, 0, 0, 0 }, + {const_cast<char*>("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above + {const_cast<char*>("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {const_cast<char*>("func_doc"), (getter)function_get_doc, (setter)function_set_doc, 0, 0}, + {NULL, 0, 0, 0, 0} /* Sentinel */ +}; + +PyTypeObject function_type = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Boost.Python.function"), + sizeof(function), + 0, + (destructor)function_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + function_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + function_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +object function_object( + py_function const& f + , python::detail::keyword_range const& keywords) +{ + return python::object( + python::detail::new_non_null_reference( + new function( + f, keywords.first, keywords.second - keywords.first))); +} + +object function_object(py_function const& f) +{ + return function_object(f, python::detail::keyword_range()); +} + + +handle<> function_handle_impl(py_function const& f) +{ + return python::handle<>( + allow_null( + new function(f, 0, 0))); +} + +} // namespace objects + +namespace detail +{ + object BOOST_PYTHON_DECL make_raw_function(objects::py_function f) + { + static keyword k; + + return objects::function_object( + f + , keyword_range(&k,&k)); + } + void BOOST_PYTHON_DECL pure_virtual_called() + { + PyErr_SetString( + PyExc_RuntimeError, const_cast<char*>("Pure virtual function called")); + throw_error_already_set(); + } +} + +}} // namespace boost::python diff --git a/libs/python/src/object/function_doc_signature.cpp b/libs/python/src/object/function_doc_signature.cpp new file mode 100644 index 000000000..41695285a --- /dev/null +++ b/libs/python/src/object/function_doc_signature.cpp @@ -0,0 +1,344 @@ +// Copyright Nikolay Mladenov 2007. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// boost::python::make_tuple below are for gcc 4.4 -std=c++0x compatibility +// (Intel C++ 10 and 11 with -std=c++0x don't need the full qualification). + +#include <boost/python/converter/registrations.hpp> +#include <boost/python/object/function_doc_signature.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/str.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> + +#include <boost/python/detail/signature.hpp> + +#include <vector> + +namespace boost { namespace python { namespace objects { + + bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 ) + { + return f1->m_fn.max_arity() < f2->m_fn.max_arity(); + } + + bool function_doc_signature_generator::are_seq_overloads( function const *f1, function const *f2 , bool check_docs) + { + py_function const & impl1 = f1->m_fn; + py_function const & impl2 = f2->m_fn; + + //the number of parameters differs by 1 + if (impl2.max_arity()-impl1.max_arity() != 1) + return false; + + // if check docs then f1 shold not have docstring or have the same docstring as f2 + if (check_docs && f2->doc() != f1->doc() && f1->doc()) + return false; + + python::detail::signature_element const* s1 = impl1.signature(); + python::detail::signature_element const* s2 = impl2.signature(); + + unsigned size = impl1.max_arity()+1; + + for (unsigned i = 0; i != size; ++i) + { + //check if the argument types are the same + if (s1[i].basename != s2[i].basename) + return false; + + //return type + if (!i) continue; + + //check if the argument default values are the same + bool f1_has_names = bool(f1->m_arg_names); + bool f2_has_names = bool(f2->m_arg_names); + if ( (f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]) + || (f1_has_names && !f2_has_names) + || (!f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object()) + ) + return false; + } + return true; + } + + std::vector<function const*> function_doc_signature_generator::flatten(function const *f) + { + object name = f->name(); + + std::vector<function const*> res; + + while (f) { + + //this if takes out the not_implemented_function + if (f->name() == name) + res.push_back(f); + + f=f->m_overloads.get(); + } + + //std::sort(res.begin(),res.end(), &arity_cmp); + + return res; + } + std::vector<function const*> function_doc_signature_generator::split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change) + { + std::vector<function const*> res; + + std::vector<function const*>::const_iterator fi = funcs.begin(); + + function const * last = *fi; + + while (++fi != funcs.end()){ + + //check if fi starts a new chain of overloads + if (!are_seq_overloads( last, *fi, split_on_doc_change )) + res.push_back(last); + + last = *fi; + } + + if (last) + res.push_back(last); + + return res; + } + + str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + str res("object"); + + res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) ); + + return res; + } + + const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s) + { + if (s.basename==std::string("void")){ + static const char * none = "None"; + return none; + } + + PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0; + if ( py_type ) + return py_type->tp_name; + else{ + static const char * object = "object"; + return object; + } + } + + str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types) + { + str param; + + python::detail::signature_element const * s = f.signature(); + if (cpp_types) + { + if(!n) + s = &f.get_return_type(); + if (s[n].basename == 0) + { + return str("..."); + } + + param = str(s[n].basename); + + if (s[n].lvalue) + param += " {lvalue}"; + + } + else + { + if (n) //we are processing an argument and trying to come up with a name for it + { + object kv; + if ( arg_names && (kv = arg_names[n-1]) ) + param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) ); + else + param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) ); + } + else //we are processing the return type + param = py_type_str(f.get_return_type()); + } + + //an argument - check for default value and append it + if(n && arg_names) + { + object kv(arg_names[n-1]); + if (kv && len(kv) == 2) + { + param = str("%s=%r" % make_tuple(param, kv[1])); + } + } + return param; + } + + str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + py_function + const& impl = f->m_fn; + ; + + + unsigned arity = impl.max_arity(); + + if(arity == unsigned(-1))// is this the proper raw function test? + { + return raw_function_pretty_signature(f,n_overloads,cpp_types); + } + + list formal_params; + + size_t n_extra_default_args=0; + + for (unsigned n = 0; n <= arity; ++n) + { + str param; + + formal_params.append( + parameter_string(impl, n, f->m_arg_names, cpp_types) + ); + + // find all the arguments with default values preceeding the arity-n_overloads + if (n && f->m_arg_names) + { + object kv(f->m_arg_names[n-1]); + + if (kv && len(kv) == 2) + { + //default argument preceeding the arity-n_overloads + if( n <= arity-n_overloads) + ++n_extra_default_args; + } + else + //argument without default, preceeding the arity-n_overloads + if( n <= arity-n_overloads) + n_extra_default_args = 0; + } + } + + n_overloads+=n_extra_default_args; + + if (!arity && cpp_types) + formal_params.append("void"); + + str ret_type (formal_params.pop(0)); + if (cpp_types ) + { + return str( + "%s %s(%s%s%s%s)" + % boost::python::make_tuple // workaround, see top + ( ret_type + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + )); + }else{ + return str( + "%s(%s%s%s%s) -> %s" + % boost::python::make_tuple // workaround, see top + ( f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , ret_type + )); + } + + return str( + "%s %s(%s%s%s%s) %s" + % boost::python::make_tuple // workaround, see top + ( cpp_types?ret_type:str("") + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , cpp_types?str(""):ret_type + )); + + } + + namespace detail { + char py_signature_tag[] = "PY signature :"; + char cpp_signature_tag[] = "C++ signature :"; + } + + list function_doc_signature_generator::function_doc_signatures( function const * f) + { + list signatures; + std::vector<function const*> funcs = flatten( f); + std::vector<function const*> split_funcs = split_seq_overloads( funcs, true); + std::vector<function const*>::const_iterator sfi=split_funcs.begin(), fi; + size_t n_overloads=0; + for (fi=funcs.begin(); fi!=funcs.end(); ++fi) + { + if(*sfi == *fi){ + if((*fi)->doc()) + { + str func_doc = str((*fi)->doc()); + + int doc_len = len(func_doc); + + bool show_py_signature = doc_len >= int(sizeof(detail::py_signature_tag)/sizeof(char)-1) + && str(detail::py_signature_tag) == func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1); + if(show_py_signature) + { + func_doc = str(func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1, _)); + doc_len = len(func_doc); + } + + bool show_cpp_signature = doc_len >= int(sizeof(detail::cpp_signature_tag)/sizeof(char)-1) + && str(detail::cpp_signature_tag) == func_doc.slice( 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)), _); + + if(show_cpp_signature) + { + func_doc = str(func_doc.slice(_, 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)))); + doc_len = len(func_doc); + } + + str res="\n"; + str pad = "\n"; + + if(show_py_signature) + { + str sig = pretty_signature(*fi, n_overloads,false); + res+=sig; + if(doc_len || show_cpp_signature )res+=" :"; + pad+= str(" "); + } + + if(doc_len) + { + if(show_py_signature) + res+=pad; + res+= pad.join(func_doc.split("\n")); + } + + if( show_cpp_signature) + { + if(len(res)>1) + res+="\n"+pad; + res+=detail::cpp_signature_tag+pad+" "+pretty_signature(*fi, n_overloads,true); + } + + signatures.append(res); + } + ++sfi; + n_overloads = 0; + }else + ++n_overloads ; + } + + return signatures; + } + + +}}} + diff --git a/libs/python/src/object/inheritance.cpp b/libs/python/src/object/inheritance.cpp new file mode 100644 index 000000000..7dc9db1cd --- /dev/null +++ b/libs/python/src/object/inheritance.cpp @@ -0,0 +1,495 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/object/inheritance.hpp> +#include <boost/python/type_id.hpp> +#include <boost/graph/breadth_first_search.hpp> +#if _MSC_FULL_VER >= 13102171 && _MSC_FULL_VER <= 13102179 +# include <boost/graph/reverse_graph.hpp> +#endif +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/reverse_graph.hpp> +#include <boost/property_map/property_map.hpp> +#include <boost/bind.hpp> +#include <boost/integer_traits.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/tuple/tuple_comparison.hpp> +#include <queue> +#include <vector> +#include <functional> + +// +// Procedure: +// +// The search is a BFS over the space of (type,address) pairs +// guided by the edges of the casting graph whose nodes +// correspond to classes, and whose edges are traversed by +// applying associated cast functions to an address. We use +// vertex distance to the goal node in the cast_graph to rate the +// paths. The vertex distance to any goal node is calculated on +// demand and outdated by the addition of edges to the graph. + +namespace boost { +namespace +{ + enum edge_cast_t { edge_cast = 8010 }; + template <class T> inline void unused_variable(const T&) { } +} + +// Install properties +BOOST_INSTALL_PROPERTY(edge, cast); + +namespace +{ + typedef void*(*cast_function)(void*); + + // + // Here we put together the low-level data structures of the + // casting graph representation. + // + typedef python::type_info class_id; + + // represents a graph of available casts + +#if 0 + struct cast_graph + : +#else + typedef +#endif + adjacency_list<vecS,vecS, bidirectionalS, no_property + + // edge index property allows us to look up edges in the connectivity matrix + , property<edge_index_t,std::size_t + + // The function which casts a void* from the edge's source type + // to its destination type. + , property<edge_cast_t,cast_function> > > +#if 0 + {}; +#else + cast_graph; +#endif + + typedef cast_graph::vertex_descriptor vertex_t; + typedef cast_graph::edge_descriptor edge_t; + + struct smart_graph + { + typedef std::vector<std::size_t>::const_iterator node_distance_map; + + typedef std::pair<cast_graph::out_edge_iterator + , cast_graph::out_edge_iterator> out_edges_t; + + // Return a map of the distances from any node to the given + // target node + node_distance_map distances_to(vertex_t target) const + { + std::size_t n = num_vertices(m_topology); + if (m_distances.size() != n * n) + { + m_distances.clear(); + m_distances.resize(n * n, (std::numeric_limits<std::size_t>::max)()); + m_known_vertices = n; + } + + std::vector<std::size_t>::iterator to_target = m_distances.begin() + n * target; + + // this node hasn't been used as a target yet + if (to_target[target] != 0) + { + typedef reverse_graph<cast_graph> reverse_cast_graph; + reverse_cast_graph reverse_topology(m_topology); + + to_target[target] = 0; + + breadth_first_search( + reverse_topology, target + , visitor( + make_bfs_visitor( + record_distances( + make_iterator_property_map( + to_target + , get(vertex_index, reverse_topology) +# ifdef BOOST_NO_STD_ITERATOR_TRAITS + , *to_target +# endif + ) + , on_tree_edge() + )))); + } + + return to_target; + } + + cast_graph& topology() { return m_topology; } + cast_graph const& topology() const { return m_topology; } + + smart_graph() + : m_known_vertices(0) + {} + + private: + cast_graph m_topology; + mutable std::vector<std::size_t> m_distances; + mutable std::size_t m_known_vertices; + }; + + smart_graph& full_graph() + { + static smart_graph x; + return x; + } + + smart_graph& up_graph() + { + static smart_graph x; + return x; + } + + // + // Our index of class types + // + using boost::python::objects::dynamic_id_function; + typedef tuples::tuple< + class_id // static type + , vertex_t // corresponding vertex + , dynamic_id_function // dynamic_id if polymorphic, or 0 + > + index_entry_interface; + typedef index_entry_interface::inherited index_entry; + enum { ksrc_static_t, kvertex, kdynamic_id }; + + typedef std::vector<index_entry> type_index_t; + + + type_index_t& type_index() + { + static type_index_t x; + return x; + } + + template <class Tuple> + struct select1st + { + typedef typename tuples::element<0, Tuple>::type result_type; + + result_type const& operator()(Tuple const& x) const + { + return tuples::get<0>(x); + } + }; + + // map a type to a position in the index + inline type_index_t::iterator type_position(class_id type) + { + typedef index_entry entry; + + return std::lower_bound( + type_index().begin(), type_index().end() + , boost::make_tuple(type, vertex_t(), dynamic_id_function(0)) + , boost::bind<bool>(std::less<class_id>() + , boost::bind<class_id>(select1st<entry>(), _1) + , boost::bind<class_id>(select1st<entry>(), _2))); + } + + inline index_entry* seek_type(class_id type) + { + type_index_t::iterator p = type_position(type); + if (p == type_index().end() || tuples::get<ksrc_static_t>(*p) != type) + return 0; + else + return &*p; + } + + // Get the entry for a type, inserting if necessary + inline type_index_t::iterator demand_type(class_id type) + { + type_index_t::iterator p = type_position(type); + + if (p != type_index().end() && tuples::get<ksrc_static_t>(*p) == type) + return p; + + vertex_t v = add_vertex(full_graph().topology()); + vertex_t v2 = add_vertex(up_graph().topology()); + unused_variable(v2); + assert(v == v2); + return type_index().insert(p, boost::make_tuple(type, v, dynamic_id_function(0))); + } + + // Map a two types to a vertex in the graph, inserting if necessary + typedef std::pair<type_index_t::iterator, type_index_t::iterator> + type_index_iterator_pair; + + inline type_index_iterator_pair + demand_types(class_id t1, class_id t2) + { + // be sure there will be no reallocation + type_index().reserve(type_index().size() + 2); + type_index_t::iterator first = demand_type(t1); + type_index_t::iterator second = demand_type(t2); + if (first == second) + ++first; + return std::make_pair(first, second); + } + + struct q_elt + { + q_elt(std::size_t distance + , void* src_address + , vertex_t target + , cast_function cast + ) + : distance(distance) + , src_address(src_address) + , target(target) + , cast(cast) + {} + + std::size_t distance; + void* src_address; + vertex_t target; + cast_function cast; + + bool operator<(q_elt const& rhs) const + { + return distance < rhs.distance; + } + }; + + // Optimization: + // + // Given p, src_t, dst_t + // + // Get a pointer pd to the most-derived object + // if it's polymorphic, dynamic_cast to void* + // otherwise pd = p + // + // Get the most-derived typeid src_td + // + // ptrdiff_t offset = p - pd + // + // Now we can keep a cache, for [src_t, offset, src_td, dst_t] of + // the cast transformation function to use on p and the next src_t + // in the chain. src_td, dst_t don't change throughout this + // process. In order to represent unreachability, when a pair is + // found to be unreachable, we stick a 0-returning "dead-cast" + // function in the cache. + + // This is needed in a few places below + inline void* identity_cast(void* p) + { + return p; + } + + void* search(smart_graph const& g, void* p, vertex_t src, vertex_t dst) + { + // I think this test was thoroughly bogus -- dwa + // If we know there's no path; bail now. + // if (src > g.known_vertices() || dst > g.known_vertices()) + // return 0; + + smart_graph::node_distance_map d(g.distances_to(dst)); + + if (d[src] == (std::numeric_limits<std::size_t>::max)()) + return 0; + + typedef property_map<cast_graph,edge_cast_t>::const_type cast_map; + cast_map casts = get(edge_cast, g.topology()); + + typedef std::pair<vertex_t,void*> search_state; + typedef std::vector<search_state> visited_t; + visited_t visited; + std::priority_queue<q_elt> q; + + q.push(q_elt(d[src], p, src, identity_cast)); + while (!q.empty()) + { + q_elt top = q.top(); + q.pop(); + + // Check to see if we have a real state + void* dst_address = top.cast(top.src_address); + if (dst_address == 0) + continue; + + if (top.target == dst) + return dst_address; + + search_state s(top.target,dst_address); + + visited_t::iterator pos = std::lower_bound( + visited.begin(), visited.end(), s); + + // If already visited, continue + if (pos != visited.end() && *pos == s) + continue; + + visited.insert(pos, s); // mark it + + // expand it: + smart_graph::out_edges_t edges = out_edges(s.first, g.topology()); + for (cast_graph::out_edge_iterator p = edges.first + , finish = edges.second + ; p != finish + ; ++p + ) + { + edge_t e = *p; + q.push(q_elt( + d[target(e, g.topology())] + , dst_address + , target(e, g.topology()) + , boost::get(casts, e))); + } + } + return 0; + } + + struct cache_element + { + typedef tuples::tuple< + class_id // source static type + , class_id // target type + , std::ptrdiff_t // offset within source object + , class_id // source dynamic type + >::inherited key_type; + + cache_element(key_type const& k) + : key(k) + , offset(0) + {} + + key_type key; + std::ptrdiff_t offset; + + BOOST_STATIC_CONSTANT( + std::ptrdiff_t, not_found = integer_traits<std::ptrdiff_t>::const_min); + + bool operator<(cache_element const& rhs) const + { + return this->key < rhs.key; + } + + bool unreachable() const + { + return offset == not_found; + } + }; + + enum { kdst_t = ksrc_static_t + 1, koffset, ksrc_dynamic_t }; + typedef std::vector<cache_element> cache_t; + + cache_t& cache() + { + static cache_t x; + return x; + } + + inline void* convert_type(void* const p, class_id src_t, class_id dst_t, bool polymorphic) + { + // Quickly rule out unregistered types + index_entry* src_p = seek_type(src_t); + if (src_p == 0) + return 0; + + index_entry* dst_p = seek_type(dst_t); + if (dst_p == 0) + return 0; + + // Look up the dynamic_id function and call it to get the dynamic + // info + boost::python::objects::dynamic_id_t dynamic_id = polymorphic + ? tuples::get<kdynamic_id>(*src_p)(p) + : std::make_pair(p, src_t); + + // Look in the cache first for a quickie address translation + std::ptrdiff_t offset = (char*)p - (char*)dynamic_id.first; + + cache_element seek(boost::make_tuple(src_t, dst_t, offset, dynamic_id.second)); + cache_t& c = cache(); + cache_t::iterator const cache_pos + = std::lower_bound(c.begin(), c.end(), seek); + + + // if found in the cache, we're done + if (cache_pos != c.end() && cache_pos->key == seek.key) + { + return cache_pos->offset == cache_element::not_found + ? 0 : (char*)p + cache_pos->offset; + } + + // If we are starting at the most-derived type, only look in the up graph + smart_graph const& g = polymorphic && dynamic_id.second != src_t + ? full_graph() : up_graph(); + + void* result = search( + g, p, tuples::get<kvertex>(*src_p) + , tuples::get<kvertex>(*dst_p)); + + // update the cache + c.insert(cache_pos, seek)->offset + = (result == 0) ? cache_element::not_found : (char*)result - (char*)p; + + return result; + } +} + +namespace python { namespace objects { + +BOOST_PYTHON_DECL void* find_dynamic_type(void* p, class_id src_t, class_id dst_t) +{ + return convert_type(p, src_t, dst_t, true); +} + +BOOST_PYTHON_DECL void* find_static_type(void* p, class_id src_t, class_id dst_t) +{ + return convert_type(p, src_t, dst_t, false); +} + +BOOST_PYTHON_DECL void add_cast( + class_id src_t, class_id dst_t, cast_function cast, bool is_downcast) +{ + // adding an edge will invalidate any record of unreachability in + // the cache. + static std::size_t expected_cache_len = 0; + cache_t& c = cache(); + if (c.size() > expected_cache_len) + { + c.erase(std::remove_if( + c.begin(), c.end(), + mem_fn(&cache_element::unreachable)) + , c.end()); + + // If any new cache entries get added, we'll have to do this + // again when the next edge is added + expected_cache_len = c.size(); + } + + type_index_iterator_pair types = demand_types(src_t, dst_t); + vertex_t src = tuples::get<kvertex>(*types.first); + vertex_t dst = tuples::get<kvertex>(*types.second); + + cast_graph* const g[2] = { &up_graph().topology(), &full_graph().topology() }; + + for (cast_graph*const* p = g + (is_downcast ? 1 : 0); p < g + 2; ++p) + { + edge_t e; + bool added; + + tie(e, added) = add_edge(src, dst, **p); + assert(added); + + put(get(edge_cast, **p), e, cast); + put(get(edge_index, **p), e, num_edges(full_graph().topology()) - 1); + } +} + +BOOST_PYTHON_DECL void register_dynamic_id_aux( + class_id static_id, dynamic_id_function get_dynamic_id) +{ + tuples::get<kdynamic_id>(*demand_type(static_id)) = get_dynamic_id; +} + +}}} // namespace boost::python::objects diff --git a/libs/python/src/object/iterator.cpp b/libs/python/src/object/iterator.cpp new file mode 100644 index 000000000..3f6c4adac --- /dev/null +++ b/libs/python/src/object/iterator.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/object/iterator_core.hpp> +#include <boost/python/object/function_object.hpp> +#include <boost/bind.hpp> +#include <boost/mpl/vector/vector10.hpp> + +namespace boost { namespace python { namespace objects { + +namespace +{ + PyObject* identity(PyObject* args_, PyObject*) + { + PyObject* x = PyTuple_GET_ITEM(args_,0); + Py_INCREF(x); + return x; + } +} + +BOOST_PYTHON_DECL object const& identity_function() +{ + static object result( + function_object( + py_function(&identity, mpl::vector2<PyObject*,PyObject*>()) + ) + ); + return result; +} + +void stop_iteration_error() +{ + PyErr_SetObject(PyExc_StopIteration, Py_None); + throw_error_already_set(); +} + +}}} // namespace boost::python::objects diff --git a/libs/python/src/object/life_support.cpp b/libs/python/src/object/life_support.cpp new file mode 100644 index 000000000..b7e9aa861 --- /dev/null +++ b/libs/python/src/object/life_support.cpp @@ -0,0 +1,121 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/object/life_support.hpp> +#include <boost/python/detail/none.hpp> +#include <boost/python/refcount.hpp> + +namespace boost { namespace python { namespace objects { + +struct life_support +{ + PyObject_HEAD + PyObject* patient; +}; + +extern "C" +{ + static void + life_support_dealloc(PyObject* self) + { + Py_XDECREF(((life_support*)self)->patient); + self->ob_type->tp_free(self); + } + + static PyObject * + life_support_call(PyObject *self, PyObject *arg, PyObject * /*kw*/) + { + // Let the patient die now + Py_XDECREF(((life_support*)self)->patient); + ((life_support*)self)->patient = 0; + // Let the weak reference die. This probably kills us. + Py_XDECREF(PyTuple_GET_ITEM(arg, 0)); + return ::boost::python::detail::none(); + } +} + +PyTypeObject life_support_type = { + PyVarObject_HEAD_INIT(NULL, 0)//(&PyType_Type) + const_cast<char*>("Boost.Python.life_support"), + sizeof(life_support), + 0, + life_support_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + life_support_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyLife_SupportObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + 0, //func_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyLife_SupportObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) +{ + if (nurse == Py_None || nurse == patient) + return nurse; + + if (Py_TYPE(&life_support_type) == 0) + { + Py_TYPE(&life_support_type) = &PyType_Type; + PyType_Ready(&life_support_type); + } + + life_support* system = PyObject_New(life_support, &life_support_type); + if (!system) + return 0; + + system->patient = 0; + + // We're going to leak this reference, but don't worry; the + // life_support system decrements it when the nurse dies. + PyObject* weakref = PyWeakref_NewRef(nurse, (PyObject*)system); + + // weakref has either taken ownership, or we have to release it + // anyway + Py_DECREF(system); + if (!weakref) + return 0; + + system->patient = patient; + Py_XINCREF(patient); // hang on to the patient until death + return weakref; +} + +}}} // namespace boost::python::objects diff --git a/libs/python/src/object/pickle_support.cpp b/libs/python/src/object/pickle_support.cpp new file mode 100644 index 000000000..428c07b6c --- /dev/null +++ b/libs/python/src/object/pickle_support.cpp @@ -0,0 +1,78 @@ +// (C) Copyright R.W. Grosse-Kunstleve 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/make_function.hpp> +#include <boost/python/object/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/str.hpp> + +namespace boost { namespace python { + +namespace { + + tuple instance_reduce(object instance_obj) + { + list result; + object instance_class(instance_obj.attr("__class__")); + result.append(instance_class); + object none; + if (!getattr(instance_obj, "__safe_for_unpickling__", none)) + { + str type_name(getattr(instance_class, "__name__")); + str module_name(getattr(instance_class, "__module__", object(""))); + if (module_name) + module_name += "."; + + PyErr_SetObject( + PyExc_RuntimeError, + ( "Pickling of \"%s\" instances is not enabled" + " (http://www.boost.org/libs/python/doc/v2/pickle.html)" + % (module_name+type_name)).ptr() + ); + + throw_error_already_set(); + } + object getinitargs = getattr(instance_obj, "__getinitargs__", none); + tuple initargs; + if (!getinitargs.is_none()) { + initargs = tuple(getinitargs()); + } + result.append(initargs); + object getstate = getattr(instance_obj, "__getstate__", none); + object instance_dict = getattr(instance_obj, "__dict__", none); + long len_instance_dict = 0; + if (!instance_dict.is_none()) { + len_instance_dict = len(instance_dict); + } + if (!getstate.is_none()) { + if (len_instance_dict > 0) { + object getstate_manages_dict = getattr( + instance_obj, "__getstate_manages_dict__", none); + if (getstate_manages_dict.is_none()) { + PyErr_SetString(PyExc_RuntimeError, + "Incomplete pickle support" + " (__getstate_manages_dict__ not set)"); + throw_error_already_set(); + } + } + result.append(getstate()); + } + else if (len_instance_dict > 0) { + result.append(instance_dict); + } + return tuple(result); + } + +} // namespace + +object const& make_instance_reduce_function() +{ + static object result(&instance_reduce); + return result; +} + +}} // namespace boost::python diff --git a/libs/python/src/object/stl_iterator.cpp b/libs/python/src/object/stl_iterator.cpp new file mode 100644 index 000000000..e32d32145 --- /dev/null +++ b/libs/python/src/object/stl_iterator.cpp @@ -0,0 +1,48 @@ +// Copyright Eric Niebler 2005. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Credits: +// Andreas Kl\:ockner for fixing increment() to handle +// error conditions. + +#include <boost/python/object.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/object/stl_iterator_core.hpp> + +namespace boost { namespace python { namespace objects +{ + +stl_input_iterator_impl::stl_input_iterator_impl() + : it_() + , ob_() +{ +} + +stl_input_iterator_impl::stl_input_iterator_impl(boost::python::object const &ob) + : it_(ob.attr("__iter__")()) + , ob_() +{ + this->increment(); +} + +void stl_input_iterator_impl::increment() +{ + this->ob_ = boost::python::handle<>( + boost::python::allow_null(PyIter_Next(this->it_.ptr()))); + if (PyErr_Occurred()) + throw boost::python::error_already_set(); +} + +bool stl_input_iterator_impl::equal(stl_input_iterator_impl const &that) const +{ + return !this->ob_ == !that.ob_; +} + +boost::python::handle<> const &stl_input_iterator_impl::current() const +{ + return this->ob_; +} + +}}} // namespace boost::python::objects diff --git a/libs/python/src/object_operators.cpp b/libs/python/src/object_operators.cpp new file mode 100644 index 000000000..b993245fe --- /dev/null +++ b/libs/python/src/object_operators.cpp @@ -0,0 +1,85 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/object_operators.hpp> +#include <boost/python/detail/raw_pyobject.hpp> + +namespace boost { namespace python { namespace api { + +# define BOOST_PYTHON_COMPARE_OP(op, opid) \ +BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ +{ \ + return object( \ + detail::new_reference( \ + PyObject_RichCompare( \ + l.ptr(), r.ptr(), opid)) \ + ); \ +} +BOOST_PYTHON_COMPARE_OP(>, Py_GT) +BOOST_PYTHON_COMPARE_OP(>=, Py_GE) +BOOST_PYTHON_COMPARE_OP(<, Py_LT) +BOOST_PYTHON_COMPARE_OP(<=, Py_LE) +BOOST_PYTHON_COMPARE_OP(==, Py_EQ) +BOOST_PYTHON_COMPARE_OP(!=, Py_NE) +# undef BOOST_PYTHON_COMPARE_OP + + +#define BOOST_PYTHON_BINARY_OPERATOR(op, name) \ +BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ +{ \ + return object( \ + detail::new_reference( \ + PyNumber_##name(l.ptr(), r.ptr())) \ + ); \ +} + +BOOST_PYTHON_BINARY_OPERATOR(+, Add) +BOOST_PYTHON_BINARY_OPERATOR(-, Subtract) +BOOST_PYTHON_BINARY_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// We choose FloorDivide instead of TrueDivide to keep the semantic +// conform with C/C++'s '/' operator +BOOST_PYTHON_BINARY_OPERATOR(/, FloorDivide) +#else +BOOST_PYTHON_BINARY_OPERATOR(/, Divide) +#endif +BOOST_PYTHON_BINARY_OPERATOR(%, Remainder) +BOOST_PYTHON_BINARY_OPERATOR(<<, Lshift) +BOOST_PYTHON_BINARY_OPERATOR(>>, Rshift) +BOOST_PYTHON_BINARY_OPERATOR(&, And) +BOOST_PYTHON_BINARY_OPERATOR(^, Xor) +BOOST_PYTHON_BINARY_OPERATOR(|, Or) +#undef BOOST_PYTHON_BINARY_OPERATOR + +#define BOOST_PYTHON_INPLACE_OPERATOR(op, name) \ +BOOST_PYTHON_DECL object& operator op##=(object& l, object const& r) \ +{ \ + return l = object( \ + (detail::new_reference) \ + PyNumber_InPlace##name(l.ptr(), r.ptr())); \ +} + +BOOST_PYTHON_INPLACE_OPERATOR(+, Add) +BOOST_PYTHON_INPLACE_OPERATOR(-, Subtract) +BOOST_PYTHON_INPLACE_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// Same reason as above for choosing FloorDivide instead of TrueDivide +BOOST_PYTHON_INPLACE_OPERATOR(/, FloorDivide) +#else +BOOST_PYTHON_INPLACE_OPERATOR(/, Divide) +#endif +BOOST_PYTHON_INPLACE_OPERATOR(%, Remainder) +BOOST_PYTHON_INPLACE_OPERATOR(<<, Lshift) +BOOST_PYTHON_INPLACE_OPERATOR(>>, Rshift) +BOOST_PYTHON_INPLACE_OPERATOR(&, And) +BOOST_PYTHON_INPLACE_OPERATOR(^, Xor) +BOOST_PYTHON_INPLACE_OPERATOR(|, Or) +#undef BOOST_PYTHON_INPLACE_OPERATOR + +object::object(handle<> const& x) + : object_base(python::incref(python::expect_non_null(x.get()))) +{} + +}}} // namespace boost::python diff --git a/libs/python/src/object_protocol.cpp b/libs/python/src/object_protocol.cpp new file mode 100644 index 000000000..95c8c73ee --- /dev/null +++ b/libs/python/src/object_protocol.cpp @@ -0,0 +1,197 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/object_protocol.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/object.hpp> +#include <boost/python/ssize_t.hpp> + +namespace boost { namespace python { namespace api { + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key) +{ + return object(detail::new_reference(PyObject_GetAttr(target.ptr(), key.ptr()))); +} + +BOOST_PYTHON_DECL object getattr(object const& target, object const& key, object const& default_) +{ + PyObject* result = PyObject_GetAttr(target.ptr(), key.ptr()); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); +} + +BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value) +{ + if (PyObject_SetAttr(target.ptr(), key.ptr(), value.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void delattr(object const& target, object const& key) +{ + if (PyObject_DelAttr(target.ptr(), key.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL object getattr(object const& target, char const* key) +{ + return object( + detail::new_reference( + PyObject_GetAttrString(target.ptr(), const_cast<char*>(key)) + )); +} + +BOOST_PYTHON_DECL object getattr(object const& target, char const* key, object const& default_) +{ + PyObject* result = PyObject_GetAttrString(target.ptr(), const_cast<char*>(key)); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); + +} +BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value) +{ + if (PyObject_SetAttrString( + target.ptr(), const_cast<char*>(key), value.ptr()) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL void delattr(object const& target, char const* key) +{ + if (PyObject_DelAttrString( + target.ptr(), const_cast<char*>(key)) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL object getitem(object const& target, object const& key) +{ + return object(detail::new_reference( + PyObject_GetItem(target.ptr(), key.ptr()))); +} + +BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value) +{ + if (PyObject_SetItem(target.ptr(), key.ptr(), value.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void delitem(object const& target, object const& key) +{ + if (PyObject_DelItem(target.ptr(), key.ptr()) == -1) + throw_error_already_set(); +} + +namespace // slicing code copied directly out of the Python implementation +{ + #undef ISINT + #define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x)) + + static PyObject * + apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ + { +#if PY_VERSION_HEX < 0x03000000 + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + ssize_t ilow = 0, ihigh = ssize_t_max; + if (!_PyEval_SliceIndex(v, &ilow)) + return NULL; + if (!_PyEval_SliceIndex(w, &ihigh)) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); + } + else +#endif + { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + PyObject *res = PyObject_GetItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return NULL; + } + } + + static int + assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) + /* u[v:w] = x */ + { +#if PY_VERSION_HEX < 0x03000000 + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + ssize_t ilow = 0, ihigh = ssize_t_max; + if (!_PyEval_SliceIndex(v, &ilow)) + return -1; + if (!_PyEval_SliceIndex(w, &ihigh)) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); + } + else +#endif + { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + int res; + if (x != NULL) + res = PyObject_SetItem(u, slice, x); + else + res = PyObject_DelItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return -1; + } + } +} + +BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end) +{ + return object( + detail::new_reference( + apply_slice(target.ptr(), begin.get(), end.get()))); +} + +BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value) +{ + if (assign_slice( + target.ptr(), begin.get(), end.get(), value.ptr()) == -1 + ) + { + throw_error_already_set(); + } +} + +BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end) +{ + if (assign_slice( + target.ptr(), begin.get(), end.get(), 0) == -1 + ) + { + throw_error_already_set(); + } +} + +}}} // namespace boost::python::api diff --git a/libs/python/src/slice.cpp b/libs/python/src/slice.cpp new file mode 100644 index 000000000..ee55f9484 --- /dev/null +++ b/libs/python/src/slice.cpp @@ -0,0 +1,37 @@ +#include "boost/python/slice.hpp" + +// Copyright (c) 2004 Jonathan Brandmeyer +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +namespace boost { namespace python { namespace detail { + +slice_base::slice_base(PyObject* start, PyObject* stop, PyObject* step) + : object(detail::new_reference( PySlice_New(start, stop, step))) +{ +} + +object +slice_base::start() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->start)); +} + +object +slice_base::stop() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->stop)); +} + +object +slice_base::step() const +{ + return object( detail::borrowed_reference( + ((PySliceObject*)this->ptr())->step)); +} + +} } } // !namespace boost::python::detail diff --git a/libs/python/src/str.cpp b/libs/python/src/str.cpp new file mode 100644 index 000000000..0bc225aa2 --- /dev/null +++ b/libs/python/src/str.cpp @@ -0,0 +1,403 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/str.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/ssize_t.hpp> + +namespace boost { namespace python { namespace detail { + +detail::new_reference str_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( +#if PY_VERSION_HEX >= 0x03000000 + (PyObject*)&PyUnicode_Type, +#else + (PyObject*)&PyString_Type, +#endif + const_cast<char*>("(O)"), + arg_.ptr()); +} + +str_base::str_base() + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString("") +#else + ::PyString_FromString("") +#endif + )) +{} + +str_base::str_base(const char* s) + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString(s) +#else + ::PyString_FromString(s) +#endif + )) +{} + +namespace { + + ssize_t str_size_as_py_ssize_t(std::size_t n) + { + if (n > static_cast<std::size_t>(ssize_t_max)) + { + throw std::range_error("str size > ssize_t_max"); + } + return static_cast<ssize_t>(n); + } + +} // namespace <anonymous> + +str_base::str_base(char const* start, char const* finish) + : object( + detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + (start, str_size_as_py_ssize_t(finish - start)) + ) + ) +{} + +str_base::str_base(char const* start, std::size_t length) // new str + : object( + detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + ( start, str_size_as_py_ssize_t(length) ) + ) + ) +{} + +str_base::str_base(object_cref other) + : object(str_base::call(other)) +{} + +#define BOOST_PYTHON_FORMAT_OBJECT(z, n, data) "O" +#define BOOST_PYTHON_OBJECT_PTR(z, n, data) , x##n .ptr() + +#define BOOST_PYTHON_DEFINE_STR_METHOD(name, arity) \ +str str_base:: name ( BOOST_PP_ENUM_PARAMS(arity, object_cref x) ) const \ +{ \ + return str(new_reference( \ + expect_non_null( \ + PyObject_CallMethod( \ + this->ptr(), const_cast<char*>( #name ), \ + const_cast<char*>( \ + "(" BOOST_PP_REPEAT(arity, BOOST_PYTHON_FORMAT_OBJECT, _) ")") \ + BOOST_PP_REPEAT_1(arity, BOOST_PYTHON_OBJECT_PTR, _))))); \ +} + +BOOST_PYTHON_DEFINE_STR_METHOD(capitalize, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(center, 1) + +long str_base::count(object_cref sub) const +{ + return extract<long>(this->attr("count")(sub)); +} + +long str_base::count(object_cref sub, object_cref start) const +{ + return extract<long>(this->attr("count")(sub,start)); +} + +long str_base::count(object_cref sub, object_cref start, object_cref end) const +{ + return extract<long>(this->attr("count")(sub,start,end)); +} + +#if PY_VERSION_HEX < 0x03000000 +object str_base::decode() const +{ + return this->attr("decode")(); +} + +object str_base::decode(object_cref encoding) const +{ + return this->attr("decode")(encoding); +} + +object str_base::decode(object_cref encoding, object_cref errors) const +{ + return this->attr("decode")(encoding,errors); +} +#endif + +object str_base::encode() const +{ + return this->attr("encode")(); +} + +object str_base::encode(object_cref encoding) const +{ + return this->attr("encode")(encoding); +} + +object str_base::encode(object_cref encoding, object_cref errors) const +{ + return this->attr("encode")(encoding,errors); +} + + +#if PY_VERSION_HEX >= 0x03000000 + #define _BOOST_PYTHON_ASLONG PyLong_AsLong +#else + #define _BOOST_PYTHON_ASLONG PyInt_AsLong +#endif + +bool str_base::endswith(object_cref suffix) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 1) + +long str_base::find(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::find(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::find(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::index(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isalnum() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalnum")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isalpha() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalpha")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isdigit() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isdigit")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::islower() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("islower")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isspace() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isspace")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::istitle() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("istitle")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::isupper() const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("isupper")().ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(join, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(ljust, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(lower, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(lstrip, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(replace, 2) +BOOST_PYTHON_DEFINE_STR_METHOD(replace, 3) + +long str_base::rfind(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rfind(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rfind(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub, object_cref start) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +long str_base::rindex(object_cref sub, object_cref start, object_cref end) const +{ + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DEFINE_STR_METHOD(rjust, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(rstrip, 0) + +list str_base::split() const +{ + return list(this->attr("split")()); +} + +list str_base::split(object_cref sep) const +{ + return list(this->attr("split")(sep)); +} + +list str_base::split(object_cref sep, object_cref maxsplit) const +{ + return list(this->attr("split")(sep,maxsplit)); +} + +list str_base::splitlines() const +{ + return list(this->attr("splitlines")()); +} + +list str_base::splitlines(object_cref keepends) const +{ + return list(this->attr("splitlines")(keepends)); +} + +bool str_base::startswith(object_cref prefix) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::startswith(object_cref prefix, object_cref start) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::startswith(object_cref prefix, object_cref start, object_cref end) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +#undef _BOOST_PYTHON_ASLONG + +BOOST_PYTHON_DEFINE_STR_METHOD(strip, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(swapcase, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(title, 0) +BOOST_PYTHON_DEFINE_STR_METHOD(translate, 1) +BOOST_PYTHON_DEFINE_STR_METHOD(translate, 2) +BOOST_PYTHON_DEFINE_STR_METHOD(upper, 0) + +static struct register_str_pytype_ptr +{ + register_str_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::str>()) + ) +#if PY_VERSION_HEX >= 0x03000000 + .m_class_object = &PyUnicode_Type; +#else + .m_class_object = &PyString_Type; +#endif + } +}register_str_pytype_ptr_; + +}}} // namespace boost::python diff --git a/libs/python/src/tuple.cpp b/libs/python/src/tuple.cpp new file mode 100644 index 000000000..6719713b7 --- /dev/null +++ b/libs/python/src/tuple.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2004. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/tuple.hpp> + +namespace boost { namespace python { namespace detail { + +detail::new_reference tuple_base::call(object const& arg_) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyTuple_Type, const_cast<char*>("(O)"), + arg_.ptr()); +} + +tuple_base::tuple_base() + : object(detail::new_reference(PyTuple_New(0))) +{} + +tuple_base::tuple_base(object_cref sequence) + : object(call(sequence)) +{} + +static struct register_tuple_pytype_ptr +{ + register_tuple_pytype_ptr() + { + const_cast<converter::registration &>( + converter::registry::lookup(boost::python::type_id<boost::python::tuple>()) + ).m_class_object = &PyTuple_Type; + } +}register_tuple_pytype_ptr_; + + +}}} // namespace boost::python diff --git a/libs/python/src/wrapper.cpp b/libs/python/src/wrapper.cpp new file mode 100644 index 000000000..f8feaef94 --- /dev/null +++ b/libs/python/src/wrapper.cpp @@ -0,0 +1,66 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/wrapper.hpp> + +namespace boost { namespace python { + +namespace detail +{ + override wrapper_base::get_override( + char const* name + , PyTypeObject* class_object + ) const + { + if (this->m_self) + { + if (handle<> m = handle<>( + python::allow_null( + ::PyObject_GetAttrString( + this->m_self, const_cast<char*>(name)))) + ) + { + PyObject* borrowed_f = 0; + + if ( + PyMethod_Check(m.get()) + && ((PyMethodObject*)m.get())->im_self == this->m_self + && class_object->tp_dict != 0 + ) + { + borrowed_f = ::PyDict_GetItemString( + class_object->tp_dict, const_cast<char*>(name)); + + + } + if (borrowed_f != ((PyMethodObject*)m.get())->im_func) + return override(m); + } + } + return override(handle<>(detail::none())); + } +} + +#if 0 +namespace converter +{ + PyObject* BOOST_PYTHON_DECL do_polymorphic_ref_to_python( + python::detail::wrapper_base const volatile* x, type_info src + ) + { + if (x == 0) + { + ::PyErr_Format( + PyExc_TypeError + , "Attempting to returning pointer or reference to instance of %s\n" + "for which no corresponding Python object exists. Wrap this function" + "with a return return value policy" + ) + } + } + +} +#endif + +}} // namespace boost::python::detail diff --git a/libs/python/test/Jamfile.v2 b/libs/python/test/Jamfile.v2 new file mode 100644 index 000000000..552418800 --- /dev/null +++ b/libs/python/test/Jamfile.v2 @@ -0,0 +1,236 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import python ; +import os ; + +lib socket ; + +use-project /boost/python : ../build ; +project /boost/python/test + : requirements + <toolset>gcc:<cxxflags>-Wextra + <target-os>qnxnto:<library>socket + ; + +local PY = ; +if [ python.configured ] +{ + PY = /python//python ; +} + +rule py-run ( sources * : input-file ? ) +{ + return [ run $(sources) /boost/python//boost_python $(PY) + : # args + : $(input-file) + : #requirements + <define>BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION + + ] ; +} + +rule py-compile ( sources * ) +{ + return [ compile $(sources) /boost/python//boost_python ] ; +} + +rule py-compile-fail ( sources * ) +{ + return [ compile-fail $(sources) /boost/python//boost_python ] ; +} + +rule require-windows ( properties * ) +{ + if ! <target-os>windows in $(properties) + { + return <build>no ; + } +} + +test-suite python + : + + [ + run exec.cpp /boost/python//boost_python/<link>static $(PY) + : # program args + : exec.py # input files + : # requirements + : # target-name + ] + + [ + run exec.cpp ../build//boost_python/<link>shared /python//python + : # program args + : exec.py + : # requirements + : exec-dynamic # target-name + ] + +# [ +# run import_.cpp ../build//boost_python /python//python +# : # program args +# : import_.py # input files +# : # requirements +# : # target-name +# ] + +[ +bpl-test crossmod_exception + : crossmod_exception.py crossmod_exception_a.cpp crossmod_exception_b.cpp +] + +[ bpl-test injected ] +[ bpl-test properties ] +[ bpl-test return_arg ] +[ bpl-test staticmethod ] +[ bpl-test shared_ptr ] +[ bpl-test enable_shared_from_this ] +[ bpl-test andreas_beyer ] +[ bpl-test wrapper_held_type ] + +[ bpl-test polymorphism2_auto_ptr + : polymorphism2_auto_ptr.py polymorphism2.py polymorphism2_auto_ptr.cpp +] + +[ bpl-test polymorphism ] +[ bpl-test polymorphism2 ] + +[ bpl-test auto_ptr ] + +[ bpl-test minimal ] +[ bpl-test args ] +[ bpl-test raw_ctor ] +[ bpl-test numpy : printer.py numeric_tests.py numarray_tests.py numpy.py numpy.cpp ] +[ bpl-test enum ] +[ bpl-test exception_translator ] +[ bpl-test pearu1 : test_cltree.py cltree.cpp ] +[ bpl-test try : newtest.py m1.cpp m2.cpp ] +[ bpl-test const_argument ] +[ bpl-test keywords : keywords.cpp keywords_test.py ] + + +[ python-extension builtin_converters_ext : test_builtin_converters.cpp /boost/python//boost_python ] +[ bpl-test builtin_converters : test_builtin_converters.py builtin_converters_ext ] + + [ bpl-test test_pointer_adoption ] + [ bpl-test operators ] + [ bpl-test operators_wrapper ] + [ bpl-test callbacks ] + [ bpl-test defaults ] + +[ bpl-test object ] +[ bpl-test class ] +[ bpl-test list ] +[ bpl-test long ] +[ bpl-test dict ] +[ bpl-test tuple ] +[ bpl-test str ] +[ bpl-test slice ] + +[ bpl-test virtual_functions ] +[ bpl-test back_reference ] +[ bpl-test implicit ] +[ bpl-test data_members ] + +[ bpl-test ben_scott1 ] + +[ bpl-test bienstman1 ] +[ bpl-test bienstman2 ] +[ bpl-test bienstman3 ] + +[ bpl-test multi_arg_constructor + : # files + : # requirements + # A bug in the Win32 intel compilers causes compilation of one of our + # tests to take forever when debug symbols are enabled. This rule + # turns them off when added to the requirements section + <toolset>intel-win:<debug-symbols>off +] + +[ bpl-test iterator : iterator.py iterator.cpp input_iterator.cpp ] + +[ bpl-test stl_iterator : stl_iterator.py stl_iterator.cpp ] + +[ bpl-test extract ] + +[ +bpl-test crossmod_opaque + : crossmod_opaque.py crossmod_opaque_a.cpp crossmod_opaque_b.cpp +] +[ bpl-test opaque ] +[ bpl-test voidptr ] + +[ bpl-test pickle1 ] +[ bpl-test pickle2 ] +[ bpl-test pickle3 ] +[ bpl-test pickle4 ] + +[ bpl-test nested ] + +[ bpl-test docstring ] +[ bpl-test pytype_function ] + +[ bpl-test vector_indexing_suite ] + +[ bpl-test pointer_vector + : # files + : # requirements + # Turn off this test on HP CXX, as the test hangs when executing. + # Whenever the cause for the failure of the polymorphism test is found + # and fixed, this should be retested. + <toolset>hp_cxx:<build>no ] + +[ python-extension map_indexing_suite_ext + : map_indexing_suite.cpp int_map_indexing_suite.cpp a_map_indexing_suite.cpp + /boost/python//boost_python ] +[ bpl-test + map_indexing_suite : map_indexing_suite.py map_indexing_suite_ext ] + +[ run import_.cpp /boost/python//boost_python $(PY) : : import_.py ] + +# if $(TEST_BIENSTMAN_NON_BUGS) +# { +# bpl-test bienstman4 ; +# bpl-test bienstman5 ; +# } + +[ bpl-test calling_conventions : : <conditional>@require-windows ] +[ bpl-test calling_conventions_mf : : <conditional>@require-windows ] + +# --- unit tests of library components --- + +[ compile indirect_traits_test.cpp ] +[ run destroy_test.cpp ] +[ py-run pointer_type_id_test.cpp ] +[ py-run bases.cpp ] +[ run if_else.cpp ] +[ py-run pointee.cpp ] +[ run result.cpp ] + +[ compile string_literal.cpp ] +[ py-compile borrowed.cpp ] +[ py-compile object_manager.cpp ] +[ py-compile copy_ctor_mutates_rhs.cpp ] + +[ py-run upcast.cpp ] + +[ py-compile select_holder.cpp ] + +[ run select_from_python_test.cpp ../src/converter/type_id.cpp + : + : + : <define>BOOST_PYTHON_STATIC_LIB + <use>$(PY) + +] + + [ py-compile select_arg_to_python_test.cpp ] + +[ py-compile-fail ./raw_pyobject_fail1.cpp ] +[ py-compile-fail ./raw_pyobject_fail2.cpp ] +[ py-compile-fail ./as_to_python_function.cpp ] +[ py-compile-fail ./object_fail1.cpp ] + + ; diff --git a/libs/python/test/a_map_indexing_suite.cpp b/libs/python/test/a_map_indexing_suite.cpp new file mode 100644 index 000000000..07a0a6b97 --- /dev/null +++ b/libs/python/test/a_map_indexing_suite.cpp @@ -0,0 +1,92 @@ +// Copyright Joel de Guzman 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/suite/indexing/map_indexing_suite.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +using namespace boost::python; + +struct A +{ + int value; + A() : value(0){}; + A(int v) : value(v) {}; +}; + +bool operator==(const A& v1, const A& v2) +{ + return (v1.value == v2.value); +} + +struct B +{ + A a; +}; + +// Converter from A to python int +struct AToPython +{ + static PyObject* convert(const A& s) + { + return boost::python::incref(boost::python::object((int)s.value).ptr()); + } +}; + +// Conversion from python int to A +struct AFromPython +{ + AFromPython() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id< A >()); + } + + static void* convertible(PyObject* obj_ptr) + { +#if PY_VERSION_HEX >= 0x03000000 + if (!PyLong_Check(obj_ptr)) return 0; +#else + if (!PyInt_Check(obj_ptr)) return 0; +#endif + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (boost::python::converter::rvalue_from_python_storage< A >*) + data)-> storage.bytes; + +#if PY_VERSION_HEX >= 0x03000000 + new (storage) A((int)PyLong_AsLong(obj_ptr)); +#else + new (storage) A((int)PyInt_AsLong(obj_ptr)); +#endif + data->convertible = storage; + } +}; + +void a_map_indexing_suite() +{ + + to_python_converter< A , AToPython >(); + AFromPython(); + + class_< std::map<int, A> >("AMap") + .def(map_indexing_suite<std::map<int, A>, true >()) + ; + + class_< B >("B") + .add_property("a", make_getter(&B::a, return_value_policy<return_by_value>()), + make_setter(&B::a, return_value_policy<return_by_value>())) + ; +} + + diff --git a/libs/python/test/andreas_beyer.cpp b/libs/python/test/andreas_beyer.cpp new file mode 100644 index 000000000..b28b15660 --- /dev/null +++ b/libs/python/test/andreas_beyer.cpp @@ -0,0 +1,61 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> + +using namespace boost; + +class A : public enable_shared_from_this<A> { + public: + A() : val(0) {}; + int val; + typedef shared_ptr<A> A_ptr; + A_ptr self() { + A_ptr self; + self = shared_from_this(); + return self; + } + +}; + +class B { + public: + B() { + a = A::A_ptr(new A()); + } + void set(A::A_ptr _a) { + this->a = _a; + } + A::A_ptr get() { + return a; + } + A::A_ptr a; +}; + +template <class T> +void hold_python(shared_ptr<T>& x) +{ + x = python::extract<shared_ptr<T> >( python::object(x) ); +} + +A::A_ptr get_b_a(shared_ptr<B> b) +{ + hold_python(b->a); + return b->get(); +} + +BOOST_PYTHON_MODULE(andreas_beyer_ext) { + python::class_<A, noncopyable> ("A") + .def("self", &A::self) + .def_readwrite("val", &A::val) + ; + python::register_ptr_to_python< A::A_ptr >(); + + python::class_<B>("B") + .def("set", &B::set) +// .def("get", &B::get) + .def("get", get_b_a) + ; +} diff --git a/libs/python/test/andreas_beyer.py b/libs/python/test/andreas_beyer.py new file mode 100644 index 000000000..84a54fbd9 --- /dev/null +++ b/libs/python/test/andreas_beyer.py @@ -0,0 +1,24 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' + >>> from andreas_beyer_ext import * + >>> b=B() + >>> a=b.get() # let b create an A + >>> a2=b.get() + >>> assert id(a) == id(a2) +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/args.cpp b/libs/python/test/args.cpp new file mode 100644 index 000000000..592a8e505 --- /dev/null +++ b/libs/python/test/args.cpp @@ -0,0 +1,99 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include "test_class.hpp" +#include <boost/python/def.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/class.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/raw_function.hpp> +#include <boost/python/return_internal_reference.hpp> + +using namespace boost::python; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +# define make_tuple boost::python::make_tuple +#endif + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + +typedef test_class<> Y; + +struct X +{ + X(int a0 = 0, int a1 = 1) : inner0(a0), inner1(a1) {} + tuple f(int x = 1, double y = 4.25, char const* z = "wow") + { + return make_tuple(x, y, z); + } + + Y const& inner(bool n) const { return n ? inner1 : inner0; } + + Y inner0; + Y inner1; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3) + + +tuple raw_func(tuple args, dict kw) +{ + return make_tuple(args, kw); +} + +BOOST_PYTHON_MODULE(args_ext) +{ + def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow") + , "This is f's docstring" + ); + + def("raw", raw_function(raw_func)); + +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1200 + // MSVC6 gives a fatal error LNK1179: invalid or corrupt file: + // duplicate comdat error if we try to re-use the exact type of f + // here, so substitute long for int. + tuple (*f)(long,double,char const*) = 0; +#endif + def("f1", f, f_overloads("f1's docstring", args("x", "y", "z"))); + def("f2", f, f_overloads(args("x", "y", "z"))); + def("f3", f, f_overloads(args("x", "y", "z"), "f3's docstring")); + + class_<Y>("Y", init<int>(args("value"), "Y's docstring")) + .def("value", &Y::value) + .def("raw", raw_function(raw_func)) + ; + + class_<X>("X", "This is X's docstring", init<>(args("self"))) + .def(init<int, optional<int> >(args("self", "a0", "a1"))) + .def("f", &X::f + , "This is X.f's docstring" + , args("self","x", "y", "z")) + + // Just to prove that all the different argument combinations work + .def("inner0", &X::inner, return_internal_reference<>(), args("self", "n"), "docstring") + .def("inner1", &X::inner, return_internal_reference<>(), "docstring", args("self", "n")) + + .def("inner2", &X::inner, args("self", "n"), return_internal_reference<>(), "docstring") + .def("inner3", &X::inner, "docstring", return_internal_reference<>(), args("self", "n")) + + .def("inner4", &X::inner, args("self", "n"), "docstring", return_internal_reference<>()) + .def("inner5", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()) + + .def("f1", &X::f, X_f_overloads(args("self", "x", "y", "z"))) + .def("f2", &X::f, X_f_overloads(args("self", "x", "y", "z"), "f2's docstring")) + .def("f2", &X::f, X_f_overloads(args("x", "y", "z"), "f2's docstring")) + ; + + def("inner", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/args.py b/libs/python/test/args.py new file mode 100644 index 000000000..44a9cd252 --- /dev/null +++ b/libs/python/test/args.py @@ -0,0 +1,147 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from args_ext import * + +>>> raw(3, 4, foo = 'bar', baz = 42) +((3, 4), {'foo': 'bar', 'baz': 42}) + + Prove that we can handle empty keywords and non-keywords + +>>> raw(3, 4) +((3, 4), {}) + +>>> raw(foo = 'bar') +((), {'foo': 'bar'}) + +>>> f(x= 1, y = 3, z = 'hello') +(1, 3.0, 'hello') + +>>> f(z = 'hello', x = 3, y = 2.5) +(3, 2.5, 'hello') + +>>> f(1, z = 'hi', y = 3) +(1, 3.0, 'hi') + +>>> try: f(1, 2, 'hello', bar = 'baz') +... except TypeError: pass +... else: print 'expected an exception: unknown keyword' + + + Exercise the functions using default stubs + +>>> f1(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f1(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f1(x = 2) +(2, 4.25, 'wow') +>>> f1() +(1, 4.25, 'wow') + +>>> f2(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f2(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f2(x = 2) +(2, 4.25, 'wow') +>>> f2() +(1, 4.25, 'wow') + +>>> f3(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f3(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f3(x = 2) +(2, 4.25, 'wow') +>>> f3() +(1, 4.25, 'wow') + + Member function tests + +>>> q = X() +>>> q.f(x= 1, y = 3, z = 'hello') +(1, 3.0, 'hello') + +>>> q.f(z = 'hello', x = 3, y = 2.5) +(3, 2.5, 'hello') + +>>> q.f(1, z = 'hi', y = 3) +(1, 3.0, 'hi') + +>>> try: q.f(1, 2, 'hello', bar = 'baz') +... except TypeError: pass +... else: print 'expected an exception: unknown keyword' + + Exercise member functions using default stubs + +>>> q.f1(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> q.f1(y = .125, x = 2) +(2, 0.125, 'wow') +>>> q.f1(x = 2) +(2, 4.25, 'wow') +>>> q.f1() +(1, 4.25, 'wow') +>>> q.f2.__doc__.splitlines()[1] +'f2( (X)self [, (int)x [, (float)y [, (str)z]]]) -> tuple :' + +>>> q.f2.__doc__.splitlines()[2] +" f2's docstring" + +>>> X.f.__doc__.splitlines()[1:5] +['f( (X)self, (int)x, (float)y, (str)z) -> tuple :', " This is X.f's docstring", '', ' C++ signature :'] + +>>> xfuncs = (X.inner0, X.inner1, X.inner2, X.inner3, X.inner4, X.inner5) +>>> for f in xfuncs: +... print f(q,1).value(), +... print f(q, n = 1).value(), +... print f(q, n = 0).value(), +... print f.__doc__.splitlines()[1:5] +1 1 0 ['inner0( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner1( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner2( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner3( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner4( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] +1 1 0 ['inner5( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] + +>>> x = X(a1 = 44, a0 = 22) +>>> x.inner0(0).value() +22 +>>> x.inner0(1).value() +44 + +>>> x = X(a0 = 7) +>>> x.inner0(0).value() +7 +>>> x.inner0(1).value() +1 + +>>> inner(n = 1, self = q).value() +1 + +>>> y = Y(value = 33) +>>> y.raw(this = 1, that = 'the other')[1] +{'this': 1, 'that': 'the other'} + +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + import args_ext + help(args_ext) + sys.exit(status) + + + diff --git a/libs/python/test/as_to_python_function.cpp b/libs/python/test/as_to_python_function.cpp new file mode 100644 index 000000000..cc083890a --- /dev/null +++ b/libs/python/test/as_to_python_function.cpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/converter/as_to_python_function.hpp> + +struct hopefully_illegal +{ + static PyObject* convert(int&); +}; + +PyObject* x = boost::python::converter::as_to_python_function<int, hopefully_illegal>::convert(0); diff --git a/libs/python/test/auto_ptr.cpp b/libs/python/test/auto_ptr.cpp new file mode 100644 index 000000000..0f61e96dc --- /dev/null +++ b/libs/python/test/auto_ptr.cpp @@ -0,0 +1,90 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include "test_class.hpp" +#include <boost/python/class.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +#include <boost/detail/workaround.hpp> + +#include <memory> + +using namespace boost::python; + +typedef test_class<> X; + +struct Y : X +{ + Y(int n) : X(n) {}; +}; + +int look(std::auto_ptr<X> const& x) +{ + return (x.get()) ? x->value() : -1; +} + +int steal(std::auto_ptr<X> x) +{ + return x->value(); +} + +int maybe_steal(std::auto_ptr<X>& x, bool doit) +{ + int n = x->value(); + if (doit) + x.release(); + return n; +} + +std::auto_ptr<X> make() +{ + return std::auto_ptr<X>(new X(77)); +} + +std::auto_ptr<X> callback(object f) +{ + std::auto_ptr<X> x(new X(77)); + return call<std::auto_ptr<X> >(f.ptr(), x); +} + +std::auto_ptr<X> extract_(object o) +{ + return extract<std::auto_ptr<X>&>(o) +#if BOOST_MSVC <= 1300 + () +#endif + ; +} + +BOOST_PYTHON_MODULE(auto_ptr_ext) +{ + class_<X, std::auto_ptr<X>, boost::noncopyable>("X", init<int>()) + .def("value", &X::value) + ; + + class_<Y, std::auto_ptr<Y>, bases<X>, boost::noncopyable>("Y", init<int>()) + ; + + // VC6 auto_ptrs do not have converting constructors +#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, < 306) + scope().attr("broken_auto_ptr") = 1; +#else + scope().attr("broken_auto_ptr") = 0; + implicitly_convertible<std::auto_ptr<Y>, std::auto_ptr<X> >(); +#endif + + def("look", look); + def("steal", steal); + def("maybe_steal", maybe_steal); + def("make", make); + def("callback", callback); + def("extract", extract_); +} + +#include "module_tail.cpp" + diff --git a/libs/python/test/auto_ptr.py b/libs/python/test/auto_ptr.py new file mode 100644 index 000000000..2e4bed61d --- /dev/null +++ b/libs/python/test/auto_ptr.py @@ -0,0 +1,100 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from auto_ptr_ext import * +>>> x = X(42) +>>> x.value() +42 +>>> look(x), look(x) +(42, 42) + +>>> maybe_steal(x, 0) +42 +>>> look(x) +42 + +>>> maybe_steal(x, 1) +42 +>>> broken_auto_ptr and -1 or look(x) +-1 + +>>> x = X(69) +>>> steal(x) +69 +>>> broken_auto_ptr and -1 or look(x) +-1 + +>>> if not broken_auto_ptr: +... try: x.value() +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> x = make() +>>> look(x) +77 + +>>> z = callback(lambda z: z) +>>> z.value() +77 + +>>> extract(x).value() +77 + +# +# Test derived to base conversions +# + +>>> y = Y(42) +>>> y.value() +42 + +>>> try: maybe_steal(y, 0) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> y.value() +42 + +>>> broken_auto_ptr and 42 or steal(y) +42 + +>>> if not broken_auto_ptr: +... try: y.value() +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> print look.__doc__.splitlines()[1] +look( (X)arg1) -> int : + +>>> print steal.__doc__.splitlines()[1] +steal( (X)arg1) -> int : + +>>> print maybe_steal.__doc__.splitlines()[1] +maybe_steal( (X)arg1, (bool)arg2) -> int : + +>>> print make.__doc__.splitlines()[1] +make() -> X : + +>>> print callback.__doc__.splitlines()[1] +callback( (object)arg1) -> X : + +>>> print extract.__doc__.splitlines()[1] +extract( (object)arg1) -> X : + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/back_reference.cpp b/libs/python/test/back_reference.cpp new file mode 100644 index 000000000..266ed2912 --- /dev/null +++ b/libs/python/test/back_reference.cpp @@ -0,0 +1,112 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/has_back_reference.hpp> +#include <boost/python/back_reference.hpp> +#include <boost/ref.hpp> +#include <boost/utility.hpp> +#include <memory> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/mpl/bool.hpp> + +// This test shows that a class can be wrapped "as itself" but also +// acquire a back-reference iff has_back_reference<> is appropriately +// specialized. +using namespace boost::python; + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + virtual ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; + +int X::counter; + +struct Y : X +{ + Y(PyObject* self, int x) : X(x), self(self) {} + Y(PyObject* self, Y const& rhs) : X(rhs), self(self) {} + private: + Y(Y const&); + PyObject* self; +}; + +struct Z : X +{ + Z(PyObject* self, int x) : X(x), self(self) {} + Z(PyObject* self, Z const& rhs) : X(rhs), self(self) {} + private: + Z(Z const&); + PyObject* self; +}; + +Y const& copy_Y(Y const& y) { return y; } +Z const& copy_Z(Z const& z) { return z; } + +namespace boost { namespace python +{ + template <> + struct has_back_reference<Y> + : mpl::true_ + { + }; + + template <> + struct has_back_reference<Z> + : mpl::true_ + { + }; +}} + +// prove that back_references get initialized with the right PyObject* +object y_identity(back_reference<Y const&> y) +{ + return y.source(); +} + +// prove that back_references contain the right value +bool y_equality(back_reference<Y const&> y1, Y const& y2) +{ + return &y1.get() == &y2; +} + +BOOST_PYTHON_MODULE(back_reference_ext) +{ + def("copy_Y", copy_Y, return_value_policy<copy_const_reference>()); + def("copy_Z", copy_Z, return_value_policy<copy_const_reference>()); + def("x_instances", &X::count); + + class_<Y>("Y", init<int>()) + .def("value", &Y::value) + .def("set", &Y::set) + ; + + class_<Z,std::auto_ptr<Z> >("Z", init<int>()) + .def("value", &Z::value) + .def("set", &Z::set) + ; + + def("y_identity", y_identity); + def("y_equality", y_equality); + +} + +#include "module_tail.cpp" diff --git a/libs/python/test/back_reference.py b/libs/python/test/back_reference.py new file mode 100644 index 000000000..6705ee7b7 --- /dev/null +++ b/libs/python/test/back_reference.py @@ -0,0 +1,37 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from back_reference_ext import * +>>> y = Y(3) +>>> z = Z(4) +>>> x_instances() +2 +>>> y2 = copy_Y(y) +>>> x_instances() +3 +>>> z2 = copy_Z(z) +>>> x_instances() +4 +>>> assert y_identity(y) is y +>>> y_equality(y, y) +1 + +>>> print y_identity.__doc__.splitlines()[1] +y_identity( (Y)arg1) -> object : +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/bases.cpp b/libs/python/test/bases.cpp new file mode 100644 index 000000000..84beb0612 --- /dev/null +++ b/libs/python/test/bases.cpp @@ -0,0 +1,62 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/bases.hpp> +#include <boost/static_assert.hpp> +#include <boost/type_traits/same_traits.hpp> + +struct A; +struct B; + +template <class X, class Y, class Z> +struct choose_bases + : boost::python::detail::select_bases< + X + , typename boost::python::detail::select_bases< + Y + , typename boost::python::detail::select_bases<Z>::type + >::type> +{ + +}; + +int main() +{ + BOOST_STATIC_ASSERT((boost::python::detail::specifies_bases< + boost::python::bases<A,B> >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + boost::python::bases<A,B>& >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + void* >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + int >::value)); + + BOOST_STATIC_ASSERT((!boost::python::detail::specifies_bases< + int[5] >::value)); + + typedef boost::python::detail::select_bases< + int + , boost::python::detail::select_bases<char*>::type > collected1; + + BOOST_STATIC_ASSERT((boost::is_same<collected1::type,boost::python::bases<> >::value)); + BOOST_STATIC_ASSERT((boost::is_same<choose_bases<int,char*,long>::type,boost::python::bases<> >::value)); + + typedef boost::python::detail::select_bases< + int + , boost::python::detail::select_bases< + boost::python::bases<A,B> + , boost::python::detail::select_bases< + A + >::type + >::type + > collected2; + + BOOST_STATIC_ASSERT((boost::is_same<collected2::type,boost::python::bases<A,B> >::value)); + BOOST_STATIC_ASSERT((boost::is_same<choose_bases<int,boost::python::bases<A,B>,long>::type,boost::python::bases<A,B> >::value)); + + return 0; +} diff --git a/libs/python/test/ben_scott1.cpp b/libs/python/test/ben_scott1.cpp new file mode 100644 index 000000000..5a675e230 --- /dev/null +++ b/libs/python/test/ben_scott1.cpp @@ -0,0 +1,54 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python.hpp> +#include <iostream> +using namespace boost::python; +using namespace boost; + +struct Product {}; +typedef shared_ptr<Product> ProductPtr; + + +struct Creator +{ + virtual ~Creator() {} + virtual ProductPtr create() = 0; +}; + + +struct Factory +{ + void reg(Creator* c) { mC = c; } + ProductPtr create() + { + std::cout << "Name: " << (typeid(*mC)).name() << std::endl; + return mC->create(); + } + +private: + Creator* mC; +}; + +struct CreatorWrap : public Creator +{ + CreatorWrap(PyObject* self) : mSelf(self) {} + ProductPtr create() { return call_method<ProductPtr>(mSelf, "create"); } + PyObject* mSelf; +}; + +BOOST_PYTHON_MODULE(ben_scott1_ext) +{ + class_<Product, ProductPtr>("Product"); + + class_<Creator, CreatorWrap, noncopyable>("Creator") + .def("create", &CreatorWrap::create) + ; + + class_<Factory>("Factory") + .def("reg", &Factory::reg, with_custodian_and_ward<1,2>()) + .def("create", &Factory::create) + ; +} + +#include "../test/module_tail.cpp" diff --git a/libs/python/test/ben_scott1.py b/libs/python/test/ben_scott1.py new file mode 100644 index 000000000..79130757a --- /dev/null +++ b/libs/python/test/ben_scott1.py @@ -0,0 +1,17 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# This regression test checks that call_method<T>(...) where T is a +# non-reference, non-pointer type that happens to be held inside the +# result object (and thus is found as an lvalue) works. +from ben_scott1_ext import * + +class CreatorImpl(Creator): + def create(self): + return Product() + +factory = Factory() +c = CreatorImpl() +factory.reg(c) + +a = factory.create() diff --git a/libs/python/test/bienstman1.cpp b/libs/python/test/bienstman1.cpp new file mode 100644 index 000000000..dc0065784 --- /dev/null +++ b/libs/python/test/bienstman1.cpp @@ -0,0 +1,40 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/return_value_policy.hpp> + +struct A {}; + +struct V +{ + virtual ~V() {}; // silence compiler warningsa + virtual void f() = 0; + + const A* inside() {return &a;} + + A a; +}; + +const A* outside(const V& v) {return &v.a;} + +BOOST_PYTHON_MODULE(bienstman1_ext) +{ + using namespace boost::python; + using boost::shared_ptr; + using boost::python::return_value_policy; + using boost::python::reference_existing_object; + + class_<A>("A"); + + class_<V, boost::noncopyable>("V", no_init) + .def("inside", &V::inside, + return_value_policy<reference_existing_object>()) + .def("outside", outside, + return_value_policy<reference_existing_object>()) + ; +} + diff --git a/libs/python/test/bienstman1.py b/libs/python/test/bienstman1.py new file mode 100644 index 000000000..06f0fff8c --- /dev/null +++ b/libs/python/test/bienstman1.py @@ -0,0 +1,23 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +# Try to reproduce a Numeric interaction bug if Numeric is installed. +>>> from bienstman1_ext import * +>>> try: from Numeric import * +... except: pass +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/bienstman2.cpp b/libs/python/test/bienstman2.cpp new file mode 100644 index 000000000..10f99923d --- /dev/null +++ b/libs/python/test/bienstman2.cpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> + +struct C {}; + +struct D {}; + +struct E +{ + const D fe (const C&) {return D();} + const D fe2(const C&, const C&) {return D();} +}; + +BOOST_PYTHON_MODULE(bienstman2_ext) +{ + using namespace boost::python; + + class_<C>("C"); + class_<D>("D"); + class_<E>("E") + .def("fe", &E::fe) // this compiles. + .def("fe2", &E::fe2) // this doesn't... well, now it does ;-) + ; +} diff --git a/libs/python/test/bienstman2.py b/libs/python/test/bienstman2.py new file mode 100644 index 000000000..359987d19 --- /dev/null +++ b/libs/python/test/bienstman2.py @@ -0,0 +1,20 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> import bienstman2_ext +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/bienstman3.cpp b/libs/python/test/bienstman3.cpp new file mode 100644 index 000000000..d765b303d --- /dev/null +++ b/libs/python/test/bienstman3.cpp @@ -0,0 +1,26 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> + +struct V +{ + virtual ~V() {}; // silence compiler warningsa + virtual void f() = 0; +}; + +struct B +{ + B(const V&) {} +}; + +BOOST_PYTHON_MODULE(bienstman3_ext) +{ + using namespace boost::python; + + class_<V, boost::noncopyable>("V", no_init); + class_<B>("B", init<const V&>()); + +} diff --git a/libs/python/test/bienstman3.py b/libs/python/test/bienstman3.py new file mode 100644 index 000000000..4f3e87114 --- /dev/null +++ b/libs/python/test/bienstman3.py @@ -0,0 +1,30 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from bienstman3_ext import * + +>>> try: +... V() +... except RuntimeError, x: +... print x +... else: +... print 'expected an exception' +... +This class cannot be instantiated from Python + +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/bienstman4.cpp b/libs/python/test/bienstman4.cpp new file mode 100644 index 000000000..34b9e211f --- /dev/null +++ b/libs/python/test/bienstman4.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/implicit.hpp> +#include <boost/mpl/list.hpp> + +struct Type1 {}; + +struct Term {Term(Type1 const&) {} }; + +struct Expression {void add(Term const&) {} }; + +BOOST_PYTHON_MODULE(bienstman4_ext) +{ + using namespace boost::python; + using boost::mpl::list; + + implicitly_convertible<Type1,Term>(); + + class_<Expression>("Expression") + .def("add", &Expression::add) + ; + + class_<Type1>("T1") + ; + + class_<Term>("Term", init<Type1&>()) + ; + + Type1 t1; + Expression e; + e.add(t1); +} + diff --git a/libs/python/test/bienstman4.py b/libs/python/test/bienstman4.py new file mode 100644 index 000000000..e2a5b0659 --- /dev/null +++ b/libs/python/test/bienstman4.py @@ -0,0 +1,23 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from bienstman4_ext import * +>>> t1 = T1() +>>> e = Expression() +>>> e.add(t1) +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/bienstman5.cpp b/libs/python/test/bienstman5.cpp new file mode 100644 index 000000000..657dadd12 --- /dev/null +++ b/libs/python/test/bienstman5.cpp @@ -0,0 +1,23 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/mpl/list.hpp> + +#include <complex> + +struct M {M(const std::complex<double>&) {} }; + +BOOST_PYTHON_MODULE(bienstman5_ext) +{ + using namespace boost::python; + + class_<M>("M", init<std::complex<double> const&>()) + ; +} + + diff --git a/libs/python/test/bienstman5.py b/libs/python/test/bienstman5.py new file mode 100644 index 000000000..59a9bc93f --- /dev/null +++ b/libs/python/test/bienstman5.py @@ -0,0 +1,21 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from bienstman5_ext import * +>>> m = M(1j) +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/borrowed.cpp b/libs/python/test/borrowed.cpp new file mode 100644 index 000000000..2c1bd1b7a --- /dev/null +++ b/libs/python/test/borrowed.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/detail/wrap_python.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/static_assert.hpp> + +using namespace boost::python; + +template <class T> +void assert_borrowed_ptr(T const&) +{ + BOOST_STATIC_ASSERT(boost::python::detail::is_borrowed_ptr<T>::value); +} + +template <class T> +void assert_not_borrowed_ptr(T const&) +{ + BOOST_STATIC_ASSERT(!boost::python::detail::is_borrowed_ptr<T>::value); +} + +int main() +{ + assert_borrowed_ptr(borrowed((PyObject*)0)); + assert_borrowed_ptr(borrowed((PyTypeObject*)0)); + assert_borrowed_ptr((detail::borrowed<PyObject> const*)0); + assert_borrowed_ptr((detail::borrowed<PyObject> volatile*)0); + assert_borrowed_ptr((detail::borrowed<PyObject> const volatile*)0); + assert_not_borrowed_ptr((PyObject*)0); + assert_not_borrowed_ptr(0); + return 0; +} diff --git a/libs/python/test/callbacks.cpp b/libs/python/test/callbacks.cpp new file mode 100644 index 000000000..66bd35240 --- /dev/null +++ b/libs/python/test/callbacks.cpp @@ -0,0 +1,150 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/ref.hpp> +#include <boost/python/ptr.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/call.hpp> +#include <boost/python/object.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; +BOOST_STATIC_ASSERT(converter::is_object_manager<handle<> >::value); + +int apply_int_int(PyObject* f, int x) +{ + return call<int>(f, x); +} + +void apply_void_int(PyObject* f, int x) +{ + call<void>(f, x); +} + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; + +X apply_X_X(PyObject* f, X x) +{ + return call<X>(f, x); +} + +void apply_void_X_ref(PyObject* f, X& x) +{ + call<void>(f, boost::ref(x)); +} + +X& apply_X_ref_handle(PyObject* f, handle<> obj) +{ + return call<X&>(f, obj); +} + +X* apply_X_ptr_handle_cref(PyObject* f, handle<> const& obj) +{ + return call<X*>(f, obj); +} + +void apply_void_X_cref(PyObject* f, X const& x) +{ + call<void>(f, boost::cref(x)); +} + +void apply_void_X_ptr(PyObject* f, X* x) +{ + call<void>(f, ptr(x)); +} + +void apply_void_X_deep_ptr(PyObject* f, X* x) +{ + call<void>(f, x); +} + +char const* apply_cstring_cstring(PyObject* f, char const* s) +{ + return call<char const*>(f, s); +} + +char const* apply_cstring_pyobject(PyObject* f, PyObject* s) +{ + return call<char const*>(f, borrowed(s)); +} + +char apply_char_char(PyObject* f, char c) +{ + return call<char>(f, c); +} + +char const* apply_to_string_literal(PyObject* f) +{ + return call<char const*>(f, "hello, world"); +} + +handle<> apply_to_own_type(handle<> x) +{ + // Tests that we can return handle<> from a callback and that we + // can pass arbitrary handle<T>. + return call<handle<> >(x.get(), type_handle(borrowed(x->ob_type))); +} + +object apply_object_object(PyObject* f, object x) +{ + return call<object>(f, x); +} + +int X::counter; + +BOOST_PYTHON_MODULE(callbacks_ext) +{ + def("apply_object_object", apply_object_object); + def("apply_to_own_type", apply_to_own_type); + def("apply_int_int", apply_int_int); + def("apply_void_int", apply_void_int); + def("apply_X_X", apply_X_X); + def("apply_void_X_ref", apply_void_X_ref); + def("apply_void_X_cref", apply_void_X_cref); + def("apply_void_X_ptr", apply_void_X_ptr); + def("apply_void_X_deep_ptr", apply_void_X_deep_ptr); + + def("apply_X_ptr_handle_cref", apply_X_ptr_handle_cref + , return_value_policy<reference_existing_object>()); + + def("apply_X_ref_handle", apply_X_ref_handle + , return_value_policy<reference_existing_object>()); + + def("apply_cstring_cstring", apply_cstring_cstring); + def("apply_cstring_pyobject", apply_cstring_pyobject); + def("apply_char_char", apply_char_char); + def("apply_to_string_literal", apply_to_string_literal); + + + class_<X>("X", init<int>()) + .def(init<X const&>()) + .def("value", &X::value) + .def("set", &X::set) + ; + + def("x_count", &X::count); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/callbacks.py b/libs/python/test/callbacks.py new file mode 100644 index 000000000..640eb1551 --- /dev/null +++ b/libs/python/test/callbacks.py @@ -0,0 +1,147 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from callbacks_ext import * + +>>> def double(x): +... return x + x +... +>>> apply_int_int(double, 42) +84 +>>> apply_void_int(double, 42) + +>>> def identity(x): +... return x + +Once we have array conversion support, this test will fail. Er, +succeed<wink>: + +>>> try: apply_to_string_literal(identity) +... except ReferenceError: pass # expected +... else: print 'expected an exception!' + +>>> try: apply_X_ref_handle(lambda ignored:X(42), None) +... except ReferenceError: pass # expected +... else: print 'expected an exception!' + +>>> x = X(42) +>>> x.y = X(7) +>>> apply_X_ref_handle(lambda z:z.y, x).value() +7 + +>>> x = apply_X_X(identity, X(42)) +>>> x.value() +42 +>>> x_count() +1 +>>> del x +>>> x_count() +0 + +>>> def increment(x): +... x.set(x.value() + 1) +... +>>> x = X(42) +>>> apply_void_X_ref(increment, x) +>>> x.value() +43 + +>>> apply_void_X_cref(increment, x) +>>> x.value() # const-ness is not respected, sorry! +44 + +>>> last_x = 1 +>>> def decrement(x): +... global last_x +... last_x = x +... if x is not None: +... x.set(x.value() - 1) + +>>> apply_void_X_ptr(decrement, x) +>>> x.value() +43 +>>> last_x.value() +43 +>>> increment(last_x) +>>> x.value() +44 +>>> last_x.value() +44 + +>>> apply_void_X_ptr(decrement, None) +>>> assert last_x is None +>>> x.value() +44 + +>>> last_x = 1 +>>> apply_void_X_deep_ptr(decrement, None) +>>> assert last_x is None +>>> x.value() +44 + +>>> apply_void_X_deep_ptr(decrement, x) +>>> x.value() +44 +>>> last_x.value() +43 + +>>> y = apply_X_ref_handle(identity, x) +>>> assert y.value() == x.value() +>>> increment(x) +>>> assert y.value() == x.value() + +>>> y = apply_X_ptr_handle_cref(identity, x) +>>> assert y.value() == x.value() +>>> increment(x) +>>> assert y.value() == x.value() + +>>> y = apply_X_ptr_handle_cref(identity, None) +>>> y + +>>> def new_x(ignored): +... return X(666) +... +>>> try: apply_X_ref_handle(new_x, 1) +... except ReferenceError: pass +... else: print 'no error' + +>>> try: apply_X_ptr_handle_cref(new_x, 1) +... except ReferenceError: pass +... else: print 'no error' + +>>> try: apply_cstring_cstring(identity, 'hello') +... except ReferenceError: pass +... else: print 'no error' + +>>> apply_char_char(identity, 'x') +'x' + +>>> apply_cstring_pyobject(identity, 'hello') +'hello' + +>>> apply_cstring_pyobject(identity, None) + + +>>> apply_char_char(identity, 'x') +'x' + +>>> assert apply_to_own_type(identity) is type(identity) + +>>> assert apply_object_object(identity, identity) is identity +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/calling_conventions.cpp b/libs/python/test/calling_conventions.cpp new file mode 100644 index 000000000..54f49aebc --- /dev/null +++ b/libs/python/test/calling_conventions.cpp @@ -0,0 +1,158 @@ +// +// adapted from bind_stdcall_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#define BOOST_PYTHON_ENABLE_CDECL +#define BOOST_PYTHON_ENABLE_STDCALL +#define BOOST_PYTHON_ENABLE_FASTCALL +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/stringize.hpp> +#include <boost/python.hpp> +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + + long TESTED_CALLING_CONVENTION f_0() + { + return 17041L; + } + + long TESTED_CALLING_CONVENTION f_1(long a) + { + return a; + } + + long TESTED_CALLING_CONVENTION f_2(long a, long b) + { + return a + 10 * b; + } + + long TESTED_CALLING_CONVENTION f_3(long a, long b, long c) + { + return a + 10 * b + 100 * c; + } + + long TESTED_CALLING_CONVENTION f_4(long a, long b, long c, long d) + { + return a + 10 * b + 100 * c + 1000 * d; + } + + long TESTED_CALLING_CONVENTION f_5(long a, long b, long c, long d, long e) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e; + } + + long TESTED_CALLING_CONVENTION f_6(long a, long b, long c, long d, long e, long f) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f; + } + + long TESTED_CALLING_CONVENTION f_7(long a, long b, long c, long d, long e, long f, long g) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g; + } + + long TESTED_CALLING_CONVENTION f_8(long a, long b, long c, long d, long e, long f, long g, long h) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h; + } + + long TESTED_CALLING_CONVENTION f_9(long a, long b, long c, long d, long e, long f, long g, long h, long i) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h + 100000000 * i; + } + +} // namespace test##TESTED_CALLING_CONVENTION + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + + def("f_0" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_0); + def("f_1" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_1); + def("f_2" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_2); + def("f_3" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_3); + def("f_4" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_4); + def("f_5" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_5); + def("f_6" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_6); + def("f_7" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_7); + def("f_8" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_8); + def("f_9" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_9); + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/libs/python/test/calling_conventions.py b/libs/python/test/calling_conventions.py new file mode 100644 index 000000000..ce74a8433 --- /dev/null +++ b/libs/python/test/calling_conventions.py @@ -0,0 +1,81 @@ +# Copyright Nicolas Lelong, 2010. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from calling_conventions_ext import * +>>> f_0__cdecl() +17041 +>>> f_1__cdecl(1) +1 +>>> f_2__cdecl(1, 2) +21 +>>> f_3__cdecl(1, 2, 3) +321 +>>> f_4__cdecl(1, 2, 3, 4) +4321 +>>> f_5__cdecl(1, 2, 3, 4, 5) +54321 +>>> f_6__cdecl(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__cdecl(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__cdecl(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__cdecl(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__stdcall() +17041 +>>> f_1__stdcall(1) +1 +>>> f_2__stdcall(1, 2) +21 +>>> f_3__stdcall(1, 2, 3) +321 +>>> f_4__stdcall(1, 2, 3, 4) +4321 +>>> f_5__stdcall(1, 2, 3, 4, 5) +54321 +>>> f_6__stdcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__stdcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__stdcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__stdcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__fastcall() +17041 +>>> f_1__fastcall(1) +1 +>>> f_2__fastcall(1, 2) +21 +>>> f_3__fastcall(1, 2, 3) +321 +>>> f_4__fastcall(1, 2, 3, 4) +4321 +>>> f_5__fastcall(1, 2, 3, 4, 5) +54321 +>>> f_6__fastcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__fastcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__fastcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__fastcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/calling_conventions_mf.cpp b/libs/python/test/calling_conventions_mf.cpp new file mode 100644 index 000000000..80ccc4068 --- /dev/null +++ b/libs/python/test/calling_conventions_mf.cpp @@ -0,0 +1,159 @@ +// +// adapted from bind_stdcall_mf_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#define BOOST_PYTHON_ENABLE_CDECL +#define BOOST_PYTHON_ENABLE_STDCALL +#define BOOST_PYTHON_ENABLE_FASTCALL +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/stringize.hpp> +#include <boost/python.hpp> +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_mf_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + void TESTED_CALLING_CONVENTION f0() { f1(17); } + void TESTED_CALLING_CONVENTION g0() const { g1(17); } + + void TESTED_CALLING_CONVENTION f1(int a1) { hash = (hash * 17041 + a1) % 32768; } + void TESTED_CALLING_CONVENTION g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; } + + void TESTED_CALLING_CONVENTION f2(int a1, int a2) { f1(a1); f1(a2); } + void TESTED_CALLING_CONVENTION g2(int a1, int a2) const { g1(a1); g1(a2); } + + void TESTED_CALLING_CONVENTION f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); } + void TESTED_CALLING_CONVENTION g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); } + + void TESTED_CALLING_CONVENTION f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); } + void TESTED_CALLING_CONVENTION g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); } + + void TESTED_CALLING_CONVENTION f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); } + void TESTED_CALLING_CONVENTION g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); } + + void TESTED_CALLING_CONVENTION f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); } + void TESTED_CALLING_CONVENTION g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); } + + void TESTED_CALLING_CONVENTION f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); } + void TESTED_CALLING_CONVENTION g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); } + + void TESTED_CALLING_CONVENTION f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); } + void TESTED_CALLING_CONVENTION g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); } +}; + +} // namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +{ + + typedef BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::X X; + + class_<X>("X" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION)) + .def("f0", &X::f0) + .def("g0", &X::g0) + .def("f1", &X::f1) + .def("g1", &X::g1) + .def("f2", &X::f2) + .def("g2", &X::g2) + .def("f3", &X::f3) + .def("g3", &X::g3) + .def("f4", &X::f4) + .def("g4", &X::g4) + .def("f5", &X::f5) + .def("g5", &X::g5) + .def("f6", &X::f6) + .def("g6", &X::g6) + .def("f7", &X::f7) + .def("g7", &X::g7) + .def("f8", &X::f8) + .def("g8", &X::g8) + .def_readonly("hash", &X::hash) + ; + +} + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/libs/python/test/calling_conventions_mf.py b/libs/python/test/calling_conventions_mf.py new file mode 100644 index 000000000..1ec9c2b6c --- /dev/null +++ b/libs/python/test/calling_conventions_mf.py @@ -0,0 +1,84 @@ +# Copyright Nicolas Lelong, 2010. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from calling_conventions_mf_ext import * +>>> x = X__cdecl() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__stdcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__fastcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/class.cpp b/libs/python/test/class.cpp new file mode 100644 index 000000000..078bebdf6 --- /dev/null +++ b/libs/python/test/class.cpp @@ -0,0 +1,28 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/object.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +struct X +{ + int x; + X(int n) : x(n) { } +}; + +int x_function(X& x) +{ return x.x; +} + + +BOOST_PYTHON_MODULE(class_ext) +{ + class_<X>("X", init<int>()); + def("x_function", x_function); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/class.py b/libs/python/test/class.py new file mode 100755 index 000000000..d68ff4378 --- /dev/null +++ b/libs/python/test/class.py @@ -0,0 +1,40 @@ +# Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from class_ext import * + +Ensure sanity: + + >>> x = X(42) + >>> x_function(x) + 42 + +Demonstrate extraction in the presence of metaclass changes: + + >>> class MetaX(X.__class__): + ... def __new__(cls, *args): + ... return super(MetaX, cls).__new__(cls, *args) + >>> class XPlusMetatype(X): + ... __metaclass__ = MetaX + >>> x = XPlusMetatype(42) + >>> x_function(x) + 42 + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/cltree.cpp b/libs/python/test/cltree.cpp new file mode 100644 index 000000000..518ae37fe --- /dev/null +++ b/libs/python/test/cltree.cpp @@ -0,0 +1,74 @@ +// Copyright David Abrahams 2005. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/utility.hpp> + +/* Non-modifiable definitions */ + +class basic { +public: + basic() { name = "cltree.basic"; } + std::string repr() { return name+"()"; } +protected: + std::string name; +}; + +class constant: public basic { +public: + constant() { name = "cltree.constant"; } +}; + +class symbol: public basic { +public: + symbol() { name = "cltree.symbol"; } +}; + +class variable: public basic { +public: + variable() { name = "cltree.variable"; } +}; + +/* EOF: Non-modifiable definitions */ + +class symbol_wrapper: public symbol { +public: + symbol_wrapper(PyObject* /*self*/): symbol() { + name = "cltree.wrapped_symbol"; + } +}; + +class variable_wrapper: public variable { +public: + variable_wrapper(PyObject* /*self*/): variable() { + name = "cltree.wrapped_variable"; + } + + // This constructor is introduced only because cannot use + // boost::noncopyable, see below. + variable_wrapper(PyObject* /*self*/,variable v): variable(v) {} + +}; + +BOOST_PYTHON_MODULE(cltree) +{ + boost::python::class_<basic>("basic") + .def("__repr__",&basic::repr) + ; + + boost::python::class_<constant, boost::python::bases<basic>, boost::noncopyable>("constant") + ; + + + boost::python::class_<symbol, symbol_wrapper, boost::noncopyable>("symbol") + ; + + boost::python::class_<variable, boost::python::bases<basic>, variable_wrapper>("variable") + ; +} + +#include "module_tail.cpp" + diff --git a/libs/python/test/complicated.hpp b/libs/python/test/complicated.hpp new file mode 100644 index 000000000..5ff19aea0 --- /dev/null +++ b/libs/python/test/complicated.hpp @@ -0,0 +1,38 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef COMPLICATED_DWA20011215_HPP +# define COMPLICATED_DWA20011215_HPP +# include <iostream> + +# include "simple_type.hpp" + +struct complicated +{ + complicated(simple const&, int = 0); + ~complicated(); + + int get_n() const; + + char* s; + int n; +}; + +inline complicated::complicated(simple const&s, int _n) + : s(s.s), n(_n) +{ + std::cout << "constructing complicated: " << this->s << ", " << _n << std::endl; +} + +inline complicated::~complicated() +{ + std::cout << "destroying complicated: " << this->s << ", " << n << std::endl; +} + +inline int complicated::get_n() const +{ + return n; +} + +#endif // COMPLICATED_DWA20011215_HPP diff --git a/libs/python/test/const_argument.cpp b/libs/python/test/const_argument.cpp new file mode 100644 index 000000000..6c5a89456 --- /dev/null +++ b/libs/python/test/const_argument.cpp @@ -0,0 +1,30 @@ +/* Copyright 2004 Jonathan Brandmeyer + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * The purpose of this test is to determine if a function can be called from + * Python with a const value type as an argument, and whether or not the + * presence of a prototype without the cv-qualifier will work around the + * compiler's bug. + */ +#include <boost/python.hpp> +#include <boost/type_traits/broken_compiler_spec.hpp> +using namespace boost::python; + +BOOST_TT_BROKEN_COMPILER_SPEC( object ) + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) +bool accept_const_arg( object ); +#endif + +bool accept_const_arg( const object ) +{ + return true; +} + + +BOOST_PYTHON_MODULE( const_argument_ext ) +{ + def( "accept_const_arg", accept_const_arg ); +} diff --git a/libs/python/test/const_argument.py b/libs/python/test/const_argument.py new file mode 100644 index 000000000..15e87e802 --- /dev/null +++ b/libs/python/test/const_argument.py @@ -0,0 +1,23 @@ +# Copyright Jonathan Brandmeyer, 2004. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from const_argument_ext import * +>>> accept_const_arg(1) +1 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/copy_ctor_mutates_rhs.cpp b/libs/python/test/copy_ctor_mutates_rhs.cpp new file mode 100644 index 000000000..41eac495e --- /dev/null +++ b/libs/python/test/copy_ctor_mutates_rhs.cpp @@ -0,0 +1,23 @@ +// Copyright David Abrahams 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/detail/copy_ctor_mutates_rhs.hpp> +#include <boost/static_assert.hpp> +#include <memory> +#include <string> + +struct foo +{ + operator std::auto_ptr<int>&() const; +}; + +int main() +{ + using namespace boost::python::detail; + BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs<int>::value); + BOOST_STATIC_ASSERT(copy_ctor_mutates_rhs<std::auto_ptr<int> >::value); + BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs<std::string>::value); + BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs<foo>::value); + return 0; +} diff --git a/libs/python/test/crossmod_exception.py b/libs/python/test/crossmod_exception.py new file mode 100644 index 000000000..dd50dae27 --- /dev/null +++ b/libs/python/test/crossmod_exception.py @@ -0,0 +1,19 @@ +# Copyright (C) 2003 Rational Discovery LLC. Distributed under the Boost +# Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +# at http://www.boost.org/LICENSE_1_0.txt) + +print "running..." + +import crossmod_exception_a +import crossmod_exception_b + +try: + crossmod_exception_b.tossit() +except IndexError: + pass +try: + crossmod_exception_a.tossit() +except IndexError: + pass + +print "Done." diff --git a/libs/python/test/crossmod_exception_a.cpp b/libs/python/test/crossmod_exception_a.cpp new file mode 100644 index 000000000..9526129af --- /dev/null +++ b/libs/python/test/crossmod_exception_a.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2003 Rational Discovery LLC +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python.hpp> + +namespace python = boost::python; + +void tossit(){ + PyErr_SetString(PyExc_IndexError,"a-blah!"); + throw python::error_already_set(); +} + +BOOST_PYTHON_MODULE(crossmod_exception_a) +{ + python::def("tossit",tossit); +} diff --git a/libs/python/test/crossmod_exception_b.cpp b/libs/python/test/crossmod_exception_b.cpp new file mode 100644 index 000000000..e2ea491ca --- /dev/null +++ b/libs/python/test/crossmod_exception_b.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2003 Rational Discovery LLC +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python.hpp> + +namespace python = boost::python; + +void tossit(){ + PyErr_SetString(PyExc_IndexError,"b-blah!"); + throw python::error_already_set(); +} + +BOOST_PYTHON_MODULE(crossmod_exception_b) +{ + python::def("tossit",tossit); +} diff --git a/libs/python/test/crossmod_opaque.py b/libs/python/test/crossmod_opaque.py new file mode 100644 index 000000000..a7a3cf2cb --- /dev/null +++ b/libs/python/test/crossmod_opaque.py @@ -0,0 +1,16 @@ +# -*- coding: latin-1 -*- +# Copyright Gottfried Ganßauge 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if __name__ == '__main__': + print "running..." + + import crossmod_opaque_a + import crossmod_opaque_b + + crossmod_opaque_a.get() + crossmod_opaque_b.get() + + print "Done." diff --git a/libs/python/test/crossmod_opaque_a.cpp b/libs/python/test/crossmod_opaque_a.cpp new file mode 100644 index 000000000..80283f47f --- /dev/null +++ b/libs/python/test/crossmod_opaque_a.cpp @@ -0,0 +1,26 @@ +// Copyright Gottfried Ganßauge 2006. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get() { return the_op; } + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(crossmod_opaque_a) +{ + bpl::def ( + "get", + &::get, + bpl::return_value_policy<bpl::return_opaque_pointer>()); +} diff --git a/libs/python/test/crossmod_opaque_b.cpp b/libs/python/test/crossmod_opaque_b.cpp new file mode 100644 index 000000000..1e3e18bcb --- /dev/null +++ b/libs/python/test/crossmod_opaque_b.cpp @@ -0,0 +1,26 @@ +// Copyright Gottfried Ganßauge 2006. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get() { return the_op; } + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(crossmod_opaque_b) +{ + bpl::def ( + "get", + &::get, + bpl::return_value_policy<bpl::return_opaque_pointer>()); +} diff --git a/libs/python/test/data_members.cpp b/libs/python/test/data_members.cpp new file mode 100644 index 000000000..6d2cc7bd4 --- /dev/null +++ b/libs/python/test/data_members.cpp @@ -0,0 +1,132 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/return_by_value.hpp> +#include "test_class.hpp" + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include <iostream> // works around a KCC intermediate code generation bug +#endif + + +using namespace boost::python; + +typedef test_class<> X; + +struct Y : test_class<1> +{ + Y(int v) : test_class<1>(v) {} + Y& operator=(Y const& rhs) { x = rhs.x; return *this; } + bool q; +}; + +double get_fair_value(X const& x) { return x.value(); } + + +struct VarBase +{ + VarBase(std::string name_) : name(name_) {} + + std::string const name; + std::string get_name1() const { return name; } + +}; + +struct Var : VarBase +{ + Var(std::string name_) : VarBase(name_), value(), name2(name.c_str()), y(6) {} + std::string const& get_name2() const { return name; } + float value; + char const* name2; + Y y; + + static int static1; + static Y static2; +}; + +int Var::static1 = 0; +Y Var::static2(0); + +// Compilability regression tests +namespace boost_python_test +{ + struct trivial + { + trivial() : value(123) {} + double value; + }; + + struct Color3 + { + static const Color3 black; + }; + + const Color3 Color3::black +#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + = {} +#endif + ; + + void compilability_test() + { + class_<trivial>("trivial") + .add_property("property", make_getter(&trivial::value, return_value_policy<return_by_value>())) + .def_readonly("readonly", &trivial::value) + ; + + class_< Color3 >("Color3", init< const Color3 & >()) + .def_readonly("BLACK", &Color3::black) // line 17 + ; + } +} + +BOOST_PYTHON_MODULE(data_members_ext) +{ + using namespace boost_python_test; + class_<X>("X", init<int>()) + .def("value", &X::value) + .def("set", &X::set) + .def_readonly("x", &X::x) + .add_property("fair_value", get_fair_value) + ; + + class_<Y>("Y", init<int>()) + .def("value", &Y::value) + .def("set", &Y::set) + .def_readwrite("x", &Y::x) + .def_readwrite("q", &Y::q) + ; + + class_<Var>("Var", init<std::string>()) + .def_readonly("name", &Var::name) + .def_readonly("name2", &Var::name2) + .def_readwrite("value", &Var::value) + .def_readonly("y", &Var::y) + + // Test return_by_value for plain values and for + // pointers... return_by_value was implemented as a + // side-effect of implementing data member support, so it made + // sense to add the test here. + .def("get_name1", &Var::get_name1, return_value_policy<return_by_value>()) + .def("get_name2", &Var::get_name2, return_value_policy<return_by_value>()) + + .add_property("name3", &Var::get_name1) + + // Test static data members + .def_readonly("ro1a", &Var::static1) + .def_readonly("ro1b", Var::static1) + .def_readwrite("rw1a", &Var::static1) + .def_readwrite("rw1b", Var::static1) + + .def_readonly("ro2a", &Var::static2) + .def_readonly("ro2b", Var::static2) + .def_readwrite("rw2a", &Var::static2) + .def_readwrite("rw2b", Var::static2) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/data_members.py b/libs/python/test/data_members.py new file mode 100644 index 000000000..70784853e --- /dev/null +++ b/libs/python/test/data_members.py @@ -0,0 +1,215 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from data_members_ext import * + + ---- Test static data members --- + +>>> v = Var('slim shady') + +>>> Var.ro2a.x +0 +>>> Var.ro2b.x +0 +>>> Var.rw2a.x +0 +>>> Var.rw2b.x +0 +>>> v.ro2a.x +0 +>>> v.ro2b.x +0 +>>> v.rw2a.x +0 +>>> v.rw2b.x +0 +>>> Var.rw2a.x = 777 +>>> Var.ro2a.x +777 +>>> Var.ro2b.x +777 +>>> Var.rw2a.x +777 +>>> Var.rw2b.x +777 +>>> v.ro2a.x +777 +>>> v.ro2b.x +777 +>>> v.rw2a.x +777 +>>> v.rw2b.x +777 +>>> Var.rw2b = Y(888) + +>>> y = Y(99) +>>> y.q = True +>>> y.q +True +>>> y.q = False +>>> y.q +False + +>>> Var.ro2a.x +888 +>>> Var.ro2b.x +888 +>>> Var.rw2a.x +888 +>>> Var.rw2b.x +888 +>>> v.ro2a.x +888 +>>> v.ro2b.x +888 +>>> v.rw2a.x +888 +>>> v.rw2b.x +888 +>>> v.rw2b.x = 999 +>>> Var.ro2a.x +999 +>>> Var.ro2b.x +999 +>>> Var.rw2a.x +999 +>>> Var.rw2b.x +999 +>>> v.ro2a.x +999 +>>> v.ro2b.x +999 +>>> v.rw2a.x +999 +>>> v.rw2b.x +999 + + +>>> Var.ro1a +0 +>>> Var.ro1b +0 +>>> Var.rw1a +0 +>>> Var.rw1b +0 +>>> v.ro1a +0 +>>> v.ro1b +0 +>>> v.rw1a +0 +>>> v.rw1b +0 +>>> Var.rw1a = 777 +>>> Var.ro1a +777 +>>> Var.ro1b +777 +>>> Var.rw1a +777 +>>> Var.rw1b +777 +>>> v.ro1a +777 +>>> v.ro1b +777 +>>> v.rw1a +777 +>>> v.rw1b +777 +>>> Var.rw1b = 888 +>>> Var.ro1a +888 +>>> Var.ro1b +888 +>>> Var.rw1a +888 +>>> Var.rw1b +888 +>>> v.ro1a +888 +>>> v.ro1b +888 +>>> v.rw1a +888 +>>> v.rw1b +888 +>>> v.rw1b = 999 +>>> Var.ro1a +999 +>>> Var.ro1b +999 +>>> Var.rw1a +999 +>>> Var.rw1b +999 +>>> v.ro1a +999 +>>> v.ro1b +999 +>>> v.rw1a +999 +>>> v.rw1b +999 + + + + ----------------- + +>>> x = X(42) +>>> x.x +42 +>>> try: x.x = 77 +... except AttributeError: pass +... else: print 'no error' + +>>> x.fair_value +42.0 +>>> y = Y(69) +>>> y.x +69 +>>> y.x = 77 +>>> y.x +77 + +>>> v = Var("pi") +>>> v.value = 3.14 +>>> v.name +'pi' +>>> v.name2 +'pi' + +>>> v.get_name1() +'pi' + +>>> v.get_name2() +'pi' + +>>> v.y.x +6 +>>> v.y.x = -7 +>>> v.y.x +-7 + +>>> v.name3 +'pi' + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/defaults.cpp b/libs/python/test/defaults.cpp new file mode 100644 index 000000000..6d87e5d6e --- /dev/null +++ b/libs/python/test/defaults.cpp @@ -0,0 +1,173 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/list.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/return_internal_reference.hpp> + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include <iostream> // works around a KCC intermediate code generation bug +#endif + +using namespace boost::python; +namespace bpl = boost::python; + +char const* const format = "int(%s); char(%s); string(%s); double(%s); "; + +/////////////////////////////////////////////////////////////////////////////// +// +// Overloaded functions +// +/////////////////////////////////////////////////////////////////////////////// +object +bar(int a, char b, std::string c, double d) +{ + return format % bpl::make_tuple(a, b, c, d); +} + +object +bar(int a, char b, std::string c) +{ + return format % bpl::make_tuple(a, b, c, 0.0); +} + +object +bar(int a, char b) +{ + return format % bpl::make_tuple(a, b, "default", 0.0); +} + +object +bar(int a) +{ + return format % bpl::make_tuple(a, 'D', "default", 0.0); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(bar_stubs, bar, 1, 4) + +/////////////////////////////////////////////////////////////////////////////// +// +// Functions with default arguments +// +/////////////////////////////////////////////////////////////////////////////// +object +foo(int a, char b = 'D', std::string c = "default", double d = 0.0) +{ + return format % bpl::make_tuple(a, b, c, d); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(foo_stubs, foo, 1, 4) + +/////////////////////////////////////////////////////////////////////////////// +// +// Overloaded member functions with default arguments +// +/////////////////////////////////////////////////////////////////////////////// +struct Y { + + Y() {} + + object + get_state() const + { + return format % bpl::make_tuple(a, b, c, d); + } + + int a; char b; std::string c; double d; +}; + + +struct X { + + X() {} + + X(int a, char b = 'D', std::string c = "constructor", double d = 0.0) + : state(format % bpl::make_tuple(a, b, c, d)) + {} + + X(std::string s, bool b) + : state("Got exactly two arguments from constructor: string(%s); bool(%s); " % bpl::make_tuple(s, b*1)) + {} + + object + bar(int a, char b = 'D', std::string c = "default", double d = 0.0) const + { + return format % bpl::make_tuple(a, b, c, d); + } + + Y const& + bar2(int a = 0, char b = 'D', std::string c = "default", double d = 0.0) + { + // tests zero arg member function and return_internal_reference policy + y.a = a; + y.b = b; + y.c = c; + y.d = d; + return y; + } + + object + foo(int a, bool b=false) const + { + return "int(%s); bool(%s); " % bpl::make_tuple(a, b*1); + } + + object + foo(std::string a, bool b=false) const + { + return "string(%s); bool(%s); " % bpl::make_tuple(a, b*1); + } + + object + foo(list a, list b, bool c=false) const + { + return "list(%s); list(%s); bool(%s); " % bpl::make_tuple(a, b, c*1); + } + + object + get_state() const + { + return state; + } + + Y y; + object state; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_bar_stubs, bar, 1, 4) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_bar_stubs2, bar2, 0, 4) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_foo_2_stubs, foo, 1, 2) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_foo_3_stubs, foo, 2, 3) + +/////////////////////////////////////////////////////////////////////////////// + +BOOST_PYTHON_MODULE(defaults_ext) +{ + def("foo", foo, foo_stubs()); + def("bar", (object(*)(int, char, std::string, double))0, bar_stubs()); + + class_<Y>("Y", init<>("doc of Y init")) // this should work + .def("get_state", &Y::get_state) + ; + + class_<X>("X",no_init) + + .def(init<optional<int, char, std::string, double> >("doc of init", args("self", "a", "b", "c", "d"))) + .def(init<std::string, bool>(args("self", "s", "b"))[default_call_policies()]) // what's a good policy here? + .def("get_state", &X::get_state) + .def("bar", &X::bar, X_bar_stubs()) + .def("bar2", &X::bar2, X_bar_stubs2("doc of X::bar2")[return_internal_reference<>()]) + .def("foo", (object(X::*)(std::string, bool) const)0, X_foo_2_stubs()) + .def("foo", (object(X::*)(int, bool) const)0, X_foo_2_stubs()) + .def("foo", (object(X::*)(list, list, bool) const)0, X_foo_3_stubs()) + ; +} + +#include "module_tail.cpp" + diff --git a/libs/python/test/defaults.py b/libs/python/test/defaults.py new file mode 100644 index 000000000..cd51a4a4d --- /dev/null +++ b/libs/python/test/defaults.py @@ -0,0 +1,140 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from defaults_ext import * +>>> bar(1) +'int(1); char(D); string(default); double(0.0); ' + +>>> bar(2, 'X') +'int(2); char(X); string(default); double(0.0); ' + +>>> bar(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0.0); ' + +>>> bar(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' + +>>> foo(1) +'int(1); char(D); string(default); double(0.0); ' + +>>> foo(2, 'X') +'int(2); char(X); string(default); double(0.0); ' + +>>> foo(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0.0); ' + +>>> foo(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' + +>>> x = X() +>>> x.bar(1) +'int(1); char(D); string(default); double(0.0); ' + +>>> x.bar(2, 'X') +'int(2); char(X); string(default); double(0.0); ' + +>>> x.bar(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0.0); ' + +>>> x.bar(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' + +>>> x.foo(5) +'int(5); bool(0); ' + +>>> x.foo(6, 0) +'int(6); bool(0); ' + +>>> x.foo(7, 1) +'int(7); bool(1); ' + +>>> x.foo("A") +'string(A); bool(0); ' + +>>> x.foo("B", False) +'string(B); bool(0); ' + +>>> x.foo("C", True) +'string(C); bool(1); ' + +>>> x.foo([0,1,2], [2,3,4]) +'list([0, 1, 2]); list([2, 3, 4]); bool(0); ' + +>>> x.foo([0,1,2], [2,3,4], False) +'list([0, 1, 2]); list([2, 3, 4]); bool(0); ' + +>>> x.foo([0,1,2], [2,3,4], True) +'list([0, 1, 2]); list([2, 3, 4]); bool(1); ' + +>>> x = X(1) +>>> x.get_state() +'int(1); char(D); string(constructor); double(0.0); ' + +>>> x = X(1, 'X') +>>> x.get_state() +'int(1); char(X); string(constructor); double(0.0); ' + +>>> x = X(1, 'X', "Yabadabadoo") +>>> x.get_state() +'int(1); char(X); string(Yabadabadoo); double(0.0); ' + +>>> x = X(1, 'X', "Phoenix", 3.65) +>>> x.get_state() +'int(1); char(X); string(Phoenix); double(3.65); ' + +>>> x.bar2().get_state() +'int(0); char(D); string(default); double(0.0); ' + +>>> x.bar2(1).get_state() +'int(1); char(D); string(default); double(0.0); ' + +>>> x.bar2(1, 'K').get_state() +'int(1); char(K); string(default); double(0.0); ' + +>>> x.bar2(1, 'K', "Kim").get_state() +'int(1); char(K); string(Kim); double(0.0); ' + +>>> x.bar2(1, 'K', "Kim", 9.9).get_state() +'int(1); char(K); string(Kim); double(9.9); ' + +>>> x = X("Phoenix", 1) +>>> x.get_state() +'Got exactly two arguments from constructor: string(Phoenix); bool(1); ' + +>>> def selected_doc(obj, *args): +... doc = obj.__doc__.splitlines() +... return "\\n".join(["|"+doc[i] for i in args]) + +>>> print selected_doc(X.__init__, 1, 2, 4, 7, 9) +|__init__( (object)self [, (int)a [, (str)b [, (str)c [, (float)d]]]]) -> None : +| doc of init +| C++ signature : +|__init__( (object)self, (str)s, (bool)b) -> None : +| C++ signature : + +>>> print selected_doc(Y.__init__, 1, 2, 4) +|__init__( (object)arg1) -> None : +| doc of Y init +| C++ signature : + +>>> print selected_doc(X.bar2, 1, 2, 4) +|bar2( (X)arg1 [, (int)arg2 [, (str)arg3 [, (str)arg4 [, (float)arg5]]]]) -> Y : +| doc of X::bar2 +| C++ signature : + +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/destroy_test.cpp b/libs/python/test/destroy_test.cpp new file mode 100644 index 000000000..cae95ae91 --- /dev/null +++ b/libs/python/test/destroy_test.cpp @@ -0,0 +1,59 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/detail/destroy.hpp> + +#include <boost/detail/lightweight_test.hpp> + +int count; +int marks[] = { + -1 + , -1, -1 + , -1, -1, -1, -1 + , -1 +}; +int* kills = marks; + +struct foo +{ + foo() : n(count++) {} + ~foo() + { + *kills++ = n; + } + int n; + + // This used to cause compiler errors with MSVC 9.0. + foo& operator~(); + foo& T(); +}; + +void assert_destructions(int n) +{ + for (int i = 0; i < n; ++i) + BOOST_TEST(marks[i] == i); + BOOST_TEST(marks[n] == -1); +} + +int main() +{ + assert_destructions(0); + typedef int a[2]; + + foo* f1 = new foo; + boost::python::detail::destroy_referent<foo const volatile&>(f1); + assert_destructions(1); + + foo* f2 = new foo[2]; + typedef foo x[2]; + + boost::python::detail::destroy_referent<x const&>(f2); + assert_destructions(3); + + typedef foo y[2][2]; + x* f3 = new y; + boost::python::detail::destroy_referent<y&>(f3); + assert_destructions(7); + + return boost::report_errors(); +} diff --git a/libs/python/test/dict.cpp b/libs/python/test/dict.cpp new file mode 100644 index 000000000..375905d69 --- /dev/null +++ b/libs/python/test/dict.cpp @@ -0,0 +1,91 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/dict.hpp> +#include <exception> +#include <string> + +using namespace boost::python; + +object new_dict() +{ + return dict(); +} + +object data_dict() +{ + dict tmp1; + tmp1["key1"] = "value1"; + + dict tmp2; + tmp2["key2"] = "value2"; + tmp1[1] = tmp2; + return tmp1; +} + +object dict_from_sequence(object sequence) +{ + return dict(sequence); +} + +object dict_keys(dict data) +{ + return data.keys(); +} + +object dict_values(dict data) +{ + return data.values(); +} + +object dict_items(dict data) +{ + return data.items(); +} + +void work_with_dict(dict data1, dict data2) +{ + if (!data1.has_key("k1")) { + throw std::runtime_error("dict does not have key 'k1'"); + } + data1.update(data2); +} + +void test_templates(object print) +{ + std::string key = "key"; + + dict tmp; + tmp[1] = "a test string"; + print(tmp.get(1)); + //print(tmp[1]); + tmp[1.5] = 13; + print(tmp.get(1.5)); + print(tmp.get(44)); + print(tmp); + print(tmp.get(2,"default")); + print(tmp.setdefault(3,"default")); + + BOOST_ASSERT(!tmp.has_key(key)); + //print(tmp[3]); +} + +BOOST_PYTHON_MODULE(dict_ext) +{ + def("new_dict", new_dict); + def("data_dict", data_dict); + def("dict_keys", dict_keys); + def("dict_values", dict_values); + def("dict_items", dict_items); + def("dict_from_sequence", dict_from_sequence); + def("work_with_dict", work_with_dict); + def("test_templates", test_templates); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/dict.py b/libs/python/test/dict.py new file mode 100644 index 000000000..a321beea9 --- /dev/null +++ b/libs/python/test/dict.py @@ -0,0 +1,45 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from dict_ext import * +>>> def printer(*args): +... for x in args: print x, +... print +... +>>> print new_dict() +{} +>>> print data_dict() +{1: {'key2': 'value2'}, 'key1': 'value1'} +>>> tmp = data_dict() +>>> print dict_keys(tmp) +[1, 'key1'] +>>> print dict_values(tmp) +[{'key2': 'value2'}, 'value1'] +>>> print dict_items(tmp) +[(1, {'key2': 'value2'}), ('key1', 'value1')] +>>> print dict_from_sequence([(1,1),(2,2),(3,3)]) +{1: 1, 2: 2, 3: 3} +>>> test_templates(printer) #doctest: +NORMALIZE_WHITESPACE +a test string +13 +None +{1.5: 13, 1: 'a test string'} +default +default +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/docstring.cpp b/libs/python/test/docstring.cpp new file mode 100644 index 000000000..c6cc0252b --- /dev/null +++ b/libs/python/test/docstring.cpp @@ -0,0 +1,116 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/operators.hpp> +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/docstring_options.hpp> +#include <boost/python/scope.hpp> +#include <boost/python/manage_new_object.hpp> +#include "test_class.hpp" + +// Just use math.h here; trying to use std::pow() causes too much +// trouble for non-conforming compilers and libraries. +#include <math.h> + +using namespace boost::python; + +typedef test_class<> X; + +X* create(int x) +{ + return new X(x); +} + +unsigned long fact(unsigned long n) +{ + return n <= 1 ? n : n * fact(n - 1); +} + +BOOST_PYTHON_MODULE(docstring_ext) +{ + scope().attr("__doc__") = + "A simple test module for documentation strings\n" + "Exercised by docstring.py" + ; + + class_<X>("X", + "A simple class wrapper around a C++ int\n" + "includes some error-checking" + + , init<int>( + "this is the __init__ function\n" + "its documentation has two lines." + , args("self", "value") + ) + + ) + .def("value", &X::value, + "gets the value of the object" + , args("self")) + .def( "value", &X::value, + "also gets the value of the object" + , args("self")) + ; + + def("create", create, return_value_policy<manage_new_object>(), + "creates a new X object", args("value")); + + def("fact", fact, "compute the factorial", args("n")); + + { + docstring_options doc_options; + doc_options.disable_user_defined(); + def("fact_usr_off_1", fact, "usr off 1", args("n")); + doc_options.enable_user_defined(); + def("fact_usr_on_1", fact, "usr on 1", args("n")); + doc_options.disable_user_defined(); + def("fact_usr_off_2", fact, "usr off 2", args("n")); + } + def("fact_usr_on_2", fact, "usr on 2", args("n")); + + { + docstring_options doc_options(true, false); + def("fact_sig_off_1", fact, "sig off 1", args("n")); + doc_options.enable_signatures(); + def("fact_sig_on_1", fact, "sig on 1", args("n")); + doc_options.disable_signatures(); + def("fact_sig_off_2", fact, "sig off 2", args("n")); + } + def("fact_sig_on_2", fact, "sig on 2", args("n")); + + { + docstring_options doc_options(false); + def("fact_usr_off_sig_off_1", fact, "usr off sig off 1", args("n")); + { + docstring_options nested_doc_options; + def("fact_usr_on_sig_on_1", fact, "usr on sig on 1", args("n")); + nested_doc_options.disable_all(); + nested_doc_options.enable_user_defined(); + def("fact_usr_on_sig_off_1", fact, "usr on sig off 1", args("n")); + nested_doc_options.enable_all(); + def("fact_usr_on_sig_on_2", fact, "usr on sig on 2", args("n")); + } + def("fact_usr_off_sig_off_2", fact, "usr off sig off 2", args("n")); + } + + { + docstring_options doc_options(true); + doc_options.disable_cpp_signatures(); + def("fact_usr_on_psig_on_csig_off_1", fact, "usr on psig on csig off 1", args("n")); + doc_options.enable_cpp_signatures(); + doc_options.disable_py_signatures(); + def("fact_usr_on_psig_off_csig_on_1", fact, "usr on psig off csig on 1", args("n")); + doc_options.enable_py_signatures(); + doc_options.disable_user_defined(); + doc_options.disable_cpp_signatures(); + def("fact_usr_off_psig_on_csig_off_1", fact, "usr off psig on csig off 1", args("n")); + doc_options.enable_cpp_signatures(); + doc_options.disable_py_signatures(); + def("fact_usr_off_psig_off_csig_on_1", fact, "usr off psig off csig on 1", args("n")); + } +} + +#include "module_tail.cpp" diff --git a/libs/python/test/docstring.py b/libs/python/test/docstring.py new file mode 100644 index 000000000..528ce8456 --- /dev/null +++ b/libs/python/test/docstring.py @@ -0,0 +1,153 @@ +# Copyright David Abrahams & Ralf W. Grosse-Kunsteve 2004-2006. +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from docstring_ext import * + +>>> def selected_doc(obj, *args): +... doc = obj.__doc__.splitlines() +... return "\\n".join(["|"+doc[i] for i in args]) + +>>> print selected_doc(X.__init__, 1, 2, 3, 4, 5) +|__init__( (object)self, (int)value) -> None : +| this is the __init__ function +| its documentation has two lines. +| +| C++ signature : + +>>> print selected_doc(X.value, 1, 2, 4, 7, 8, 10) +|value( (X)self) -> int : +| gets the value of the object +| C++ signature : +|value( (X)self) -> int : +| also gets the value of the object +| C++ signature : + +>>> print selected_doc(create, 1, 2, 3, 4) +|create( (int)value) -> X : +| creates a new X object +| +| C++ signature : + +>>> print selected_doc(fact, 1, 2, 3, 4) +|fact( (int)n) -> int : +| compute the factorial +| +| C++ signature : + +>>> len(fact_usr_off_1.__doc__.splitlines()) +5 +>>> print selected_doc(fact_usr_off_1, 1, 3) +|fact_usr_off_1( (int)n) -> int : +| C++ signature : +>>> len(fact_usr_on_1.__doc__.splitlines()) +6 +>>> print selected_doc(fact_usr_on_1, 1, 2, 4) +|fact_usr_on_1( (int)n) -> int : +| usr on 1 +| C++ signature : +>>> len(fact_usr_off_2.__doc__.splitlines()) +5 +>>> print selected_doc(fact_usr_off_2, 1, 3) +|fact_usr_off_2( (int)n) -> int : +| C++ signature : +>>> len(fact_usr_on_2.__doc__.splitlines()) +6 +>>> print selected_doc(fact_usr_on_2, 1, 2, 4) +|fact_usr_on_2( (int)n) -> int : +| usr on 2 +| C++ signature : + + +>>> len(fact_sig_off_1.__doc__.splitlines()) +2 +>>> print selected_doc(fact_sig_off_1, 1) +|sig off 1 +>>> len(fact_sig_on_1.__doc__.splitlines()) +6 +>>> print selected_doc(fact_sig_on_1, 1, 2, 4) +|fact_sig_on_1( (int)n) -> int : +| sig on 1 +| C++ signature : + +>>> len(fact_sig_off_2.__doc__.splitlines()) +2 +>>> print selected_doc(fact_sig_off_2, 1) +|sig off 2 +>>> len(fact_sig_on_2.__doc__.splitlines()) +6 +>>> print selected_doc(fact_sig_on_2, 1, 2, 4) +|fact_sig_on_2( (int)n) -> int : +| sig on 2 +| C++ signature : + + +>>> print fact_usr_off_sig_off_1.__doc__ +None +>>> len(fact_usr_on_sig_on_1.__doc__.splitlines()) +6 +>>> print selected_doc(fact_usr_on_sig_on_1, 1, 2, 4) +|fact_usr_on_sig_on_1( (int)n) -> int : +| usr on sig on 1 +| C++ signature : + +>>> len(fact_usr_on_sig_off_1.__doc__.splitlines()) +2 +>>> print selected_doc(fact_usr_on_sig_off_1, 1) +|usr on sig off 1 +>>> len(fact_usr_on_sig_on_2.__doc__.splitlines()) +6 +>>> print selected_doc(fact_usr_on_sig_on_2, 1, 2, 4) +|fact_usr_on_sig_on_2( (int)n) -> int : +| usr on sig on 2 +| C++ signature : + +>>> print selected_doc(fact_usr_on_psig_on_csig_off_1, 1, 2) +|fact_usr_on_psig_on_csig_off_1( (int)n) -> int : +| usr on psig on csig off 1 + +>>> print selected_doc(fact_usr_on_psig_off_csig_on_1, 1, 3) +|usr on psig off csig on 1 +|C++ signature : + +>>> print fact_usr_off_psig_on_csig_off_1.__doc__.splitlines()[1] +fact_usr_off_psig_on_csig_off_1( (int)n) -> int + +>>> print selected_doc(fact_usr_off_psig_off_csig_on_1,1) +|C++ signature : + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + + import docstring_ext + + result = doctest.testmod(sys.modules.get(__name__)) + + import pydoc + import re + docmodule = lambda m: re.sub(".\10", "", pydoc.text.docmodule(m)) + try: + print 'printing module help:' + print docmodule(docstring_ext) + except object, x: + print '********* failed **********' + print x + result = list(result) + result[0] += 1 + return tuple(result) + + return result + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/enable_shared_from_this.cpp b/libs/python/test/enable_shared_from_this.cpp new file mode 100644 index 000000000..c246284a1 --- /dev/null +++ b/libs/python/test/enable_shared_from_this.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> +#include "test_class.hpp" + +#include <memory> + +using namespace boost::python; +using boost::shared_ptr; + +class Test; +typedef shared_ptr<Test> TestPtr; + +class Test : public boost::enable_shared_from_this<Test> { +public: + static TestPtr construct() { + return TestPtr(new Test); + } + + void act() { + TestPtr kungFuDeathGrip(shared_from_this()); + } + + void take(TestPtr t) { + } +}; + +BOOST_PYTHON_MODULE(enable_shared_from_this_ext) +{ + class_<Test, TestPtr, boost::noncopyable>("Test") + .def("construct", &Test::construct).staticmethod("construct") + .def("act", &Test::act) + .def("take", &Test::take) + ; +} + +#include "module_tail.cpp" + + diff --git a/libs/python/test/enable_shared_from_this.py b/libs/python/test/enable_shared_from_this.py new file mode 100755 index 000000000..cca46ec81 --- /dev/null +++ b/libs/python/test/enable_shared_from_this.py @@ -0,0 +1,26 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from enable_shared_from_this_ext import * + +>>> x = Test.construct() +>>> x.take(x) +>>> x.act() +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + diff --git a/libs/python/test/enum.cpp b/libs/python/test/enum.cpp new file mode 100644 index 000000000..e5c4f4fa9 --- /dev/null +++ b/libs/python/test/enum.cpp @@ -0,0 +1,55 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/enum.hpp> +#include <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) +# include <boost/type_traits/is_enum.hpp> +# include <boost/mpl/bool.hpp> +#endif +using namespace boost::python; + +enum color { red = 1, green = 2, blue = 4, blood = 1 }; + +#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) +namespace boost // Pro7 has a hard time detecting enums +{ + template <> struct is_enum<color> : boost::mpl::true_ {}; +} +#endif + +color identity_(color x) { return x; } + +struct colorized { + colorized() : x(red) {} + color x; +}; + +BOOST_PYTHON_MODULE(enum_ext) +{ + enum_<color>("color") + .value("red", red) + .value("green", green) + .value("blue", blue) + .value("blood", blood) + .export_values() + ; + + def("identity", identity_); + +#if BOOST_WORKAROUND(__MWERKS__, <=0x2407) + color colorized::*px = &colorized::x; + class_<colorized>("colorized") + .def_readwrite("x", px) + ; +#else + class_<colorized>("colorized") + .def_readwrite("x", &colorized::x) + ; +#endif +} + +#include "module_tail.cpp" diff --git a/libs/python/test/enum.py b/libs/python/test/enum.py new file mode 100644 index 000000000..c3ba3fe7e --- /dev/null +++ b/libs/python/test/enum.py @@ -0,0 +1,85 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from enum_ext import * + +>>> identity(color.red) # in case of duplicated enums it always take the last enum +enum_ext.color.blood + +>>> identity(color.green) +enum_ext.color.green + +>>> identity(color.blue) +enum_ext.color.blue + +>>> identity(color(1)) # in case of duplicated enums it always take the last enum +enum_ext.color.blood + +>>> identity(color(2)) +enum_ext.color.green + +>>> identity(color(3)) +enum_ext.color(3) + +>>> identity(color(4)) +enum_ext.color.blue + + --- check export to scope --- + +>>> identity(red) +enum_ext.color.blood + +>>> identity(green) +enum_ext.color.green + +>>> identity(blue) +enum_ext.color.blue + +>>> try: identity(1) +... except TypeError: pass +... else: print 'expected a TypeError' + +>>> c = colorized() +>>> c.x +enum_ext.color.blood +>>> c.x = green +>>> c.x +enum_ext.color.green +>>> red == blood +True +>>> red == green +False +>>> hash(red) == hash(blood) +True +>>> hash(red) == hash(green) +False +''' + +# pickling of enums only works with Python 2.3 or higher +exercise_pickling = ''' +>>> import pickle +>>> p = pickle.dumps(color.green, pickle.HIGHEST_PROTOCOL) +>>> l = pickle.loads(p) +>>> identity(l) +enum_ext.color.green +''' + +def run(args = None): + import sys + import doctest + import pickle + + if args is not None: + sys.argv = args + self = sys.modules.get(__name__) + if (hasattr(pickle, "HIGHEST_PROTOCOL")): + self.__doc__ += exercise_pickling + return doctest.testmod(self) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/exception_translator.cpp b/libs/python/test/exception_translator.cpp new file mode 100644 index 000000000..1e91c9296 --- /dev/null +++ b/libs/python/test/exception_translator.cpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/exception_translator.hpp> + +struct error {}; + +void translate(error const& /*e*/) +{ + PyErr_SetString(PyExc_RuntimeError, "!!!error!!!"); +} + +void throw_error() +{ + throw error(); + +} + +BOOST_PYTHON_MODULE(exception_translator_ext) +{ + using namespace boost::python; + register_exception_translator<error>(&translate); + + def("throw_error", throw_error); +} + diff --git a/libs/python/test/exception_translator.py b/libs/python/test/exception_translator.py new file mode 100644 index 000000000..9537c6f6f --- /dev/null +++ b/libs/python/test/exception_translator.py @@ -0,0 +1,27 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from exception_translator_ext import * +>>> try: +... throw_error(); +... except RuntimeError, x: +... print x +... else: +... print 'Expected a RuntimeError!' +!!!error!!! +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/exec.cpp b/libs/python/test/exec.cpp new file mode 100644 index 000000000..9fb005ea5 --- /dev/null +++ b/libs/python/test/exec.cpp @@ -0,0 +1,193 @@ +// Copyright Stefan Seefeld 2005. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <iostream> + + +namespace python = boost::python; + +// An abstract base class +class Base : public boost::noncopyable +{ +public: + virtual ~Base() {}; + virtual std::string hello() = 0; +}; + +// C++ derived class +class CppDerived : public Base +{ +public: + virtual ~CppDerived() {} + virtual std::string hello() { return "Hello from C++!";} +}; + +// Familiar Boost.Python wrapper class for Base +struct BaseWrap : Base, python::wrapper<Base> +{ + virtual std::string hello() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + // workaround for VC++ 6.x or 7.0, see + // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions + return python::call<std::string>(this->get_override("hello").ptr()); +#else + return this->get_override("hello")(); +#endif + } +}; + +// Pack the Base class wrapper into a module +BOOST_PYTHON_MODULE(embedded_hello) +{ + python::class_<BaseWrap, boost::noncopyable> base("Base"); +} + + +void eval_test() +{ + python::object result = python::eval("'abcdefg'.upper()"); + std::string value = python::extract<std::string>(result) BOOST_EXTRACT_WORKAROUND; + BOOST_TEST(value == "ABCDEFG"); +} + +void exec_test() +{ + // Register the module with the interpreter + if (PyImport_AppendInittab(const_cast<char*>("embedded_hello"), +#if PY_VERSION_HEX >= 0x03000000 + PyInit_embedded_hello +#else + initembedded_hello +#endif + ) == -1) + throw std::runtime_error("Failed to add embedded_hello to the interpreter's " + "builtin modules"); + // Retrieve the main module + python::object main = python::import("__main__"); + + // Retrieve the main module's namespace + python::object global(main.attr("__dict__")); + + // Define the derived class in Python. + python::object result = python::exec( + "from embedded_hello import * \n" + "class PythonDerived(Base): \n" + " def hello(self): \n" + " return 'Hello from Python!' \n", + global, global); + + python::object PythonDerived = global["PythonDerived"]; + + // Creating and using instances of the C++ class is as easy as always. + CppDerived cpp; + BOOST_TEST(cpp.hello() == "Hello from C++!"); + + // But now creating and using instances of the Python class is almost + // as easy! + python::object py_base = PythonDerived(); + Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND; + + // Make sure the right 'hello' method is called. + BOOST_TEST(py.hello() == "Hello from Python!"); +} + +void exec_file_test(std::string const &script) +{ + // Run a python script in an empty environment. + python::dict global; + python::object result = python::exec_file(script.c_str(), global, global); + + // Extract an object the script stored in the global dictionary. + BOOST_TEST(python::extract<int>(global["number"]) == 42); +} + +void exec_test_error() +{ + // Execute a statement that raises a python exception. + python::dict global; + python::object result = python::exec("print(unknown) \n", global, global); +} + +void exercise_embedding_html() +{ + using namespace boost::python; + /* code from: libs/python/doc/tutorial/doc/tutorial.qbk + (generates libs/python/doc/tutorial/doc/html/python/embedding.html) + */ + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + + object ignored = exec("hello = file('hello.txt', 'w')\n" + "hello.write('Hello world!')\n" + "hello.close()", + main_namespace); +} + +void check_pyerr(bool pyerr_expected=false) +{ + if (PyErr_Occurred()) + { + if (!pyerr_expected) { + BOOST_ERROR("Python Error detected"); + PyErr_Print(); + } + else { + PyErr_Clear(); + } + } + else + { + BOOST_ERROR("A C++ exception was thrown for which " + "there was no exception handler registered."); + } +} + +int main(int argc, char **argv) +{ + BOOST_TEST(argc == 2 || argc == 3); + std::string script = argv[1]; + // Initialize the interpreter + Py_Initialize(); + + if (python::handle_exception(eval_test)) { + check_pyerr(); + } + else if(python::handle_exception(exec_test)) { + check_pyerr(); + } + else if (python::handle_exception(boost::bind(exec_file_test, script))) { + check_pyerr(); + } + + if (python::handle_exception(exec_test_error)) + { + check_pyerr(/*pyerr_expected*/ true); + } + else + { + BOOST_ERROR("Python exception expected, but not seen."); + } + + if (argc > 2) { + // The main purpose is to test compilation. Since this test generates + // a file and I (rwgk) am uncertain about the side-effects, run it only + // if explicitly requested. + exercise_embedding_html(); + } + + // Boost.Python doesn't support Py_Finalize yet. + // Py_Finalize(); + return boost::report_errors(); +} + +// Including this file makes sure +// that on Windows, any crashes (e.g. null pointer dereferences) invoke +// the debugger immediately, rather than being translated into structured +// exceptions that can interfere with debugging. +#include "module_tail.cpp" diff --git a/libs/python/test/exec.py b/libs/python/test/exec.py new file mode 100644 index 000000000..c7bf28f35 --- /dev/null +++ b/libs/python/test/exec.py @@ -0,0 +1,6 @@ +# Copyright Stefan Seefeld 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +if 1: + number = 42 diff --git a/libs/python/test/extract.cpp b/libs/python/test/extract.cpp new file mode 100644 index 000000000..40584a077 --- /dev/null +++ b/libs/python/test/extract.cpp @@ -0,0 +1,143 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/extract.hpp> +#include <boost/python/list.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/implicit.hpp> +#include <string> +#include <boost/lexical_cast.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include "test_class.hpp" + +using namespace boost::python; + +typedef test_class<> X; + +bool extract_bool(object x) { return extract<bool>(x); } + +boost::python::list extract_list(object x) +{ + extract<list> get_list((x)); + + // Make sure we always have the right idea about whether it's a list + bool is_list_1 = get_list.check(); + bool is_list_2 = PyObject_IsInstance(x.ptr(), (PyObject*)&PyList_Type); + if (is_list_1 != is_list_2) { + throw std::runtime_error("is_list_1 == is_list_2 failure."); + } + return get_list(); +} + +char const* extract_cstring(object x) +{ + return extract<char const*>(x); +} + +std::string extract_string(object x) +{ + std::string s = extract<std::string>(x); + return s; +} + +std::string const& extract_string_cref(object x) +{ +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +# pragma warning(push) +# pragma warning(disable:4172) // msvc lies about returning a reference to temporary +#elif defined(_MSC_VER) && defined(__ICL) && __ICL <= 900 +# pragma warning(push) +# pragma warning(disable:473) // intel/win32 does too +#endif + + return extract<std::string const&>(x); + +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(_MSC_VER) && defined(__ICL) && __ICL <= 800 +# pragma warning(pop) +#endif +} + +X extract_X(object x) +{ + return extract<X>(x); +} + +X* extract_X_ptr(object x) { return extract<X*>(x); } + +X& extract_X_ref(object x) +{ + extract<X&> get_x(x); + return get_x; +} + +int double_X(object n) +{ + extract<X> x(n); + return x().value() + x().value(); +} + +bool check_bool(object x) { return extract<bool>(x).check(); } +bool check_list(object x) { return extract<list>(x).check(); } +bool check_cstring(object x) { return extract<char const*>(x).check(); } +bool check_string(object x) { return extract<std::string>(x).check(); } +bool check_string_cref(object x) { return extract<std::string const&>(x).check(); } +bool check_X(object x) { return extract<X>(x).check(); } +bool check_X_ptr(object x) { return extract<X*>(x).check(); } +bool check_X_ref(object x) { return extract<X&>(x).check(); } + +std::string x_rep(X const& x) +{ + return "X(" + boost::lexical_cast<std::string>(x.value()) + ")"; +} + +BOOST_PYTHON_MODULE(extract_ext) +{ + implicitly_convertible<int, X>(); + + def("extract_bool", extract_bool); + def("extract_list", extract_list); + def("extract_cstring", extract_cstring); + def("extract_string", extract_string); + def("extract_string_cref", extract_string_cref, return_value_policy<reference_existing_object>()); + def("extract_X", extract_X); + def("extract_X_ptr", extract_X_ptr, return_value_policy<reference_existing_object>()); + def("extract_X_ref", extract_X_ref, return_value_policy<reference_existing_object>()); + + def("check_bool", check_bool); + def("check_list", check_list); + def("check_cstring", check_cstring); + def("check_string", check_string); + def("check_string_cref", check_string_cref); + def("check_X", check_X); + def("check_X_ptr", check_X_ptr); + def("check_X_ref", check_X_ref); + + def("double_X", double_X); + + def("count_Xs", &X::count); + ; + + object x_class( + class_<X>("X", init<int>()) + .def( "__repr__", x_rep)); + + // Instantiate an X object through the Python interface + object x_obj = x_class(3); + + // Get the C++ object out of the Python object + X const& x = extract<X&>(x_obj); + if (x.value() != 3) { + throw std::runtime_error("x.value() == 3 failure."); + } +} + + +#include "module_tail.cpp" + diff --git a/libs/python/test/extract.py b/libs/python/test/extract.py new file mode 100644 index 000000000..842a9f6e4 --- /dev/null +++ b/libs/python/test/extract.py @@ -0,0 +1,107 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' + >>> from extract_ext import * + +Just about anything has a truth value in Python + + >>> assert check_bool(None) + >>> extract_bool(None) + 0 + + >>> assert check_bool(2) + >>> extract_bool(2) + 1 + + >>> assert not check_bool('') + +Check that object manager types work properly. These are a different +case because they wrap Python objects instead of being wrapped by them. + + >>> assert not check_list(2) + >>> try: x = extract_list(2) + ... except TypeError, x: + ... if str(x) != 'Expecting an object of type list; got an object of type int instead': + ... print x + ... else: + ... print 'expected an exception, got', x, 'instead' + +Can't extract a list from a tuple. Use list(x) to convert a sequence +to a list: + + >>> assert not check_list((1, 2, 3)) + >>> assert check_list([1, 2, 3]) + >>> extract_list([1, 2, 3]) + [1, 2, 3] + +Can get a char const* from a Python string: + + >>> assert check_cstring('hello') + >>> extract_cstring('hello') + 'hello' + +Can't get a char const* from a Python int: + + >>> assert not check_cstring(1) + >>> try: x = extract_cstring(1) + ... except TypeError: pass + ... else: + ... print 'expected an exception, got', x, 'instead' + +Extract an std::string (class) rvalue from a native Python type + + >>> assert check_string('hello') + >>> extract_string('hello') + 'hello' + +Constant references are not treated as rvalues for the purposes of +extract: + + >>> assert not check_string_cref('hello') + +We can extract lvalues where appropriate: + + >>> x = X(42) + >>> check_X(x) + 1 + >>> extract_X(x) + X(42) + + >>> check_X_ptr(x) + 1 + >>> extract_X_ptr(x) + X(42) + >>> extract_X_ref(x) + X(42) + +Demonstrate that double-extraction of an rvalue works, and all created +copies of the object are destroyed: + + >>> n = count_Xs() + >>> double_X(333) + 666 + >>> count_Xs() - n + 0 + +General check for cleanliness: + + >>> del x + >>> count_Xs() + 0 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/if_else.cpp b/libs/python/test/if_else.cpp new file mode 100644 index 000000000..1c6258db7 --- /dev/null +++ b/libs/python/test/if_else.cpp @@ -0,0 +1,44 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/static_assert.hpp> +#include <boost/python/detail/if_else.hpp> +#include <boost/type_traits/same_traits.hpp> + + typedef char c1; + typedef char c2[2]; + typedef char c3[3]; + typedef char c4[4]; + +template <unsigned size> +struct choose +{ + typedef typename boost::python::detail::if_< + (sizeof(c1) == size) + >::template then< + c1 + >::template elif< + (sizeof(c2) == size) + >::template then< + c2 + >::template elif< + (sizeof(c3) == size) + >::template then< + c3 + >::template elif< + (sizeof(c4) == size) + >::template then< + c4 + >::template else_<void*>::type type; +}; + +int main() +{ + BOOST_STATIC_ASSERT((boost::is_same<choose<1>::type,c1>::value)); + BOOST_STATIC_ASSERT((boost::is_same<choose<2>::type,c2>::value)); + BOOST_STATIC_ASSERT((boost::is_same<choose<3>::type,c3>::value)); + BOOST_STATIC_ASSERT((boost::is_same<choose<4>::type,c4>::value)); + BOOST_STATIC_ASSERT((boost::is_same<choose<5>::type,void*>::value)); + return 0; +} diff --git a/libs/python/test/implicit.cpp b/libs/python/test/implicit.cpp new file mode 100644 index 000000000..a1bae59e8 --- /dev/null +++ b/libs/python/test/implicit.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/class.hpp> +#include <boost/python/implicit.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include "test_class.hpp" + +using namespace boost::python; + +typedef test_class<> X; + +int x_value(X const& x) +{ + return x.value(); +} + +X make_x(int n) { return X(n); } + + +// foo/bar -- a regression for a vc7 bug workaround +struct bar {}; +struct foo +{ + virtual ~foo() {}; // silence compiler warnings + virtual void f() = 0; + operator bar() const { return bar(); } +}; + +BOOST_PYTHON_MODULE(implicit_ext) +{ + implicitly_convertible<foo,bar>(); + implicitly_convertible<int,X>(); + + def("x_value", x_value); + def("make_x", make_x); + + class_<X>("X", init<int>()) + .def("value", &X::value) + .def("set", &X::set) + ; + + implicitly_convertible<X,int>(); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/implicit.py b/libs/python/test/implicit.py new file mode 100644 index 000000000..ac82d9486 --- /dev/null +++ b/libs/python/test/implicit.py @@ -0,0 +1,44 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from implicit_ext import * +>>> x_value(X(42)) +42 +>>> x_value(42) +42 +>>> x = make_x(X(42)) +>>> x.value() +42 +>>> try: make_x('fool') +... except TypeError: pass +... else: print 'no error' + +>>> print x_value.__doc__.splitlines()[1] +x_value( (X)arg1) -> int : + +>>> print make_x.__doc__.splitlines()[1] +make_x( (object)arg1) -> X : + +>>> print X.value.__doc__.splitlines()[1] +value( (X)arg1) -> int : + +>>> print X.set.__doc__.splitlines()[1] +set( (X)arg1, (object)arg2) -> None : + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/import_.cpp b/libs/python/test/import_.cpp new file mode 100644 index 000000000..3e21de0ba --- /dev/null +++ b/libs/python/test/import_.cpp @@ -0,0 +1,70 @@ +// Copyright Stefan Seefeld 2007. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <boost/bind.hpp> +#include <iostream> +#include <sstream> + +namespace bpl = boost::python; + +void import_test(char const *py_file_path) +{ + // Retrieve the main module + bpl::object main = bpl::import("__main__"); + + // Retrieve the main module's namespace + bpl::object global(main.attr("__dict__")); + + // Inject search path for import_ module + + bpl::str script( + "import sys, os.path\n" + "path = os.path.dirname(%r)\n" + "sys.path.insert(0, path)" + % bpl::str(py_file_path)); + + bpl::object result = bpl::exec(script, global, global); + + // Retrieve the main module + bpl::object import_ = bpl::import("import_"); + int value = bpl::extract<int>(import_.attr("value")) BOOST_EXTRACT_WORKAROUND; + std::cout << value << std::endl; + BOOST_TEST(value == 42); +} + +int main(int argc, char **argv) +{ + BOOST_TEST(argc == 2); + + // Initialize the interpreter + Py_Initialize(); + + if (bpl::handle_exception(boost::bind(import_test,argv[1]))) + { + if (PyErr_Occurred()) + { + BOOST_ERROR("Python Error detected"); + PyErr_Print(); + } + else + { + BOOST_ERROR("A C++ exception was thrown for which " + "there was no exception handler registered."); + } + } + + // Boost.Python doesn't support Py_Finalize yet. + // Py_Finalize(); + return boost::report_errors(); +} + +// Including this file makes sure +// that on Windows, any crashes (e.g. null pointer dereferences) invoke +// the debugger immediately, rather than being translated into structured +// exceptions that can interfere with debugging. +#include "module_tail.cpp" diff --git a/libs/python/test/import_.py b/libs/python/test/import_.py new file mode 100644 index 000000000..48de6e5ec --- /dev/null +++ b/libs/python/test/import_.py @@ -0,0 +1,5 @@ +# Copyright Stefan Seefeld 2007. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +value = 42 diff --git a/libs/python/test/indirect_traits_test.cpp b/libs/python/test/indirect_traits_test.cpp new file mode 100644 index 000000000..594cfe555 --- /dev/null +++ b/libs/python/test/indirect_traits_test.cpp @@ -0,0 +1,117 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +//#include <stdio.h> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include <boost/type_traits/is_member_function_pointer.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/python/detail/indirect_traits.hpp> +#include <boost/mpl/assert.hpp> + +//#define print(expr) printf("%s ==> %s\n", #expr, expr) + +// not all the compilers can handle an incomplete class type here. +struct X {}; + +using namespace boost::python::indirect_traits; + +typedef void (X::*pmf)(); + +BOOST_MPL_ASSERT((is_reference_to_function<int (&)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function<int (*)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function<int&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function<pmf>)); + +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<int (&)()>)); +BOOST_MPL_ASSERT((is_pointer_to_function<int (*)()>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<int (*&)()>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<int (*const&)()>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_function<pmf>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<int (&)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<int (*)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<int&>)); +BOOST_MPL_ASSERT((is_reference_to_function_pointer<int (*&)()>)); +BOOST_MPL_ASSERT((is_reference_to_function_pointer<int (*const&)()>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_function_pointer<pmf>)); + +BOOST_MPL_ASSERT((is_reference_to_pointer<int*&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int* const&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int*const volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const*&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const* const&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_pointer<int const*const volatile&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<pmf>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_pointer<int*>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int*&>)); +BOOST_MPL_ASSERT((is_reference_to_const<int* const&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_const<int*const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_const<int*>)); + +BOOST_MPL_ASSERT((is_reference_to_non_const<int*&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int* const&>)); +BOOST_MPL_ASSERT((is_reference_to_non_const<int*volatile&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int*const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_non_const<int*>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int*&>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int* const&>)); +BOOST_MPL_ASSERT((is_reference_to_volatile<int*volatile&>)); +BOOST_MPL_ASSERT((is_reference_to_volatile<int*const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int const volatile>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int>)); +BOOST_MPL_ASSERT_NOT((is_reference_to_volatile<int*>)); + +namespace tt = boost::python::indirect_traits; + +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<int>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<int&>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<int*>)); + + +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<pmf>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<pmf const&>)); + +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_class<X>)); + +BOOST_MPL_ASSERT((tt::is_reference_to_class<X&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_class<X const&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_class<X volatile&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_class<X const volatile&>)); + +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<int>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<int*>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<int&>)); + +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<X>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<X&>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<pmf>)); +BOOST_MPL_ASSERT_NOT((is_pointer_to_class<pmf const>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X*>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X const*>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X volatile*>)); +BOOST_MPL_ASSERT((is_pointer_to_class<X const volatile*>)); + +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf const&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf volatile&>)); +BOOST_MPL_ASSERT((tt::is_reference_to_member_function_pointer<pmf const volatile&>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_member_function_pointer<pmf[2]>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_member_function_pointer<pmf(&)[2]>)); +BOOST_MPL_ASSERT_NOT((tt::is_reference_to_member_function_pointer<pmf>)); + diff --git a/libs/python/test/injected.cpp b/libs/python/test/injected.cpp new file mode 100644 index 000000000..73e1e14ba --- /dev/null +++ b/libs/python/test/injected.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include "test_class.hpp" +#include <memory> +#include <boost/shared_ptr.hpp> +#include <boost/python/make_constructor.hpp> +#include <boost/python/args.hpp> + +using namespace boost::python; + +typedef test_class<> X; + +X* empty() { return new X(1000); } + +std::auto_ptr<X> sum(int a, int b) { return std::auto_ptr<X>(new X(a+b)); } + +boost::shared_ptr<X> product(int a, int b, int c) +{ + return boost::shared_ptr<X>(new X(a*b*c)); +} + +BOOST_PYTHON_MODULE(injected_ext) +{ + class_<X>("X", init<int>()) + .def("__init__", make_constructor(empty)) + .def("__init__", make_constructor(sum)) + .def("__init__", make_constructor(product + , default_call_policies() + , ( arg_("a"), arg_("b"), arg_("c")) + ), + "this is product's docstring") + .def("value", &X::value) + ; +} diff --git a/libs/python/test/injected.py b/libs/python/test/injected.py new file mode 100644 index 000000000..32ea0bf9d --- /dev/null +++ b/libs/python/test/injected.py @@ -0,0 +1,28 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from injected_ext import * +>>> X(3,5).value() - (3+5) +0 +>>> X(a=3,b=5,c=7).value() - (3*5*7) +0 +>>> X().value() +1000 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + diff --git a/libs/python/test/input_iterator.cpp b/libs/python/test/input_iterator.cpp new file mode 100644 index 000000000..70b994186 --- /dev/null +++ b/libs/python/test/input_iterator.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/iterator.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <list> + +using namespace boost::python; + +typedef std::list<int> list_int; + +// Prove that we can handle InputIterators which return rvalues. +struct doubler +{ + typedef int result_type; + int operator()(int x) const { return x * 2; } +}; + +typedef boost::transform_iterator<doubler, list_int::iterator> doubling_iterator; +typedef std::pair<doubling_iterator,doubling_iterator> list_range2; + +list_range2 range2(list_int& x) +{ + return list_range2( + boost::make_transform_iterator<doubler>(x.begin(), doubler()) + , boost::make_transform_iterator<doubler>(x.end(), doubler())); +} + +// We do this in a separate module from iterators_ext (iterators.cpp) +// to work around an MSVC6 linker bug, which causes it to complain +// about a "duplicate comdat" if the input iterator is instantiated in +// the same module with the others. +BOOST_PYTHON_MODULE(input_iterator) +{ + def("range2", &::range2); + + class_<list_range2>("list_range2") + // We can wrap InputIterators which return by-value + .def("__iter__" + , range(&list_range2::first, &list_range2::second)) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/int_map_indexing_suite.cpp b/libs/python/test/int_map_indexing_suite.cpp new file mode 100644 index 000000000..397850131 --- /dev/null +++ b/libs/python/test/int_map_indexing_suite.cpp @@ -0,0 +1,16 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/class.hpp> +#include <boost/python/suite/indexing/map_indexing_suite.hpp> + +void int_map_indexing_suite() +{ + using namespace boost::python; + + // Compile check only... + class_<std::map<int, int> >("IntMap") + .def(map_indexing_suite<std::map<int, int> >()) + ; +} diff --git a/libs/python/test/iterator.cpp b/libs/python/test/iterator.cpp new file mode 100644 index 000000000..458ba2926 --- /dev/null +++ b/libs/python/test/iterator.cpp @@ -0,0 +1,137 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_internal_reference.hpp> +#include <boost/python/copy_non_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/iterator.hpp> +#include <list> +#include <utility> +#include <iterator> +#include <algorithm> + +using namespace boost::python; + +typedef std::list<int> list_int; +typedef std::list<list_int> list_list; + + +void push_back(list_int& x, int y) +{ + x.push_back(y); +} + +void push_list_back(list_list& x, list_int const& y) +{ + x.push_back(y); +} + +int back(list_int& x) +{ + return x.back(); +} + +typedef std::pair<list_int::iterator,list_int::iterator> list_range; + +struct list_range2 : list_range +{ + list_int::iterator& begin() { return this->first; } + list_int::iterator& end() { return this->second; } +}; + +list_range range(list_int& x) +{ + return list_range(x.begin(), x.end()); +} + +struct two_lists +{ + two_lists() + { + int primes[] = { 2, 3, 5, 7, 11, 13 }; + std::copy(primes, primes + sizeof(primes)/sizeof(*primes), std::back_inserter(one)); + int evens[] = { 2, 4, 6, 8, 10, 12 }; + std::copy(evens, evens + sizeof(evens)/sizeof(*evens), std::back_inserter(two)); + } + + struct two_start + { + typedef list_int::iterator result_type; + result_type operator()(two_lists& ll) const { return ll.two.begin(); } + }; + friend struct two_start; + + list_int::iterator one_begin() { return one.begin(); } + list_int::iterator two_begin() { return two.begin(); } + + list_int::iterator one_end() { return one.end(); } + list_int::iterator two_end() { return two.end(); } + +private: + list_int one; + list_int two; +}; + +BOOST_PYTHON_MODULE(iterator_ext) +{ + using boost::python::iterator; // gcc 2.96 bug workaround + def("range", &::range); + + class_<list_int>("list_int") + .def("push_back", push_back) + .def("back", back) + .def("__iter__", iterator<list_int>()) + ; + + class_<list_range>("list_range") + + // We can specify data members + .def("__iter__" + , range(&list_range::first, &list_range::second)) + ; + + // No runtime tests for this one yet + class_<list_range2>("list_range2") + + // We can specify member functions returning a non-const reference + .def("__iter__", range(&list_range2::begin, &list_range2::end)) + ; + + class_<two_lists>("two_lists") + + // We can spcify member functions + .add_property( + "primes" + , range(&two_lists::one_begin, &two_lists::one_end)) + + // Prove that we can explicitly specify call policies + .add_property( + "evens" + , range<return_value_policy<copy_non_const_reference> >( + &two_lists::two_begin, &two_lists::two_end)) + + // Prove that we can specify call policies and target + .add_property( + "twosies" + , range<return_value_policy<copy_non_const_reference>, two_lists>( + // And we can use adaptable function objects when + // partial specialization is available. +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + two_lists::two_start() +# else + &two_lists::two_begin +# endif + , &two_lists::two_end)) + ; + + class_<list_list>("list_list") + .def("push_back", push_list_back) + .def("__iter__", iterator<list_list,return_internal_reference<> >()) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/iterator.py b/libs/python/test/iterator.py new file mode 100644 index 000000000..96f5fd04b --- /dev/null +++ b/libs/python/test/iterator.py @@ -0,0 +1,77 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from iterator_ext import * +>>> from input_iterator import * +>>> x = list_int() +>>> x.push_back(1) +>>> x.back() +1 +>>> x.push_back(3) +>>> x.push_back(5) +>>> for y in x: +... print y +1 +3 +5 +>>> z = range(x) +>>> for y in z: +... print y +1 +3 +5 + + Range2 wraps a transform_iterator which doubles the elements it + traverses. This proves we can wrap input iterators + +>>> z2 = range2(x) +>>> for y in z2: +... print y +2 +6 +10 + +>>> l2 = two_lists() +>>> for y in l2.primes: +... print y +2 +3 +5 +7 +11 +13 +>>> for y in l2.evens: +... print y +2 +4 +6 +8 +10 +12 +>>> ll = list_list() +>>> ll.push_back(x) +>>> x.push_back(7) +>>> ll.push_back(x) +>>> for a in ll: #doctest: +NORMALIZE_WHITESPACE +... for b in a: +... print b, +... print +... +1 3 5 +1 3 5 7 +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/keywords.cpp b/libs/python/test/keywords.cpp new file mode 100644 index 000000000..39bac0627 --- /dev/null +++ b/libs/python/test/keywords.cpp @@ -0,0 +1,118 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python.hpp> +#include <string> + +struct Foo +{ + Foo( + int a = 0 + , double b = 0 + , const std::string &n = std::string() + ) : + a_(a) + , b_(b) + , n_(n) + {} + + void set(int a=0, double b=0, const std::string &n=std::string()) + { + a_ = a; + b_ = b; + n_ = n; + } + + int geta() const { return a_; } + + double getb() const { return b_; } + + std::string getn() const { return n_; } + +private: + int a_; + double b_; + std::string n_; +}; + +struct Bar +{ + Bar( + int a = 0 + , double b = 0 + , const std::string &n = std::string() + ) : + a_(a) + , b_(b) + , n_(n) + {} + + void set(int a=0, double b=0, const std::string &n=std::string()) + { + a_ = a; + b_ = b; + n_ = n; + } + + void seta(int a) + { + a_ = a; + } + + int geta() const { return a_; } + + double getb() const { return b_; } + + std::string getn() const { return n_; } + +private: + int a_; + double b_; + std::string n_; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(bar_set, Bar::set, 0,3) + +using namespace boost::python; +BOOST_PYTHON_MODULE(keywords) +{ +#if BOOST_WORKAROUND(__GNUC__, == 2) + using boost::python::arg; +#endif + + class_<Foo>( + "Foo" + , init<int, double, const std::string&>( + ( arg("a") = 0 + , arg("b") = 0.0 + , arg("n") = std::string() + ) + )) + + .def("set", &Foo::set, (arg("a") = 0, arg("b") = 0.0, arg("n") = std::string()) ) + + .def("set2", &Foo::set, (arg("a"), "b", "n") ) + + .def("a", &Foo::geta) + .def("b", &Foo::getb) + .def("n", &Foo::getn) + ; + + class_<Bar>("Bar" + , init<optional<int, double, const std::string &> >() + ) + .def("set", &Bar::set, bar_set()) + .def("set2", &Bar::set, bar_set("set2's docstring")) + .def("seta", &Bar::seta, arg("a")) + + .def("a", &Bar::geta) + .def("b", &Bar::getb) + .def("n", &Bar::getn) + ; + +} + + + +#include "module_tail.cpp" diff --git a/libs/python/test/keywords_test.py b/libs/python/test/keywords_test.py new file mode 100644 index 000000000..261de0b39 --- /dev/null +++ b/libs/python/test/keywords_test.py @@ -0,0 +1,106 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from keywords import * +>>> f = Foo() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f = Foo(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f = Foo(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f = Foo(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f = Foo(a=1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f = Foo(b=1) +>>> f.a(), f.b(), f.n() +(0, 1.0, '') +>>> f = Foo(n="1") +>>> f.a(), f.b(), f.n() +(0, 0.0, '1') +>>> f = Foo(1,n="1") +>>> f.a(), f.b(), f.n() +(1, 0.0, '1') +>>> f.set() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f.set(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f.set(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f.set(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f.set(a=1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f.set(b=1) +>>> f.a(), f.b(), f.n() +(0, 1.0, '') +>>> f.set(n="1") +>>> f.a(), f.b(), f.n() +(0, 0.0, '1') +>>> f.set(1,n="1") +>>> f.a(), f.b(), f.n() +(1, 0.0, '1') +>>> f.set2(b=2.0,n="2",a=2) +>>> f.a(), f.b(), f.n() +(2, 2.0, '2') + +# lets see how badly we've broken the 'regular' functions +>>> f = Bar() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f = Bar(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f = Bar(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f = Bar(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f.set() +>>> f.a(), f.b(), f.n() +(0, 0.0, '') +>>> f.set(1) +>>> f.a(), f.b(), f.n() +(1, 0.0, '') +>>> f.set(1,1.0) +>>> f.a(), f.b(), f.n() +(1, 1.0, '') +>>> f.set(1,1.0,"1") +>>> f.a(), f.b(), f.n() +(1, 1.0, '1') +>>> f.set2.__doc__.splitlines()[1] +'set2( (Bar)arg1 [, (int)arg2 [, (float)arg3 [, (str)arg4]]]) -> None :' +>>> f.set2.__doc__.splitlines()[2] +" set2's docstring" +''' + + + + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + diff --git a/libs/python/test/list.cpp b/libs/python/test/list.cpp new file mode 100644 index 000000000..3e9fcbe66 --- /dev/null +++ b/libs/python/test/list.cpp @@ -0,0 +1,154 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/list.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/make_function.hpp> +#include <boost/lexical_cast.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> +#include "test_class.hpp" + +using namespace boost::python; + +object new_list() +{ + return list(); +} + +list listify(object x) +{ + return list(x); +} + +object listify_string(char const* s) +{ + return list(s); +} + +std::string x_rep(test_class<> const& x) +{ + return "X(" + boost::lexical_cast<std::string>(x.value()) + ")"; +} + +object apply_object_list(object f, list x) +{ + return f(x); +} + +list apply_list_list(object f, list x) +{ + return call<list>(f.ptr(), x); +} + +void append_object(list& x, object y) +{ + x.append(y); +} + +void append_list(list& x, list const& y) +{ + x.append(y); +} + +typedef test_class<> X; + +int notcmp(object const& x, object const& y) +{ + return y < x ? -1 : y > x ? 1 : 0; +} + +void exercise(list x, object y, object print) +{ + x.append(y); + x.append(5); + x.append(X(3)); + + print("after append:"); + print(x); + + print("number of", y, "instances:", x.count(y)); + + print("number of 5s:", x.count(5)); + + x.extend("xyz"); + print("after extend:"); + print(x); + print("index of", y, "is:", x.index(y)); + print("index of 'l' is:", x.index("l")); + + x.insert(4, 666); + print("after inserting 666:"); + print(x); + print("inserting with object as index:"); + x.insert(x[x.index(5)], "---"); + print(x); + + print("popping..."); + x.pop(); + print(x); + x.pop(x[x.index(5)]); + print(x); + x.pop(x.index(5)); + print(x); + + print("removing", y); + x.remove(y); + print(x); + print("removing", 666); + x.remove(666); + print(x); + + print("reversing..."); + x.reverse(); + print(x); + + print("sorted:"); + x.pop(2); // make sorting predictable + x.pop(2); // remove [1,2] so the list is sortable in py3k + x.sort(); + print(x); + + print("reverse sorted:"); +#if PY_VERSION_HEX >= 0x03000000 + x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true)))); +#else + x.sort(¬cmp); +#endif + print(x); + + list w; + w.append(5); + w.append(6); + w += "hi"; + BOOST_ASSERT(w[0] == 5); + BOOST_ASSERT(w[1] == 6); + BOOST_ASSERT(w[2] == 'h'); + BOOST_ASSERT(w[3] == 'i'); +} + +BOOST_PYTHON_MODULE(list_ext) +{ + def("new_list", new_list); + def("listify", listify); + def("listify_string", listify_string); + def("apply_object_list", apply_object_list); + def("apply_list_list", apply_list_list); + + def("append_object", append_object); + def("append_list", append_list); + + def("exercise", exercise); + + class_<X>("X", init<int>()) + .def( "__repr__", x_rep) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/list.py b/libs/python/test/list.py new file mode 100644 index 000000000..8be211238 --- /dev/null +++ b/libs/python/test/list.py @@ -0,0 +1,118 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from list_ext import * + +>>> new_list() +[] + +>>> listify((1,2,3)) +[1, 2, 3] + +>>> letters = listify_string('hello') +>>> letters +['h', 'e', 'l', 'l', 'o'] + +>>> X(22) +X(22) + +>>> def identity(x): +... return x +>>> assert apply_object_list(identity, letters) is letters + + 5 is not convertible to a list + +>>> try: result = apply_object_list(identity, 5) +... except TypeError: pass +... else: print 'expected an exception, got', result, 'instead' + +>>> assert apply_list_list(identity, letters) is letters + + 5 is not convertible to a list as a return value + +>>> try: result = apply_list_list(len, letters) +... except TypeError: pass +... else: print 'expected an exception, got', result, 'instead' + +>>> append_object(letters, '.') +>>> letters +['h', 'e', 'l', 'l', 'o', '.'] + + tuples do not automatically convert to lists when passed as arguments + +>>> try: append_list(letters, (1,2)) +... except TypeError: pass +... else: print 'expected an exception' + +>>> append_list(letters, [1,2]) +>>> letters +['h', 'e', 'l', 'l', 'o', '.', [1, 2]] + + Check that subclass functions are properly called + +>>> class mylist(list): +... def append(self, o): +... list.append(self, o) +... if not hasattr(self, 'nappends'): +... self.nappends = 1 +... else: +... self.nappends += 1 +... +>>> l2 = mylist() +>>> append_object(l2, 'hello') +>>> append_object(l2, 'world') +>>> l2 +['hello', 'world'] +>>> l2.nappends +2 + +>>> def printer(*args): +... for x in args: print x, +... print +... + +>>> y = X(42) +>>> exercise(letters, y, printer) #doctest: +NORMALIZE_WHITESPACE +after append: +['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(42), 5, X(3)] +number of X(42) instances: 1 +number of 5s: 1 +after extend: +['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y', 'z'] +index of X(42) is: 7 +index of 'l' is: 2 +after inserting 666: +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y', 'z'] +inserting with object as index: +['h', 'e', 'l', 'l', 666, '---', 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y', 'z'] +popping... +['h', 'e', 'l', 'l', 666, '---', 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y'] +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(42), 5, X(3), 'x', 'y'] +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(42), X(3), 'x', 'y'] +removing X(42) +['h', 'e', 'l', 'l', 666, 'o', '.', [1, 2], X(3), 'x', 'y'] +removing 666 +['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(3), 'x', 'y'] +reversing... +['y', 'x', X(3), [1, 2], '.', 'o', 'l', 'l', 'e', 'h'] +sorted: +['.', 'e', 'h', 'l', 'l', 'o', 'x', 'y'] +reverse sorted: +['y', 'x', 'o', 'l', 'l', 'h', 'e', '.'] +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/long.cpp b/libs/python/test/long.cpp new file mode 100644 index 000000000..61e4518ff --- /dev/null +++ b/libs/python/test/long.cpp @@ -0,0 +1,63 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/long.hpp> +#include <boost/python/class.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +object new_long() +{ + return long_(); +} + +long_ longify(object x) +{ + return long_(x); +} + +object longify_string(char const* s) +{ + return long_(s); +} + +char const* is_long1(long_& x) +{ + long_ y = x; + x += 50; + BOOST_ASSERT(x == y + 50); + return "yes"; +} + +int is_long2(char const*) +{ + return 0; +} + +// tests for accepting objects (and derived classes) in constructors +// from "Milind Patil" <milind_patil-at-hotmail.com> + +struct Y +{ + Y(boost::python::long_) {} +}; + +BOOST_PYTHON_MODULE(long_ext) +{ + def("new_long", new_long); + def("longify", longify); + def("longify_string", longify_string); + def("is_long", is_long1); + def("is_long", is_long2); + + class_< Y >("Y", init< boost::python::long_ >()) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/long.py b/libs/python/test/long.py new file mode 100644 index 000000000..13d8775bb --- /dev/null +++ b/libs/python/test/long.py @@ -0,0 +1,33 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from long_ext import * +>>> print new_long() +0 +>>> print longify(42) +42 +>>> print longify_string('300') +300 +>>> is_long(20L) +'yes' +>>> is_long('20') +0 + +>>> x = Y(4294967295L) +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/m1.cpp b/libs/python/test/m1.cpp new file mode 100644 index 000000000..a873bc35d --- /dev/null +++ b/libs/python/test/m1.cpp @@ -0,0 +1,344 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include <boost/python/def.hpp> +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/lvalue_from_pytype.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/to_python_converter.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/converter/pytype_function.hpp> +#include <string.h> +#include "simple_type.hpp" +#include "complicated.hpp" + +// Declare some straightforward extension types +extern "C" void +dealloc(PyObject* self) +{ + PyObject_Del(self); +} + +// Noddy is a type we got from one of the Python sample files +struct NoddyObject : PyObject +{ + int x; +}; + +PyTypeObject NoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Noddy"), + sizeof(NoddyObject), + 0, + dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Create a Noddy containing 42 +PyObject* new_noddy() +{ + NoddyObject* noddy = PyObject_New(NoddyObject, &NoddyType); + noddy->x = 42; + return (PyObject*)noddy; +} + +// Simple is a wrapper around a struct simple, which just contains a char* +struct SimpleObject +{ + PyObject_HEAD + simple x; +}; + +struct extract_simple_object +{ + static simple& execute(SimpleObject& o) { return o.x; } +}; + +PyTypeObject SimpleType = { + PyVarObject_HEAD_INIT(NULL, 0) + const_cast<char*>("Simple"), + sizeof(SimpleObject), + 0, + dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PYTHON_API_VERSION >= 1012 + 0 /* tp_del */ +#endif +}; + +// Create a Simple containing "hello, world" +PyObject* new_simple() +{ + SimpleObject* simple = PyObject_New(SimpleObject, &SimpleType); + simple->x.s = const_cast<char*>("hello, world"); + return (PyObject*)simple; +} + +// +// Declare some wrappers/unwrappers to test the low-level conversion +// mechanism. +// +using boost::python::to_python_converter; + +// Wrap a simple by copying it into a Simple +struct simple_to_python + : to_python_converter<simple, simple_to_python, true> + //, boost::python::converter::wrap_pytype<&SimpleType> +{ + static PyObject* convert(simple const& x) + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return (PyObject*)p; + } + static PyTypeObject const *get_pytype(){return &SimpleType; } +}; + +struct int_from_noddy +{ + static int& execute(NoddyObject& p) + { + return p.x; + } +}; + +// +// Some C++ functions to expose to Python +// + +// Returns the length of s's held string +int f(simple const& s) +{ + return strlen(s.s); +} + +int f_mutable_ref(simple& s) +{ + return strlen(s.s); +} + +int f_mutable_ptr(simple* s) +{ + return strlen(s->s); +} + +int f_const_ptr(simple const* s) +{ + return strlen(s->s); +} + +int f2(SimpleObject const& s) +{ + return strlen(s.x.s); +} + +// A trivial passthru function for simple objects +simple const& g(simple const& x) +{ + return x; +} + +struct A +{ + A() : x(0) {} + virtual ~A() {} + char const* name() { return "A"; } + int x; +}; + +struct B : A +{ + B() : x(1) {} + static char const* name(B*) { return "B"; } + int x; +}; + +struct C : A +{ + C() : x(2) {} + char const* name() { return "C"; } + virtual ~C() {} + int x; +}; + +struct D : B, C +{ + D() : x(3) {} + char const* name() { return "D"; } + int x; +}; + +A take_a(A const& a) { return a; } +B take_b(B& b) { return b; } +C take_c(C* c) { return *c; } +D take_d(D* const& d) { return *d; } + +D take_d_shared_ptr(boost::shared_ptr<D> d) { return *d; } + +boost::shared_ptr<A> d_factory() { return boost::shared_ptr<B>(new D); } + +struct Unregistered {}; +Unregistered make_unregistered(int) { return Unregistered(); } + +Unregistered* make_unregistered2(int) { return new Unregistered; } + +BOOST_PYTHON_MODULE(m1) +{ + using namespace boost::python; + using boost::shared_ptr; + + simple_to_python(); + + lvalue_from_pytype<int_from_noddy,&NoddyType>(); + + lvalue_from_pytype< +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // doesn't support non-type member pointer parameters + extract_member<SimpleObject, simple, &SimpleObject::x> +#else + extract_simple_object +#endif + , &SimpleType + >(); + + lvalue_from_pytype<extract_identity<SimpleObject>,&SimpleType>(); + + def("new_noddy", new_noddy); + def("new_simple", new_simple); + + def("make_unregistered", make_unregistered); + def("make_unregistered2", make_unregistered2, return_value_policy<manage_new_object>()); + + // Expose f() in all its variations + def("f", f); + def("f_mutable_ref", f_mutable_ref); + def("f_mutable_ptr", f_mutable_ptr); + def("f_const_ptr", f_const_ptr); + + def("f2", f2); + + // Expose g() + def("g", g , return_value_policy<copy_const_reference>() + ); + + def("take_a", take_a); + def("take_b", take_b); + def("take_c", take_c); + def("take_d", take_d); + + + def("take_d_shared_ptr", take_d_shared_ptr); + def("d_factory", d_factory); + + class_<A, shared_ptr<A> >("A") + .def("name", &A::name) + ; + + // sequence points don't ensure that "A" is constructed before "B" + // or "C" below if we make them part of the same chain + class_<B,bases<A> >("B") + .def("name", &B::name) + ; + + class_<C,bases<A> >("C") + .def("name", &C::name) + ; + + class_<D, bases<B,C> >("D") + .def("name", &D::name) + ; + + class_<complicated>("complicated", + init<simple const&,int>()) + .def(init<simple const&>()) + .def("get_n", &complicated::get_n) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/m2.cpp b/libs/python/test/m2.cpp new file mode 100644 index 000000000..5bcdea604 --- /dev/null +++ b/libs/python/test/m2.cpp @@ -0,0 +1,108 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This module exercises the converters exposed in m1 at a low level +// by exposing raw Python extension functions that use wrap<> and +// unwrap<> objects. +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/copy_non_const_reference.hpp> +#include <boost/python/copy_const_reference.hpp> +#include <boost/python/return_value_policy.hpp> +#include "simple_type.hpp" + +#if PY_VERSION_HEX >= 0x03000000 +# define PyString_FromString PyUnicode_FromString +# define PyInt_FromLong PyLong_FromLong +#endif + +// Get a simple (by value) from the argument, and return the +// string it holds. +PyObject* unwrap_simple(simple x) +{ + return PyString_FromString(x.s); +} + +// Likewise, but demands that its possible to get a non-const +// reference to the simple. +PyObject* unwrap_simple_ref(simple& x) +{ + return PyString_FromString(x.s); +} + +// Likewise, with a const reference to the simple object. +PyObject* unwrap_simple_const_ref(simple const& x) +{ + return PyString_FromString(x.s); +} + +// Get an int (by value) from the argument, and convert it to a +// Python Int. +PyObject* unwrap_int(int x) +{ + return PyInt_FromLong(x); +} + +// Get a non-const reference to an int from the argument +PyObject* unwrap_int_ref(int& x) +{ + return PyInt_FromLong(x); +} + +// Get a const reference to an int from the argument. +PyObject* unwrap_int_const_ref(int const& x) +{ + return PyInt_FromLong(x); +} + +#if PY_VERSION_HEX >= 0x03000000 +# undef PyString_FromString +# undef PyInt_FromLong +#endif + +// rewrap<T> extracts a T from the argument, then converts the T back +// to a PyObject* and returns it. +template <class T> +struct rewrap +{ + static T f(T x) { return x; } +}; + +BOOST_PYTHON_MODULE(m2) +{ + using boost::python::return_value_policy; + using boost::python::copy_const_reference; + using boost::python::copy_non_const_reference; + using boost::python::def; + + def("unwrap_int", unwrap_int); + def("unwrap_int_ref", unwrap_int_ref); + def("unwrap_int_const_ref", unwrap_int_const_ref); + def("unwrap_simple", unwrap_simple); + def("unwrap_simple_ref", unwrap_simple_ref); + def("unwrap_simple_const_ref", unwrap_simple_const_ref); + + def("wrap_int", &rewrap<int>::f); + + def("wrap_int_ref", &rewrap<int&>::f + , return_value_policy<copy_non_const_reference>() + ); + + def("wrap_int_const_ref", &rewrap<int const&>::f + , return_value_policy<copy_const_reference>() + ); + + def("wrap_simple", &rewrap<simple>::f); + + def("wrap_simple_ref", &rewrap<simple&>::f + , return_value_policy<copy_non_const_reference>() + ); + + def("wrap_simple_const_ref", &rewrap<simple const&>::f + , return_value_policy<copy_const_reference>() + ); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/map_indexing_suite.cpp b/libs/python/test/map_indexing_suite.cpp new file mode 100644 index 000000000..b8771cf41 --- /dev/null +++ b/libs/python/test/map_indexing_suite.cpp @@ -0,0 +1,68 @@ +// Copyright Joel de Guzman 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/suite/indexing/map_indexing_suite.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +using namespace boost::python; + +struct X // a container element +{ + std::string s; + X():s("default") {} + X(std::string s):s(s) {} + std::string repr() const { return s; } + void reset() { s = "reset"; } + void foo() { s = "foo"; } + bool operator==(X const& x) const { return s == x.s; } + bool operator!=(X const& x) const { return s != x.s; } +}; + +std::string x_value(X const& x) +{ + return "gotya " + x.s; +} + + +BOOST_PYTHON_MODULE(map_indexing_suite_ext) +{ + class_<X>("X") + .def(init<>()) + .def(init<X>()) + .def(init<std::string>()) + .def("__repr__", &X::repr) + .def("reset", &X::reset) + .def("foo", &X::foo) + ; + + def("x_value", x_value); + implicitly_convertible<std::string, X>(); + + class_<std::map<std::string, X> >("XMap") + .def(map_indexing_suite<std::map<std::string, X> >()) + ; + + void int_map_indexing_suite(); // moved to int_map_indexing_suite.cpp to + int_map_indexing_suite(); // avoid MSVC 6/7 internal structure overflow + +#if 0 + // Compile check only... + class_<std::map<int, int> >("IntMap") + .def(map_indexing_suite<std::map<int, int> >()) + ; +#endif + + // Some more.. + class_<std::map<std::string, boost::shared_ptr<X> > >("TestMap") + .def(map_indexing_suite<std::map<std::string, boost::shared_ptr<X> >, true>()) + ; + + void a_map_indexing_suite(); // moved to a_map_indexing_suite.cpp to + a_map_indexing_suite(); // avoid MSVC 6/7 internal structure overflow + +} + +#include "module_tail.cpp" diff --git a/libs/python/test/map_indexing_suite.py b/libs/python/test/map_indexing_suite.py new file mode 100644 index 000000000..9d9e2b26f --- /dev/null +++ b/libs/python/test/map_indexing_suite.py @@ -0,0 +1,242 @@ +# Copyright Joel de Guzman 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' + +##################################################################### +# Check an object that we will use as container element +##################################################################### + +>>> from map_indexing_suite_ext import * +>>> assert "map_indexing_suite_IntMap_entry" in dir() +>>> assert "map_indexing_suite_TestMap_entry" in dir() +>>> assert "map_indexing_suite_XMap_entry" in dir() +>>> assert "map_indexing_suite_AMap_entry" in dir() +>>> x = X('hi') +>>> x +hi +>>> x.reset() # a member function that modifies X +>>> x +reset +>>> x.foo() # another member function that modifies X +>>> x +foo + +# test that a string is implicitly convertible +# to an X +>>> x_value('bochi bochi') +'gotya bochi bochi' + +##################################################################### +# Iteration +##################################################################### +>>> def print_xmap(xmap): +... s = '[ ' +... for x in xmap: +... s += repr(x) +... s += ' ' +... s += ']' +... print s + +##################################################################### +# Setting (adding entries) +##################################################################### +>>> xm = XMap() +>>> xm['joel'] = 'apple' +>>> xm['tenji'] = 'orange' +>>> xm['mariel'] = 'grape' +>>> xm['tutit'] = 'banana' +>>> xm['kim'] = 'kiwi' + +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# Changing an entry +##################################################################### +>>> xm['joel'] = 'pineapple' +>>> print_xmap(xm) +[ (joel, pineapple) (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# Deleting an entry +##################################################################### +>>> del xm['joel'] +>>> print_xmap(xm) +[ (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# adding an entry +##################################################################### +>>> xm['joel'] = 'apple' +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) (tenji, orange) (tutit, banana) ] + +##################################################################### +# Indexing +##################################################################### +>>> len(xm) +5 +>>> xm['joel'] +apple +>>> xm['tenji'] +orange +>>> xm['mariel'] +grape +>>> xm['tutit'] +banana +>>> xm['kim'] +kiwi + +##################################################################### +# Calling a mutating function of a container element +##################################################################### +>>> xm['joel'].reset() +>>> xm['joel'] +reset + +##################################################################### +# Copying a container element +##################################################################### +>>> x = X(xm['mariel']) +>>> x +grape +>>> x.foo() +>>> x +foo +>>> xm['mariel'] # should not be changed to 'foo' +grape + +##################################################################### +# Referencing a container element +##################################################################### +>>> x = xm['mariel'] +>>> x +grape +>>> x.foo() +>>> x +foo +>>> xm['mariel'] # should be changed to 'foo' +foo + +>>> xm['mariel'] = 'grape' # take it back +>>> xm['joel'] = 'apple' # take it back + +##################################################################### +# Contains +##################################################################### +>>> assert 'joel' in xm +>>> assert 'mariel' in xm +>>> assert 'tenji' in xm +>>> assert 'tutit' in xm +>>> assert 'kim' in xm +>>> assert not 'X' in xm +>>> assert not 12345 in xm + +##################################################################### +# Some references to the container elements +##################################################################### + +>>> z0 = xm['joel'] +>>> z1 = xm['mariel'] +>>> z2 = xm['tenji'] +>>> z3 = xm['tutit'] +>>> z4 = xm['kim'] + +>>> z0 # proxy +apple +>>> z1 # proxy +grape +>>> z2 # proxy +orange +>>> z3 # proxy +banana +>>> z4 # proxy +kiwi + +##################################################################### +# Delete some container element +##################################################################### + +>>> del xm['tenji'] +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) (tutit, banana) ] + +>>> del xm['tutit'] +>>> print_xmap(xm) +[ (joel, apple) (kim, kiwi) (mariel, grape) ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy +apple +>>> z1 # proxy +grape +>>> z2 # proxy detached +orange +>>> z3 # proxy detached +banana +>>> z4 # proxy +kiwi + +##################################################################### +# Show that iteration allows mutable access to the elements +##################################################################### +>>> for x in xm: +... x.data().reset() +>>> print_xmap(xm) +[ (joel, reset) (kim, reset) (mariel, reset) ] + +##################################################################### +# Some more... +##################################################################### + +>>> tm = TestMap() +>>> tm["joel"] = X("aaa") +>>> tm["kimpo"] = X("bbb") +>>> print_xmap(tm) +[ (joel, aaa) (kimpo, bbb) ] +>>> for el in tm: #doctest: +NORMALIZE_WHITESPACE +... print el.key(), +... dom = el.data() +joel kimpo + +##################################################################### +# Test custom converter... +##################################################################### + +>>> am = AMap() +>>> am[3] = 4 +>>> am[3] +4 +>>> for i in am: +... i.data() +4 + +##################################################################### +# END.... +##################################################################### + +''' + + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argxm = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print 'running...' + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + + + + + diff --git a/libs/python/test/minimal.cpp b/libs/python/test/minimal.cpp new file mode 100644 index 000000000..5efee26bc --- /dev/null +++ b/libs/python/test/minimal.cpp @@ -0,0 +1,16 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include <iostream> // works around a KCC intermediate code generation bug +#endif + +BOOST_PYTHON_MODULE(minimal_ext) +{ +} + +#include "module_tail.cpp" diff --git a/libs/python/test/minimal.py b/libs/python/test/minimal.py new file mode 100644 index 000000000..28e7918f7 --- /dev/null +++ b/libs/python/test/minimal.py @@ -0,0 +1,7 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +print "IMPORTING minimal_ext" +import minimal_ext +print "DONE IMPORTING minimal_ext" + diff --git a/libs/python/test/module_tail.cpp b/libs/python/test/module_tail.cpp new file mode 100644 index 000000000..f9cdca189 --- /dev/null +++ b/libs/python/test/module_tail.cpp @@ -0,0 +1,58 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if defined(_WIN32) +# ifdef __MWERKS__ +# pragma ANSI_strict off +# endif +# include <windows.h> +# ifdef __MWERKS__ +# pragma ANSI_strict reset +# endif + +# ifdef _MSC_VER +# include <eh.h> // for _set_se_translator() +# pragma warning(push) +# pragma warning(disable:4297) +# pragma warning(disable:4535) +extern "C" void straight_to_debugger(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +extern "C" void (*old_translator)(unsigned, EXCEPTION_POINTERS*) + = _set_se_translator(straight_to_debugger); +# pragma warning(pop) +# endif + +#endif // _WIN32 + +#include <exception> +#include <boost/python/extract.hpp> +#include <boost/python/str.hpp> +struct test_failure : std::exception +{ + test_failure(char const* expr, char const* /*function*/, char const* file, unsigned line) + : msg(file + boost::python::str(":%s:") % line + ": Boost.Python assertion failure: " + expr) + {} + + ~test_failure() throw() {} + + char const* what() const throw() + { + return boost::python::extract<char const*>(msg)(); + } + + boost::python::str msg; +}; + +namespace boost +{ + +void assertion_failed(char const * expr, char const * function, char const * file, long line) +{ + throw ::test_failure(expr,function, file, line); +} + +} // namespace boost diff --git a/libs/python/test/multi_arg_constructor.cpp b/libs/python/test/multi_arg_constructor.cpp new file mode 100644 index 000000000..7d49bb556 --- /dev/null +++ b/libs/python/test/multi_arg_constructor.cpp @@ -0,0 +1,27 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> + +struct A +{ + A(const double, const double, const double, const double, const double + , const double, const double + , const double, const double + ) {} +}; + +BOOST_PYTHON_MODULE(multi_arg_constructor_ext) +{ + using namespace boost::python; + + class_<A>( + "A" + , init<double, double, double, double, double, double, double, double, double>() + ) + ; + +} + diff --git a/libs/python/test/multi_arg_constructor.py b/libs/python/test/multi_arg_constructor.py new file mode 100644 index 000000000..eb8d338b3 --- /dev/null +++ b/libs/python/test/multi_arg_constructor.py @@ -0,0 +1,21 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from multi_arg_constructor_ext import * +>>> a = A(1.0, 2, 3, 4, 5, 6, 7.0, 8.1, 9.3) +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/nested.cpp b/libs/python/test/nested.cpp new file mode 100644 index 000000000..de656d2b8 --- /dev/null +++ b/libs/python/test/nested.cpp @@ -0,0 +1,51 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/operators.hpp> +#include <boost/python/scope.hpp> +#include "test_class.hpp" +#if __GNUC__ != 2 +# include <ostream> +#else +# include <ostream.h> +#endif + +typedef test_class<> X; +typedef test_class<1> Y; + +std::ostream& operator<<(std::ostream& s, X const& x) +{ + return s << x.value(); +} + +std::ostream& operator<<(std::ostream& s, Y const& x) +{ + return s << x.value(); +} + + +BOOST_PYTHON_MODULE(nested_ext) +{ + using namespace boost::python; + + // Establish X as the current scope. + scope x_class + = class_<X>("X", init<int>()) + .def(str(self)) + ; + + + // Y will now be defined in the current scope + class_<Y>("Y", init<int>()) + .def(str(self)) + ; +} + + +#include "module_tail.cpp" + + + diff --git a/libs/python/test/nested.py b/libs/python/test/nested.py new file mode 100644 index 000000000..c3446e848 --- /dev/null +++ b/libs/python/test/nested.py @@ -0,0 +1,40 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' + >>> from nested_ext import * + + >>> X + <class 'nested_ext.X'> + + >>> X.__module__ + 'nested_ext' + + >>> X.__name__ + 'X' + + >>> X.Y + <class 'nested_ext.Y'> + + >>> X.Y.__module__ + 'nested_ext' + + >>> X.Y.__name__ + 'Y' + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/newtest.py b/libs/python/test/newtest.py new file mode 100644 index 000000000..1862dcb49 --- /dev/null +++ b/libs/python/test/newtest.py @@ -0,0 +1,206 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from m1 import * + +>>> from m2 import * + + Prove that we get an appropriate error from trying to return a type + for which we have no registered to_python converter + +>>> def check_unregistered(f, msgprefix): +... try: +... f(1) +... except TypeError, x: +... if not str(x).startswith(msgprefix): +... print str(x) +... else: +... print 'expected a TypeError' +... +>>> check_unregistered(make_unregistered, 'No to_python (by-value) converter found for C++ type') +>>> check_unregistered(make_unregistered2, 'No Python class registered for C++ class') + +>>> n = new_noddy() +>>> s = new_simple() +>>> unwrap_int(n) +42 +>>> unwrap_int_ref(n) +42 +>>> unwrap_int_const_ref(n) +42 +>>> unwrap_simple(s) +'hello, world' +>>> unwrap_simple_ref(s) +'hello, world' +>>> unwrap_simple_const_ref(s) +'hello, world' +>>> unwrap_int(5) +5 + +Can't get a non-const reference to a built-in integer object +>>> try: +... unwrap_int_ref(7) +... except: pass +... else: print 'no exception' + +>>> unwrap_int_const_ref(9) +9 + +>>> wrap_int(n) +42 + +try: wrap_int_ref(n) +... except: pass +... else: print 'no exception' + +>>> wrap_int_const_ref(n) +42 + +>>> unwrap_simple_ref(wrap_simple(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_ref(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_const_ref(s)) +'hello, world' + +>>> f(s) +12 + +>>> unwrap_simple(g(s)) +'hello, world' + +>>> f(g(s)) +12 + +>>> f_mutable_ref(g(s)) +12 + +>>> f_const_ptr(g(s)) +12 + +>>> f_mutable_ptr(g(s)) +12 + +>>> f2(g(s)) +12 + +Create an extension class which wraps "complicated" (init1 and get_n) +are a complicated constructor and member function, respectively. + +>>> c1 = complicated(s, 99) +>>> c1.get_n() +99 +>>> c2 = complicated(s) +>>> c2.get_n() +0 + + a quick regression test for a bug where None could be converted + to the target of any member function. To see it, we need to + access the __dict__ directly, to bypass the type check supplied + by the Method property which wraps the method when accessed as an + attribute. + +>>> try: A.__dict__['name'](None) +... except TypeError: pass +... else: print 'expected an exception!' + + +>>> a = A() +>>> b = B() +>>> c = C() +>>> d = D() + + +>>> take_a(a).name() +'A' + +>>> try: +... take_b(a) +... except: pass +... else: print 'no exception' + +>>> try: +... take_c(a) +... except: pass +... else: print 'no exception' + +>>> try: +... take_d(a) +... except: pass +... else: print 'no exception' + +------ +>>> take_a(b).name() +'A' + +>>> take_b(b).name() +'B' + +>>> try: +... take_c(b) +... except: pass +... else: print 'no exception' + +>>> try: +... take_d(b) +... except: pass +... else: print 'no exception' + +------- +>>> take_a(c).name() +'A' + +>>> try: +... take_b(c) +... except: pass +... else: print 'no exception' + +>>> take_c(c).name() +'C' + +>>> try: +... take_d(c) +... except: pass +... else: print 'no exception' + +------- +>>> take_a(d).name() +'A' +>>> take_b(d).name() +'B' +>>> take_c(d).name() +'C' +>>> take_d(d).name() +'D' + +>>> take_d_shared_ptr(d).name() +'D' + +>>> d_as_a = d_factory() +>>> dd = take_d(d_as_a) +>>> dd.name() +'D' +>>> print g.__doc__.splitlines()[1] +g( (Simple)arg1) -> Simple : + +""" + +def run(args = None): + + import sys + import doctest + + if args is not None: + sys.argv = args + + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/numarray_tests.py b/libs/python/test/numarray_tests.py new file mode 100644 index 000000000..be3d9d4e4 --- /dev/null +++ b/libs/python/test/numarray_tests.py @@ -0,0 +1,63 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import printer + +# So we can coerce portably across Python versions +bool = type(1 == 1) + +''' +>>> from numpy_ext import * +>>> x = new_array() +>>> y = x.copy() +>>> p = _printer() +>>> check = p.check +>>> exercise_numarray(x, p) + +>>> check(str(y)) + +>>> check(y.argmax()); +>>> check(y.argmax(0)); + +>>> check(y.argmin()); +>>> check(y.argmin(0)); + +>>> check(y.argsort()); +>>> check(y.argsort(1)); + +>>> y.byteswap(); +>>> check(y); + +>>> check(y.diagonal()); +>>> check(y.diagonal(1)); +>>> check(y.diagonal(0, 0)); +>>> check(y.diagonal(0, 1, 0)); + +>>> check(y.is_c_array()); + +# coerce because numarray still returns an int and the C++ interface forces +# the return type to bool +>>> check( bool(y.isbyteswapped()) ); + +>>> check(y.trace()); +>>> check(y.trace(1)); +>>> check(y.trace(0, 0)); +>>> check(y.trace(0, 1, 0)); + +>>> check(y.new('D').getshape()); +>>> check(y.new('D').type()); +>>> y.sort(); +>>> check(y); +>>> check(y.type()); + +>>> check(y.factory((1.2, 3.4))); +>>> check(y.factory((1.2, 3.4), "f8")) +>>> check(y.factory((1.2, 3.4), "f8", true)) +>>> check(y.factory((1.2, 3.4), "f8", true, false)) +>>> check(y.factory((1.2, 3.4), "f8", true, false, None)) +>>> check(y.factory((1.2, 3.4), "f8", true, false, None, (1,2,1))) + +>>> p.results +[] +>>> del p +''' diff --git a/libs/python/test/numeric_tests.py b/libs/python/test/numeric_tests.py new file mode 100644 index 000000000..569ec19e5 --- /dev/null +++ b/libs/python/test/numeric_tests.py @@ -0,0 +1,39 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import printer +''' +>>> from numpy_ext import * +>>> x = new_array() +>>> x[1,1] = 0.0 + +>>> try: take_array(3) +... except TypeError: pass +... else: print 'expected a TypeError' + +>>> take_array(x) + +>>> print x +[[1 2 3] + [4 0 6] + [7 8 9]] + +>>> y = x.copy() + + +>>> p = _printer() +>>> check = p.check +>>> exercise(x, p) +>>> y[2,1] = 3 +>>> check(y); + +>>> check(y.astype('D')); + +>>> check(y.copy()); + +>>> check(y.typecode()); + +>>> p.results +[] +>>> del p +''' diff --git a/libs/python/test/numpy.cpp b/libs/python/test/numpy.cpp new file mode 100644 index 000000000..9472f92ed --- /dev/null +++ b/libs/python/test/numpy.cpp @@ -0,0 +1,136 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/numeric.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/str.hpp> + +using namespace boost::python; +namespace py = boost::python; + +// See if we can invoke array() from C++ +numeric::array new_array() +{ + return numeric::array( + py::make_tuple( + py::make_tuple(1,2,3) + , py::make_tuple(4,5,6) + , py::make_tuple(7,8,9) + ) + ); +} + +// test argument conversion +void take_array(numeric::array /*x*/) +{ +} + +// A separate function to invoke the info() member. Must happen +// outside any doctests since this prints directly to stdout and the +// result text includes the address of the 'self' array. +void info(numeric::array const& z) +{ + z.info(); +} + +namespace +{ + object handle_error() + { + PyObject* type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + handle<> ty(type), v(value), tr(traceback); + return object("exception"); + str format("exception type: %sn"); + format += "exception value: %sn"; + format += "traceback:n%s" ; + object ret = format % py::make_tuple(ty, v, tr); + return ret; + } +} +#define CHECK(expr) \ +{ \ + object result; \ + try { result = object(expr); } \ + catch(error_already_set) \ + { \ + result = handle_error(); \ + } \ + check(result); \ +} + +// Tests which work on both Numeric and numarray array objects. Of +// course all of the operators "just work" since numeric::array +// inherits that behavior from object. +void exercise(numeric::array& y, object check) +{ + y[py::make_tuple(2,1)] = 3; + CHECK(y); + CHECK(y.astype('D')); + CHECK(y.copy()); + CHECK(y.typecode()); +} + +// numarray-specific tests. check is a callable object which we can +// use to record intermediate results, which are later compared with +// the results of corresponding python operations. +void exercise_numarray(numeric::array& y, object check) +{ + CHECK(str(y)); + + CHECK(y.argmax()); + CHECK(y.argmax(0)); + + CHECK(y.argmin()); + CHECK(y.argmin(0)); + + CHECK(y.argsort()); + CHECK(y.argsort(1)); + + y.byteswap(); + CHECK(y); + + CHECK(y.diagonal()); + CHECK(y.diagonal(1)); + CHECK(y.diagonal(0, 0)); + CHECK(y.diagonal(0, 1, 0)); + + CHECK(y.is_c_array()); + CHECK(y.isbyteswapped()); + + CHECK(y.trace()); + CHECK(y.trace(1)); + CHECK(y.trace(0, 0)); + CHECK(y.trace(0, 1, 0)); + + CHECK(y.new_("D").getshape()); + CHECK(y.new_("D").type()); + y.sort(); + CHECK(y); + CHECK(y.type()); + + CHECK(y.factory(py::make_tuple(1.2, 3.4))); + CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8")); + CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8", true)); + CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8", true, false)); + CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8", true, false, object())); + CHECK (y.factory(py::make_tuple(1.2, 3.4), "f8", true, false, object(), py::make_tuple(1,2,1))); + +} + +BOOST_PYTHON_MODULE(numpy_ext) +{ + def("new_array", new_array); + def("take_array", take_array); + def("exercise", exercise); + def("exercise_numarray", exercise_numarray); + def("set_module_and_type", &numeric::array::set_module_and_type); + def("get_module_name", &numeric::array::get_module_name); + def("info", info); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/numpy.py b/libs/python/test/numpy.py new file mode 100644 index 000000000..84e8313d1 --- /dev/null +++ b/libs/python/test/numpy.py @@ -0,0 +1,87 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +false = 0; +true = 1; + +import doctest, numeric_tests +def _count_failures(test_modules = (numeric_tests,)): + failures = 0 + for m in test_modules: + failures += doctest.testmod(m)[0] + return failures + +def _run(args = None): + import sys, numarray_tests, numeric_tests + + if args is not None: + sys.argv = args + + # See which of the numeric modules are installed + has_numeric = 0 + try: import Numeric + except ImportError: pass + else: + has_numeric = 1 + m = Numeric + + has_numarray = 0 + try: import numarray + except ImportError: pass + else: + has_numarray = 1 + m = numarray + + # Bail if neither one is installed + if not (has_numeric or has_numarray): + return 0 + + # test the info routine outside the doctest. See numpy.cpp for an + # explanation + import numpy_ext + if (has_numarray): + numpy_ext.info(m.array((1,2,3))) + + failures = 0 + + # + # Run tests 4 different ways if both modules are installed, just + # to show that set_module_and_type() is working properly + # + + # run all the tests with default module search + print 'testing default extension module:', \ + numpy_ext.get_module_name() or '[numeric support not installed]' + + failures += _count_failures() + + # test against Numeric if installed + if has_numeric: + print 'testing Numeric module explicitly' + numpy_ext.set_module_and_type('Numeric', 'ArrayType') + + failures += _count_failures() + + if has_numarray: + print 'testing numarray module explicitly' + numpy_ext.set_module_and_type('numarray', 'NDArray') + # Add the _numarray_tests to the list of things to test in + # this case. + failures += _count_failures((numarray_tests, numeric_tests)) + + # see that we can go back to the default + numpy_ext.set_module_and_type('', '') + print 'testing default module again:', \ + numpy_ext.get_module_name() or '[numeric support not installed]' + + failures += _count_failures() + + return failures + +if __name__ == '__main__': + print "running..." + import sys + status = _run() + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/object.cpp b/libs/python/test/object.cpp new file mode 100644 index 000000000..b1f015187 --- /dev/null +++ b/libs/python/test/object.cpp @@ -0,0 +1,392 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/object.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +class NotCopyable +{ +} not_copyable; + +object ref_to_noncopyable() +{ + return object(boost::ref(not_copyable)); +} + +object call_object_3(object f) +{ + return f(3); +} + +object message() +{ + return object("hello, world!"); +} + +object number() +{ + return object(42); +} + +object obj_getattr(object x, char const* name) +{ + return x.attr(name); +} + +object obj_objgetattr(object x, object const& name) +{ + return x.attr(name); +} + +object obj_const_getattr(object const& x, char const* name) +{ + return x.attr(name); +} + +object obj_const_objgetattr(object const& x, object const& name) +{ + return x.attr(name); +} + +void obj_setattr(object x, char const* name, object value) +{ + x.attr(name) = value; +} + +void obj_objsetattr(object x, object const& name, object value) +{ + x.attr(name) = value; +} + +void obj_setattr42(object x, char const* name) +{ + x.attr(name) = 42; +} + +void obj_objsetattr42(object x, object const& name) +{ + x.attr(name) = 42; +} + +void obj_moveattr(object& x, char const* src, char const* dst) +{ + x.attr(dst) = x.attr(src); +} + +void obj_objmoveattr(object& x, object const& src, object const& dst) +{ + x.attr(dst) = x.attr(src); +} + +void obj_delattr(object x, char const* name) +{ + x.attr(name).del(); +} + +void obj_objdelattr(object x, object const& name) +{ + x.attr(name).del(); +} + +object obj_getitem(object x, object key) +{ + return x[key]; +} + +object obj_getitem3(object x) +{ + return x[3]; +} + +object obj_const_getitem(object const& x, object key) +{ + return x[key]; +} + +void obj_setitem(object x, object key, object value) +{ + x[key] = value; +} + +void obj_setitem42(object x, object key) +{ + x[key] = 42; +} + +void obj_moveitem(object& x, object src, object dst) +{ + x[dst] = x[src]; +} + +void obj_moveitem2(object const& x_src, object k_src, object& x_dst, object k_dst) +{ + x_dst[k_dst] = x_src[k_src]; +} + +bool test(object y) +{ + return y; +} + +bool test_not(object y) +{ + return !y; +} + +bool test_attr(object y, char* name) +{ + return y.attr(name); +} + +bool test_objattr(object y, object& name) +{ + return y.attr(name); +} + +bool test_not_attr(object y, char* name) +{ + return !y.attr(name); +} + +bool test_not_objattr(object y, object& name) +{ + return !y.attr(name); +} + +bool test_item(object y, object key) +{ + return y[key]; +} + +bool test_not_item(object y, object key) +{ + return !y[key]; +} + +bool check_string_slice() +{ + object s("hello, world"); + + if (s.slice(_,-3) != "hello, wo") + return false; + + if (s.slice(-3,_) != "rld") + return false; + + if (s.slice(_,_) != s) + return false; + + if (", " != s.slice(5,7)) + return false; + + return s.slice(2,-1).slice(1,-1) == "lo, wor"; +} + +object test_call(object c, object args, object kwds) +{ + return c(*args, **kwds); +} + +bool check_binary_operators() +{ + int y; + + object x(3); + +#define TEST_BINARY(op) \ + for (y = 1; y < 6; ++y) \ + { \ + if ((x op y) != (3 op y)) \ + return false; \ + } \ + for (y = 1; y < 6; ++y) \ + { \ + if ((y op x) != (y op 3)) \ + return false; \ + } \ + for (y = 1; y < 6; ++y) \ + { \ + object oy(y); \ + if ((oy op x) != (oy op 3)) \ + return false; \ + } + TEST_BINARY(>) + TEST_BINARY(>=) + TEST_BINARY(<) + TEST_BINARY(<=) + TEST_BINARY(==) + TEST_BINARY(!=) + + TEST_BINARY(+) + TEST_BINARY(-) + TEST_BINARY(*) + TEST_BINARY(/) + TEST_BINARY(%) + TEST_BINARY(<<) + TEST_BINARY(>>) + TEST_BINARY(&) + TEST_BINARY(^) + TEST_BINARY(|) + return true; +} + +bool check_inplace(object l, object o) +{ + int y; +#define TEST_INPLACE(op) \ + for (y = 1; y < 6; ++y) \ + { \ + object x(666); \ + x op##= y; \ + if (x != (666 op y)) \ + return false; \ + } \ + for (y = 1; y < 6; ++y) \ + { \ + object x(666); \ + x op##= object(y); \ + if (!(x == (666 op y))) \ + return false; \ + } + TEST_INPLACE(+) + TEST_INPLACE(-) + TEST_INPLACE(*) + TEST_INPLACE(/) + TEST_INPLACE(%) + TEST_INPLACE(<<) + TEST_INPLACE(>>) + TEST_INPLACE(&) + TEST_INPLACE(^) + TEST_INPLACE(|) + + l += l; + for (y = 0; y < 6; ++y) + { + if (l[y] != y % 3) + return false; + } + +#define TEST_ITEM_INPLACE(index, op, n, r1, r2) \ + l[index] op##= n; \ + if (l[index] != r1) \ + return false; \ + l[index] op##= object(n); \ + if (!(l[index] == r2)) \ + return false; + + TEST_ITEM_INPLACE(0,+,7,7,14) + TEST_ITEM_INPLACE(1,-,2,-1,-3) + TEST_ITEM_INPLACE(2,*,3,6,18) + TEST_ITEM_INPLACE(2,/,2,9,4) + TEST_ITEM_INPLACE(0,%,4,2,2) + l[0] += 1; + TEST_ITEM_INPLACE(0,<<,2,12,48) + TEST_ITEM_INPLACE(0,>>,1,24,12) + l[4] = 15; + TEST_ITEM_INPLACE(4,&,(16+4+1),5,5) + TEST_ITEM_INPLACE(0,^,1,13,12) + TEST_ITEM_INPLACE(0,|,1,13,13) + + o.attr("x0") = 0; + o.attr("x1") = 1; + o.attr("x2") = 2; + o.attr("x3") = 0; + o.attr("x4") = 1; + +#define TEST_ATTR_INPLACE(index, op, n, r1, r2) \ + o.attr("x" #index) op##= n; \ + if (o.attr("x" #index) != r1) \ + return false; \ + o.attr("x" #index) op##= object(n); \ + if (o.attr("x" #index) != r2) \ + return false; + + TEST_ATTR_INPLACE(0,+,7,7,14) + TEST_ATTR_INPLACE(1,-,2,-1,-3) + TEST_ATTR_INPLACE(2,*,3,6,18) + TEST_ATTR_INPLACE(2,/,2,9,4) + TEST_ATTR_INPLACE(0,%,4,2,2) + o.attr("x0") += 1; + TEST_ATTR_INPLACE(0,<<,2,12,48) + TEST_ATTR_INPLACE(0,>>,1,24,12) + o.attr("x4") = 15; + TEST_ATTR_INPLACE(4,&,(16+4+1),5,5) + TEST_ATTR_INPLACE(0,^,1,13,12) + TEST_ATTR_INPLACE(0,|,1,13,13) + + if (l[0] != o.attr("x0")) + return false; + if (l[1] != o.attr("x1")) + return false; + if (l[2] != o.attr("x2")) + return false; + if (l[3] != o.attr("x3")) + return false; + if (l[4] != o.attr("x4")) + return false; + + // set item 5 to be a list, by calling l.__class__ + l[5] = l.attr("__class__")(); + // append an element + l[5].attr("append")(2); + // Check its value + if (l[5][0] != 2) + return false; + + return true; +} + +BOOST_PYTHON_MODULE(object_ext) +{ + class_<NotCopyable, boost::noncopyable>("NotCopyable", no_init); + + def("ref_to_noncopyable", ref_to_noncopyable); + def("call_object_3", call_object_3); + def("message", message); + def("number", number); + + def("obj_getattr", obj_getattr); + def("obj_objgetattr", obj_objgetattr); + def("obj_const_getattr", obj_const_getattr); + def("obj_const_objgetattr", obj_const_objgetattr); + def("obj_setattr", obj_setattr); + def("obj_objsetattr", obj_objsetattr); + def("obj_setattr42", obj_setattr42); + def("obj_objsetattr42", obj_objsetattr42); + def("obj_moveattr", obj_moveattr); + def("obj_objmoveattr", obj_objmoveattr); + def("obj_delattr", obj_delattr); + def("obj_objdelattr", obj_objdelattr); + + def("obj_getitem", obj_getitem); + def("obj_getitem3", obj_getitem); + def("obj_const_getitem", obj_const_getitem); + def("obj_setitem", obj_setitem); + def("obj_setitem42", obj_setitem42); + def("obj_moveitem", obj_moveitem); + def("obj_moveitem2", obj_moveitem2); + + def("test", test); + def("test_not", test_not); + + def("test_attr", test_attr); + def("test_objattr", test_objattr); + def("test_not_attr", test_not_attr); + def("test_not_objattr", test_not_objattr); + + def("test_item", test_item); + def("test_not_item", test_not_item); + + def("test_call", test_call); + def("check_binary_operators", check_binary_operators); + def("check_inplace", check_inplace); + def("check_string_slice", check_string_slice); + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/object.py b/libs/python/test/object.py new file mode 100644 index 000000000..84972e64f --- /dev/null +++ b/libs/python/test/object.py @@ -0,0 +1,179 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from object_ext import * + +>>> type(ref_to_noncopyable()) +<class 'object_ext.NotCopyable'> + +>>> def print1(x): +... print x +>>> call_object_3(print1) +3 +>>> message() +'hello, world!' +>>> number() +42 + +>>> test('hi') +1 +>>> test(None) +0 +>>> test_not('hi') +0 +>>> test_not(0) +1 + + Attributes + +>>> class X: pass +... +>>> x = X() + +>>> try: obj_getattr(x, 'foo') +... except AttributeError: pass +... else: print 'expected an exception' +>>> try: obj_objgetattr(x, 'objfoo') +... except AttributeError: pass +... else: print 'expected an exception' + +>>> obj_setattr(x, 'foo', 1) +>>> x.foo +1 +>>> obj_objsetattr(x, 'objfoo', 1) +>>> try:obj_objsetattr(x, 1) +... except TypeError: pass +... else: print 'expected an exception' +>>> x.objfoo +1 +>>> obj_getattr(x, 'foo') +1 +>>> obj_objgetattr(x, 'objfoo') +1 +>>> try:obj_objgetattr(x, 1) +... except TypeError: pass +... else: print 'expected an exception' +>>> obj_const_getattr(x, 'foo') +1 +>>> obj_const_objgetattr(x, 'objfoo') +1 +>>> obj_setattr42(x, 'foo') +>>> x.foo +42 +>>> obj_objsetattr42(x, 'objfoo') +>>> x.objfoo +42 +>>> obj_moveattr(x, 'foo', 'bar') +>>> x.bar +42 +>>> obj_objmoveattr(x, 'objfoo', 'objbar') +>>> x.objbar +42 +>>> test_attr(x, 'foo') +1 +>>> test_objattr(x, 'objfoo') +1 +>>> test_not_attr(x, 'foo') +0 +>>> test_not_objattr(x, 'objfoo') +0 +>>> x.foo = None +>>> test_attr(x, 'foo') +0 +>>> x.objfoo = None +>>> test_objattr(x, 'objfoo') +0 +>>> test_not_attr(x, 'foo') +1 +>>> test_not_objattr(x, 'objfoo') +1 +>>> obj_delattr(x, 'foo') +>>> obj_objdelattr(x, 'objfoo') +>>> try:obj_delattr(x, 'foo') +... except AttributeError: pass +... else: print 'expected an exception' +>>> try:obj_objdelattr(x, 'objfoo') +... except AttributeError: pass +... else: print 'expected an exception' + + Items + +>>> d = {} +>>> obj_setitem(d, 'foo', 1) +>>> d['foo'] +1 +>>> obj_getitem(d, 'foo') +1 +>>> obj_const_getitem(d, 'foo') +1 +>>> obj_setitem42(d, 'foo') +>>> obj_getitem(d, 'foo') +42 +>>> d['foo'] +42 +>>> obj_moveitem(d, 'foo', 'bar') +>>> d['bar'] +42 +>>> obj_moveitem2(d, 'bar', d, 'baz') +>>> d['baz'] +42 +>>> test_item(d, 'foo') +1 +>>> test_not_item(d, 'foo') +0 +>>> d['foo'] = None +>>> test_item(d, 'foo') +0 +>>> test_not_item(d, 'foo') +1 + + Slices + +>>> assert check_string_slice() + + Operators + +>>> def print_args(*args, **kwds): +... print args, kwds +>>> test_call(print_args, (0, 1, 2, 3), {'a':'A'}) +(0, 1, 2, 3) {'a': 'A'} + + +>>> assert check_binary_operators() + +>>> class X: pass +... +>>> assert check_inplace(range(3), X()) + + + Now make sure that object is actually managing reference counts + +>>> import weakref +>>> class Z: pass +... +>>> z = Z() +>>> def death(r): print 'death' +... +>>> r = weakref.ref(z, death) +>>> z.foo = 1 +>>> obj_getattr(z, 'foo') +1 +>>> del z +death +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/object_fail1.cpp b/libs/python/test/object_fail1.cpp new file mode 100644 index 000000000..6bb2eda5c --- /dev/null +++ b/libs/python/test/object_fail1.cpp @@ -0,0 +1,11 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/object.hpp> + +int f(boost::python::object const& x) +{ + x._("hello") = 1; + return 0; +} diff --git a/libs/python/test/object_manager.cpp b/libs/python/test/object_manager.cpp new file mode 100644 index 000000000..e3608c1f1 --- /dev/null +++ b/libs/python/test/object_manager.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/converter/object_manager.hpp> +#include <boost/python/borrowed.hpp> +#include <boost/static_assert.hpp> +#include <boost/python/handle.hpp> + +using namespace boost::python; +using namespace boost::python::converter; + +struct X {}; + +int main() +{ + BOOST_STATIC_ASSERT(is_object_manager<handle<> >::value); + BOOST_STATIC_ASSERT(!is_object_manager<int>::value); + BOOST_STATIC_ASSERT(!is_object_manager<X>::value); + + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<>&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<> const&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<> volatile&>::value); + BOOST_STATIC_ASSERT(is_reference_to_object_manager<handle<> const volatile&>::value); + + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<handle<> >::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<X>::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<X&>::value); + BOOST_STATIC_ASSERT(!is_reference_to_object_manager<X const&>::value); + + return 0; +} + diff --git a/libs/python/test/opaque.cpp b/libs/python/test/opaque.cpp new file mode 100644 index 000000000..f15e9458f --- /dev/null +++ b/libs/python/test/opaque.cpp @@ -0,0 +1,76 @@ +// Copyright David Abrahams and Gottfried Ganssauge 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +typedef struct opaque_ *opaque; +typedef struct opaque2_ *opaque2; + +opaque the_op = ((opaque) 0x47110815); +opaque2 the_op2 = ((opaque2) 0x08154711); + +opaque get() { return the_op; } + +void use(opaque op) +{ + if (op != the_op) + throw std::runtime_error (std::string ("failed")); +} + +int useany(opaque op) +{ + return op ? 1 : 0; +} + +opaque getnull() +{ + return 0; +} + +void failuse (opaque op) +{ + if (op == the_op) + throw std::runtime_error (std::string ("success")); +} + +opaque2 get2 () { return the_op2; } + +void use2 (opaque2 op) +{ + if (op != the_op2) + throw std::runtime_error (std::string ("failed")); +} + +void failuse2 (opaque2 op) +{ + if (op == the_op2) + throw std::runtime_error (std::string ("success")); +} + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque2_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(opaque_ext) +{ + bpl::def ( + "get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("use", &::use); + bpl::def ("useany", &::useany); + bpl::def ("getnull", &::getnull, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("failuse", &::failuse); + + bpl::def ( + "get2", + &::get2, + bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def ("use2", &::use2); + bpl::def ("failuse2", &::failuse2); +} + +# include "module_tail.cpp" diff --git a/libs/python/test/opaque.py b/libs/python/test/opaque.py new file mode 100644 index 000000000..2ee0aa0c0 --- /dev/null +++ b/libs/python/test/opaque.py @@ -0,0 +1,87 @@ +# -*- coding: latin-1 -*- +# Copyright Gottfried Ganßauge 2003..2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +""" +>>> from opaque_ext import * + + + Check for correct conversion + +>>> use(get()) + + Check that None is converted to a NULL opaque pointer + +>>> useany(get()) +1 +>>> useany(None) +0 + + Check that we don't lose type information by converting NULL + opaque pointers to None + +>>> assert getnull() is None +>>> useany(getnull()) +0 + +>>> failuse(get()) +Traceback (most recent call last): + ... +RuntimeError: success + + Check that there is no conversion from integers ... + +>>> try: use(0) +... except TypeError: pass +... else: print 'expected a TypeError' + + ... and from strings to opaque objects + +>>> try: use("") +... except TypeError: pass +... else: print 'expected a TypeError' + + Now check the same for another opaque pointer type + +>>> use2(get2()) +>>> failuse2(get2()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> try: use2(0) +... except TypeError: pass +... else: print 'expected a TypeError' +>>> try: use2("") +... except TypeError: pass +... else: print 'expected a TypeError' + + Check that opaque types are distinct + +>>> try: use(get2()) +... except TypeError: pass +... else: print 'expected a TypeError' +>>> try: use2(get()) +... except TypeError: pass +... else: print 'expected a TypeError' + + This used to result in a segmentation violation + +>>> type(get()) != type (get2()) +1 +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/operators.cpp b/libs/python/test/operators.cpp new file mode 100644 index 000000000..c58f2b005 --- /dev/null +++ b/libs/python/test/operators.cpp @@ -0,0 +1,175 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/operators.hpp> +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include "test_class.hpp" +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/operators.hpp> +#include <boost/operators.hpp> +//#include <boost/python/str.hpp> +// Just use math.h here; trying to use std::pow() causes too much +// trouble for non-conforming compilers and libraries. +#include <math.h> + +#if __GNUC__ != 2 +# include <ostream> +#else +# include <ostream.h> +#endif + +using namespace boost::python; + + +using namespace boost::python; + +struct X : test_class<> +{ + typedef test_class<> base_t; + + X(int x) : base_t(x) {} + X const operator+(X const& r) const { return X(value() + r.value()); } + +// typedef int (X::*safe_bool)() const; +// operator safe_bool() const { return value() != 0 ? &X::value : 0; } +}; + +X operator-(X const& l, X const& r) { return X(l.value() - r.value()); } +X operator-(int l, X const& r) { return X(l - r.value()); } +X operator-(X const& l, int r) { return X(l.value() - r); } + +X operator-(X const& x) { return X(-x.value()); } + +X& operator-=(X& l, X const& r) { l.set(l.value() - r.value()); return l; } + +bool operator<(X const& x, X const& y) { return x.value() < y.value(); } +bool operator<(X const& x, int y) { return x.value() < y; } +bool operator<(int x, X const& y) { return x < y.value(); } + +X abs(X x) { return X(x.value() < 0 ? -x.value() : x.value()); } + +X pow(X x, int y) +{ + return X(int(pow(double(x.value()), double(y)))); +} + +X pow(X x, X y) +{ + return X(int(pow(double(x.value()), double(y.value())))); +} + +int pow(int x, X y) +{ + return int(pow(double(x), double(y.value()))); +} + +std::ostream& operator<<(std::ostream& s, X const& x) +{ + return s << x.value(); +} + +struct number + : boost::integer_arithmetic<number> +{ + explicit number(long x_) : x(x_) {} + operator long() const { return x; } + + template <class T> + number& operator+=(T const& rhs) + { x += rhs; return *this; } + + template <class T> + number& operator-=(T const& rhs) + { x -= rhs; return *this; } + + template <class T> + number& operator*=(T const& rhs) + { x *= rhs; return *this; } + + template <class T> + number& operator/=(T const& rhs) + { x /= rhs; return *this; } + + template <class T> + number& operator%=(T const& rhs) + { x %= rhs; return *this; } + + long x; +}; + +BOOST_PYTHON_MODULE(operators_ext) +{ + class_<X>("X", init<int>()) + .def("value", &X::value) + .def(self + self) + .def(self - self) + .def(self - int()) + .def(other<int>() - self) + .def(-self) + .def(self < other<int>()) + .def(self < self) + .def(1 < self) + .def(self -= self) + + .def(abs(self)) + .def(str(self)) + + .def(pow(self,self)) + .def(pow(self,int())) + .def(pow(int(),self)) + .def( + !self + // "not self" is legal here but causes friction on a few + // nonconforming compilers; it's cute because it looks + // like python, but doing it here doesn't prove much and + // just causes tests to fail or complicated workarounds to + // be enacted. + ) + ; + + class_<number>("number", init<long>()) + // interoperate with self + .def(self += self) + .def(self + self) + .def(self -= self) + .def(self - self) + .def(self *= self) + .def(self * self) + .def(self /= self) + .def(self / self) + .def(self %= self) + .def(self % self) + + // Convert to Python int + .def(int_(self)) + + // interoperate with long + .def(self += long()) + .def(self + long()) + .def(long() + self) + .def(self -= long()) + .def(self - long()) + .def(long() - self) + .def(self *= long()) + .def(self * long()) + .def(long() * self) + .def(self /= long()) + .def(self / long()) + .def(long() / self) + .def(self %= long()) + .def(self % long()) + .def(long() % self) + ; + + class_<test_class<1> >("Z", init<int>()) + .def(int_(self)) + .def(float_(self)) + .def(complex_(self)) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/operators.py b/libs/python/test/operators.py new file mode 100644 index 000000000..f39134b66 --- /dev/null +++ b/libs/python/test/operators.py @@ -0,0 +1,102 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from operators_ext import * + + Check __nonzero__ support + +>>> assert X(2) +>>> assert not X(0) + + ---- + +>>> x = X(42) +>>> x.value() +42 +>>> y = x - X(5) +>>> y.value() +37 +>>> y = x - 4 +>>> y.value() +38 +>>> y = 3 - x +>>> y.value() +-39 +>>> (-y).value() +39 + +>>> (x + y).value() +3 + +>>> abs(y).value() +39 + +>>> x < 10 +0 +>>> x < 43 +1 + +>>> 10 < x +1 +>>> 43 < x +0 + +>>> x < y +0 +>>> y < x +1 + + ------ +>>> x > 10 +1 +>>> x > 43 +0 + +>>> 10 > x +0 +>>> 43 > x +1 + +>>> x > y +1 +>>> y > x +0 + +>>> y = x - 5 +>>> x -= y +>>> x.value() +5 +>>> str(x) +'5' + +>>> z = Z(10) +>>> int(z) +10 +>>> float(z) +10.0 +>>> complex(z) +(10+0j) + +>>> pow(2,x) +32 +>>> pow(x,2).value() +25 +>>> pow(X(2),x).value() +32 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/operators_wrapper.cpp b/libs/python/test/operators_wrapper.cpp new file mode 100644 index 000000000..12f30048d --- /dev/null +++ b/libs/python/test/operators_wrapper.cpp @@ -0,0 +1,42 @@ +#include "boost/python.hpp" +#include <memory> + +struct vector +{ + virtual ~vector() {} + + vector operator+( const vector& ) const + { return vector(); } + + vector& operator+=( const vector& ) + { return *this; } + + vector operator-() const + { return *this; } +}; + +struct dvector : vector +{}; + +using namespace boost::python; + +struct vector_wrapper + : vector, wrapper< vector > +{ + vector_wrapper(vector const&) {} + vector_wrapper() {} +}; + +BOOST_PYTHON_MODULE( operators_wrapper_ext ) +{ + class_< vector_wrapper >( "vector" ) + .def( self + self ) + .def( self += self ) + .def( -self ) + ; + + scope().attr("v") = vector(); + std::auto_ptr<vector> dp(new dvector); + register_ptr_to_python< std::auto_ptr<vector> >(); + scope().attr("d") = dp; +} diff --git a/libs/python/test/operators_wrapper.py b/libs/python/test/operators_wrapper.py new file mode 100644 index 000000000..6c889b0a3 --- /dev/null +++ b/libs/python/test/operators_wrapper.py @@ -0,0 +1,11 @@ +from operators_wrapper_ext import * + +class D2(vector): pass +d2 = D2() + +for lhs in (v,d,d2): + -lhs + for rhs in (v,d,d2): + lhs + rhs + lhs += rhs + diff --git a/libs/python/test/pickle1.cpp b/libs/python/test/pickle1.cpp new file mode 100644 index 000000000..cc4ad6795 --- /dev/null +++ b/libs/python/test/pickle1.cpp @@ -0,0 +1,62 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below can be fully restored by passing the + appropriate argument to the constructor. Therefore it is sufficient + to define the pickle interface method __getinitargs__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> + +#include <string> + +namespace boost_python_test { + + // 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 + "!"; } + std::string get_country() const { return country; } + }; + + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + return boost::python::make_tuple(w.get_country()); + } + }; + + // To support test of "pickling not enabled" error message. + struct noop {}; +} + +BOOST_PYTHON_MODULE(pickle1_ext) +{ + using namespace boost::python; + using namespace boost_python_test; + class_<world>("world", init<const std::string&>()) + .def("greet", &world::greet) + .def_pickle(world_pickle_suite()) + ; + + // To support test of "pickling not enabled" error message. + class_<noop>("noop"); +} diff --git a/libs/python/test/pickle1.py b/libs/python/test/pickle1.py new file mode 100644 index 000000000..8369768d6 --- /dev/null +++ b/libs/python/test/pickle1.py @@ -0,0 +1,41 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +r'''>>> import pickle1_ext + >>> import pickle + >>> pickle1_ext.world.__module__ + 'pickle1_ext' + >>> pickle1_ext.world.__safe_for_unpickling__ + 1 + >>> pickle1_ext.world.__name__ + 'world' + >>> pickle1_ext.world('Hello').__reduce__() + (<class 'pickle1_ext.world'>, ('Hello',)) + >>> wd = pickle1_ext.world('California') + >>> pstr = pickle.dumps(wd) + >>> wl = pickle.loads(pstr) + >>> print wd.greet() + Hello from California! + >>> print wl.greet() + Hello from California! + + >>> noop = pickle1_ext.noop() + >>> try: pickle.dumps(noop) + ... except RuntimeError, e: print str(e)[:55] + Pickling of "pickle1_ext.noop" instances is not enabled +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/pickle2.cpp b/libs/python/test/pickle2.cpp new file mode 100644 index 000000000..c9610946e --- /dev/null +++ b/libs/python/test/pickle2.cpp @@ -0,0 +1,97 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + For simplicity, the __dict__ is not included in the result of + __getstate__. This is not generally recommended, but a valid + approach if it is anticipated that the object's __dict__ will + always be empty. Note that safety guards are provided to catch + the cases where this assumption is not true. + + pickle3.cpp shows how to include the object's __dict__ in the + result of __getstate__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/extract.hpp> + +namespace boost_python_test { + + // A friendly class. + class world + { + 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; } + private: + std::string country; + int secret_number; + }; + + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + return boost::python::make_tuple(w.get_country()); + } + + static + boost::python::tuple + getstate(const world& w) + { + return boost::python::make_tuple(w.get_secret_number()); + } + + static + void + setstate(world& w, boost::python::tuple state) + { + using namespace boost::python; + if (len(state) != 1) + { + PyErr_SetObject(PyExc_ValueError, + ("expected 1-item tuple in call to __setstate__; got %s" + % state).ptr() + ); + throw_error_already_set(); + } + + long number = extract<long>(state[0]); + if (number != 42) + w.set_secret_number(number); + } + }; + +} + +BOOST_PYTHON_MODULE(pickle2_ext) +{ + using namespace boost_python_test; + boost::python::class_<world>( + "world", boost::python::init<const std::string&>()) + .def("greet", &world::greet) + .def("get_secret_number", &world::get_secret_number) + .def("set_secret_number", &world::set_secret_number) + .def_pickle(world_pickle_suite()) + ; +} diff --git a/libs/python/test/pickle2.py b/libs/python/test/pickle2.py new file mode 100644 index 000000000..2ad663fff --- /dev/null +++ b/libs/python/test/pickle2.py @@ -0,0 +1,50 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +r'''>>> import pickle2_ext + >>> import pickle + >>> pickle2_ext.world.__module__ + 'pickle2_ext' + >>> pickle2_ext.world.__safe_for_unpickling__ + 1 + >>> pickle2_ext.world.__name__ + 'world' + >>> pickle2_ext.world('Hello').__reduce__() + (<class 'pickle2_ext.world'>, ('Hello',), (0,)) + >>> for number in (24, 42): + ... wd = pickle2_ext.world('California') + ... wd.set_secret_number(number) + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number() + ... print wl.greet(), wl.get_secret_number() + Hello from California! 24 + Hello from California! 24 + Hello from California! 42 + Hello from California! 0 + +# Now show that the __dict__ is not taken care of. + >>> wd = pickle2_ext.world('California') + >>> wd.x = 1 + >>> wd.__dict__ + {'x': 1} + >>> try: pstr = pickle.dumps(wd) + ... except RuntimeError, err: print err + ... + Incomplete pickle support (__getstate_manages_dict__ not set) +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/pickle3.cpp b/libs/python/test/pickle3.cpp new file mode 100644 index 000000000..7afe2dbfa --- /dev/null +++ b/libs/python/test/pickle3.cpp @@ -0,0 +1,107 @@ +// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + The object's __dict__ is included in the result of __getstate__. + This requires more code (compare with pickle2.cpp), but is + unavoidable if the object's __dict__ is not always empty. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/back_reference.hpp> + +namespace boost_python_test { + + // A friendly class. + class world + { + 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; } + private: + std::string country; + int secret_number; + }; + + struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + return boost::python::make_tuple(w.get_country()); + } + + static + boost::python::tuple + getstate(boost::python::object w_obj) + { + world const& w = boost::python::extract<world const&>(w_obj)(); + + return boost::python::make_tuple( + w_obj.attr("__dict__"), + w.get_secret_number()); + } + + static + void + setstate(boost::python::object w_obj, boost::python::tuple state) + { + using namespace boost::python; + world& w = extract<world&>(w_obj)(); + + if (len(state) != 2) + { + PyErr_SetObject(PyExc_ValueError, + ("expected 2-item tuple in call to __setstate__; got %s" + % state).ptr() + ); + throw_error_already_set(); + } + + // restore the object's __dict__ + dict d = extract<dict>(w_obj.attr("__dict__"))(); + d.update(state[0]); + + // restore the internal state of the C++ object + long number = extract<long>(state[1]); + if (number != 42) + w.set_secret_number(number); + } + + static bool getstate_manages_dict() { return true; } + }; + +} + +BOOST_PYTHON_MODULE(pickle3_ext) +{ + using namespace boost_python_test; + boost::python::class_<world>( + "world", boost::python::init<const std::string&>()) + .def("greet", &world::greet) + .def("get_secret_number", &world::get_secret_number) + .def("set_secret_number", &world::set_secret_number) + .def_pickle(world_pickle_suite()) + ; +} diff --git a/libs/python/test/pickle3.py b/libs/python/test/pickle3.py new file mode 100644 index 000000000..6be3128c5 --- /dev/null +++ b/libs/python/test/pickle3.py @@ -0,0 +1,45 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +r'''>>> import pickle3_ext + >>> import pickle + >>> pickle3_ext.world.__module__ + 'pickle3_ext' + >>> pickle3_ext.world.__safe_for_unpickling__ + 1 + >>> pickle3_ext.world.__getstate_manages_dict__ + 1 + >>> pickle3_ext.world.__name__ + 'world' + >>> pickle3_ext.world('Hello').__reduce__() + (<class 'pickle3_ext.world'>, ('Hello',), ({}, 0)) + >>> for number in (24, 42): + ... wd = pickle3_ext.world('California') + ... wd.set_secret_number(number) + ... wd.x = 2 * number + ... wd.y = 'y' * number + ... wd.z = 3. * number + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number(), wd.x, wd.y, wd.z + ... print wl.greet(), wl.get_secret_number(), wl.x, wl.y, wl.z + Hello from California! 24 48 yyyyyyyyyyyyyyyyyyyyyyyy 72.0 + Hello from California! 24 48 yyyyyyyyyyyyyyyyyyyyyyyy 72.0 + Hello from California! 42 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 + Hello from California! 0 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/pickle4.cpp b/libs/python/test/pickle4.cpp new file mode 100644 index 000000000..1374cc7dc --- /dev/null +++ b/libs/python/test/pickle4.cpp @@ -0,0 +1,44 @@ +// Copyright Ralf W. Grosse-Kunstleve 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + This example shows how to enable pickling without using the + pickle_suite. The pickling interface (__getinitargs__) is + implemented in Python. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> + +#include <string> + +namespace boost_python_test { + + // 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 + "!"; } + std::string get_country() const { return country; } + }; + +} + +BOOST_PYTHON_MODULE(pickle4_ext) +{ + using namespace boost::python; + using namespace boost_python_test; + class_<world>("world", init<const std::string&>()) + .enable_pickling() + .def("greet", &world::greet) + .def("get_country", &world::get_country) + ; +} diff --git a/libs/python/test/pickle4.py b/libs/python/test/pickle4.py new file mode 100644 index 000000000..a5069c90d --- /dev/null +++ b/libs/python/test/pickle4.py @@ -0,0 +1,39 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +r'''>>> import pickle4_ext + >>> import pickle + >>> def world_getinitargs(self): + ... return (self.get_country(),) + >>> pickle4_ext.world.__getinitargs__ = world_getinitargs + >>> pickle4_ext.world.__module__ + 'pickle4_ext' + >>> pickle4_ext.world.__safe_for_unpickling__ + 1 + >>> pickle4_ext.world.__name__ + 'world' + >>> pickle4_ext.world('Hello').__reduce__() + (<class 'pickle4_ext.world'>, ('Hello',)) + >>> wd = pickle4_ext.world('California') + >>> pstr = pickle.dumps(wd) + >>> wl = pickle.loads(pstr) + >>> print wd.greet() + Hello from California! + >>> print wl.greet() + Hello from California! +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/pointee.cpp b/libs/python/test/pointee.cpp new file mode 100644 index 000000000..d962e79f5 --- /dev/null +++ b/libs/python/test/pointee.cpp @@ -0,0 +1,34 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/pointee.hpp> +#include <boost/type_traits/same_traits.hpp> +#include <memory> +#include <boost/shared_ptr.hpp> +#include <boost/static_assert.hpp> + +struct A; + +int main() +{ + BOOST_STATIC_ASSERT( + (boost::is_same< + boost::python::pointee<std::auto_ptr<char**> >::type + , char** + >::value)); + + BOOST_STATIC_ASSERT( + (boost::is_same< + boost::python::pointee<boost::shared_ptr<A> >::type + , A>::value)); + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + BOOST_STATIC_ASSERT( + (boost::is_same< + boost::python::pointee<char*>::type + , char + >::value)); +#endif + return 0; +} diff --git a/libs/python/test/pointer_type_id_test.cpp b/libs/python/test/pointer_type_id_test.cpp new file mode 100644 index 000000000..02e168c7e --- /dev/null +++ b/libs/python/test/pointer_type_id_test.cpp @@ -0,0 +1,43 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/type_id.hpp> + +#include <boost/detail/lightweight_test.hpp> +#include <boost/python/converter/pointer_type_id.hpp> + +int main() +{ + using namespace boost::python::converter; + + boost::python::type_info x + = boost::python::type_id<int>(); + + + BOOST_TEST(pointer_type_id<int*>() == x); + BOOST_TEST(pointer_type_id<int const*>() == x); + BOOST_TEST(pointer_type_id<int volatile*>() == x); + BOOST_TEST(pointer_type_id<int const volatile*>() == x); + + BOOST_TEST(pointer_type_id<int*&>() == x); + BOOST_TEST(pointer_type_id<int const*&>() == x); + BOOST_TEST(pointer_type_id<int volatile*&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*&>() == x); + + BOOST_TEST(pointer_type_id<int*const&>() == x); + BOOST_TEST(pointer_type_id<int const*const&>() == x); + BOOST_TEST(pointer_type_id<int volatile*const&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*const&>() == x); + + BOOST_TEST(pointer_type_id<int*volatile&>() == x); + BOOST_TEST(pointer_type_id<int const*volatile&>() == x); + BOOST_TEST(pointer_type_id<int volatile*volatile&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*volatile&>() == x); + + BOOST_TEST(pointer_type_id<int*const volatile&>() == x); + BOOST_TEST(pointer_type_id<int const*const volatile&>() == x); + BOOST_TEST(pointer_type_id<int volatile*const volatile&>() == x); + BOOST_TEST(pointer_type_id<int const volatile*const volatile&>() == x); + + return boost::report_errors(); +} diff --git a/libs/python/test/pointer_vector.cpp b/libs/python/test/pointer_vector.cpp new file mode 100644 index 000000000..08cd48619 --- /dev/null +++ b/libs/python/test/pointer_vector.cpp @@ -0,0 +1,52 @@ +// Copyright Joel de Guzman 2005-2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <vector> + +using namespace boost::python; + +class Abstract +{ +public: + virtual ~Abstract() {}; // silence compiler warningsa + virtual std::string f() =0; +}; + +class Concrete1 : public Abstract +{ +public: + virtual std::string f() { return "harru"; } +}; + +typedef std::vector<Abstract*> ListOfObjects; + +class DoesSomething +{ +public: + DoesSomething() {} + + ListOfObjects returnList() + { + ListOfObjects lst; + lst.push_back(new Concrete1()); return lst; + } +}; + +BOOST_PYTHON_MODULE(pointer_vector_ext) +{ +class_<Abstract, boost::noncopyable>("Abstract", no_init) + .def("f", &Abstract::f) + ; + +class_<ListOfObjects>("ListOfObjects") + .def( vector_indexing_suite<ListOfObjects>() ) + ; + +class_<DoesSomething>("DoesSomething") + .def("returnList", &DoesSomething::returnList) + ; +} + + diff --git a/libs/python/test/pointer_vector.py b/libs/python/test/pointer_vector.py new file mode 100644 index 000000000..16900e8eb --- /dev/null +++ b/libs/python/test/pointer_vector.py @@ -0,0 +1,31 @@ +# Copyright Joel de Guzman 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' + +>>> import pointer_vector_ext +>>> d = pointer_vector_ext.DoesSomething() +>>> lst = d.returnList() +>>> lst[0].f(); +'harru' + +''' + + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print 'running...' + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + + + diff --git a/libs/python/test/polymorphism.cpp b/libs/python/test/polymorphism.cpp new file mode 100644 index 000000000..02713ae26 --- /dev/null +++ b/libs/python/test/polymorphism.cpp @@ -0,0 +1,162 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/pure_virtual.hpp> +#include <boost/python/def.hpp> +#include <boost/utility.hpp> + +using namespace boost::python; + +struct Callback +{ + Callback(PyObject* o) : mSelf(o) {} + PyObject* mSelf; +}; + +struct P +{ + virtual ~P(){} + virtual std::string f() = 0; + std::string g() { return "P::g()"; } +}; + +struct PCallback : P, Callback +{ + PCallback (PyObject* self) : Callback(self) {} + + std::string f() + { + return call_method<std::string>(mSelf, "f"); + } +}; + +struct Q : virtual P +{ + std::string f() { return "Q::f()"; } +}; + +struct A +{ + virtual ~A(){} + virtual std::string f() { return "A::f()"; } +}; + +struct ACallback : A, Callback +{ + ACallback (PyObject* self) : Callback(self) {} + + + std::string f() + { + return call_method<std::string>(mSelf, "f"); + } + + std::string default_f() + { + return A::f(); + } +}; + +struct B : A +{ + virtual std::string f() { return "B::f()"; } +}; + +struct C : A +{ + virtual std::string f() { return "C::f()"; } +}; + +struct D : A +{ + virtual std::string f() { return "D::f()"; } + std::string g() { return "D::g()"; } +}; + +struct DCallback : D, Callback +{ + DCallback (PyObject* self) : Callback(self) {} + + std::string f() + { + return call_method<std::string>(mSelf, "f"); + } + + std::string default_f() + { + return A::f(); + } +}; + + +A& getBCppObj () +{ + static B b; + return b; +} + +std::string call_f(A& a) { return a.f(); } + +A* factory(unsigned choice) +{ + switch (choice % 3) + { + case 0: return new A; + break; + case 1: return new B; + break; + default: return new C; + break; + } +} + +C& getCCppObj () +{ + static C c; + return c; +} + +A* pass_a(A* x) { return x; } + +BOOST_PYTHON_MODULE_INIT(polymorphism_ext) +{ + class_<A,boost::noncopyable,ACallback>("A") + .def("f", &A::f, &ACallback::default_f) + ; + + def("getBCppObj", getBCppObj, return_value_policy<reference_existing_object>()); + + class_<C,bases<A>,boost::noncopyable>("C") + .def("f", &C::f) + ; + + class_<D,bases<A>,DCallback,boost::noncopyable>("D") + .def("f", &D::f, &DCallback::default_f) + .def("g", &D::g) + ; + + def("pass_a", &pass_a, return_internal_reference<>()); + + def("getCCppObj", getCCppObj, return_value_policy<reference_existing_object>()); + + def("factory", factory, return_value_policy<manage_new_object>()); + + def("call_f", call_f); + + class_<P,boost::noncopyable,PCallback>("P") + .def("f", pure_virtual(&P::f)) + ; + + class_<Q, bases<P> >("Q") + .def("g", &P::g) // make sure virtual inheritance doesn't interfere + ; +} + +//#include "module_tail.cpp" diff --git a/libs/python/test/polymorphism.py b/libs/python/test/polymorphism.py new file mode 100644 index 000000000..0218b8108 --- /dev/null +++ b/libs/python/test/polymorphism.py @@ -0,0 +1,74 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import unittest +from polymorphism_ext import * + +class PolymorphTest(unittest.TestCase): + + def testReturnCpp(self): + + # Python Created Object With Same Id As + # Cpp Created B Object + # b = B(872) + + # Get Reference To Cpp Created B Object + a = getBCppObj() + + # Python Created B Object and Cpp B Object + # Should have same result by calling f() + self.failUnlessEqual ('B::f()', a.f()) + self.failUnlessEqual ('B::f()', call_f(a)) + self.failUnlessEqual ('A::f()', call_f(A())) + + def test_references(self): + # B is not exposed to Python + a = getBCppObj() + self.failUnlessEqual(type(a), A) + + # C is exposed to Python + c = getCCppObj() + self.failUnlessEqual(type(c), C) + + def test_factory(self): + self.failUnlessEqual(type(factory(0)), A) + self.failUnlessEqual(type(factory(1)), A) + self.failUnlessEqual(type(factory(2)), C) + + def test_return_py(self): + + class X(A): + def f(self): + return 'X.f' + + x = X() + + self.failUnlessEqual ('X.f', x.f()) + self.failUnlessEqual ('X.f', call_f(x)) + + def test_wrapper_downcast(self): + a = pass_a(D()) + self.failUnlessEqual('D::g()', a.g()) + + def test_pure_virtual(self): + p = P() + self.assertRaises(RuntimeError, p.f) + + q = Q() + self.failUnlessEqual ('Q::f()', q.f()) + + class R(P): + def f(self): + return 'R.f' + + r = R() + self.failUnlessEqual ('R.f', r.f()) + + +if __name__ == "__main__": + + # remove the option which upsets unittest + import sys + sys.argv = [ x for x in sys.argv if x != '--broken-auto-ptr' ] + + unittest.main() diff --git a/libs/python/test/polymorphism2.cpp b/libs/python/test/polymorphism2.cpp new file mode 100644 index 000000000..8aefbc3af --- /dev/null +++ b/libs/python/test/polymorphism2.cpp @@ -0,0 +1,172 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/reference_existing_object.hpp> +#include <boost/python/pure_virtual.hpp> +#include <boost/python/wrapper.hpp> +#include <boost/python/def.hpp> +#include <boost/python/call.hpp> +#include <boost/utility.hpp> + +#include <memory> + +#ifdef HELD_BY_AUTO_PTR +# define HELD_PTR(X) , std::auto_ptr< X > +#else +# define HELD_PTR(X) +#endif + +using namespace boost::python; + +struct P +{ + virtual ~P(){} + virtual char const* f() = 0; + char const* g() { return "P::g()"; } +}; + +struct PCallback : P, wrapper<P> +{ + char const* f() + { +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return call<char const*>(this->get_override("f").ptr()); +#else + return this->get_override("f")(); +#endif + } +}; + +struct Q : virtual P +{ + char const* f() { return "Q::f()"; } +}; + +struct A +{ + virtual ~A(){} + virtual char const* f() { return "A::f()"; } +}; + +struct ACallback : A, wrapper<A> +{ + char const* f() + { + if (override f = this->get_override("f")) +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return call<char const*>(f.ptr()); +#else + return f(); +#endif + + return A::f(); + } + + char const* default_f() { return this->A::f(); } +}; + +struct B : A +{ + virtual char const* f() { return "B::f()"; } +}; + +struct C : A +{ + virtual char const* f() { return "C::f()"; } +}; + +struct D : A +{ + virtual char const* f() { return "D::f()"; } + char const* g() { return "D::g()"; } +}; + +struct DCallback : D, wrapper<D> +{ + char const* f() + { + if (override f = this->get_override("f")) +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return call<char const*>(f.ptr()); +#else + return f(); +#endif + //else + return D::f(); + } +}; + + +A& getBCppObj () +{ + static B b; + return b; +} + +char const* call_f(A& a) { return a.f(); } + +A* factory(unsigned choice) +{ + switch (choice % 3) + { + case 0: return new A; + break; + case 1: return new B; + break; + default: return new C; + break; + } +} + +C& getCCppObj () +{ + static C c; + return c; +} + +A* pass_a(A* x) { return x; } + +#ifdef HELD_BY_AUTO_PTR +BOOST_PYTHON_MODULE_INIT(polymorphism2_auto_ptr_ext) +#else +BOOST_PYTHON_MODULE_INIT(polymorphism2_ext) +#endif +{ + class_<ACallback HELD_PTR(A),boost::noncopyable>("A") + .def("f", &A::f, &ACallback::default_f) + ; + + def("getBCppObj", getBCppObj, return_value_policy<reference_existing_object>()); + + class_<C HELD_PTR(C),bases<A>,boost::noncopyable>("C") + .def("f", &C::f) + ; + + class_<DCallback HELD_PTR(D),bases<A>,boost::noncopyable>("D") + .def("f", &D::f) + .def("g", &D::g) + ; + + def("pass_a", &pass_a, return_internal_reference<>()); + + def("getCCppObj", getCCppObj, return_value_policy<reference_existing_object>()); + + def("factory", factory, return_value_policy<manage_new_object>()); + + def("call_f", call_f); + + class_<PCallback,boost::noncopyable>("P") + .def("f", pure_virtual(&P::f)) + ; + + class_<Q HELD_PTR(Q), bases<P> >("Q") + .def("g", &P::g) // make sure virtual inheritance doesn't interfere + ; +} + +//#include "module_tail.cpp" diff --git a/libs/python/test/polymorphism2.py b/libs/python/test/polymorphism2.py new file mode 100644 index 000000000..2690bac9a --- /dev/null +++ b/libs/python/test/polymorphism2.py @@ -0,0 +1,94 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import unittest +import sys + +class PolymorphTest(unittest.TestCase): + + def testReturnCpp(self): + + # Python Created Object With Same Id As + # Cpp Created B Object + # b = B(872) + + # Get Reference To Cpp Created B Object + a = getBCppObj() + + # Python Created B Object and Cpp B Object + # Should have same result by calling f() + self.failUnlessEqual ('B::f()', a.f()) + self.failUnlessEqual ('B::f()', call_f(a)) + self.failUnlessEqual ('A::f()', call_f(A())) + + def test_references(self): + # B is not exposed to Python + a = getBCppObj() + self.failUnlessEqual(type(a), A) + + # C is exposed to Python + c = getCCppObj() + self.failUnlessEqual(type(c), C) + + def test_factory(self): + self.failUnlessEqual(type(factory(0)), A) + self.failUnlessEqual(type(factory(1)), A) + self.failUnlessEqual(type(factory(2)), C) + + def test_return_py(self): + + class X(A): + def f(self): + return 'X.f' + + x = X() + + self.failUnlessEqual ('X.f', x.f()) + self.failUnlessEqual ('X.f', call_f(x)) + + def test_self_default(self): + + class X(A): + def f(self): + return 'X.f() -> ' + A.f(self) + + x = X() + + self.failUnlessEqual ('X.f() -> A::f()', x.f()) + + # This one properly raises the "dangling reference" exception + # self.failUnlessEqual ('X.f() -> A::f()', call_f(x)) + + def test_wrapper_downcast(self): + a = pass_a(D()) + self.failUnlessEqual('D::g()', a.g()) + + def test_pure_virtual(self): + p = P() + self.assertRaises(RuntimeError, p.f) + + q = Q() + self.failUnlessEqual ('Q::f()', q.f()) + + class R(P): + def f(self): + return 'R.f' + + r = R() + self.failUnlessEqual ('R.f', r.f()) + + +def test(): + # remove the option that upsets unittest + import sys + sys.argv = [ x for x in sys.argv if x != '--broken-auto-ptr' ] + unittest.main() + +# This nasty hack basically says that if we're loaded by another module, we'll +# be testing polymorphism2_auto_ptr_ext instead of polymorphism2_ext. +if __name__ == "__main__": + from polymorphism2_ext import * + test() +else: + from polymorphism2_auto_ptr_ext import * + diff --git a/libs/python/test/polymorphism2_auto_ptr.cpp b/libs/python/test/polymorphism2_auto_ptr.cpp new file mode 100644 index 000000000..8cd5ef247 --- /dev/null +++ b/libs/python/test/polymorphism2_auto_ptr.cpp @@ -0,0 +1,6 @@ +// Copyright David Abrahams 2005. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define HELD_BY_AUTO_PTR +#include "polymorphism2.cpp" diff --git a/libs/python/test/polymorphism2_auto_ptr.py b/libs/python/test/polymorphism2_auto_ptr.py new file mode 100644 index 000000000..88cf664ab --- /dev/null +++ b/libs/python/test/polymorphism2_auto_ptr.py @@ -0,0 +1,5 @@ +# Copyright David Abrahams 2005. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import polymorphism2 +polymorphism2.test() diff --git a/libs/python/test/printer.py b/libs/python/test/printer.py new file mode 100644 index 000000000..e08f7c453 --- /dev/null +++ b/libs/python/test/printer.py @@ -0,0 +1,13 @@ +# Copyright David Abrahams 2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +class _printer(object): + def __init__(self): + self.results = []; + def __call__(self, *stuff): + for x in stuff: + self.results.append(str(x)) + def check(self, x): + if self.results[0] != str(x): + print ' Expected:\n %s\n but the C++ interface gave:\n %s' % (x, self.results[0]) + del self.results[0] diff --git a/libs/python/test/properties.cpp b/libs/python/test/properties.cpp new file mode 100644 index 000000000..d338beb91 --- /dev/null +++ b/libs/python/test/properties.cpp @@ -0,0 +1,100 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python.hpp> + +using namespace boost::python; + +namespace test { + +// Hmm. return_internal_reference<>() wants to wrap a real class. +class ret_type +{ + public: + ret_type() : i(42.5) {} + double i; +}; + +class crash_me +{ + private: + ret_type i; + public: + ret_type& get_i() { return i; } +}; + +} + +struct X +{ + X( int value ) : m_value( value ) + { ++s_count; } + + X( const X &other ) : m_value( other.m_value ) + { ++s_count; } + + ~X() + { --s_count; } + + int get_value() const + { return m_value; } + + void set_value(int new_value) + { m_value = new_value; } + + static int get_instance_count() + { return s_count; } + + int m_value; + + static int s_count; +}; + +int X::s_count = 0; + +int get_X_instance_count() +{ return X::get_instance_count(); } + + + +BOOST_PYTHON_MODULE(properties_ext) +{ + typedef return_value_policy<return_by_value> return_by_value_t; + typedef return_internal_reference<> return_by_internal_reference_t; + class_<X>("X", init<int>() ) + //defining read only property + .add_property( "value_r", &X::get_value ) + .add_property( "value_r_ds", &X::get_value, "value_r_ds is read-only") + //defining read \ write property + .add_property( "value_rw", &X::get_value, &X::set_value ) + .add_property( "value_rw_ds", &X::get_value, &X::set_value, + "value_rw_ds is read-write") + //defining read \ write property using make_getter and make_setter + .add_property( "value_direct", + make_getter( &X::m_value, return_by_value_t() ), + make_setter( &X::m_value, return_by_internal_reference_t() ) ) + //defining read only property for static member + .add_static_property( "instance_count", &X::get_instance_count ) + //defining read \ write property for static member using make_getter and make_setter + .add_static_property( "instance_count_direct", + make_getter( &X::s_count, return_by_value_t() ), + make_setter( &X::s_count, return_by_internal_reference_t() ) ) + //defining class property using a global function + .add_static_property( "instance_count_injected", &get_X_instance_count ); + + + class_< test::ret_type>( "ret_type") + .add_property( "i", &test::ret_type::i, &test::ret_type::i) + ; + + class_< test::crash_me> crash_me_wrapper( "crash_me"); + + crash_me_wrapper + .def( "get_i", &test::crash_me::get_i , return_internal_reference<>()) + ; + + crash_me_wrapper.add_property( "i", crash_me_wrapper.attr("get_i")); + +} + +#include "module_tail.cpp" diff --git a/libs/python/test/properties.py b/libs/python/test/properties.py new file mode 100644 index 000000000..720fb8598 --- /dev/null +++ b/libs/python/test/properties.py @@ -0,0 +1,106 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +This is test module for properties. + +>>> r = properties.ret_type() +>>> r.i = 22.5 +>>> r.i +22.5 +>>> c = properties.crash_me() +>>> c.i.i +42.5 + +>>> X = properties.X + +>>> x1 = X(1) + +value read only +>>> x1.value_r +1 + +value read - write +>>> x1.value_rw +1 + +value direct access +>>> x1.value_direct +1 + +class instance count read - only +>>> X.instance_count +1 + +class instance count direct +>>> X.instance_count_direct +1 + +class instance count injected +>>> X.instance_count_injected +1 + +class instance count from object +>>> x1.instance_count +1 + +class instance count from object +>>> x1.instance_count_direct +1 + +class instance count from object: +>>> x1.instance_count_injected +1 + +as expected you can't assign new value to read only property +>>> x1.value_r = 2 +Traceback (most recent call last): + File "properties.py", line 49, in ? + x1.value_r = 2 +AttributeError: can't set attribute + +setting value_rw to 2. value_direct: +>>> x1.value_rw = 2 +>>> x1.value_rw +2 + +setting value_direct to 3. value_direct: +>>> x1.value_direct = 3 +>>> x1.value_direct +3 + +>>> assert x1.value_r == 3 + +>>> x2 = X(2) + +after creating second intstance of X instances count is 2 +>>> x2.instance_count +2 + +>>> del x2 +>>> assert x1.instance_count == 1 + +>>> assert properties.X.value_r_ds.__doc__ == "value_r_ds is read-only" + +>>> assert properties.X.value_rw_ds.__doc__ == "value_rw_ds is read-write" + +""" + +#import sys; sys.path.append(r'P:\Actimize4.0\smart_const\py_smart_const___Win32_Debug') +import properties_ext as properties + + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/pyrun.py b/libs/python/test/pyrun.py new file mode 100644 index 000000000..e033069eb --- /dev/null +++ b/libs/python/test/pyrun.py @@ -0,0 +1,7 @@ +import sys + +pythonpath = sys.argv[1] +scriptfile = sys.argv[2] +sys.argv = sys.argv[2:] +sys.path.append(pythonpath) +execfile(scriptfile) diff --git a/libs/python/test/pytype_function.cpp b/libs/python/test/pytype_function.cpp new file mode 100644 index 000000000..46cce19e6 --- /dev/null +++ b/libs/python/test/pytype_function.cpp @@ -0,0 +1,85 @@ +// Copyright Joel de Guzman 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/to_python_converter.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +struct A +{ +}; + +struct B +{ + A a; + B(const A& a_):a(a_){} +}; + +// Converter from A to python int +struct BToPython +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + : converter::to_python_target_type<A> //inherits get_pytype +#endif +{ + static PyObject* convert(const B& b) + { + return boost::python::incref(boost::python::object(b.a).ptr()); + } +}; + +// Conversion from python int to A +struct BFromPython +{ + BFromPython() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id< B >() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &converter::expected_from_python_type<A>::get_pytype//convertible to A can be converted to B +#endif + ); + } + + static void* convertible(PyObject* obj_ptr) + { + extract<const A&> ex(obj_ptr); + if (!ex.check()) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (boost::python::converter::rvalue_from_python_storage< B >*)data)-> storage.bytes; + + extract<const A&> ex(obj_ptr); + new (storage) B(ex()); + data->convertible = storage; + } +}; + + +B func(const B& b) { return b ; } + + +BOOST_PYTHON_MODULE(pytype_function_ext) +{ + to_python_converter< B , BToPython,true >(); //has get_pytype + BFromPython(); + + class_<A>("A") ; + + def("func", &func); + +} + +#include "module_tail.cpp" diff --git a/libs/python/test/pytype_function.py b/libs/python/test/pytype_function.py new file mode 100755 index 000000000..83674632a --- /dev/null +++ b/libs/python/test/pytype_function.py @@ -0,0 +1,32 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from pytype_function_ext import * + +>>> print func.__doc__.splitlines()[1] +func( (A)arg1) -> A : + +>>> print func.__module__ +pytype_function_ext + +>>> print func.__name__ +func +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + + + diff --git a/libs/python/test/raw_ctor.cpp b/libs/python/test/raw_ctor.cpp new file mode 100644 index 000000000..a825ae019 --- /dev/null +++ b/libs/python/test/raw_ctor.cpp @@ -0,0 +1,43 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/class.hpp> +#include <boost/python/raw_function.hpp> +#include <boost/python/make_constructor.hpp> +#include <boost/python/dict.hpp> +#include <boost/python/tuple.hpp> +#include <boost/python/module.hpp> + +using namespace boost::python; + +class Foo +{ + public: + Foo(tuple args, dict kw) + : args(args), kw(kw) {} + + tuple args; + dict kw; +}; + +object init_foo(tuple args, dict kw) +{ + tuple rest(args.slice(1,_)); + return args[0].attr("__init__")(rest, kw); +} + +BOOST_PYTHON_MODULE(raw_ctor_ext) +{ + // using no_init postpones defining __init__ function until after + // raw_function for proper overload resolution order, since later + // defs get higher priority. + class_<Foo>("Foo", no_init) + .def("__init__", raw_function(&init_foo)) + .def(init<tuple, dict>()) + .def_readwrite("args", &Foo::args) + .def_readwrite("kw", &Foo::kw) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/raw_ctor.py b/libs/python/test/raw_ctor.py new file mode 100644 index 000000000..686948ff0 --- /dev/null +++ b/libs/python/test/raw_ctor.py @@ -0,0 +1,76 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> 'importing' +'importing' +>>> from raw_ctor_ext import * +>>> 'imported' +'imported' +>>> import sys +>>> sys.stdout.flush() +>>> f = Foo(1, 2, 'a', bar = 3, baz = 4) +>>> f.args +(1, 2, 'a') +>>> f.kw.items() +[('bar', 3), ('baz', 4)] +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/python/test/raw_pyobject_fail1.cpp b/libs/python/test/raw_pyobject_fail1.cpp new file mode 100644 index 000000000..f9dd54bc3 --- /dev/null +++ b/libs/python/test/raw_pyobject_fail1.cpp @@ -0,0 +1,11 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/converter/arg_to_python.hpp> + +int main() +{ + boost::python::converter::arg_to_python<PyTypeObject*> x(0); + return 0; +} diff --git a/libs/python/test/raw_pyobject_fail2.cpp b/libs/python/test/raw_pyobject_fail2.cpp new file mode 100644 index 000000000..62c57ae74 --- /dev/null +++ b/libs/python/test/raw_pyobject_fail2.cpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/converter/arg_to_python.hpp> + +struct X : PyObject {}; + +int main() +{ + boost::python::converter::arg_to_python<X*> x(0); + return 0; +} diff --git a/libs/python/test/register_ptr.cpp b/libs/python/test/register_ptr.cpp new file mode 100644 index 000000000..6cd4d7856 --- /dev/null +++ b/libs/python/test/register_ptr.cpp @@ -0,0 +1,55 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python.hpp> +#include <boost/shared_ptr.hpp> + +using namespace boost; +using namespace python; + +struct A +{ + virtual int f() { return 0; } +}; + +shared_ptr<A> New() { return shared_ptr<A>( new A() ); } + +int Call( const shared_ptr<A> & a ) +{ + return a->f(); +} + +int Fail( shared_ptr<A> & a ) +{ + return a->f(); +} + +struct A_Wrapper: A +{ + A_Wrapper(PyObject* self_): self(self_) {} + A_Wrapper(PyObject* self_, const A& a): self(self_), A(a) {} + + int f() + { + return call_method<int>(self, "f"); + } + + int default_f() + { + return A::f(); + } + + PyObject* self; +}; + +BOOST_PYTHON_MODULE(register_ptr) +{ + class_<A, A_Wrapper>("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; + register_ptr_to_python< shared_ptr<A> >(); + def("New", &New); + def("Call", &Call); + def("Fail", &Fail); +} diff --git a/libs/python/test/register_ptr_test.py b/libs/python/test/register_ptr_test.py new file mode 100644 index 000000000..674e5572f --- /dev/null +++ b/libs/python/test/register_ptr_test.py @@ -0,0 +1,25 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import unittest +from register_ptr import * + +class RegisterPtrTest(unittest.TestCase): + + def testIt(self): + + class B(A): + def f(self): + return 10 + + a = New() # this must work + b = B() + self.assertEqual(Call(a), 0) + self.assertEqual(Call(b), 10) + def fails(): + Fail(A()) + self.assertRaises(TypeError, fails) + self.assertEqual(Fail(a), 0) # ok, since a is held by shared_ptr + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/test/result.cpp b/libs/python/test/result.cpp new file mode 100644 index 000000000..d5f43cc3d --- /dev/null +++ b/libs/python/test/result.cpp @@ -0,0 +1,111 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/detail/result.hpp> +#include <boost/type.hpp> +#include <functional> + +using boost::python::detail::result; +using boost::type; + +void expect_int(type<int>*) {} +void expect_string(type<char*>*) {} + +struct X {}; + +int main() +{ + // Test the usage which works for functions, member functions, and data members + expect_int( + result((int(*)())0) + ); + + expect_int( + result((int(*)(char))0) + ); + + expect_int( + result((int(X::*)())0) + ); + + expect_int( + result((int(X::*)(char))0) + ); + + expect_int( + result((int(X::*))0) + ); + + expect_string( + result((char*(*)())0) + ); + + expect_string( + result((char*(*)(char))0) + ); + + expect_string( + result((char*(X::*)())0) + ); + + expect_string( + result((char*(X::*)(char))0) + ); + + expect_string( + result((char*(X::*))0) + ); + + // Show that we can use the general version that works for + // AdaptableFunctions + expect_int( + result((int(*)())0,0) + ); + + expect_int( + result((int(*)(char))0,0) + ); + + expect_int( + result((int(X::*)())0,0) + ); + + expect_int( + result((int(X::*)(char))0,0) + ); + + expect_int( + result((int(X::*))0,0) + ); + + expect_int( + result(std::plus<int>(),0) + ); + + expect_string( + result((char*(*)())0,0) + ); + + expect_string( + result((char*(*)(char))0,0) + ); + + expect_string( + result((char*(X::*)())0,0) + ); + + expect_string( + result((char*(X::*)(char))0,0) + ); + + expect_string( + result((char*(X::*))0,0) + ); + + expect_string( + result(std::plus<char*>(),0) + ); + + return 0; +} diff --git a/libs/python/test/return_arg.cpp b/libs/python/test/return_arg.cpp new file mode 100644 index 000000000..d8d3c1ddb --- /dev/null +++ b/libs/python/test/return_arg.cpp @@ -0,0 +1,67 @@ +// Copyright David Abrahams and Nikolay Mladenov 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/def.hpp> +#include <boost/python/return_arg.hpp> + +struct Widget +{ + Widget() + : sensitive_(true) + {} + + bool get_sensitive() const + { + return sensitive_; + } + + void set_sensitive(bool s) + { + this->sensitive_ = s; + } + + private: + bool sensitive_; +}; + +struct Label : Widget +{ + Label() {} + + std::string get_label() const + { + return label_; + } + + void set_label(const std::string &l) + { + label_ = l; + } + + private: + std::string label_; +}; + +void return_arg_f(boost::python::object) {} + +using namespace boost::python; +BOOST_PYTHON_MODULE(return_arg_ext) +{ + class_<Widget>("Widget") + .def("sensitive", &Widget::get_sensitive) + .def("sensitive", &Widget::set_sensitive, return_self<>()) + ; + + class_<Label, bases<Widget> >("Label") + .def("label", &Label::get_label)//,return_arg<0>()) //error(s) + .def("label", &Label::set_label, return_self<>()) + ; + + def("return_arg", return_arg_f, return_arg<1>()); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/return_arg.py b/libs/python/test/return_arg.py new file mode 100644 index 000000000..f191d5964 --- /dev/null +++ b/libs/python/test/return_arg.py @@ -0,0 +1,27 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from return_arg_ext import * +>>> l1=Label() +>>> assert l1 is l1.label("bar") +>>> assert l1 is l1.label("bar").sensitive(0) +>>> assert l1.label("foo").sensitive(0) is l1.sensitive(1).label("bar") +>>> assert return_arg is return_arg(return_arg) + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/select_arg_to_python_test.cpp b/libs/python/test/select_arg_to_python_test.cpp new file mode 100644 index 000000000..c5faace36 --- /dev/null +++ b/libs/python/test/select_arg_to_python_test.cpp @@ -0,0 +1,70 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/converter/arg_to_python.hpp> +#include <boost/python/type_id.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/object.hpp> +#include <iostream> + +// gcc 2.95.x and MIPSpro 7.3.1.3 linker seem to demand this definition +#if ((defined(__GNUC__) && __GNUC__ < 3)) \ + || (defined(__sgi) && defined(__EDG_VERSION__) && (__EDG_VERSION__ == 238)) +namespace boost { namespace python { +BOOST_PYTHON_DECL bool handle_exception_impl(function0<void>) +{ + return true; +} +}} +#endif + +int result; + +#define ASSERT_SAME(T1,T2) assert_same< T1,T2 >() + +template <class T, class U> +void assert_same(U* = 0, T* = 0) +{ + BOOST_STATIC_ASSERT((boost::is_same<T,U>::value)); + +} + + +int main() +{ + using namespace boost::python::converter::detail; + using namespace boost::python::converter; + using namespace boost::python; + using namespace boost; + + + ASSERT_SAME( + select_arg_to_python<int>::type, value_arg_to_python<int> + ); + + ASSERT_SAME( + select_arg_to_python<reference_wrapper<int> >::type, reference_arg_to_python<int> + ); + + ASSERT_SAME( + select_arg_to_python<pointer_wrapper<int> >::type, pointer_shallow_arg_to_python<int> + ); + + ASSERT_SAME( + select_arg_to_python<int*>::type, pointer_deep_arg_to_python<int*> + ); + + ASSERT_SAME( + select_arg_to_python<handle<> >::type, object_manager_arg_to_python<handle<> > + ); + + ASSERT_SAME( + select_arg_to_python<object>::type, object_manager_arg_to_python<object> + ); + + ASSERT_SAME( + select_arg_to_python<char[20]>::type, arg_to_python<char const*> + ); + + return result; +} diff --git a/libs/python/test/select_from_python_test.cpp b/libs/python/test/select_from_python_test.cpp new file mode 100644 index 000000000..bb60962a3 --- /dev/null +++ b/libs/python/test/select_from_python_test.cpp @@ -0,0 +1,161 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/converter/arg_from_python.hpp> +#include <boost/python/type_id.hpp> +#include <iostream> + +// gcc 2.95.x, MIPSpro 7.3.1.3 and IBM XL for Linux linker seem to demand this definition +#if (defined(__GNUC__) && (__GNUC__ < 3)) \ + || (defined(__sgi) && defined(__EDG_VERSION__) && (__EDG_VERSION__ == 238)) \ + || (defined(__IBMCPP__) && defined(__linux__)) +namespace boost { namespace python { +BOOST_PYTHON_DECL bool handle_exception_impl(function0<void>) +{ + return true; +} +}} +#endif + +int result; + +#define ASSERT_SAME(T1,T2) \ + if (!is_same< T1, T2 >::value) { \ + std::cout << "*********************\n"; \ + std::cout << python::type_id< T1 >() << " != " << python::type_id< T2 >() << "\n"; \ + std::cout << "*********************\n"; \ + result = 1; \ + } + +int main() +{ + using namespace boost::python::converter; + using namespace boost; + + + ASSERT_SAME( + select_arg_from_python<int>::type, arg_rvalue_from_python<int> + ); + + ASSERT_SAME( + select_arg_from_python<int const>::type, arg_rvalue_from_python<int const> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile>::type, arg_rvalue_from_python<int volatile> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile>::type, arg_rvalue_from_python<int const volatile> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*>::type, pointer_arg_from_python<int*> + ); + + ASSERT_SAME( + select_arg_from_python<int const*>::type, pointer_arg_from_python<int const*> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*>::type, pointer_arg_from_python<int volatile*> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*>::type, pointer_arg_from_python<int const volatile*> + ); + + + + + ASSERT_SAME( + select_arg_from_python<int&>::type, reference_arg_from_python<int&> + ); + + ASSERT_SAME( + select_arg_from_python<int const&>::type, arg_rvalue_from_python<int const&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile&>::type, reference_arg_from_python<int volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile&>::type, reference_arg_from_python<int const volatile&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*&>::type, reference_arg_from_python<int*&> + ); + + ASSERT_SAME( + select_arg_from_python<int const*&>::type, reference_arg_from_python<int const*&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*&>::type, reference_arg_from_python<int volatile*&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*&>::type, reference_arg_from_python<int const volatile*&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int* const&>::type, pointer_cref_arg_from_python<int*const&> + ); + + ASSERT_SAME( + select_arg_from_python<int const* const&>::type, pointer_cref_arg_from_python<int const*const&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile* const&>::type, pointer_cref_arg_from_python<int volatile*const&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile* const&>::type, pointer_cref_arg_from_python<int const volatile*const&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*volatile&>::type, reference_arg_from_python<int*volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const*volatile&>::type, reference_arg_from_python<int const*volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*volatile&>::type, reference_arg_from_python<int volatile*volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*volatile&>::type, reference_arg_from_python<int const volatile*volatile&> + ); + + + + ASSERT_SAME( + select_arg_from_python<int*const volatile&>::type, reference_arg_from_python<int*const volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const*const volatile&>::type, reference_arg_from_python<int const*const volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int volatile*const volatile&>::type, reference_arg_from_python<int volatile*const volatile&> + ); + + ASSERT_SAME( + select_arg_from_python<int const volatile*const volatile&>::type, reference_arg_from_python<int const volatile*const volatile&> + ); + return result; +} diff --git a/libs/python/test/select_holder.cpp b/libs/python/test/select_holder.cpp new file mode 100644 index 000000000..4ecc52e7a --- /dev/null +++ b/libs/python/test/select_holder.cpp @@ -0,0 +1,76 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/object/class_metadata.hpp> +#include <boost/python/has_back_reference.hpp> +#include <boost/python/detail/not_specified.hpp> +#include <boost/static_assert.hpp> +#include <boost/type_traits/same_traits.hpp> +#include <boost/function/function0.hpp> +#include <boost/mpl/bool.hpp> +#include <memory> + +struct BR {}; + +struct Base {}; +struct Derived : Base {}; + +namespace boost { namespace python +{ + // specialization + template <> + struct has_back_reference<BR> + : mpl::true_ + { + }; +}} // namespace boost::python + +template <class T, class U> +void assert_same(U* = 0, T* = 0) +{ + BOOST_STATIC_ASSERT((boost::is_same<T,U>::value)); + +} + +template <class T, class Held, class Holder> +void assert_holder(T* = 0, Held* = 0, Holder* = 0) +{ + using namespace boost::python::detail; + using namespace boost::python::objects; + + typedef typename class_metadata< + T,Held,not_specified,not_specified + >::holder h; + + assert_same<Holder>( + (h*)0 + ); +} + +int test_main(int, char * []) +{ + using namespace boost::python::detail; + using namespace boost::python::objects; + + assert_holder<Base,not_specified,value_holder<Base> >(); + + assert_holder<BR,not_specified,value_holder_back_reference<BR,BR> >(); + assert_holder<Base,Base,value_holder_back_reference<Base,Base> >(); + assert_holder<BR,BR,value_holder_back_reference<BR,BR> >(); + + assert_holder<Base,Derived + ,value_holder_back_reference<Base,Derived> >(); + + assert_holder<Base,std::auto_ptr<Base> + ,pointer_holder<std::auto_ptr<Base>,Base> >(); + + assert_holder<Base,std::auto_ptr<Derived> + ,pointer_holder_back_reference<std::auto_ptr<Derived>,Base> >(); + + assert_holder<BR,std::auto_ptr<BR> + ,pointer_holder_back_reference<std::auto_ptr<BR>,BR> > (); + + return 0; +} + diff --git a/libs/python/test/shared_ptr.cpp b/libs/python/test/shared_ptr.cpp new file mode 100644 index 000000000..e5f20a732 --- /dev/null +++ b/libs/python/test/shared_ptr.cpp @@ -0,0 +1,217 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/call_method.hpp> +#include <boost/python/extract.hpp> +#include <boost/python/def.hpp> +#include <boost/shared_ptr.hpp> +#include "test_class.hpp" + +#include <memory> + +using namespace boost::python; +using boost::shared_ptr; + +typedef test_class<> X; +typedef test_class<1> Y; + +template <class T> +struct functions +{ + static int look(shared_ptr<T> const& x) + { + return (x.get()) ? x->value() : -1; + } + + static void store(shared_ptr<T> x) + { + storage = x; + } + + static void release_store() + { + store(shared_ptr<T>()); + } + + static void modify(shared_ptr<T>& x) + { + x.reset(); + } + + static shared_ptr<T> get() { return storage; } + static shared_ptr<T> &get1() { return storage; } + + static int look_store() + { + return look(get()); + } + + template <class C> + static void expose(C const& c) + { + def("look", &look); + def("store", &store); + def("modify", &modify); + def("identity", &identity); + def("null", &null); + + const_cast<C&>(c) + .def("look", &look) + .staticmethod("look") + .def("store", &store) + .staticmethod("store") + .def("modify", &modify) + .staticmethod("modify") + .def("look_store", &look_store) + .staticmethod("look_store") + .def("identity", &identity) + .staticmethod("identity") + .def("null", &null) + .staticmethod("null") + .def("get1", &get1, return_internal_reference<>()) + .staticmethod("get1") + .def("get", &get) + .staticmethod("get") + .def("count", &T::count) + .staticmethod("count") + .def("release", &release_store) + .staticmethod("release") + ; + } + + static shared_ptr<T> identity(shared_ptr<T> x) { return x; } + static shared_ptr<T> null(T const&) { return shared_ptr<T>(); } + + + static shared_ptr<T> storage; +}; + +template <class T> shared_ptr<T> functions<T>::storage; + +struct Z : test_class<2> +{ + Z(int x) : test_class<2>(x) {} + virtual int v() { return this->value(); } +}; + +struct ZWrap : Z +{ + ZWrap(PyObject* self, int x) + : Z(x), m_self(self) {} + + + virtual int v() { return call_method<int>(m_self, "v"); } + int default_v() { return Z::v(); } + + + PyObject* m_self; +}; + +struct YY : Y +{ + YY(int n) : Y(n) {} +}; + +struct YYY : Y +{ + YYY(int n) : Y(n) {} +}; + +shared_ptr<Y> factory(int n) +{ + return shared_ptr<Y>(n < 42 ? new Y(n) : new YY(n)); +} + +// regressions from Nicodemus + struct A + { + virtual ~A() {}; // silence compiler warnings + virtual int f() = 0; + static int call_f(shared_ptr<A>& a) { return a->f(); } + }; + + struct B: A + { + int f() { return 1; } + }; + + boost::shared_ptr<A> New(bool make) + { + return boost::shared_ptr<A>( make ? new B() : 0 ); + } + + struct A_Wrapper: A + { + A_Wrapper(PyObject* self_): + A(), self(self_) {} + + int f() { + return call_method< int >(self, "f"); + } + + PyObject* self; + }; + +// ------ + +// from Neal Becker + +struct Test { + boost::shared_ptr<X> x; +}; +// ------ + + +BOOST_PYTHON_MODULE(shared_ptr_ext) +{ + class_<A, boost::shared_ptr<A_Wrapper>, boost::noncopyable>("A") + .def("call_f", &A::call_f) + .staticmethod("call_f") + ; + + // This is the ugliness required to register a to-python converter + // for shared_ptr<A>. + objects::class_value_wrapper< + shared_ptr<A> + , objects::make_ptr_instance<A, objects::pointer_holder<shared_ptr<A>,A> > + >(); + + def("New", &New); + + def("factory", factory); + + functions<X>::expose( + class_<X, boost::noncopyable>("X", init<int>()) + .def("value", &X::value) + ); + + functions<Y>::expose( + class_<Y, boost::shared_ptr<Y> >("Y", init<int>()) + .def("value", &Y::value) + ); + + class_<YY, bases<Y>, boost::noncopyable>("YY", init<int>()) + ; + + class_<YYY, shared_ptr<YYY>, bases<Y> >("YYY", init<int>()) + ; + + functions<Z>::expose( + class_<Z, ZWrap>("Z", init<int>()) + .def("value", &Z::value) + .def("v", &Z::v, &ZWrap::default_v) + ); + +// from Neal Becker + class_<Test> ("Test") + .def_readonly ("x", &Test::x, "x") + ; +// ------ +} + +#include "module_tail.cpp" + diff --git a/libs/python/test/shared_ptr.py b/libs/python/test/shared_ptr.py new file mode 100644 index 000000000..554b4a6b6 --- /dev/null +++ b/libs/python/test/shared_ptr.py @@ -0,0 +1,130 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from shared_ptr_ext import * + + Test that shared_ptr<Derived> can be converted to shared_ptr<Base> + +>>> Y.store(YYY(42)) + +>>> x = X(17) +>>> null_x = null(x) +>>> null_x # should be None +>>> identity(null_x) # should also be None + +>>> a = New(1) +>>> A.call_f(a) +1 +>>> New(0) + +>>> type(factory(3)) +<class 'shared_ptr_ext.Y'> +>>> type(factory(42)) +<class 'shared_ptr_ext.YY'> + +>>> class P(Z): +... def v(self): +... return -Z.v(self); +... def __del__(self): +... print 'bye' +... +>>> p = P(12) +>>> p.value() +12 +>>> p.v() +-12 +>>> look(p) +12 +>>> try: modify(p) +... except TypeError: pass +... else: 'print expected a TypeError' +>>> look(None) +-1 +>>> store(p) +>>> del p +>>> Z.get().v() +-12 +>>> Z.count() +1 +>>> Z.look_store() +12 +>>> Z.release() +bye +>>> Z.count() +0 + +>>> z = Z(13) +>>> z.value() +13 +>>> z.v() +13 +>>> try: modify(z) +... except TypeError: pass +... else: 'print expected a TypeError' + +>>> Z.get() # should be None +>>> store(z) +>>> assert Z.get() is z # show that deleter introspection works +>>> del z +>>> Z.get().value() +13 +>>> Z.count() +1 +>>> Z.look_store() +13 +>>> Z.release() +>>> Z.count() +0 + +>>> x = X(17) +>>> x.value() +17 +>>> look(x) +17 +>>> try: modify(x) +... except TypeError: pass +... else: 'print expected a TypeError' +>>> look(None) +-1 +>>> store(x) +>>> del x +>>> X.count() +1 +>>> X.look_store() +17 +>>> X.release() +>>> X.count() +0 + + +>>> y = Y(19) +>>> y.value() +19 +>>> modify(y) +>>> look(y) +-1 +>>> store(Y(23)) +>>> Y.count() +1 +>>> Y.look_store() +23 +>>> Y.release() +>>> Y.count() +0 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/simple_type.hpp b/libs/python/test/simple_type.hpp new file mode 100644 index 000000000..d1314ff97 --- /dev/null +++ b/libs/python/test/simple_type.hpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef SIMPLE_TYPE_DWA2001128_HPP +# define SIMPLE_TYPE_DWA2001128_HPP + +struct simple +{ + char* s; +}; + +#endif // SIMPLE_TYPE_DWA2001128_HPP diff --git a/libs/python/test/slice.cpp b/libs/python/test/slice.cpp new file mode 100644 index 000000000..5072d7f7c --- /dev/null +++ b/libs/python/test/slice.cpp @@ -0,0 +1,140 @@ +#include <boost/python.hpp> +#include <boost/python/slice.hpp> +#include <boost/python/str.hpp> +#include <vector> + +// Copyright (c) 2004 Jonathan Brandmeyer +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +using namespace boost::python; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) +# define make_tuple boost::python::make_tuple +#endif + +// These checks are only valid under Python 2.3 +// (rich slicing wasn't supported for builtins under Python 2.2) +bool check_string_rich_slice() +{ + object s("hello, world"); + + // default slice + if (s[slice()] != "hello, world") + return false; + + // simple reverse + if (s[slice(_,_,-1)] != "dlrow ,olleh") + return false; + + // reverse with mixed-sign offsets + if (s[slice(-6,1,-1)] != " ,oll") + return false; + + // all of the object.cpp check_string_slice() checks should work + // with the form that omits the step argument. + if (s[slice(_,-3)] != "hello, wo") + return false; + if (s[slice(-3,_)] != "rld") + return false; + if (", " != s[slice(5,7)]) + return false; + + return s[slice(2,-1)][slice(1,-1)] == "lo, wor"; +} + +// Tried to get more info into the error message (actual array +// contents) but Numeric complains that treating an array as a boolean +// value doesn't make any sense. +#define ASSERT_EQUAL( e1, e2 ) \ + if (!all((e1) == (e2))) \ + return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2); \ +else + +// These tests work with Python 2.2, but you must have Numeric installed. +object check_numeric_array_rich_slice( + char const* module_name, char const* array_type_name, object all) +{ + using numeric::array; + array::set_module_and_type(module_name, array_type_name); + + array original = array( make_tuple( make_tuple( 11, 12, 13, 14), + make_tuple( 21, 22, 23, 24), + make_tuple( 31, 32, 33, 34), + make_tuple( 41, 42, 43, 44))); + array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12), + make_tuple( 21, 22))); + array odd_cells = array( make_tuple( make_tuple( 11, 13), + make_tuple( 31, 33))); + array even_cells = array( make_tuple( make_tuple( 22, 24), + make_tuple( 42, 44))); + array lower_right_quadrant_reversed = array( + make_tuple( make_tuple(44, 43), + make_tuple(34, 33))); + + // The following comments represent equivalent Python expressions used + // to validate the array behavior. + // original[::] == original + ASSERT_EQUAL(original[slice()],original); + + // original[:2,:2] == array( [[11, 12], [21, 22]]) + ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant); + + // original[::2,::2] == array( [[11, 13], [31, 33]]) + ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells); + + // original[1::2, 1::2] == array( [[22, 24], [42, 44]]) + ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells); + + // original[:-3:-1, :-3,-1] == array( [[44, 43], [34, 33]]) + ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed); + + return object(1); +} + +// Verify functions accepting a slice argument can be called +bool accept_slice( slice) { return true; } + +#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \ + || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710) +int check_slice_get_indices(slice index); +#endif +int check_slice_get_indices( +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + const +#endif + slice index) +{ + // A vector of integers from [-5, 5]. + std::vector<int> coll(11); + typedef std::vector<int>::iterator coll_iterator; + + for (coll_iterator i = coll.begin(); i != coll.end(); ++i) { + *i = i - coll.begin() - 5; + } + + slice::range<std::vector<int>::iterator> bounds; + try { + bounds = index.get_indices(coll.begin(), coll.end()); + } + catch (std::invalid_argument) { + return 0; + } + int sum = 0; + while (bounds.start != bounds.stop) { + sum += *bounds.start; + std::advance( bounds.start, bounds.step); + } + sum += *bounds.start; + return sum; +} + + +BOOST_PYTHON_MODULE(slice_ext) +{ + def( "accept_slice", accept_slice); + def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice); + def( "check_string_rich_slice", check_string_rich_slice); + def( "check_slice_get_indices", check_slice_get_indices); +} diff --git a/libs/python/test/slice.py b/libs/python/test/slice.py new file mode 100644 index 000000000..95f4883b0 --- /dev/null +++ b/libs/python/test/slice.py @@ -0,0 +1,72 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from slice_ext import * +>>> accept_slice(slice(1, None, (1,2))) +1 +>>> try: +... accept_slice(list((1,2))) +... print "test failed" +... except: +... print "test passed" +... +test passed +>>> try: +... from Numeric import array +... except: +... print 1 +... else: +... check_numeric_array_rich_slice('Numeric', 'ArrayType', lambda x:x) +... +1 +>>> try: +... from numarray import array, all +... except: +... print 1 +... else: +... check_numeric_array_rich_slice('numarray', 'NDArray', all) +... +1 +>>> import sys +>>> if sys.version_info[0] == 2 and sys.version_info[1] >= 3: +... check_string_rich_slice() +... elif sys.version_info[0] > 2: +... check_string_rich_slice() +... else: +... print 1 +... +1 +>>> check_slice_get_indices( slice(None)) +0 +>>> check_slice_get_indices( slice(2,-2)) +0 +>>> check_slice_get_indices( slice(2, None, 2)) +5 +>>> check_slice_get_indices( slice(2, None, -1)) +-12 +>>> check_slice_get_indices( slice( 20, None)) +0 +>>> check_slice_get_indices( slice( -2, -5, -2)) +6 +""" + +# Performs an affirmative and negative argument resolution check, +# checks the operation of extended slicing in Numeric arrays +# (only performed if Numeric.array or numarray.array can be found). +# checks the operation of extended slicing in new strings (Python 2.3 only). + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/staticmethod.cpp b/libs/python/test/staticmethod.cpp new file mode 100644 index 000000000..dcd75ca82 --- /dev/null +++ b/libs/python/test/staticmethod.cpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/call_method.hpp> +#include <boost/ref.hpp> +#include <boost/utility.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + virtual ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; +int X::counter; +int getXmagic(){return 7654321;} + +BOOST_PYTHON_MODULE(staticmethod_ext) +{ + class_<X>("X", init<int>()) + .def("value", &X::value) + .def("set", &X::set) + .def("count", &X::count) + .staticmethod("count") + .def("magic", &getXmagic) + .staticmethod("magic") + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/staticmethod.py b/libs/python/test/staticmethod.py new file mode 100644 index 000000000..cc2fb6a7b --- /dev/null +++ b/libs/python/test/staticmethod.py @@ -0,0 +1,57 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from staticmethod_ext import * + +>>> class X1(X): +... pass + + +>>> x = X(16) +>>> x1 = X1(17) + + + +>>> x1.count() +2 + +>>> x.count() +2 + +>>> X1.count() +2 + +>>> X.count() +2 + + +>>> x1.magic() +7654321 + +>>> x.magic() +7654321 + +>>> X1.magic() +7654321 + +>>> X.magic() +7654321 + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/stl_iterator.cpp b/libs/python/test/stl_iterator.cpp new file mode 100644 index 000000000..409e0da84 --- /dev/null +++ b/libs/python/test/stl_iterator.cpp @@ -0,0 +1,33 @@ +// Copyright Eric Niebler 2005. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/iterator.hpp> +#include <boost/python/stl_iterator.hpp> +#include <list> + +using namespace boost::python; + +typedef std::list<int> list_int; + +void assign(list_int& x, object const& y) +{ + stl_input_iterator<int> begin(y), end; + x.clear(); + for( ; begin != end; ++begin) + x.push_back(*begin); +} + +BOOST_PYTHON_MODULE(stl_iterator_ext) +{ + using boost::python::iterator; // gcc 2.96 bug workaround + + class_<list_int>("list_int") + .def("assign", assign) + .def("__iter__", iterator<list_int>()) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/stl_iterator.py b/libs/python/test/stl_iterator.py new file mode 100644 index 000000000..2c324c0ab --- /dev/null +++ b/libs/python/test/stl_iterator.py @@ -0,0 +1,39 @@ +# Copyright Eric Niebler 2005. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from stl_iterator_ext import * +>>> x = list_int() +>>> x.assign(iter([1,2,3,4,5])) +>>> for y in x: +... print y +1 +2 +3 +4 +5 +>>> def generator(): +... yield 1 +... yield 2 +... raise RuntimeError, "oops" +>>> try: +... x.assign(iter(generator())) +... print "NOT OK" +... except RuntimeError: +... print "OK" +OK +''' +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/str.cpp b/libs/python/test/str.cpp new file mode 100644 index 000000000..0505b250a --- /dev/null +++ b/libs/python/test/str.cpp @@ -0,0 +1,84 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/assert.hpp> + +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/str.hpp> +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +object convert_to_string(object data) +{ + return str(data); +} + +void work_with_string(object print) +{ + str data("this is a demo string"); + print(data.split(" ")); + print(data.split(" ",3)); + print(str("<->").join(data.split(" "))); + print(data.capitalize()); + print('[' + data.center(30) + ']'); + print(data.count("t")); +#if PY_VERSION_HEX < 0x03000000 + print(data.encode("utf-8")); + print(data.decode("utf-8")); +#else + print(data.encode("utf-8").attr("decode")("utf-8")); + print(data.encode("utf-8").attr("decode")("utf-8")); +#endif + + BOOST_ASSERT(!data.endswith("xx")); + BOOST_ASSERT(!data.startswith("test")); + + print(data.splitlines()); + print(data.strip()); + print(data.swapcase()); + print(data.title()); + + print("find"); + print(data.find("demo")); + print(data.find("demo"),3,5); + print(data.find(std::string("demo"))); + print(data.find(std::string("demo"),9)); + + print("expandtabs"); + str tabstr("\t\ttab\tdemo\t!"); + print(tabstr.expandtabs()); + print(tabstr.expandtabs(4)); + print(tabstr.expandtabs(7L)); + + print("operators"); + print( str("part1") + str("part2") ); +// print( str("a test string").slice(3,_) ); +// print( str("another test")[5] ); + + print(data.replace("demo",std::string("blabla"))); + print(data.rfind("i",5)); + print(data.rindex("i",5)); + + BOOST_ASSERT(!data.startswith("asdf")); + BOOST_ASSERT(!data.endswith("asdf")); + + print(data.translate(str('a')*256)); + + + bool tmp = data.isalnum() || data.isalpha() || data.isdigit() || data.islower() || + data.isspace() || data.istitle() || data.isupper(); + (void)tmp; // ignored. +} + + +BOOST_PYTHON_MODULE(str_ext) +{ + def("convert_to_string",convert_to_string); + def("work_with_string",work_with_string); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/str.py b/libs/python/test/str.py new file mode 100644 index 000000000..5f10580cf --- /dev/null +++ b/libs/python/test/str.py @@ -0,0 +1,53 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from str_ext import * +>>> def printer(*args): +... for x in args: print x, +... print +... +>>> work_with_string(printer) #doctest: +NORMALIZE_WHITESPACE +['this', 'is', 'a', 'demo', 'string'] +['this', 'is', 'a', 'demo string'] +this<->is<->a<->demo<->string +This is a demo string +[ this is a demo string ] +2 +this is a demo string +this is a demo string +['this is a demo string'] +this is a demo string +THIS IS A DEMO STRING +This Is A Demo String +find +10 +10 3 5 +10 +10 +expandtabs + tab demo ! + tab demo ! + tab demo ! +operators +part1part2 +this is a blabla string +18 +18 +aaaaaaaaaaaaaaaaaaaaa +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/string_literal.cpp b/libs/python/test/string_literal.cpp new file mode 100644 index 000000000..7a349d6c2 --- /dev/null +++ b/libs/python/test/string_literal.cpp @@ -0,0 +1,42 @@ +// Copyright David Abrahams 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/detail/string_literal.hpp> +//#include <stdio.h> + +#include <boost/detail/lightweight_test.hpp> +#include <boost/static_assert.hpp> + +using namespace boost::python::detail; + + +template <class T> +void expect_string_literal(T const&) +{ + BOOST_STATIC_ASSERT(is_string_literal<T const>::value); +} + +int main() +{ + expect_string_literal("hello"); + BOOST_STATIC_ASSERT(!is_string_literal<int*&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int* const&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int*volatile&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int*const volatile&>::value); + + BOOST_STATIC_ASSERT(!is_string_literal<char const*>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char* const&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*volatile&>::value); + BOOST_STATIC_ASSERT(!is_string_literal<char*const volatile&>::value); + + BOOST_STATIC_ASSERT(!is_string_literal<char[20]>::value); + BOOST_STATIC_ASSERT(is_string_literal<char const[20]>::value); + BOOST_STATIC_ASSERT(is_string_literal<char const[3]>::value); + + BOOST_STATIC_ASSERT(!is_string_literal<int[20]>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int const[20]>::value); + BOOST_STATIC_ASSERT(!is_string_literal<int const[3]>::value); + return boost::report_errors(); +} diff --git a/libs/python/test/test_builtin_converters.cpp b/libs/python/test/test_builtin_converters.cpp new file mode 100644 index 000000000..f66e61bd8 --- /dev/null +++ b/libs/python/test/test_builtin_converters.cpp @@ -0,0 +1,152 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <complex> +#include <boost/python/handle.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/object.hpp> +#include <boost/python/detail/wrap_python.hpp> + +template <class T> +struct by_value +{ + static T rewrap(T x) + { + return x; + } + static int size(void) + { + return sizeof(T); + } +}; + +template <class T> +struct by_const_reference +{ + static T rewrap(T const& x) + { + return x; + } +}; + +template <class T> +struct by_reference +{ + static T rewrap(T& x) + { + return x; + } +}; + +using boost::python::def; +using boost::python::handle; +using boost::python::object; +using boost::python::borrowed; + +// Used to test that arbitrary handle<>s can be returned +handle<PyTypeObject> get_type(handle<> x) +{ + return handle<PyTypeObject>(borrowed(x->ob_type)); +} + +handle<> return_null_handle() +{ + return handle<>(); +} + +char const* rewrap_value_mutable_cstring(char* x) { return x; } + +object identity_(object x) { return x; } + +BOOST_PYTHON_MODULE(builtin_converters_ext) +{ + def("get_type", get_type); + def("return_null_handle", return_null_handle); + +// These methods are used solely for getting some C++ type sizes + def("bool_size", by_value<bool>::size); + def("char_size", by_value<char>::size); + def("int_size", by_value<int>::size); + def("short_size", by_value<short>::size); + def("long_size", by_value<long>::size); +#ifdef HAVE_LONG_LONG + def("long_long_size", by_value<BOOST_PYTHON_LONG_LONG>::size); +#endif + + def("rewrap_value_bool", by_value<bool>::rewrap); + def("rewrap_value_char", by_value<char>::rewrap); + def("rewrap_value_signed_char", by_value<signed char>::rewrap); + def("rewrap_value_unsigned_char", by_value<unsigned char>::rewrap); + def("rewrap_value_int", by_value<int>::rewrap); + def("rewrap_value_unsigned_int", by_value<unsigned int>::rewrap); + def("rewrap_value_short", by_value<short>::rewrap); + def("rewrap_value_unsigned_short", by_value<unsigned short>::rewrap); + def("rewrap_value_long", by_value<long>::rewrap); + def("rewrap_value_unsigned_long", by_value<unsigned long>::rewrap); +// using Python's macro instead of Boost's - we don't seem to get the +// config right all the time. +#ifdef HAVE_LONG_LONG + def("rewrap_value_long_long", by_value<BOOST_PYTHON_LONG_LONG>::rewrap); + def("rewrap_value_unsigned_long_long", by_value<unsigned BOOST_PYTHON_LONG_LONG>::rewrap); +# endif + def("rewrap_value_float", by_value<float>::rewrap); + def("rewrap_value_double", by_value<double>::rewrap); + def("rewrap_value_long_double", by_value<long double>::rewrap); + def("rewrap_value_complex_float", by_value<std::complex<float> >::rewrap); + def("rewrap_value_complex_double", by_value<std::complex<double> >::rewrap); + def("rewrap_value_complex_long_double", by_value<std::complex<long double> >::rewrap); + def("rewrap_value_wstring", +# if defined(BOOST_NO_STD_WSTRING) || !defined(Py_USING_UNICODE) + identity_ +# else + by_value<std::wstring>::rewrap +# endif + ); + def("rewrap_value_string", +# if defined(BOOST_NO_STD_WSTRING) || !defined(Py_USING_UNICODE) + identity_ +# else + by_value<std::wstring>::rewrap +# endif + ); + def("rewrap_value_string", by_value<std::string>::rewrap); + def("rewrap_value_cstring", by_value<char const*>::rewrap); + def("rewrap_value_handle", by_value<handle<> >::rewrap); + def("rewrap_value_object", by_value<object>::rewrap); + + // Expose this to illustrate our failings ;-). See test_builtin_converters.py + def("rewrap_value_mutable_cstring", rewrap_value_mutable_cstring); + + + def("rewrap_const_reference_bool", by_const_reference<bool>::rewrap); + def("rewrap_const_reference_char", by_const_reference<char>::rewrap); + def("rewrap_const_reference_signed_char", by_const_reference<signed char>::rewrap); + def("rewrap_const_reference_unsigned_char", by_const_reference<unsigned char>::rewrap); + def("rewrap_const_reference_int", by_const_reference<int>::rewrap); + def("rewrap_const_reference_unsigned_int", by_const_reference<unsigned int>::rewrap); + def("rewrap_const_reference_short", by_const_reference<short>::rewrap); + def("rewrap_const_reference_unsigned_short", by_const_reference<unsigned short>::rewrap); + def("rewrap_const_reference_long", by_const_reference<long>::rewrap); + def("rewrap_const_reference_unsigned_long", by_const_reference<unsigned long>::rewrap); +// using Python's macro instead of Boost's - we don't seem to get the +// config right all the time. +# ifdef HAVE_LONG_LONG + def("rewrap_const_reference_long_long", by_const_reference<BOOST_PYTHON_LONG_LONG>::rewrap); + def("rewrap_const_reference_unsigned_long_long", by_const_reference<unsigned BOOST_PYTHON_LONG_LONG>::rewrap); +# endif + def("rewrap_const_reference_float", by_const_reference<float>::rewrap); + def("rewrap_const_reference_double", by_const_reference<double>::rewrap); + def("rewrap_const_reference_long_double", by_const_reference<long double>::rewrap); + def("rewrap_const_reference_complex_float", by_const_reference<std::complex<float> >::rewrap); + def("rewrap_const_reference_complex_double", by_const_reference<std::complex<double> >::rewrap); + def("rewrap_const_reference_complex_long_double", by_const_reference<std::complex<long double> >::rewrap); + def("rewrap_const_reference_string", by_const_reference<std::string>::rewrap); + def("rewrap_const_reference_cstring", by_const_reference<char const*>::rewrap); + def("rewrap_const_reference_handle", by_const_reference<handle<> >::rewrap); + def("rewrap_const_reference_object", by_const_reference<object>::rewrap); + def("rewrap_reference_object", by_reference<object>::rewrap); +} + diff --git a/libs/python/test/test_builtin_converters.py b/libs/python/test/test_builtin_converters.py new file mode 100644 index 000000000..5a6c8c50a --- /dev/null +++ b/libs/python/test/test_builtin_converters.py @@ -0,0 +1,302 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +r""" +>>> from builtin_converters_ext import * + +# Provide values for integer converter tests +>>> def _signed_values(s): +... base = 2 ** (8 * s - 1) +... return [[-base, -1, 1, base - 1], [-base - 1, base]] +>>> def _unsigned_values(s): +... base = 2 ** (8 * s) +... return [[1, base - 1], [-1L, -1, base]] + +# Wrappers to simplify tests +>>> def should_pass(method, values): +... result = map(method, values[0]) +... if result != values[0]: +... print "Got %s but expected %s" % (result, values[0]) +>>> def test_overflow(method, values): +... for v in values[1]: +... try: method(v) +... except OverflowError: pass +... else: print "OverflowError expected" + +# Synthesize idendity functions in case long long not supported +>>> if not 'rewrap_value_long_long' in dir(): +... def rewrap_value_long_long(x): return long(x) +... def rewrap_value_unsigned_long_long(x): return long(x) +... def rewrap_const_reference_long_long(x): return long(x) +... def rewrap_const_reference_unsigned_long_long(x): return long(x) +>>> if not 'long_long_size' in dir(): +... def long_long_size(): return long_size() + +>>> try: bool_exists = bool +... except: pass +... else: +... rewrap_value_bool(True) +... rewrap_value_bool(False) +True +False + +>>> rewrap_value_bool(None) +0 +>>> rewrap_value_bool(0) +0 +>>> rewrap_value_bool(33) +1 +>>> rewrap_value_char('x') +'x' + + Note that there's currently silent truncation of strings passed to + char arguments. + +>>> rewrap_value_char('xy') +'x' +>>> rewrap_value_signed_char(42) +42 +>>> rewrap_value_unsigned_char(42) +42 +>>> rewrap_value_int(42) +42 +>>> rewrap_value_unsigned_int(42) +42 +>>> rewrap_value_short(42) +42 +>>> rewrap_value_unsigned_short(42) +42 +>>> rewrap_value_long(42) +42 +>>> rewrap_value_unsigned_long(42) +42 + + test unsigned long values which don't fit in a signed long. + strip any 'L' characters in case the platform has > 32 bit longs + +>>> hex(rewrap_value_unsigned_long(0x80000001L)).replace('L','') +'0x80000001' + +>>> rewrap_value_long_long(42) == 42 +True +>>> rewrap_value_unsigned_long_long(42) == 42 +True + + show that we have range checking. + +>>> should_pass(rewrap_value_signed_char, _signed_values(char_size())) +>>> should_pass(rewrap_value_short, _signed_values(short_size())) +>>> should_pass(rewrap_value_int, _signed_values(int_size())) +>>> should_pass(rewrap_value_long, _signed_values(long_size())) +>>> should_pass(rewrap_value_long_long, _signed_values(long_long_size())) + +>>> should_pass(rewrap_value_unsigned_char, _unsigned_values(char_size())) +>>> should_pass(rewrap_value_unsigned_short, _unsigned_values(short_size())) +>>> should_pass(rewrap_value_unsigned_int, _unsigned_values(int_size())) +>>> should_pass(rewrap_value_unsigned_long, _unsigned_values(long_size())) +>>> should_pass(rewrap_value_unsigned_long_long, +... _unsigned_values(long_long_size())) + +>>> test_overflow(rewrap_value_signed_char, _signed_values(char_size())) +>>> test_overflow(rewrap_value_short, _signed_values(short_size())) +>>> test_overflow(rewrap_value_int, _signed_values(int_size())) +>>> test_overflow(rewrap_value_long, _signed_values(long_size())) +>>> test_overflow(rewrap_value_long_long, _signed_values(long_long_size())) + +>>> test_overflow(rewrap_value_unsigned_char, _unsigned_values(char_size())) +>>> test_overflow(rewrap_value_unsigned_short, _unsigned_values(short_size())) +>>> test_overflow(rewrap_value_unsigned_int, _unsigned_values(int_size())) +>>> test_overflow(rewrap_value_unsigned_long, _unsigned_values(long_size())) + +# Exceptionally for PyLong_AsUnsignedLongLong(), a negative value raises +# TypeError on Python versions prior to 2.7 +>>> for v in _unsigned_values(long_long_size())[1]: +... try: rewrap_value_unsigned_long_long(v) +... except (OverflowError, TypeError): pass +... else: print "OverflowError or TypeError expected" + +>>> assert abs(rewrap_value_float(4.2) - 4.2) < .000001 +>>> rewrap_value_double(4.2) - 4.2 +0.0 +>>> rewrap_value_long_double(4.2) - 4.2 +0.0 + +>>> assert abs(rewrap_value_complex_float(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_value_complex_double(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_value_complex_long_double(4+.2j) - (4+.2j)) < .000001 + +>>> rewrap_value_cstring('hello, world') +'hello, world' +>>> rewrap_value_string('yo, wassup?') +'yo, wassup?' + +>>> print rewrap_value_wstring(u'yo, wassup?') +yo, wassup? + + test that overloading on unicode works: + +>>> print rewrap_value_string(u'yo, wassup?') +yo, wassup? + + wrap strings with embedded nulls: + +>>> rewrap_value_string('yo,\0wassup?') +'yo,\x00wassup?' + +>>> rewrap_value_handle(1) +1 +>>> x = 'hi' +>>> assert rewrap_value_handle(x) is x +>>> assert rewrap_value_object(x) is x + + Note that we can currently get a mutable pointer into an immutable + Python string: + +>>> rewrap_value_mutable_cstring('hello, world') +'hello, world' + +>>> rewrap_const_reference_bool(None) +0 +>>> rewrap_const_reference_bool(0) +0 + +>>> try: rewrap_const_reference_bool('yes') +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> rewrap_const_reference_char('x') +'x' + + Note that there's currently silent truncation of strings passed to + char arguments. + +>>> rewrap_const_reference_char('xy') +'x' +>>> rewrap_const_reference_signed_char(42) +42 +>>> rewrap_const_reference_unsigned_char(42) +42 +>>> rewrap_const_reference_int(42) +42 +>>> rewrap_const_reference_unsigned_int(42) +42 +>>> rewrap_const_reference_short(42) +42 +>>> rewrap_const_reference_unsigned_short(42) +42 +>>> rewrap_const_reference_long(42) +42 +>>> rewrap_const_reference_unsigned_long(42) +42 +>>> rewrap_const_reference_long_long(42) == 42 +True +>>> rewrap_const_reference_unsigned_long_long(42) == 42 +True + + +>>> assert abs(rewrap_const_reference_float(4.2) - 4.2) < .000001 +>>> rewrap_const_reference_double(4.2) - 4.2 +0.0 +>>> rewrap_const_reference_long_double(4.2) - 4.2 +0.0 + +>>> assert abs(rewrap_const_reference_complex_float(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_const_reference_complex_double(4+.2j) - (4+.2j)) < .000001 +>>> assert abs(rewrap_const_reference_complex_long_double(4+.2j) - (4+.2j)) < .000001 + +>>> rewrap_const_reference_cstring('hello, world') +'hello, world' +>>> rewrap_const_reference_string('yo, wassup?') +'yo, wassup?' + +>>> rewrap_const_reference_handle(1) +1 +>>> x = 'hi' +>>> assert rewrap_const_reference_handle(x) is x +>>> assert rewrap_const_reference_object(x) is x +>>> assert rewrap_reference_object(x) is x + + +Check that None <==> NULL + +>>> rewrap_const_reference_cstring(None) + +But None cannot be converted to a string object: + +>>> try: rewrap_const_reference_string(None) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +Now check implicit conversions between floating/integer types + +>>> rewrap_const_reference_float(42) +42.0 + +>>> rewrap_const_reference_float(42L) +42.0 + +>>> try: rewrap_const_reference_int(42.0) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> rewrap_value_float(42) +42.0 + +>>> try: rewrap_value_int(42.0) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +Check that classic classes also work + +>>> class FortyTwo: +... def __int__(self): +... return 42 +... def __float__(self): +... return 42.0 +... def __complex__(self): +... return complex(4+.2j) +... def __str__(self): +... return '42' + +>>> try: rewrap_const_reference_float(FortyTwo()) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> try: rewrap_value_int(FortyTwo()) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> try: rewrap_const_reference_string(FortyTwo()) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +>>> try: rewrap_value_complex_double(FortyTwo()) +... except TypeError: pass +... else: print 'expected a TypeError exception' + +# show that arbitrary handle<T> instantiations can be returned +>>> assert get_type(1) is type(1) + +>>> assert return_null_handle() is None +""" + +def run(args = None): + import sys + import doctest + import builtin_converters_ext + + if 'rewrap_value_long_long' in dir(builtin_converters_ext): + print 'LONG_LONG supported, testing...' + else: + print 'LONG_LONG not supported, skipping those tests...' + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/test_class.hpp b/libs/python/test/test_class.hpp new file mode 100644 index 000000000..5404fdba2 --- /dev/null +++ b/libs/python/test/test_class.hpp @@ -0,0 +1,32 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef TEST_CLASS_DWA2002326_HPP +# define TEST_CLASS_DWA2002326_HPP +# include <boost/detail/lightweight_test.hpp> + +template <int n = 0> +struct test_class +{ + explicit test_class(int x) : x(x), magic(7654321 + n) { ++counter; } + test_class(test_class const& rhs) : x(rhs.x), magic(7654321 + n) { ++counter; } + virtual ~test_class() { BOOST_TEST(magic == 7654321 + n); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_TEST(magic == 7654321 + n); this->x = _x; } + int value() const { BOOST_TEST(magic == 7654321 + n); return x; } + operator int() const { return x; } + static int count() { return counter; } + + int x; + long magic; + static int counter; + + private: + void operator=(test_class const&); +}; + +template <int n> +int test_class<n>::counter; + +#endif // TEST_CLASS_DWA2002326_HPP diff --git a/libs/python/test/test_cltree.py b/libs/python/test/test_cltree.py new file mode 100644 index 000000000..016cf63d1 --- /dev/null +++ b/libs/python/test/test_cltree.py @@ -0,0 +1,43 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#!/usr/bin/env python + +from cltree import basic,symbol,constant,variable + +b = basic() +c = constant() +s = symbol() +v = variable() + +assert isinstance(b,basic) +assert not isinstance(b,symbol) +assert not isinstance(b,constant) +assert not isinstance(b,variable) + +assert isinstance(c,basic) +assert isinstance(c,constant) +assert not isinstance(c,symbol) +assert not isinstance(c,variable) + +assert not isinstance(s,basic) +assert isinstance(s,symbol) +assert not isinstance(s,constant) +assert not isinstance(s,variable) + +assert isinstance(v,basic) +assert not isinstance(v,symbol) +assert not isinstance(v,constant) +assert isinstance(v,variable) + +print 'b=',b +assert repr(b)=='cltree.basic()' +print 's=',s +assert repr(s)!='cltree.wrapped_symbol()' # because not isinstance(s,basic) +print 'c=',c +assert repr(c)=='cltree.constant()' +print 'v=',v +assert repr(v)=='cltree.wrapped_variable()' + + +print 'ok' diff --git a/libs/python/test/test_overload_resolution.cpp b/libs/python/test/test_overload_resolution.cpp new file mode 100644 index 000000000..e15bcc6a7 --- /dev/null +++ b/libs/python/test/test_overload_resolution.cpp @@ -0,0 +1,53 @@ +// Copyright Troy D. Straszheim 2009 +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// +// example that shows problems with overloading and automatic conversion. +// if you call one of the below functions from python with bool/int/double, +// you'll see that the overload called is first match, not best match. +// See overload matching in luabind for an example of how to do this better. +// +// see this mail: +// http://mail.python.org/pipermail/cplusplus-sig/2009-March/014362.html +// +// This test isn't called by the cmake/jamfiles. For future use. +// +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <complex> +#include <boost/python/handle.hpp> +#include <boost/python/cast.hpp> +#include <boost/python/object.hpp> +#include <boost/python/detail/wrap_python.hpp> + +using boost::python::def; +using boost::python::handle; +using boost::python::object; +using boost::python::borrowed; + +std::string takes_bool(bool b) { return "bool"; } +std::string takes_int(int b) { return "int"; } +std::string takes_double(double b) { return "double"; } + + +BOOST_PYTHON_MODULE(overload_resolution) +{ + def("bid", takes_bool); + def("bid", takes_int); + def("bid", takes_double); + + def("dib", takes_double); + def("dib", takes_int); + def("dib", takes_bool); + + def("idb", takes_int); + def("idb", takes_double); + def("idb", takes_bool); + + def("bdi", takes_bool); + def("bdi", takes_double); + def("bdi", takes_int); +} + diff --git a/libs/python/test/test_pointer_adoption.cpp b/libs/python/test/test_pointer_adoption.cpp new file mode 100644 index 000000000..a4e14af5d --- /dev/null +++ b/libs/python/test/test_pointer_adoption.cpp @@ -0,0 +1,125 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/return_value_policy.hpp> +#include <boost/python/manage_new_object.hpp> +#include <boost/python/return_internal_reference.hpp> +#include <boost/python/class.hpp> + +using namespace boost::python; + +int a_instances = 0; + +int num_a_instances() { return a_instances; } + +struct inner +{ + inner(std::string const& s) + : s(s) + {} + + void change(std::string const& new_s) + { + this->s = new_s; + } + + std::string s; +}; + +struct Base +{ + virtual ~Base() {} +}; + +struct A : Base +{ + A(std::string const& s) + : x(s) + { + ++a_instances; + } + + ~A() + { + --a_instances; + } + + std::string content() const + { + return x.s; + } + + inner& get_inner() + { + return x; + } + + inner x; +}; + +struct B +{ + B() : x(0) {} + B(A* x_) : x(x_) {} + + inner const* adopt(A* _x) { this->x = _x; return &_x->get_inner(); } + + std::string a_content() + { + return x ? x->content() : std::string("empty"); + } + + A* x; +}; + + +A* create(std::string const& s) +{ + return new A(s); +} + +A* as_A(Base* b) +{ + return dynamic_cast<A*>(b); +} + +BOOST_PYTHON_MODULE(test_pointer_adoption_ext) +{ + def("num_a_instances", num_a_instances); + + // Specify the manage_new_object return policy to take + // ownership of create's result + def("create", create, return_value_policy<manage_new_object>()); + + def("as_A", as_A, return_internal_reference<>()); + + class_<Base>("Base") + ; + + class_<A, bases<Base> >("A", no_init) + .def("content", &A::content) + .def("get_inner", &A::get_inner, return_internal_reference<>()) + ; + + class_<inner>("inner", no_init) + .def("change", &inner::change) + ; + + class_<B>("B") + .def(init<A*>()[with_custodian_and_ward_postcall<1,2>()]) + + .def("adopt", &B::adopt + // Adopt returns a pointer referring to a subobject of its 2nd argument (1st being "self") + , return_internal_reference<2 + // Meanwhile, self holds a reference to the 2nd argument. + , with_custodian_and_ward<1,2> >() + ) + + .def("a_content", &B::a_content) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/test_pointer_adoption.py b/libs/python/test/test_pointer_adoption.py new file mode 100644 index 000000000..5bb9dd6dc --- /dev/null +++ b/libs/python/test/test_pointer_adoption.py @@ -0,0 +1,93 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from test_pointer_adoption_ext import * + +>>> num_a_instances() +0 + +>>> a = create('dynamically allocated') +>>> num_a_instances() +1 + +>>> a.content() +'dynamically allocated' + +>>> innards = a.get_inner() +>>> innards.change('with an exposed reference') +>>> a.content() +'with an exposed reference' + +# The a instance should be kept alive... +>>> a = None +>>> num_a_instances() +1 + +# ...until we're done with its innards +>>> innards = None +>>> num_a_instances() +0 + +>>> b = B() +>>> a = create('another') +>>> b.a_content() +'empty' +>>> innards = b.adopt(a); +>>> b.a_content() +'another' +>>> num_a_instances() +1 +>>> del a # innards and b are both holding a reference +>>> num_a_instances() +1 +>>> innards.change('yet another') +>>> b.a_content() +'yet another' + +>>> del innards +>>> num_a_instances() # b still owns a reference to a +1 +>>> del b +>>> num_a_instances() +0 + +Test call policies for constructors here + +>>> a = create('second a') +>>> num_a_instances() +1 +>>> b = B(a) +>>> num_a_instances() +1 +>>> a.content() +'second a' + +>>> del a +>>> num_a_instances() +1 +>>> b.a_content() +'second a' + +>>> del b +>>> num_a_instances() +0 + +>>> assert as_A(create('dynalloc')) is not None +>>> base = Base() +>>> assert as_A(base) is None +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/tuple.cpp b/libs/python/test/tuple.cpp new file mode 100644 index 000000000..d48e91d88 --- /dev/null +++ b/libs/python/test/tuple.cpp @@ -0,0 +1,33 @@ +// Copyright David Abrahams 2005. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/tuple.hpp> + +using namespace boost::python; + +object convert_to_tuple(object data) +{ + return tuple(data); +} + +void test_operators(tuple t1, tuple t2, object print) +{ + print(t1 + t2); +} + +tuple mktuple0() { return make_tuple(); } +tuple mktuple1(int x) { return make_tuple(x); } +tuple mktuple2(char const* a1, int x) { return make_tuple(a1, x); } + +BOOST_PYTHON_MODULE(tuple_ext) +{ + def("convert_to_tuple",convert_to_tuple); + def("test_operators",test_operators); + def("make_tuple", mktuple0); + def("make_tuple", mktuple1); + def("make_tuple", mktuple2); +} diff --git a/libs/python/test/tuple.py b/libs/python/test/tuple.py new file mode 100644 index 000000000..9d25aef41 --- /dev/null +++ b/libs/python/test/tuple.py @@ -0,0 +1,37 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from tuple_ext import * +>>> def printer(*args): +... for x in args: print x, +... print +... +>>> print convert_to_tuple("this is a test string") +('t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g') +>>> t1 = convert_to_tuple("this is") +>>> t2 = (1,2,3,4) +>>> test_operators(t1,t2,printer) #doctest: +NORMALIZE_WHITESPACE +('t', 'h', 'i', 's', ' ', 'i', 's', 1, 2, 3, 4) +>>> make_tuple() +() +>>> make_tuple(42) +(42,) +>>> make_tuple('hello', 42) +('hello', 42) +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/upcast.cpp b/libs/python/test/upcast.cpp new file mode 100644 index 000000000..255429f16 --- /dev/null +++ b/libs/python/test/upcast.cpp @@ -0,0 +1,19 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/cast.hpp> +#include <boost/detail/lightweight_test.hpp> + +struct X { long x; }; +struct Y : X, PyObject {}; + +int main() +{ + PyTypeObject o; + Y y; + BOOST_TEST(&Py_REFCNT(boost::python::upcast<PyObject>(&o)) == &Py_REFCNT(&o)); + BOOST_TEST(&Py_REFCNT(boost::python::upcast<PyObject>(&y)) == &Py_REFCNT(&y)); + return boost::report_errors(); +} diff --git a/libs/python/test/vector_indexing_suite.cpp b/libs/python/test/vector_indexing_suite.cpp new file mode 100644 index 000000000..0f9cd74ca --- /dev/null +++ b/libs/python/test/vector_indexing_suite.cpp @@ -0,0 +1,62 @@ +// Copyright Joel de Guzman 2004. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/implicit.hpp> + +using namespace boost::python; + +struct X // a container element +{ + std::string s; + X():s("default") {} + X(std::string s):s(s) {} + std::string repr() const { return s; } + void reset() { s = "reset"; } + void foo() { s = "foo"; } + bool operator==(X const& x) const { return s == x.s; } + bool operator!=(X const& x) const { return s != x.s; } +}; + +std::string x_value(X const& x) +{ + return "gotya " + x.s; +} + +BOOST_PYTHON_MODULE(vector_indexing_suite_ext) +{ + class_<X>("X") + .def(init<>()) + .def(init<X>()) + .def(init<std::string>()) + .def("__repr__", &X::repr) + .def("reset", &X::reset) + .def("foo", &X::foo) + ; + + def("x_value", x_value); + implicitly_convertible<std::string, X>(); + + class_<std::vector<X> >("XVec") + .def(vector_indexing_suite<std::vector<X> >()) + ; + + // Compile check only... + class_<std::vector<float> >("FloatVec") + .def(vector_indexing_suite<std::vector<float> >()) + ; + + // Compile check only... + class_<std::vector<bool> >("BoolVec") + .def(vector_indexing_suite<std::vector<bool> >()) + ; + + // vector of strings + class_<std::vector<std::string> >("StringVec") + .def(vector_indexing_suite<std::vector<std::string> >()) + ; +} + diff --git a/libs/python/test/vector_indexing_suite.py b/libs/python/test/vector_indexing_suite.py new file mode 100644 index 000000000..5fe2efe4d --- /dev/null +++ b/libs/python/test/vector_indexing_suite.py @@ -0,0 +1,370 @@ +# Copyright Joel de Guzman 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' + +##################################################################### +# Check an object that we will use as container element +##################################################################### + +>>> from vector_indexing_suite_ext import * +>>> x = X('hi') +>>> x +hi +>>> x.reset() # a member function that modifies X +>>> x +reset +>>> x.foo() # another member function that modifies X +>>> x +foo + +# test that a string is implicitly convertible +# to an X +>>> x_value('bochi bochi') +'gotya bochi bochi' + +##################################################################### +# Iteration +##################################################################### +>>> def print_xvec(xvec): +... s = '[ ' +... for x in xvec: +... s += repr(x) +... s += ' ' +... s += ']' +... print s + +##################################################################### +# Replace all the contents using slice syntax +##################################################################### + +>>> v = XVec() +>>> v[:] = [X('a'),X('b'),X('c'),X('d'),X('e')] +>>> print_xvec(v) +[ a b c d e ] + +##################################################################### +# Indexing +##################################################################### +>>> len(v) +5 +>>> v[0] +a +>>> v[1] +b +>>> v[2] +c +>>> v[3] +d +>>> v[4] +e +>>> v[-1] +e +>>> v[-2] +d +>>> v[-3] +c +>>> v[-4] +b +>>> v[-5] +a + +##################################################################### +# Deleting an element +##################################################################### + +>>> del v[0] +>>> v[0] = 'yaba' # must do implicit conversion +>>> print_xvec(v) +[ yaba c d e ] + +##################################################################### +# Calling a mutating function of a container element +##################################################################### +>>> v[3].reset() +>>> v[3] +reset + +##################################################################### +# Copying a container element +##################################################################### +>>> x = X(v[3]) +>>> x +reset +>>> x.foo() +>>> x +foo +>>> v[3] # should not be changed to 'foo' +reset + +##################################################################### +# Referencing a container element +##################################################################### +>>> x = v[3] +>>> x +reset +>>> x.foo() +>>> x +foo +>>> v[3] # should be changed to 'foo' +foo + +##################################################################### +# Slice +##################################################################### + +>>> sl = v[0:2] +>>> print_xvec(sl) +[ yaba c ] +>>> sl[0].reset() +>>> sl[0] +reset + +##################################################################### +# Reset the container again +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # perform implicit conversion to X +>>> print_xvec(v) +[ a b c d e ] + +##################################################################### +# Slice: replace [1:3] with an element +##################################################################### +>>> v[1:3] = X('z') +>>> print_xvec(v) +[ a z d e ] + +##################################################################### +# Slice: replace [0:2] with a list +##################################################################### +>>> v[0:2] = ['1','2','3','4'] # perform implicit conversion to X +>>> print_xvec(v) +[ 1 2 3 4 d e ] + +##################################################################### +# Slice: delete [3:4] +##################################################################### +>>> del v[3:4] +>>> print_xvec(v) +[ 1 2 3 d e ] + +##################################################################### +# Slice: set [3:] to a list +##################################################################### +>>> v[3:] = [X('trailing'), X('stuff')] # a list +>>> print_xvec(v) +[ 1 2 3 trailing stuff ] + +##################################################################### +# Slice: delete [:3] +##################################################################### +>>> del v[:3] +>>> print_xvec(v) +[ trailing stuff ] + +##################################################################### +# Slice: insert a tuple to [0:0] +##################################################################### +>>> v[0:0] = ('leading','stuff') # can also be a tuple +>>> print_xvec(v) +[ leading stuff trailing stuff ] + +##################################################################### +# Reset the container again +##################################################################### +>>> v[:] = ['a','b','c','d','e'] + +##################################################################### +# Some references to the container elements +##################################################################### +>>> z0 = v[0] +>>> z1 = v[1] +>>> z2 = v[2] +>>> z3 = v[3] +>>> z4 = v[4] + +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy +c +>>> z3 # proxy +d +>>> z4 # proxy +e + +##################################################################### +# Delete a container element +##################################################################### + +>>> del v[2] +>>> print_xvec(v) +[ a b d e ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy detached +c +>>> z3 # proxy index adjusted +d +>>> z4 # proxy index adjusted +e + +##################################################################### +# Delete all container elements +##################################################################### +>>> del v[:] +>>> print_xvec(v) +[ ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy detached +a +>>> z1 # proxy detached +b +>>> z2 # proxy detached +c +>>> z3 # proxy detached +d +>>> z4 # proxy detached +e + +##################################################################### +# Reset the container again +##################################################################### +>>> v[:] = ['a','b','c','d','e'] + +##################################################################### +# renew the references to the container elements +##################################################################### +>>> z0 = v[0] +>>> z1 = v[1] +>>> z2 = v[2] +>>> z3 = v[3] +>>> z4 = v[4] + +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy +c +>>> z3 # proxy +d +>>> z4 # proxy +e + +##################################################################### +# Set [2:4] to a list such that there will be more elements +##################################################################### +>>> v[2:4] = ['x','y','v'] +>>> print_xvec(v) +[ a b x y v e ] + +##################################################################### +# Show that the references are still valid +##################################################################### +>>> z0 # proxy +a +>>> z1 # proxy +b +>>> z2 # proxy detached +c +>>> z3 # proxy detached +d +>>> z4 # proxy index adjusted +e + +##################################################################### +# Contains +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again + +>>> assert 'a' in v +>>> assert 'b' in v +>>> assert 'c' in v +>>> assert 'd' in v +>>> assert 'e' in v +>>> assert not 'X' in v +>>> assert not 12345 in v + +##################################################################### +# Show that iteration allows mutable access to the elements +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> for x in v: +... x.reset() +>>> print_xvec(v) +[ reset reset reset reset reset ] + +##################################################################### +# append +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> v.append('f') +>>> print_xvec(v) +[ a b c d e f ] + +##################################################################### +# extend +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> v.extend(['f','g','h','i','j']) +>>> print_xvec(v) +[ a b c d e f g h i j ] + +##################################################################### +# extend using a generator expression +##################################################################### +>>> v[:] = ['a','b','c','d','e'] # reset again +>>> def generator(): +... addlist = ['f','g','h','i','j'] +... for i in addlist: +... if i != 'g': +... yield i +>>> v.extend(generator()) +>>> print_xvec(v) +[ a b c d e f h i j ] + +##################################################################### +# vector of strings +##################################################################### +>>> sv = StringVec() +>>> sv.append('a') +>>> print sv[0] +a + +##################################################################### +# END.... +##################################################################### + +''' + + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print 'running...' + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + + + + + diff --git a/libs/python/test/virtual_functions.cpp b/libs/python/test/virtual_functions.cpp new file mode 100644 index 000000000..774b11b12 --- /dev/null +++ b/libs/python/test/virtual_functions.cpp @@ -0,0 +1,125 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/python/def.hpp> +#include <boost/python/return_internal_reference.hpp> +#include <boost/python/call_method.hpp> +#include <boost/ref.hpp> +#include <boost/utility.hpp> + +#define BOOST_ENABLE_ASSERT_HANDLER +#include <boost/assert.hpp> + +using namespace boost::python; + +struct X +{ + explicit X(int x) : x(x), magic(7654321) { ++counter; } + X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; } + virtual ~X() { BOOST_ASSERT(magic == 7654321); magic = 6666666; x = 9999; --counter; } + + void set(int _x) { BOOST_ASSERT(magic == 7654321); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321); return x; } + static int count() { return counter; } + private: + void operator=(X const&); + private: + int x; + long magic; + static int counter; +}; + +struct Y : X +{ + Y(int x) : X(x) {}; +}; + +struct abstract : X +{ + abstract(int x) : X(x) {}; + int call_f(Y const& y) { return f(y); } + virtual int f(Y const& y) = 0; + abstract& call_g(Y const& y) { return g(y); } + virtual abstract& g(Y const& y) = 0; +}; + +struct concrete : X +{ + concrete(int x) : X(x) {}; + int call_f(Y const& y) { return f(y); } + virtual int f(Y const& y) { set(y.value()); return y.value(); } +}; + +struct abstract_callback : abstract +{ + abstract_callback(PyObject* p, int x) + : abstract(x), self(p) + {} + + int f(Y const& y) + { + return call_method<int>(self, "f", boost::ref(y)); + } + + abstract& g(Y const& y) + { + return call_method<abstract&>(self, "g", boost::ref(y)); + } + + PyObject* self; +}; + +struct concrete_callback : concrete +{ + concrete_callback(PyObject* p, int x) + : concrete(x), self(p) + {} + + concrete_callback(PyObject* p, concrete const& x) + : concrete(x), self(p) + {} + + int f(Y const& y) + { + return call_method<int>(self, "f", boost::ref(y)); + } + + int f_impl(Y const& y) + { + return this->concrete::f(y); + } + + PyObject* self; +}; + +int X::counter; + +BOOST_PYTHON_MODULE(virtual_functions_ext) +{ + class_<concrete, concrete_callback>("concrete", init<int>()) + .def("value", &concrete::value) + .def("set", &concrete::set) + .def("call_f", &concrete::call_f) + .def("f", &concrete_callback::f_impl) + ; + + class_<abstract, boost::noncopyable, abstract_callback + >("abstract", init<int>()) + + .def("value", &abstract::value) + .def("call_f", &abstract::call_f) + .def("call_g", &abstract::call_g, return_internal_reference<>()) + .def("set", &abstract::set) + ; + + class_<Y>("Y", init<int>()) + .def("value", &Y::value) + .def("set", &Y::set) + ; +} + +#include "module_tail.cpp" diff --git a/libs/python/test/virtual_functions.py b/libs/python/test/virtual_functions.py new file mode 100644 index 000000000..1372f9afb --- /dev/null +++ b/libs/python/test/virtual_functions.py @@ -0,0 +1,110 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from virtual_functions_ext import * + +>>> class C1(concrete): +... def f(self, y): +... return concrete.f(self, Y(-y.value())) + +>>> class C2(concrete): +... pass + +>>> class A1(abstract): +... def f(self, y): +... return y.value() * 2 +... def g(self, y): +... return self + +>>> class A2(abstract): +... pass + + +>>> y1 = Y(16) +>>> y2 = Y(17) + + + +# +# Test abstract with f,g overridden +# +>>> a1 = A1(42) +>>> a1.value() +42 + +# Call f,g indirectly from C++ +>>> a1.call_f(y1) +32 +>>> assert type(a1.call_g(y1)) is abstract + +# Call f directly from Python +>>> a1.f(y2) +34 + +# +# Test abstract with f not overridden +# +>>> a2 = A2(42) +>>> a2.value() +42 + +# Call f indirectly from C++ +>>> try: a2.call_f(y1) +... except AttributeError: pass +... else: print 'no exception' + +# Call f directly from Python +>>> try: a2.call_f(y2) +... except AttributeError: pass +... else: print 'no exception' + +############# Concrete Tests ############ + +# +# Test concrete with f overridden +# +>>> c1 = C1(42) +>>> c1.value() +42 + +# Call f indirectly from C++ +>>> c1.call_f(y1) +-16 + +# Call f directly from Python +>>> c1.f(y2) +-17 + +# +# Test concrete with f not overridden +# +>>> c2 = C2(42) +>>> c2.value() +42 + +# Call f indirectly from C++ +>>> c2.call_f(y1) +16 + +# Call f directly from Python +>>> c2.f(y2) +17 + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/voidptr.cpp b/libs/python/test/voidptr.cpp new file mode 100644 index 000000000..82e412bea --- /dev/null +++ b/libs/python/test/voidptr.cpp @@ -0,0 +1,43 @@ +// Copyright Niall Douglas 2005. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +# include <boost/python/return_opaque_pointer.hpp> +# include <boost/python/def.hpp> +# include <boost/python/module.hpp> +# include <boost/python/return_value_policy.hpp> + +static void *test=(void *) 78; + +void *get() +{ + return test; +} + +void *getnull() +{ + return 0; +} + +void use(void *a) +{ + if(a!=test) + throw std::runtime_error(std::string("failed")); +} + +int useany(void *a) +{ + return a ? 1 : 0; +} + + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(voidptr_ext) +{ + bpl::def("get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def("getnull", &::getnull, bpl::return_value_policy<bpl::return_opaque_pointer>()); + bpl::def("use", &::use); + bpl::def("useany", &::useany); +} diff --git a/libs/python/test/voidptr.py b/libs/python/test/voidptr.py new file mode 100644 index 000000000..da1fa9c14 --- /dev/null +++ b/libs/python/test/voidptr.py @@ -0,0 +1,54 @@ +# Copyright Niall Douglas 2005. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + +""" +>>> from voidptr_ext import * + + + Check for correct conversion + +>>> use(get()) + + Check that None is converted to a NULL void pointer + +>>> useany(get()) +1 +>>> useany(None) +0 + + Check that we don't lose type information by converting NULL + opaque pointers to None + +>>> assert getnull() is None +>>> useany(getnull()) +0 + + Check that there is no conversion from integers ... + +>>> try: use(0) +... except TypeError: pass +... else: print 'expected a TypeError' + + ... and from strings to opaque objects + +>>> try: use("") +... except TypeError: pass +... else: print 'expected a TypeError' +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/libs/python/test/wrapper_held_type.cpp b/libs/python/test/wrapper_held_type.cpp new file mode 100644 index 000000000..e99422796 --- /dev/null +++ b/libs/python/test/wrapper_held_type.cpp @@ -0,0 +1,69 @@ +// Copyright David Abrahams 2005. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/python/register_ptr_to_python.hpp> +#include <boost/python/def.hpp> +#include <boost/python/class.hpp> +#include <boost/python/wrapper.hpp> +#include <boost/python/module.hpp> +#include <boost/python/implicit.hpp> + +#include <memory> + +struct data +{ + virtual ~data() {}; // silence compiler warnings + virtual int id() const + { + return 42; + } +}; + +std::auto_ptr<data> create_data() +{ + return std::auto_ptr<data>( new data ); +} + +void do_nothing( std::auto_ptr<data>& ){} + + +namespace bp = boost::python; + +struct data_wrapper : data, bp::wrapper< data > +{ + data_wrapper(data const & arg ) + : data( arg ) + , bp::wrapper< data >() + {} + + data_wrapper() + : data() + , bp::wrapper< data >() + {} + + virtual int id() const + { + if( bp::override id = this->get_override( "id" ) ) + return bp::call<int>(id.ptr()); // id(); + else + return data::id( ); + } + + virtual int default_id( ) const + { + return this->data::id( ); + } + +}; + +BOOST_PYTHON_MODULE(wrapper_held_type_ext) +{ + bp::class_< data_wrapper, std::auto_ptr< data > >( "data" ) + .def( "id", &data::id, &::data_wrapper::default_id ); + + bp::def( "do_nothing", &do_nothing ); + bp::def( "create_data", &create_data ); +} + +#include "module_tail.cpp" diff --git a/libs/python/test/wrapper_held_type.py b/libs/python/test/wrapper_held_type.py new file mode 100644 index 000000000..4b33ff738 --- /dev/null +++ b/libs/python/test/wrapper_held_type.py @@ -0,0 +1,34 @@ +# Copyright David Abrahams 2005. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from wrapper_held_type_ext import * +>>> d = data() +>>> print d.id() +42 +>>> do_nothing( d ) +>>> print d.id() +42 +>>> d = create_data() +>>> print d.id() +42 +>>> do_nothing( d ) +>>> print d.id() +42 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + diff --git a/libs/python/todo.html b/libs/python/todo.html new file mode 100644 index 000000000..c2c4bdf7b --- /dev/null +++ b/libs/python/todo.html @@ -0,0 +1,240 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> +<title>Boost.Python TODO list Boost</title> +<meta name="copyright" content="Copyright David Abrahams 2003. Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)" /> +<link rel="stylesheet" href="../../rst.css" type="text/css" /> +</head> +<body> +<div class="document" id="boost-python-todo-list-logo"> +<h1 class="title"><a class="reference" href="index.html">Boost.Python</a> TODO list <a class="reference" href="../../index.htm"><img alt="Boost" class="boost-logo" src="../../boost.png" /></a></h1> +<table class="docinfo" frame="void" rules="none"> +<col class="docinfo-name" /> +<col class="docinfo-content" /> +<tbody valign="top"> +<tr><th class="docinfo-name">Copyright:</th> +<td>Copyright David Abrahams 2003. Use, modification, and +distribution are subject to the Boost Software License, Version +1.0. (See accompanying file <a class="reference" href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at +<a class="reference" href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</td></tr> +</tbody> +</table> +<!-- -*- mode: rst -*- --> +<div class="contents topic"> +<p class="topic-title first"><a id="outline" name="outline">Outline</a></p> +<ul class="simple"> +<li><a class="reference" href="#class-support" id="id4" name="id4">Class Support</a><ul> +<li><a class="reference" href="#base-class-for-virtual-function-callback-wrappers" id="id5" name="id5">Base Class for Virtual Function Callback Wrappers</a></li> +</ul> +</li> +<li><a class="reference" href="#miscellaneous" id="id6" name="id6">Miscellaneous</a><ul> +<li><a class="reference" href="#support-for-enums-with-duplicate-values" id="id7" name="id7">Support for Enums with Duplicate Values</a></li> +</ul> +</li> +<li><a class="reference" href="#functions" id="id8" name="id8">Functions</a><ul> +<li><a class="reference" href="#wrapping-function-objects" id="id9" name="id9">Wrapping Function Objects</a></li> +<li><a class="reference" href="#best-match-overload-resolution" id="id10" name="id10">"Best Match" Overload Resolution</a></li> +</ul> +</li> +<li><a class="reference" href="#type-converters" id="id11" name="id11">Type Converters</a><ul> +<li><a class="reference" href="#lvalue-conversions-from-non-const-pytypeobject-s" id="id12" name="id12">Lvalue conversions from non-const <tt class="docutils literal"><span class="pre">PyTypeObject*</span></tt>s</a></li> +<li><a class="reference" href="#converter-scoping" id="id13" name="id13">Converter Scoping</a></li> +<li><a class="reference" href="#boost-tuple" id="id14" name="id14"><tt class="docutils literal"><span class="pre">boost::tuple</span></tt></a></li> +<li><a class="reference" href="#file-conversions" id="id15" name="id15"><tt class="docutils literal"><span class="pre">FILE*</span></tt> conversions</a></li> +<li><a class="reference" href="#void-conversions" id="id16" name="id16"><tt class="docutils literal"><span class="pre">void*</span></tt> conversions</a></li> +<li><a class="reference" href="#post-call-actions" id="id17" name="id17">Post-Call Actions</a></li> +<li><a class="reference" href="#pyunicode-support" id="id18" name="id18"><tt class="docutils literal"><span class="pre">PyUnicode</span></tt> Support</a></li> +<li><a class="reference" href="#ownership-metadata" id="id19" name="id19">Ownership Metadata</a></li> +</ul> +</li> +<li><a class="reference" href="#documentation" id="id20" name="id20">Documentation</a><ul> +<li><a class="reference" href="#builtin-converters" id="id21" name="id21">Builtin Converters</a></li> +<li><a class="reference" href="#internals" id="id22" name="id22">Internals</a></li> +</ul> +</li> +<li><a class="reference" href="#large-scale" id="id23" name="id23">Large Scale</a><ul> +<li><a class="reference" href="#full-threading-support" id="id24" name="id24">Full Threading Support</a></li> +<li><a class="reference" href="#langbinding" id="id25" name="id25">Langbinding</a></li> +<li><a class="reference" href="#refactoring-and-reorganization" id="id26" name="id26">Refactoring and Reorganization</a></li> +<li><a class="reference" href="#numarray-support-enhancements" id="id27" name="id27">NumArray Support Enhancements</a></li> +<li><a class="reference" href="#pyfinalize-safety" id="id28" name="id28"><tt class="docutils literal"><span class="pre">PyFinalize</span></tt> Safety</a></li> +</ul> +</li> +</ul> +</div> +<div class="section"> +<h1><a class="toc-backref" href="#id4" id="class-support" name="class-support">Class Support</a></h1> +<div class="section"> +<h2><a class="toc-backref" href="#id5" id="base-class-for-virtual-function-callback-wrappers" name="base-class-for-virtual-function-callback-wrappers">Base Class for Virtual Function Callback Wrappers</a></h2> +<ul class="simple"> +<li><a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1456023">http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1456023</a> +(bottom of message)</li> +<li><a class="reference" href="http://mail.python.org/pipermail/c++-sig/2003-August/005297.html">http://mail.python.org/pipermail/c++-sig/2003-August/005297.html</a> +(search for <tt class="docutils literal"><span class="pre">VirtualDispatcher</span></tt>) describes how callback classes +can swap ownership relationship with their Python wrappers.</li> +<li><a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301">http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301</a> +describes how this can also be used to considerably simplify +callback classes, solve some "dangling reference" problems, and +optimize the calling of non-overridden virtual functions.</li> +</ul> +</div> +</div> +<div class="section"> +<h1><a class="toc-backref" href="#id6" id="miscellaneous" name="miscellaneous">Miscellaneous</a></h1> +<div class="section"> +<h2><a class="toc-backref" href="#id7" id="support-for-enums-with-duplicate-values" name="support-for-enums-with-duplicate-values">Support for Enums with Duplicate Values</a></h2> +<blockquote> +Scott Snyder provided a patch; Dave was dissatisfied for some +reason, but maybe it should just be applied if no further action +occurs <a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/1824616">http://aspn.activestate.com/ASPN/Mail/Message/1824616</a>.</blockquote> +</div> +</div> +<div class="section"> +<h1><a class="toc-backref" href="#id8" id="functions" name="functions">Functions</a></h1> +<div class="section"> +<h2><a class="toc-backref" href="#id9" id="wrapping-function-objects" name="wrapping-function-objects">Wrapping Function Objects</a></h2> +<blockquote> +<p>It should be possible to wrap classes which support <tt class="docutils literal"><span class="pre">operator()</span></tt> +as Python methods.</p> +<p><a class="reference" href="http://mail.python.org/pipermail/c++-sig/2003-August/005184.html">http://mail.python.org/pipermail/c++-sig/2003-August/005184.html</a></p> +</blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id10" id="best-match-overload-resolution" name="best-match-overload-resolution">"Best Match" Overload Resolution</a></h2> +<blockquote> +<p>Overload resolution currently depends on the order in which <tt class="docutils literal"><span class="pre">def</span></tt> +calls are made (preferring later overloads). This should be +changed so that the best-matching overload is always selected. +This may await <a class="reference" href="#langbinding">Langbinding</a> integration, since the technology is +already in <a class="reference" href="http://luabind.sf.net">Luabind</a>.</p> +</blockquote> +</div> +</div> +<div class="section"> +<h1><a class="toc-backref" href="#id11" id="type-converters" name="type-converters">Type Converters</a></h1> +<div class="section"> +<h2><a class="toc-backref" href="#id12" id="lvalue-conversions-from-non-const-pytypeobject-s" name="lvalue-conversions-from-non-const-pytypeobject-s">Lvalue conversions from non-const <tt class="docutils literal"><span class="pre">PyTypeObject*</span></tt>s</a></h2> +<blockquote> +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1662717">http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1662717</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id13" id="converter-scoping" name="converter-scoping">Converter Scoping</a></h2> +<blockquote> +<p><a class="reference" href="http://article.gmane.org/gmane.comp.python.c++/2044">http://article.gmane.org/gmane.comp.python.c++/2044</a></p> +<p>If this gets done at all, it is going to happen in conjunction +with <a class="reference" href="#langbinding">Luabind integration</a>.</p> +</blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id14" id="boost-tuple" name="boost-tuple"><tt class="docutils literal"><span class="pre">boost::tuple</span></tt></a></h2> +<blockquote> +Conversions to and from Python would be nice. See +<a class="reference" href="http://news.gmane.org/find-root.php?message_id=%3cuvewak97m.fsf%40boost%2dconsulting.com%3e">http://news.gmane.org/find-root.php?message_id=%3cuvewak97m.fsf%40boost%2dconsulting.com%3e</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id15" id="file-conversions" name="file-conversions"><tt class="docutils literal"><span class="pre">FILE*</span></tt> conversions</a></h2> +<blockquote> +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/1411366">http://aspn.activestate.com/ASPN/Mail/Message/1411366</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id16" id="void-conversions" name="void-conversions"><tt class="docutils literal"><span class="pre">void*</span></tt> conversions</a></h2> +<blockquote> +Pointers to <em>cv</em> <tt class="docutils literal"><span class="pre">void</span></tt> should be able to be passed and +returned as opaque values.</blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id17" id="post-call-actions" name="post-call-actions">Post-Call Actions</a></h2> +<blockquote> +From-Python converters should be passed an extra reference to a +chain of post-call actions in the Policies object, where they can +register an additional action. See the end of +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1755435">http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1755435</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id18" id="pyunicode-support" name="pyunicode-support"><tt class="docutils literal"><span class="pre">PyUnicode</span></tt> Support</a></h2> +<blockquote> +<p>Review and possibly incorporate changes from <a class="reference" href="mailto:qinlj-at-solidshare.com">Lijun Qin</a> at +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1771145">http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1771145</a></p> +</blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id19" id="ownership-metadata" name="ownership-metadata">Ownership Metadata</a></h2> +<blockquote> +In the thread at +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301">http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301</a>, +Niall Douglas describes an idea for solving some "false" +dangling pointer/reference return errors by attaching data about +objects which lets the framework determine that the reference +count on an object doesn't tell us anything about the lifetime +of its data.</blockquote> +</div> +</div> +<div class="section"> +<h1><a class="toc-backref" href="#id20" id="documentation" name="documentation">Documentation</a></h1> +<div class="section"> +<h2><a class="toc-backref" href="#id21" id="builtin-converters" name="builtin-converters">Builtin Converters</a></h2> +<blockquote> +Builtin correspondences between builtiin Python types and C++ +types need to be documented</blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id22" id="internals" name="internals">Internals</a></h2> +<blockquote> +<p>The structure of the framework needs to get documented; <a class="reference" href="mailto:brett.calcott-at-paradise.net.nz">Brett +Calcott</a> has promised to turn <a class="reference" href="doc/internals.html">this document</a> into something fit +for users</p> +</blockquote> +</div> +</div> +<div class="section"> +<h1><a class="toc-backref" href="#id23" id="large-scale" name="large-scale">Large Scale</a></h1> +<div class="section"> +<h2><a class="toc-backref" href="#id24" id="full-threading-support" name="full-threading-support">Full Threading Support</a></h2> +<blockquote> +Various people have proposed patches to improve threading support +in Boost.Python: see the thread at +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/1826544">http://aspn.activestate.com/ASPN/Mail/Message/1826544</a> and +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/1865842">http://aspn.activestate.com/ASPN/Mail/Message/1865842</a> for some +examples. The only problem is that these are incomplete +solutions and verifying that we <em>do</em> have a complete solution is +going to take some time and attention.</blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id25" id="langbinding" name="langbinding">Langbinding</a></h2> +<blockquote> +This project to generalizes Boost.Python to work for other +languages, initially Lua. See discussions at +<a class="reference" href="http://lists.sourceforge.net/lists/listinfo/boost-langbinding">http://lists.sourceforge.net/lists/listinfo/boost-langbinding</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id26" id="refactoring-and-reorganization" name="refactoring-and-reorganization">Refactoring and Reorganization</a></h2> +<blockquote> +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1673338">http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1673338</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id27" id="numarray-support-enhancements" name="numarray-support-enhancements">NumArray Support Enhancements</a></h2> +<blockquote> +Consider integrating the enhancements described in +<a class="reference" href="http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1757092">http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1757092</a></blockquote> +</div> +<div class="section"> +<h2><a class="toc-backref" href="#id28" id="pyfinalize-safety" name="pyfinalize-safety"><tt class="docutils literal"><span class="pre">PyFinalize</span></tt> Safety</a></h2> +<blockquote> +<p>Currently Boost.Python has several global (or function-static) +objects whose existence keeps reference counts from dropping to +zero until the Boost.Python shared object is unloaded. This can +cause a crash because when the reference counts <em>do</em> go to zero, +there's no interpreter. In order to make it safe to call +<tt class="docutils literal"><span class="pre">PyFinalize()</span></tt> we must register an <tt class="docutils literal"><span class="pre">atexit</span></tt> routine which +destroys these objects and releases all Python reference counts +so that Python can clean them up while there's still an +interpreter. <a class="reference" href="mailto:dirk-at-gerrits.homeip.net">Dirk Gerrits</a> has promised to do this job.</p> +</blockquote> +</div> +</div> +</div> +</body> +</html> diff --git a/libs/python/todo.txt b/libs/python/todo.txt new file mode 100644 index 000000000..fb4f1c3c3 --- /dev/null +++ b/libs/python/todo.txt @@ -0,0 +1,206 @@ +.. -*- mode: rst -*- + +==================================== + Boost.Python_ TODO list |(logo)|__ +==================================== + +.. |(logo)| image:: ../../boost.png + :alt: Boost + :class: boost-logo + +__ ../../index.htm + +.. _`Boost.Python`: index.html + +:copyright: Copyright David Abrahams 2003. Use, modification, and + distribution are subject to the Boost Software License, Version + 1.0. (See accompanying file `LICENSE_1_0.txt`_ or copy at + http://www.boost.org/LICENSE_1_0.txt) + +.. contents:: Outline + +.. _`LICENSE_1_0.txt`: ../../LICENSE_1_0.txt + +Class Support +============= + +Base Class for Virtual Function Callback Wrappers +------------------------------------------------- + +* http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1456023 + (bottom of message) + +* http://mail.python.org/pipermail/c++-sig/2003-August/005297.html + (search for ``VirtualDispatcher``) describes how callback classes + can swap ownership relationship with their Python wrappers. + +* http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301 + describes how this can also be used to considerably simplify + callback classes, solve some "dangling reference" problems, and + optimize the calling of non-overridden virtual functions. + +Miscellaneous +============= + +Support for Enums with Duplicate Values +--------------------------------------- + + Scott Snyder provided a patch; Dave was dissatisfied for some + reason, but maybe it should just be applied if no further action + occurs http://aspn.activestate.com/ASPN/Mail/Message/1824616. + + +Functions +========= + +Wrapping Function Objects +-------------------------- + + It should be possible to wrap classes which support ``operator()`` + as Python methods. + + http://mail.python.org/pipermail/c++-sig/2003-August/005184.html + + +"Best Match" Overload Resolution +-------------------------------- + + Overload resolution currently depends on the order in which ``def`` + calls are made (preferring later overloads). This should be + changed so that the best-matching overload is always selected. + This may await Langbinding_ integration, since the technology is + already in Luabind_. + + .. _Luabind: http://luabind.sf.net + +Type Converters +=============== + +Lvalue conversions from non-const ``PyTypeObject*``\ s +------------------------------------------------------ + + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1662717 + +Converter Scoping +----------------- + + http://article.gmane.org/gmane.comp.python.c++/2044 + + If this gets done at all, it is going to happen in conjunction + with `Luabind integration`__. + + __ Langbinding_ + + +``boost::tuple`` +---------------- + + Conversions to and from Python would be nice. See + http://news.gmane.org/find-root.php?message_id=%3cuvewak97m.fsf%40boost%2dconsulting.com%3e + +``FILE*`` conversions +--------------------- + + http://aspn.activestate.com/ASPN/Mail/Message/1411366 + +``void*`` conversions +--------------------- + + Pointers to *cv* ``void`` should be able to be passed and + returned as opaque values. + +Post-Call Actions +----------------- + + From-Python converters should be passed an extra reference to a + chain of post-call actions in the Policies object, where they can + register an additional action. See the end of + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1755435 + +``PyUnicode`` Support +--------------------- + + Review and possibly incorporate changes from `Lijun Qin`_ at + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1771145 + + .. _`Lijun Qin`: mailto:qinlj-at-solidshare.com + +Ownership Metadata +------------------ + + In the thread at + http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1860301, + Niall Douglas describes an idea for solving some "false" + dangling pointer/reference return errors by attaching data about + objects which lets the framework determine that the reference + count on an object doesn't tell us anything about the lifetime + of its data. + +Documentation +============= + +Builtin Converters +------------------ + + Builtin correspondences between builtiin Python types and C++ + types need to be documented + +Internals +--------- + + The structure of the framework needs to get documented; `Brett + Calcott`_ has promised to turn `this document`__ into something fit + for users + + __ doc/internals.html + + .. _`Brett Calcott`: mailto:brett.calcott-at-paradise.net.nz + + +Large Scale +=========== + +Full Threading Support +---------------------- + + Various people have proposed patches to improve threading support + in Boost.Python: see the thread at + http://aspn.activestate.com/ASPN/Mail/Message/1826544 and + http://aspn.activestate.com/ASPN/Mail/Message/1865842 for some + examples. The only problem is that these are incomplete + solutions and verifying that we *do* have a complete solution is + going to take some time and attention. + +Langbinding +----------- + + This project to generalizes Boost.Python to work for other + languages, initially Lua. See discussions at + http://lists.sourceforge.net/lists/listinfo/boost-langbinding + +Refactoring and Reorganization +------------------------------ + + http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1673338 + +NumArray Support Enhancements +----------------------------- + + Consider integrating the enhancements described in + http://aspn.activestate.com/ASPN/Mail/Message/C++-sig/1757092 + +``PyFinalize`` Safety +--------------------- + + Currently Boost.Python has several global (or function-static) + objects whose existence keeps reference counts from dropping to + zero until the Boost.Python shared object is unloaded. This can + cause a crash because when the reference counts *do* go to zero, + there's no interpreter. In order to make it safe to call + ``PyFinalize()`` we must register an ``atexit`` routine which + destroys these objects and releases all Python reference counts + so that Python can clean them up while there's still an + interpreter. `Dirk Gerrits`_ has promised to do this job. + + .. _`Dirk Gerrits`: mailto:dirk-at-gerrits.homeip.net + |