From 4fd20185e986bcb6c2b4bd7c0e85852b6ca36364 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 9 Oct 2002 02:52:47 +0000 Subject: [PATCH] Clean up Boost.Python v1 flotsam, update documentation [SVN r15815] --- doc/building.html | 434 ++++--- doc/comparisons.html | 231 ---- doc/cross_module.html | 336 ----- doc/data_structures.txt | 192 --- doc/enums.html | 120 -- doc/example1.html | 75 -- doc/exporting_classes.html | 143 --- doc/extending.html | 73 -- doc/index.html | 233 +--- doc/inheritance.html | 166 --- doc/overloading.html | 155 --- doc/overriding.html | 208 --- doc/pickle.html | 272 ---- doc/pointers.html | 148 --- doc/richcmp.html | 106 -- doc/special.html | 973 -------------- doc/under-the-hood.html | 61 - doc/v2/acknowledgments.html | 111 +- doc/v2/callbacks.html | 385 +++--- doc/v2/def.html | 1 + doc/v2/faq.html | 4 +- doc/v2/index.html | 56 +- doc/v2/python.html | 108 ++ doc/v2/reference.html | 94 +- doc/v2/scope.html | 13 +- example/Attic/project.zip | Bin 0 -> 1469 bytes example/project.zip | Bin 0 -> 1469 bytes include/boost/python.hpp | 62 + include/boost/python/detail/module_init.hpp | 53 - include/boost/python/errors.hpp | 2 - include/boost/python/init.hpp | 6 +- include/boost/python/operators.hpp | 851 +++++------- include/boost/python/operators2.hpp | 340 ----- src/converter/registry.cpp | 2 +- src/errors.cpp | 8 +- test/Jamfile | 3 +- test/comprehensive.cpp | 1265 ------------------ test/comprehensive.hpp | 235 ---- test/comprehensive.py | 1281 ------------------- 39 files changed, 1180 insertions(+), 7626 deletions(-) delete mode 100644 doc/comparisons.html delete mode 100644 doc/cross_module.html delete mode 100644 doc/data_structures.txt delete mode 100644 doc/enums.html delete mode 100644 doc/example1.html delete mode 100644 doc/exporting_classes.html delete mode 100644 doc/extending.html delete mode 100644 doc/inheritance.html delete mode 100644 doc/overloading.html delete mode 100644 doc/overriding.html delete mode 100644 doc/pickle.html delete mode 100644 doc/pointers.html delete mode 100644 doc/richcmp.html delete mode 100644 doc/special.html delete mode 100644 doc/under-the-hood.html create mode 100644 doc/v2/python.html create mode 100644 example/Attic/project.zip create mode 100644 example/project.zip create mode 100644 include/boost/python.hpp delete mode 100644 include/boost/python/detail/module_init.hpp delete mode 100755 include/boost/python/operators2.hpp delete mode 100644 test/comprehensive.cpp delete mode 100644 test/comprehensive.hpp delete mode 100644 test/comprehensive.py diff --git a/doc/building.html b/doc/building.html index cdca6b97..d76a708c 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1,222 +1,294 @@ - + + + + + - Building an Extension Module + Boost.Python - Building and Testing + -
-

c++boost.gif (8819 bytes)Building an - Extension Module

+ + + + -

Building Boost.Python

+ + +
+

+

+
+

Boost.Python

-

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

Building and Testing

+
+
-

Configuration

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

Contents

+ +
+
Requirements
+ +
Building Boost.Python
+ +
+
+
Configuration
+ +
Results
+ +
Testing
+
+
+ +
Building your Extension Module
+ +
Build Variants
+
+
+ +

Requirements

+ Boost.Python requires Python 2.2 or + later. + +

Building Boost.Python

+ +

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

+ +

Configuration

+ You may need to configure the following variables to point Boost.Build at + your Python installation: + + + + + + + + + + + + + + + + -
Variable NameSemanticsDefaultNotes
PYTHON_ROOTThe root directory of your Python installation
- - + + + + + + + + + + - - + - - + - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + - - + -
Variable Name Semantics Default Notes -
PYTHON_ROOT - The root directory of your Python installation Windows: c:/tools/python - Unix: /usr/local - On Unix, this is the --with-prefix= directory - used to configure Python + Unix: /usr/localOn Unix, this is the --with-prefix= directory used + to configure Python
PYTHON_VERSIONThe The 2-part python Major.Minor version number2.2
PYTHON_VERSION - The The 2-part python Major.Minor version number - Windows: 2.1 - Unix: 1.5 Be sure not to include a third number, e.g. not - "2.2.1", even if that's the version you - have. + "2.2.1", even if that's the version you have.
PYTHON_INCLUDES - path to Python #include directories - Autoconfigured from PYTHON_ROOT +
PYTHON_INCLUDES
PYTHON_LIB_PATH - path to Python library object. - Autoconfigured from PYTHON_ROOT + path to Python #include directories
PYTHON_STDLIB_PATH - path to Python standard library modules - Autoconfigured from PYTHON_ROOT + Autoconfigured from PYTHON_ROOT
PYTHON_LIB_PATHpath to Python library object.Autoconfigured from PYTHON_ROOT
PYTHON_STDLIB_PATHpath to Python standard library modulesAutoconfigured from PYTHON_ROOT
CYGWIN_ROOTpath to the user's Cygwin installation
CYGWIN_ROOT - path to the user's Cygwin installation - Cygwin only. This and the following two settings are - useful when building with multiple toolsets on Windows, since - Cygwin requires a different build of Python. +
GCC_PYTHON_ROOT - path to the user's Cygwin Python installation - $(CYGWIN_ROOT)/usr/local - Cygwin only + Cygwin only. This and the + following two settings are useful when building with multiple + toolsets on Windows, since Cygwin requires a different build of + Python.
GCC_DEBUG_PYTHON_ROOT - path to the user's Cygwin pydebug build - $(CYGWIN_ROOT)/usr/local/pydebug - Cygwin only +
GCC_PYTHON_ROOT
+ path to the user's Cygwin Python installation -

Results

-

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

Testing

-

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

+ Cygwin only + + + + GCC_DEBUG_PYTHON_ROOT + + path to the user's Cygwin pydebug build + + $(CYGWIN_ROOT)/usr/local/pydebug + + Cygwin only + + + +

Results

+ +

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

+ +

Testing

+ +

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

+ +
-bjam -sTOOLS=toolset test
+bjam -sTOOLS=toolset test
 
-
-This will -update all of the Boost.Python v1 test and example targets. The tests -are relatively quiet by default. To get more-verbose output, you might try -
+
+ This will update all of the Boost.Python v1 test and example targets. The + tests are relatively quiet by default. To get more-verbose output, you + might try + +
-bjam -sTOOLS=toolset -sPYTHON_TEST_ARGS=-v test
+bjam -sTOOLS=toolset -sPYTHON_TEST_ARGS=-v test
 
-
-which will print each test's Python code with the expected output as -it passes. +
+ which will print each test's Python code with the expected output as it + passes. -

Building your Extension Module

+

Building your Extension Module

+ Though there are other approaches, the easiest way to build an extension + module using Boost.Python is with Boost.Build. Until Boost.Build v2 is + released, cross-project build dependencies are not supported, so it works + most smoothly if you add a new subproject to your boost installation. The + libs/python/example subdirectory of your boost installation + contains a minimal example (along with many extra sources). To copy the + example subproject: - Though there are other approaches, the easiest way to build an - extension module using Boost.Python is with Boost.Build. Until - Boost.Build v2 is released, cross-project build dependencies are - not supported, so it works most smoothly if you add a new - subproject to your boost installation. The - libs/python/example subdirectory of your boost - installation contains a minimal example (along with many extra - sources). To copy the example subproject: - -
    +
    1. Create a new subdirectory in, libs/python, say - libs/python/my_project. + libs/python/my_project.
    2. -
    3. Copy libs/python/example/Jamfile - to your new directory. +
    4. Copy libs/python/example/Jamfile to your new + directory.
    5. -
    6. Edit the Jamfile as appropriate for your project. You'll - want to change the "subproject" rule - invocation at the top, and the names of some of the source files - and/or targets. +
    7. Edit the Jamfile as appropriate for your project. You'll want to + change the "subproject" rule invocation at the top, and + the names of some of the source files and/or targets.
    8. +
    + If you can't modify or copy your boost installation, the alternative is + to create your own Boost.Build project. A similar example you can use as + a starting point is available in this archive. You'll need to edit the + Jamfile and Jamrules files, depending on the relative location of your + Boost installation and the new project. Note that automatic testing of + extension modules is not available in this configuration. -
+

Build Variants

+ Three variant + configurations of all python-related targets are supported, and can be + selected by setting the BUILD + variable: - If you can't modify or copy your boost installation, the - alternative is to create your own Boost.Build project. A similar - example you can use as a starting point is available in this archive. You'll - need to edit the Jamfile and Jamrules files, depending on the - relative location of your Boost installation and the new - project. Note that automatic testing of extension modules is not - available in this configuration. + - +

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

-

The first two variants of the boost_python - library are built by default, and are compatible with the - default Python distribution. The debug-python - variant corresponds to a specially-built debugging version of - Python. On Unix platforms, this python is built by adding - --with-pydebug when configuring the Python - build. On Windows, the debugging version of Python is generated - by the "Win32 Debug" target of the - PCBuild.dsw Visual C++ 6.0 project in the - PCBuild subdirectory of your Python distribution. +

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

+
- Extension modules built with Python debugging enabled are not - link-compatible with a non-debug build of Python. Since few - people actually have a debug build of Python (it doesn't come - with the standard distribution), the normal - debug variant builds modules which are compatible - with ordinary Python. +

© Copyright David Abrahams 2002. 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.

+

Updated: O8 October, 2002 (David Abrahams)

+ + -

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

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

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


- Next: Wrapping Enums Previous: A Peek Under the Hood Up: Top - -
-

© Copyright David Abrahams 2002. 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. - -

Updated: May 15, 2002 (David Abrahams) -

diff --git a/doc/comparisons.html b/doc/comparisons.html deleted file mode 100644 index 57cec744..00000000 --- a/doc/comparisons.html +++ /dev/null @@ -1,231 +0,0 @@ - - - Comparisons with Other Systems - -
-

- c++boost.gif (8819 bytes)
- Comparisons with - Other Systems -

- -

CXX

-

- Like Boost.Python, CXX attempts to - provide a C++-oriented interface to Python. In most cases, as with the - boost library, it relieves the user from worrying about - reference-counts. Both libraries automatically convert thrown C++ - exceptions into Python exceptions. As far as I can tell, CXX has no - support for subclassing C++ extension types in Python. An even - more significant difference is that a user's C++ code is still basically - ``dealing with Python objects'', though they are wrapped in - C++ classes. This means such jobs as argument parsing and conversion are - still left to be done explicitly by the user. - -

- CXX claims to interoperate well with the C++ Standard Library - (a.k.a. STL) by providing iterators into Python Lists and Dictionaries, - but the claim is unfortunately unsupportable. The problem is that in - general, access to Python sequence and mapping elements through - iterators requires the use of proxy objects as the return value of - iterator dereference operations. This usage conflicts with the basic - ForwardIterator requirements in - section 24.1.3 of the standard (dereferencing must produce a - reference). Although you may be able to use these iterators with some - operations in some standard library implementations, it is neither - guaranteed to work nor portable. - -

- As far as I can tell, CXX enables one to write what is essentially - idiomatic Python code in C++, manipulating Python objects through the - same fully-generic interfaces we use in Python. While you're hardly - programming directly to the ``bare metal'' with CXX, it basically - presents a ``C++-ized'' version of the Python 'C' API. Some fraction of - that capability is available in Boost.Python through boost/python/objects.hpp, - which provides C++ objects corresponding to Python lists, tuples, - strings, and dictionaries, and through boost/python/callback.hpp, - which allows you to call back into python with C++ arguments. - -

- Paul F. Dubois, the original - author of CXX, has told me that what I've described is only half of the - picture with CXX, but I never understood his explanation well-enough to - fill in the other half. Here is his response to the commentary above: - -

-``My intention with CXX was not to do what you are doing. It was to enable a -person to write an extension directly in C++ rather than C. I figured others had -the wrapping business covered. I thought maybe CXX would provide an easier -target language for those making wrappers, but I never explored -that.''
-Paul Dubois -
- -

SWIG

-

- SWIG is an impressively mature tool - for exporting an existing ANSI 'C' interface into various scripting - languages. Swig relies on a parser to read your source code and produce - additional source code files which can be compiled into a Python (or - Perl or Tcl) extension module. It has been successfully used to create - many Python extension modules. Like Boost.Python, SWIG is trying to allow an - existing interface to be wrapped with little or no change to the - existing code. The documentation says ``SWIG parses a form of ANSI C - syntax that has been extended with a number of special directives. As a - result, interfaces are usually built by grabbing a header file and - tweaking it a little bit.'' For C++ interfaces, the tweaking has often - proven to amount to more than just a little bit. One user - writes: - -

``The problem with swig (when I used it) is that it - couldnt handle templates, didnt do func overloading properly etc. For - ANSI C libraries this was fine. But for usual C++ code this was a - problem. Simple things work. But for anything very complicated (or - realistic), one had to write code by hand. I believe Boost.Python doesn't have - this problem[sic]... IMHO overloaded functions are very important to - wrap correctly.''
-Prabhu Ramachandran -
- -

- By contrast, Boost.Python doesn't attempt to parse C++ - the problem is simply - too complex to do correctly. Technically, one does - write code by hand to use Boost.Python. The goal, however, has been to make - that code nearly as simple as listing the names of the classes and - member functions you want to expose in Python. - -

SIP

-

- SIP - is a system similar to SWIG, though seemingly more - C++-oriented. The author says that like Boost.Python, SIP supports overriding - extension class member functions in Python subclasses. It appears to - have been designed specifically to directly support some features of - PyQt/PyKDE, which is its primary client. Documentation is almost - entirely missing at the time of this writing, so a detailed comparison - is difficult. - -

ILU

-

- ILU - is a very ambitious project which tries to describe a module's interface - (types and functions) in terms of an Interface - Specification Language (ISL) so that it can be uniformly interfaced - to a wide range of computer languages, including Common Lisp, C++, C, - Modula-3, and Python. ILU can parse the ISL to generate a C++ language - header file describing the interface, of which the user is expected to - provide an implementation. Unlike Boost.Python, this means that the system - imposes implementation details on your C++ code at the deepest level. It - is worth noting that some of the C++ names generated by ILU are supposed - to be reserved to the C++ implementation. It is unclear from the - documentation whether ILU supports overriding C++ virtual functions in Python. - -

GRAD

-

- GRAD - is another very ambitious project aimed at generating Python wrappers for - interfaces written in ``legacy languages'', among which C++ is the first one - implemented. Like SWIG, it aims to parse source code and automatically - generate wrappers, though it appears to take a more sophisticated approach - to parsing in general and C++ in particular, so it should do a much better - job with C++. It appears to support function overloading. The - documentation is missing a lot of information I'd like to see, so it is - difficult to give an accurate and fair assessment. I am left with the - following questions: -

-

- Anyone in the possession of the answers to these questions will earn my - gratitude for a write-up ;-) - -

Zope ExtensionClasses

-

- - ExtensionClasses in Zope use the same underlying mechanism as Boost.Python - to support subclassing of extension types in Python, including - multiple-inheritance. Both systems support pickling/unpickling of - extension class instances in very similar ways. Both systems rely on the - same ``Don - Beaudry Hack'' that also inspired Don's MESS System. -

- The major differences are: -

-

- Next: A Simple Example Using Boost.Python - Previous: A Brief Introduction to writing Python Extension Modules - Up: Top -

- © Copyright David Abrahams 2000. 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. -

- Updated: Mar 6, 2001 -

- diff --git a/doc/cross_module.html b/doc/cross_module.html deleted file mode 100644 index 08c39bfe..00000000 --- a/doc/cross_module.html +++ /dev/null @@ -1,336 +0,0 @@ - - -Cross-extension-module dependencies - -
- -c++boost.gif (8819 bytes) - -
-

Cross-extension-module dependencies

- -It is good programming practice to organize large projects as modules -that interact with each other via well defined interfaces. With -Boost.Python it is possible to reflect this organization at the C++ -level at the Python level. This is, each logical C++ module can be -organized as a separate Python extension module. - -

-At first sight this might seem natural and straightforward. However, it -is a fairly complex problem to establish cross-extension-module -dependencies while maintaining the same ease of use Boost.Python -provides for classes that are wrapped in the same extension module. To -a large extent this complexity can be hidden from the author of a -Boost.Python extension module, but not entirely. - -


-

The recipe

- -Suppose there is an extension module that exposes certain instances of -the C++ std::vector template library such that it can be used -from Python in the following manner: - -
-import std_vector
-v = std_vector.double([1, 2, 3, 4])
-v.push_back(5)
-v.size()
-
- -Suppose the std_vector module is done well and reflects all -C++ functions that are useful at the Python level, for all C++ built-in -data types (std_vector.int, std_vector.long, etc.). - -

-Suppose further that there is statistic module with a C++ class that -has constructors or member functions that use or return a -std::vector. For example: - -

-class xy {
-  public:
-    xy(const std::vector<double>& x, const std::vector<double>& y) : m_x(x), m_y(y) {}
-    const std::vector<double>& x() const { return m_x; }
-    const std::vector<double>& y() const { return m_y; }
-    double correlation();
-  private:
-    std::vector<double> m_x;
-    std::vector<double> m_y;
-}
-
- -What is more natural than reusing the std_vector extension -module to expose these constructors or functions to Python? - -

-Unfortunately, what seems natural needs a little work in both the -std_vector and the statistics module. - -

-In the std_vector extension module, -std::vector<double> is exposed to Python in the usual -way with the class_builder<> template. To also enable the -automatic conversion of std::vector<double> function -arguments or return values in other Boost.Python C++ modules, the -converters that convert a std::vector<double> C++ object -to a Python object and vice versa (i.e. the to_python() and -from_python() template functions) have to be exported. For -example: - -

-  #include <boost/python/cross_module.hpp>
-  //...
-  class_builder<std::vector<double> > v_double(std_vector_module, "double");
-  export_converters(v_double);
-
- -In the extension module that wraps class xy we can now import -these converters with the import_converters<> template. -For example: - -
-  #include <boost/python/cross_module.hpp>
-  //...
-  import_converters<std::vector<double> > v_double_converters("std_vector", "double");
-
- -That is all. All the attributes that are defined for -std_vector.double in the std_vector Boost.Python -module will be available for the returned objects of xy.x() -and xy.y(). Similarly, the constructor for xy will -accept objects that were created by the std_vectormodule. - -
-

Placement of import_converters<> template instantiations

- -import_converts<> can be viewed as a drop-in replacement -for class_wrapper<>, and the recommendations for the -placement of class_wrapper<> template instantiations -also apply to to import_converts<>. In particular, it is -important that an instantiation of class_wrapper<> is -visible to any code which wraps a C++ function with a T, -T*, const T&, etc. parameter or return value. -Therefore you may want to group all class_wrapper<> and -import_converts<> instantiations at the top of your -module's init function, then def() the member functions later -to avoid problems with inter-class dependencies. - -
-

Non-copyable types

- -export_converters() instantiates C++ template functions that -invoke the copy constructor of the wrapped type. For a type that is -non-copyable this will result in compile-time error messages. In such a -case, export_converters_noncopyable() can be used to export -the converters that do not involve the copy constructor of the wrapped -type. For example: - -
-class_builder<store> py_store(your_module, "store");
-export_converters_noncopyable(py_store);
-
- -The corresponding import_converters<> statement does not -need any special attention: - -
-import_converters<store> py_store("noncopyable_export", "store");
-
- -
-

Python module search path

- -The std_vector and statistics modules can now be used -in the following way: - -
-import std_vector
-import statistics
-x = std_vector.double([1, 2, 3, 4])
-y = std_vector.double([2, 4, 6, 8])
-xy = statistics.xy(x, y)
-xy.correlation()
-
- -In this example it is clear that Python has to be able to find both the -std_vector and the statistics extension module. In -other words, both extension modules need to be in the Python module -search path (sys.path). - -

-The situation is not always this obvious. Suppose the -statistics module has a random() function that -returns a vector of random numbers with a given length: - -

-import statistics
-x = statistics.random(5)
-y = statistics.random(5)
-xy = statistics.xy(x, y)
-xy.correlation()
-
- -A naive user will not easily anticipate that the std_vector -module is used to pass the x and y vectors around. If -the std_vector module is in the Python module search path, -this form of ignorance is of no harm. On the contrary, we are glad -that we do not have to bother the user with details like this. - -

-If the std_vector module is not in the Python module search -path, a Python exception will be raised: - -

-Traceback (innermost last):
-  File "foo.py", line 2, in ?
-    x = statistics.random(5)
-ImportError: No module named std_vector
-
- -As is the case with any system of a non-trivial complexity, it is -important that the setup is consistent and complete. - -
-

Two-way module dependencies

- -Boost.Python supports two-way module dependencies. This is best -illustrated by a simple example. - -

-Suppose there is a module ivect that implements vectors of -integers, and a similar module dvect that implements vectors -of doubles. We want to be able do convert an integer vector to a double -vector and vice versa. For example: - -

-import ivect
-iv = ivect.ivect((1,2,3,4,5))
-dv = iv.as_dvect()
-
- -The last expression will implicitly import the dvect module in -order to enable the conversion of the C++ representation of -dvect to a Python object. The analogous is possible for a -dvect: - -
-import dvect
-dv = dvect.dvect((1,2,3,4,5))
-iv = dv.as_ivect()
-
- -Now the ivect module is imported implicitly. - -

-Note that the two-way dependencies are possible because the -dependencies are resolved only when needed. This is, the initialization -of the ivect module does not rely on the dvect -module, and vice versa. Only if as_dvect() or -as_ivect() is actually invoked will the corresponding module -be implicitly imported. This also means that, for example, the -dvect module does not have to be available at all if -as_dvect() is never used. - -


-

Clarification of compile-time and link-time dependencies

- -Boost.Python's support for resolving cross-module dependencies at -runtime does not imply that compile-time dependencies are eliminated. -For example, the statistics extension module in the example above will -need to #include <vector>. This is immediately obvious -from the definition of class xy. - -

-If a library is wrapped that consists of both header files and compiled -components (e.g. libdvect.a, dvect.lib, etc.), both -the Boost.Python extension module with the -export_converters() statement and the module with the -import_converters<> statement need to be linked against -the object library. Ideally one would build a shared library (e.g. -libdvect.so, dvect.dll, etc.). However, this -introduces the issue of having to configure the search path for the -dynamic loading correctly. For small libraries it is therefore often -more convenient to ignore the fact that the object files are loaded -into memory more than once. - -


-

Summary of motivation for cross-module support

- -The main purpose of Boost.Python's cross-module support is to allow for -a modular system layout. With this support it is straightforward to -reflect C++ code organization at the Python level. Without the -cross-module support, a multi-purpose module like std_vector -would be impractical because the entire wrapper code would somehow have -to be duplicated in all extension modules that use it, making them -harder to maintain and harder to build. - -

-Another motivation for the cross-module support is that two extension -modules that wrap the same class cannot both be imported into Python. -For example, if there are two modules A and B that -both wrap a given class X, this will work: - -

-import A
-x = A.X()
-
- -This will also work: - -
-import B
-x = B.X()
-
- -However, this will fail: - -
-import A
-import B
-python: /net/cci/rwgk/boost/boost/python/detail/extension_class.hpp:866:
-static void boost::python::detail::class_registry<X>::register_class(boost::python::detail::extension_class_base *):
-Assertion `static_class_object == 0' failed.
-Abort
-
- -A good solution is to wrap class X only once. Depending on the -situation, this could be done by module A or B, or an -additional small extension module that only wraps and exports -class X. - -

-Finally, there can be important psychological or political reasons for -using the cross-module support. If a group of classes is lumped -together with many others in a huge module, the authors will have -difficulties in being identified with their work. The situation is -much more transparent if the work is represented by a module with a -recognizable name. This is not just a question of strong egos, but also -of getting credit and funding. - -


-

Why not use export_converters() universally?

- -There is some overhead associated with the Boost.Python cross-module -support. Depending on the platform, the size of the code generated by -export_converters() is roughly 10%-20% of that generated -by class_builder<>. For a large extension module with -many wrapped classes, this could mean a significant difference. -Therefore the general recommendation is to use -export_converters() only for classes that are likely to -be used as function arguments or return values in other modules. - -
-© Copyright Ralf W. Grosse-Kunstleve 2001. 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. - -

-Updated: April 2001 - -

diff --git a/doc/data_structures.txt b/doc/data_structures.txt deleted file mode 100644 index 90e41b91..00000000 --- a/doc/data_structures.txt +++ /dev/null @@ -1,192 +0,0 @@ -Given a real Python class 'A', a wrapped C++ class 'B', and this definition: - - class C(A, B): - def __init__(self): - B.__init__(self) - self.x = 1 - ... - - c = C() - -this diagram describes the internal structure of an instance of 'C', including -its inheritance relationships. Note that ExtensionClass is derived from -Class, and is in fact identical for all intents and purposes. - - MetaClass - +---------+ +---------+ -types.ClassType: | | | | - | | | | - | | | | - +---------+ +---------+ - ^ ^ ^ - PyClassObject | ExtensionClass | | - A: +------------+ | B: +------------+ | | - | ob_type -+-+ | ob_type -+-----+ | - | | ()<--+- __bases__ | | - | | | __dict__ -+->{...} | - | | 'B'<-+- __name__ | | - +------------+ +------------+ | - ^ ^ | - | | | - +-----+ +-------------+ | - | | | - | | Class | - | | C: +------------+ | - | | | ob_type -+------------+ - tuple:(*, *)<--+- __bases__ | - | __dict__ -+->{__module__, } - 'C' <-+- __name__ | - +------------+ - ^ (in case of inheritance from more than one - | extension class, this vector would contain - +---------------+ a pointer to an instance holder for the data - | of each corresponding C++ class) - | ExtensionInstance - | c: +---------------------+ std::vector - +----+- __class__ | +---+-- - | m_wrapped_objects -+->| * | ... - {'x': 1}<-+- __dict__ | +-|-+-- - +---------------------+ | InstanceValueHolder - | +--------------------------------+ - +-->| (contains a C++ instance of B) | - +--------------------------------+ - - - - - - -In our inheritance test cases in extclass_demo.cpp/test_extclass.py, we have the -following C++ inheritance hierarchy: - - +-----+ +----+ - | A1 | | A2 | - +-----+ +----+ - ^ ^ ^ ^ ^ - | | | | | - +-----+ | +---------+-----+ - | | | | - | +---+----------+ - .......!...... | | - : A_callback : +-+--+ +-+--+ - :............: | B1 | | B2 | - +----+ +----+ - ^ - | - +-------+---------+ - | | - +-+-+ ......!....... - | C | : B_callback : - +---+ :............: - - -A_callback and B_callback are used as part of the wrapping mechanism but not -represented in Python. C is also not represented in Python but is delivered -there polymorphically through a smart pointer. - -This is the data structure in Python. - - ExtensionClass - A1: +------------+ - ()<--+- __bases__ | - | __dict__ -+->{...} - +------------+ - ^ - | ExtensionInstance - | a1: +---------------------+ vec InstanceValueHolder - +---------+- __class__ | +---+ +---------------------+ - | | m_wrapped_objects -+->| *-+-->| contains A_callback | - | +---------------------+ +---+ +---------------------+ - | - | ExtensionInstance - | pa1_a1: +---------------------+ vec InstancePtrHolder,A1> - +---------+- __class__ | +---+ +---+ - | | m_wrapped_objects -+->| *-+-->| *-+-+ A1 - | +---------------------+ +---+ +---+ | +---+ - | +->| | - | ExtensionInstance +---+ - | pb1_a1: +---------------------+ vec InstancePtrHolder,A1> - +---------+- __class__ | +---+ +---+ - | | m_wrapped_objects -+->| *-+-->| *-+-+ B1 - | +---------------------+ +---+ +---+ | +---+ - | +->| | - | ExtensionInstance +---+ - | pb2_a1: +---------------------+ vec InstancePtrHolder,A1> - +---------+- __class__ | +---+ +---+ - | | m_wrapped_objects -+->| *-+-->| *-+-+ B2 - | +---------------------+ +---+ +---+ | +---+ - | +->| | - | +---+ - | ExtensionClass - | A2: +------------+ - | ()<--+- __bases__ | - | | __dict__ -+->{...} - | +------------+ - | ^ - | | ExtensionInstance - | a2: | +---------------------+ vec InstanceValueHolder - | +-+- __class__ | +---+ +-------------+ - | | | m_wrapped_objects -+->| *-+-->| contains A2 | - | | +---------------------+ +---+ +-------------+ - | | - | | ExtensionInstance - | pa2_a2: | +---------------------+ vec InstancePtrHolder,A2> - | +-+- __class__ | +---+ +---+ - | | | m_wrapped_objects -+->| *-+-->| *-+-+ A2 - | | +---------------------+ +---+ +---+ | +---+ - | | +->| | - | | ExtensionInstance +---+ - | pb1_a2: | +---------------------+ vec InstancePtrHolder,A2> - | +-+- __class__ | +---+ +---+ - | | | m_wrapped_objects -+->| *-+-->| *-+-+ B1 - | | +---------------------+ +---+ +---+ | +---+ - | | +->| | - | | +---+ - | | - | +---------------+------------------------------+ - | | | - +------+-------------------------+-|----------------------------+ | - | | | | | - | Class | | ExtensionClass | | ExtensionClass - | DA1: +------------+ | | B1: +------------+ | | B2: +------------+ -(*,)<---+- __bases__ | (*,*)<---+- __bases__ | (*,*)<---+- __bases__ | - | __dict__ -+->{...} | __dict__ -+->{...} | __dict__ -+->{...} - +------------+ +------------+ +------------+ - ^ ^ ^ - | ExtensionInstance | | - | da1: +---------------------+ | vec InstanceValueHolder - +-------+- __class__ | | +---+ +---------------------+ | - | m_wrapped_objects -+--|-->| *-+-->| contains A_callback | | - +---------------------+ | +---+ +---------------------+ | - +--------------------------------------+ | - | ExtensionInstance | - b1: | +---------------------+ vec InstanceValueHolder | - +-+- __class__ | +---+ +---------------------+ | - | | m_wrapped_objects -+->| *-+-->| contains B_callback | | - | +---------------------+ +---+ +---------------------+ | - | | - | ExtensionInstance | -pb1_b1: | +---------------------+ vec InstancePtrHolder,B1> | - +-+- __class__ | +---+ +---+ | - | | m_wrapped_objects -+->| *-+-->| *-+-+ B1 | - | +---------------------+ +---+ +---+ | +---+ | - | +->| | | - | ExtensionInstance +---+ | - pc_b1: | +---------------------+ vec InstancePtrHolder,B1> | - +-+- __class__ | +---+ +---+ | - | | m_wrapped_objects -+->| *-+-->| *-+-+ C | - | +---------------------+ +---+ +---+ | +---+ | - | +->| | | - | +---+ | - | | - | Class +---------------------------------------+ - | DB1: +------------+ | ExtensionInstance - (*,)<---+- __bases__ | a2: | +---------------------+ vec InstanceValueHolder - | __dict__ -+->{...} +-+- __class__ | +---+ +-------------+ - +------------+ | m_wrapped_objects -+->| *-+-->| contains A2 | - ^ +---------------------+ +---+ +-------------+ - | ExtensionInstance - db1: | +---------------------+ vec InstanceValueHolder - +-+- __class__ | +---+ +----------------------+ - | m_wrapped_objects -+-->| *-+-->| contains B1_callback | - +---------------------+ +---+ +----------------------+ diff --git a/doc/enums.html b/doc/enums.html deleted file mode 100644 index c58ca34d..00000000 --- a/doc/enums.html +++ /dev/null @@ -1,120 +0,0 @@ - - - Wrapping enums - -
-

- c++boost.gif (8819 bytes)
- Wrapping enums -

- -

Because there is in general no way to deduce that a value of arbitrary type T -is an enumeration constant, the Boost Python Library cannot automatically -convert enum values to and from Python. To handle this case, you need to decide -how you want the enum to show up in Python (since Python doesn't have -enums). Once you have done that, you can write some simple -from_python() and to_python() functions. - -

If you are satisfied with a Python int as a way to represent your enum -values, we provide a shorthand for these functions. You just need to cause -boost::python::enum_as_int_converters<EnumType> to be -instantiated, where -EnumType is your enumerated type. There are two convenient ways to do this: - -

    -
  1. Explicit instantiation: - -
    -  template class boost::python::enum_as_int_converters<my_enum>;
    -
    - -Some buggy C++ implementations require a class to be instantiated in the same -namespace in which it is defined. In that case, the simple incantation above becomes: - -
    -
    -   ...
    -} // close my_namespace
    -
    -// drop into namespace python and explicitly instantiate
    -namespace boost { namespace python {
    -  template class enum_as_int_converters<my_enum_type>;
    -}} // namespace boost::python
    -
    -namespace my_namespace { // re-open my_namespace
    -   ...
    -
    -
    - - -
  2. If you have such an implementation, you may find this technique more convenient -
    -// instantiate as base class in any namespace
    -struct EnumTypeConverters
    -    : boost::python::enum_as_int_converters<EnumType>
    -{
    -};
    -
    -
- -

Either of the above is equivalent to the following declarations: -

-BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
-
-  MyEnumType from_python(PyObject* x, boost::python::type<MyEnumType>)
-  {
-      return static_cast<MyEnum>(
-        from_python(x, boost::python::type<long>()));
-  }
-
-  MyEnumType from_python(PyObject* x, boost::python::type<const MyEnumType&>)
-  {
-      return static_cast<MyEnum>(
-        from_python(x, boost::python::type<long>()));
-  }
-
-  PyObject* to_python(MyEnumType x)
-  {
-      return to_python(static_cast<long>(x));
-  }
-BOOST_PYTHON_END_CONVERSION_NAMESPACE
-
- -

This technique defines the conversions of -MyEnumType in terms of the conversions for the built-in - long type. - -You may also want to add a bunch of lines like this to your module -initialization. These bind the corresponding enum values to the appropriate -names so they can be used from Python: - -

-mymodule.add(boost::python::make_ref(enum_value_1), "enum_value_1");
-mymodule.add(boost::python::make_ref(enum_value_2), "enum_value_2");
-...
-
- -You can also add these to an extension class definition, if your enum happens to -be local to a class and you want the analogous interface in Python: - -
-my_class_builder.add(boost::python::to_python(enum_value_1), "enum_value_1");
-my_class_builder.add(boost::python::to_python(enum_value_2), "enum_value_2");
-...
-
-

- Next: Pointers and Smart Pointers - Previous: Building an Extension Module - Up: Top -

- © Copyright David Abrahams 2000. 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. -

- Updated: Mar 6, 2001 -

- diff --git a/doc/example1.html b/doc/example1.html deleted file mode 100644 index ee01e72c..00000000 --- a/doc/example1.html +++ /dev/null @@ -1,75 +0,0 @@ - - - A Simple Example - -
-

- - -

-

- A Simple Example -

-

- Suppose we have the following C++ API which we want to expose in - Python: -

-
-#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; }
-}
-
-
-
-

- Here is the C++ code for a python module called getting_started1 - which exposes the API. -

-
-#include <boost/python/class_builder.hpp>
-namespace python = boost::python;
-
-BOOST_PYTHON_MODULE_INIT(getting_started1)
-{
-    // Create an object representing this extension module.
-    python::module_builder this_module("getting_started1");
-
-    // Add regular functions to the module.
-    this_module.def(greet, "greet");
-    this_module.def(square, "square");
-}
-
-
-

- That's it! If we build this shared library and put it on our - PYTHONPATH we can now access our C++ functions from - Python. -

-
->>> import getting_started1
->>> print getting_started1.greet()
-hello, world
->>> number = 11
->>> print number, '*', number, '=', getting_started1.square(number)
-11 * 11 = 121
-
-

- Next: Exporting Classes - Previous: Comparisons with other systems Up: - Top -

- © Copyright David Abrahams 2000. 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. -

- Updated: Mar 6, 2000 -

- diff --git a/doc/exporting_classes.html b/doc/exporting_classes.html deleted file mode 100644 index cbeb8a9e..00000000 --- a/doc/exporting_classes.html +++ /dev/null @@ -1,143 +0,0 @@ - - - Exporting Classes - -
-

- - -

-

- Exporting Classes -

-

- Now let's expose a C++ class to Python: - -

-#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!";
-  }
-}
-
-

- To expose the class, we use a class_builder in addition to the - module_builder from the previous example. Class member functions - are exposed by using the def() member function on the - class_builder: -

-#include <boost/python/class_builder.hpp>
-namespace python = boost::python;
-
-BOOST_PYTHON_MODULE_INIT(getting_started2)
-{
-    // Create an object representing this extension module.
-    python::module_builder this_module("getting_started2");
-
-    // Create the Python type object for our extension class.
-    python::class_builder<hello> hello_class(this_module, "hello");
-
-    // Add the __init__ function.
-    hello_class.def(python::constructor<std::string>());
-    // Add a regular member function.
-    hello_class.def(&hello::greet, "greet");
-
-    // Add invite() as a regular function to the module.
-    this_module.def(invite, "invite");
-
-    // Even better, invite() can also be made a member of hello_class!!!
-    hello_class.def(invite, "invite");
-}
-
-

-Now we can use the class normally from Python: - -

->>> 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!'
-
- -Notes:
    -
  • We expose the class' constructor by calling def() on the - class_builder with an argument whose type is - constructor<params>, where params - matches the list of constructor argument types: - - -
  • Regular member functions are defined by calling def() with a - member function pointer and its Python name: - -
  • Any function added to a class whose initial argument matches the class (or -any base) will act like a member function in Python. - -
  • To define a nested class, just pass the enclosing -class_builder (instead of a module_builder) as the -first argument to the nested class_builder's constructor. - - -
-

- We can even make a subclass of hello.world: - -

->>> 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!'
-
-

- Pretty cool! You can't do that with an ordinary Python extension type! - - Of course, you may now have a slightly empty feeling in the pit of - your little pythonic stomach. Perhaps you wanted to see the following - wordy invitation: - -

-'Hello from Florida, where the weather is fine! Please come soon!'
-
- - After all, invite calls hello::greet(), and you - reimplemented that in your Python subclass, wordy. If so, read on... - -

- Next: Overridable virtual functions - Previous: A Simple Example Up: - Top -

- © Copyright David Abrahams 2000. 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. -

- Updated: Mar 6, 2001 -

- diff --git a/doc/extending.html b/doc/extending.html deleted file mode 100644 index 8839ab43..00000000 --- a/doc/extending.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - A Brief Introduction to writing Python extension modules - -

- c++boost.gif (8819 bytes) -

-

- A Brief Introduction to writing Python extension modules -

-

- Interfacing any language to Python involves building a module which can - be loaded by the Python interpreter, but which isn't written in Python. - This is known as an extension module. Many of the built-in Python - libraries are constructed in 'C' this way; Python even supplies its - fundamental - types using the same mechanism. An extension module can be statically - linked with the Python interpreter, but it more commonly resides in a - shared library or DLL. -

- As you can see from The Python Extending - and Embedding Tutorial, writing an extension module normally means - worrying about -

- This last item typically occupies a great deal of code in an extension - module. Remember that Python is a completely dynamic language. A callable - object receives its arguments in a tuple; it is up to that object to extract - those arguments from the tuple, check their types, and raise appropriate - exceptions. There are numerous other tedious details that need to be - managed; too many to mention here. The Boost Python Library is designed to - lift most of that burden.
-
- -

- Another obstacle that most people run into eventually when extending - Python is that there's no way to make a true Python class in an extension - module. The typical solution is to create a new Python type in the - extension module, and then write an additional module in 100% Python. The - Python module defines a Python class which dispatches to an instance of - the extension type, which it contains. This allows users to write - subclasses of the class in the Python module, almost as though they were - sublcassing the extension type. Aside from being tedious, it's not really - the same as having a true class, because there's no way for the user to - override a method of the extension type which is called from the - extension module. Boost.Python solves this problem by taking advantage of Python's metaclass - feature to provide objects which look, walk, and hiss almost exactly - like regular Python classes. Boost.Python classes are actually cleaner than - Python classes in some subtle ways; a more detailed discussion will - follow (someday).

-

Next: Comparisons with Other Systems Up: Top

-

- © Copyright David Abrahams 2000. 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.

- diff --git a/doc/index.html b/doc/index.html index fffe13e9..f9bcc646 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,205 +1,64 @@ - - - The Boost Python Library (Boost.Python) - -

- c++boost.gif (8819 bytes)
The Boost Python Library (Boost.Python) -

+ -

Synopsis

-

- Use the Boost Python Library to quickly and easily export a C++ library to Python such that the Python interface is - very similar to the C++ interface. It is designed to be minimally - intrusive on your C++ design. In most cases, you should not have to alter - your C++ classes in any way in order to use them with Boost.Python. The system - should simply ``reflect'' your C++ classes and functions into - Python. + + + + + -

+ Boost.Python + - -
Note: this is the last official release of -Boost.Python v1. Development of this version of the library has -stopped; it will be retired soon in favor of the redesigned and -improved version 2. A summary of the development goals is available on -the Python C++-sig -page, which also serves as a mailing list for users of both versions -of the library. A preview of the v2 documentation is available here, -and instructions for getting started with a prerelease are available -upon request. -
+ + + + -

Supported Platforms

-

Boost.Python is known to have been tested -against Python 2.2.1 using -the following compilers: +

+ +
+

+

+
+

Boost.Python

-
+


-
  • MSVC++6sp5 - with STLPort-4.5.3. A compiler bug interferes with - libs/python/example/simple_vector.cpp. All - other tests pass. +

    Contents

    -

    -

  • MSVC++7 (Visual - Studio .NET). All tests pass. +
    +
    Tutorial Introduction
    -

    -

  • Metrowerks - CodeWarrior Pro7.2 and Pro7.0 for Windows. All tests pass. +
    Building and Testing
    -

    -

  • GCC 3.0.4 under Cygwin and - RedHat Linux 7.1. - All tests pass. +
    Reference
    -

    -

  • Compaq C++ V6.2-024 for Digital UNIX (an EDG-based compiler). - All tests pass.
    - Note that the Boost.Compatibility - library must be included (see e.g. tru64_cxx.mak in the build - directory). +
    Configuration Information
    -

    -

  • Silicon Graphics MIPSpro Version 7.3.1.2m (an EDG-based compiler). - All tests pass.
    - Note that the Boost.Compatibility - library must be included (see e.g. irix_CC.mak in the build - directory). +
    Rationale
    -

    -

  • GCC 2.95.2 under MinGW and RedHat Linux 7.1. - Compilation succeeds, but some tests fail at runtime due to - exception handling bugs. It is therefore highly recommended - to use GCC 3.0.4 instead. +
    Definitions
    -

    -

  • Intel - C++ 6.0 beta: Comprehensive test fails to link due to a - linker bug. Other tests seem to work. +
    Frequently Asked Questions (FAQs)
    -

    -

  • Intel - C++ 5.0 Comprehensive test fails at runtime due to an - exception-handling bug. Other tests seem to work. +
    Progress Reports
    - +
    Acknowledgments
    +
  • +
    -

    -Note that pickling doesn't work with Python 2.2 -due to a core language bug. This is fixed in -2.2.1. +

    Revised + + 08 October, 2002 + +

    -

    -Boost.Python has also been used with other versions of Python back to -Python 1.5.2. It is expected that the older Python releases still work, -but we are not regularly testing for backward compatibility. - -

    Credits

    -
      -
    • David Abrahams originated - and wrote most of the library, and continues to coordinate development. - -
    • Ullrich Koethe - had independently developed a similar system. When he discovered Boost.Python, - 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++, and has designed an extremely easy-to-use way of - exposing numeric operators, including - a way to avoid explicit coercion by means of overloading. - -
    • Ralf W. - Grosse-Kunstleve contributed pickle support - and numerous other small improvements. He's working on a way to allow - types exported by multiple modules to interact. - -
    • 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. - -
    • The development of Boost.Python wouldn't have been possible without - the generous support of Dragon - Systems/Lernout and Hauspie, Inc who supported its development as an - open-source project. -
    - -

    Table of Contents

    - -
      -
    1. A Brief Introduction to writing Python - extension modules - -
    2. Comparisons between Boost.Python and other - systems for extending Python - -
    3. A Simple Example - -
    4. Exporting Classes - -
    5. Overridable Virtual Functions - -
    6. Function Overloading - -
    7. Inheritance - -
    8. Special Method and Operator Support - -
    9. A Peek Under the Hood - -
    10. Building an Extension Module - -
    11. Pickle Support - -
    12. Cross-Extension-Module Dependencies - -
    13. Wrapping Enums - -
    14. Pointers and Smart Pointers - -
    15. Internal Data Structures - -
    - -

    - Documentation is a major ongoing project; assistance is greatly - appreciated! In the meantime, useful examples of every Boost.Python feature should - be evident in the regression test files test/comprehensive.[py/hpp/cpp] - -

    - Questions should be directed to the Python C++ SIG. - -

    - © Copyright David Abrahams 2001. 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. -

    - Updated: Apr 2002 +

    © Copyright Dave + Abrahams 2002. All Rights Reserved.

    + + diff --git a/doc/inheritance.html b/doc/inheritance.html deleted file mode 100644 index 56e96872..00000000 --- a/doc/inheritance.html +++ /dev/null @@ -1,166 +0,0 @@ - - - Inheritance - -
    -

    - c++boost.gif (8819 bytes)Inheritance -

    - -

    Inheritance in Python

    - -

    - Boost.Python extension classes support single and multiple-inheritance in - Python, just like regular Python classes. You can arbitrarily mix - built-in Python classes with extension classes in a derived class' - tuple of bases. Whenever a Boost.Python extension class is among the bases for a - new class in Python, the result is an extension class: -

    -
    ->>> class MyPythonClass:
    -...     def f(): return 'MyPythonClass.f()'
    -...
    ->>> import my_extension_module
    ->>> class Derived(my_extension_module.MyExtensionClass, MyPythonClass):
    -...     '''This is an extension class'''
    -...     pass
    -...
    ->>> x = Derived()
    ->>> x.f()
    -'MyPythonClass.f()'
    ->>> x.g()
    -'MyExtensionClass.g()'
    -
    -
    - -

    Reflecting C++ Inheritance Relationships

    -

    - Boost.Python also allows us to represent C++ inheritance relationships so that - wrapped derived classes may be passed where values, pointers, or - references to a base class are expected as arguments. The - declare_base member function of - class_builder<> is used to establish the relationship - between base and derived classes: - -

    -
    -#include <memory> // for std::auto_ptr<>
    -
    -struct Base {
    -    virtual ~Base() {}
    -    virtual const char* name() const { return "Base"; }
    -};
    -
    -struct Derived : Base {
    -    Derived() : x(-1) {}
    -    virtual const char* name() const { return "Derived"; }
    -    int x;
    -};
    -
    -std::auto_ptr<Base> derived_as_base() {
    -    return std::auto_ptr<Base>(new Derived);
    -}
    -
    -const char* get_name(const Base& b) {
    -    return b.name();
    -}
    -
    -int get_derived_x(const Derived& d) {
    -    return d.x;
    -}
    -    
    -#include <boost/python/class_builder.hpp> - -// namespace alias for code brevity -namespace python = boost::python; - -BOOST_PYTHON_MODULE_INIT(my_module) -{ -    python::module_builder my_module("my_module"); - -    python::class_builder<Base> base_class(my_module, "Base"); -    base_class.def(python::constructor<>()); - -    python::class_builder<Derived> derived_class(my_module, "Derived"); -    derived_class.def(python::constructor<>()); - // Establish the inheritance relationship between Base and Derived - derived_class.declare_base(base_class); - - my_module.def(derived_as_base, "derived_as_base"); - my_module.def(get_name, "get_name"); - my_module.def(get_derived_x, "get_derived_x"); -} -
    -
    - -

    - Then, in Python: -

    -
    ->>> from my_module import *
    ->>> base = Base()
    ->>> derived = Derived()
    ->>> get_name(base)
    -'Base'
    -
    -
    -objects of wrapped class Derived may be passed where Base is expected -
    -
    ->>> get_name(derived) 
    -'Derived'
    -
    -
    -objects of wrapped class Derived can be passed where Derived is -expected but where type information has been lost. -
    -
    ->>> get_derived_x(derived_as_base()) 
    --1
    -
    -
    - -

    Inheritance Without Virtual Functions

    - -

    - If for some reason your base class has no virtual functions but you still want - to represent the inheritance relationship between base and derived classes, - pass the special symbol boost::python::without_downcast as the 2nd parameter - to declare_base: - -

    -
    -struct Base2 {};
    -struct Derived2 { int f(); };
    -
    - ... -   python::class_builder<Base> base2_class(my_module, "Base2"); -   base2_class.def(python::constructor<>()); - -   python::class_builder<Derived2> derived2_class(my_module, "Derived2"); -   derived2_class.def(python::constructor<>()); - derived_class.declare_base(base_class, python::without_downcast); -
    -
    - -

    This approach will allow Derived2 objects to be passed where - Base2 is expected, but does not attempt to implicitly convert (downcast) - smart-pointers to Base2 into Derived2 pointers, - references, or values. - -

    - Next: Special Method and Operator Support - Previous: Function Overloading - Up: Top -

    - © Copyright David Abrahams 2000. 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. -

    - Updated: Nov 26, 2000 -

    - diff --git a/doc/overloading.html b/doc/overloading.html deleted file mode 100644 index 242e023f..00000000 --- a/doc/overloading.html +++ /dev/null @@ -1,155 +0,0 @@ - - - Function Overloading - -
    -

    - c++boost.gif (8819 bytes)Function Overloading -

    - -

    An Example

    -

    - To expose overloaded functions in Python, simply def() each - one with the same Python name: -

    -
    -inline int f1() { return 3; }
    -inline int f2(int x) { return x + 1; }
    -
    -class X {
    -public:
    -    X() : m_value(0) {}
    -    X(int n) : m_value(n) {}
    -    int value() const { return m_value; }
    -    void value(int v) { m_value = v; }
    -private:
    -    int m_value;
    -};
    -  ...
    -
    -BOOST_PYTHON_MODULE_INIT(overload_demo)
    -{
    -    try
    -    {
    -        boost::python::module_builder overload_demo("overload_demo");
    -        // Overloaded functions at module scope
    -        overload_demo.def(f1, "f");
    -        overload_demo.def(f2, "f");
    -
    -        boost::python::class_builder<X> x_class(overload_demo, "X");
    -        // Overloaded constructors
    -        x_class.def(boost::python::constructor<>());
    -        x_class.def(boost::python::constructor<int>());
    -
    -        // Overloaded member functions
    -        x_class.def((int (X::*)() const)&X::value, "value");
    -        x_class.def((void (X::*)(int))&X::value, "value");
    -  ...
    -
    -
    - -

    - Now in Python: -

    -
    ->>> from overload_demo import *
    ->>> x0 = X()
    ->>> x1 = X(1)
    ->>> x0.value()
    -0
    ->>> x1.value()
    -1
    ->>> x0.value(3)
    ->>> x0.value()
    -3
    ->>> X('hello')
    -TypeError: No overloaded functions match (X, string). Candidates are:
    -void (*)()
    -void (*)(int)
    ->>> f()
    -3
    ->>> f(4)
    -5
    -
    -
    - -

    Discussion

    -

    - Notice that overloading in the Python module was produced three ways:

      -
    1. by combining the non-overloaded C++ functions int f1() - and int f2(int) and exposing them as f in Python. -
    2. by exposing the overloaded constructors of class X -
    3. by exposing the overloaded member functions X::value. -
    -

    - Techniques 1. and 3. above are really alternatives. In case 3, you need - to form a pointer to each of the overloaded functions. The casting - syntax shown above is one way to do that in C++. Case 1 does not require - complicated-looking casts, but may not be viable if you can't change - your C++ interface. N.B. There's really nothing unsafe about casting an - overloaded (member) function address this way: the compiler won't let - you write it at all unless you get it right. - -

    An Alternative to Casting

    -

    - This approach is not neccessarily better, but may be preferable for some - people who have trouble writing out the types of (member) function - pointers or simply prefer to avoid all casts as a matter of principle: -

    -
    -// Forwarding functions for X::value
    -inline void set_x_value(X& self, int v) { self.value(v); }
    -inline int get_x_value(X& self) { return self.value(); }
    -   ...
    -        // Overloaded member functions
    -        x_class.def(set_x_value, "value");
    -        x_class.def(get_x_value, "value");
    -
    -
    -

    Here we are taking advantage of the ability to expose C++ functions at -namespace scope as Python member functions. - -

    Overload Resolution

    -

    - The function overload resolution mechanism works as follows: - -

      - -
    • Attribute lookup for extension classes proceeds in the - usual Python way using a depth-first, left-to-right search. When a - class is found which has a matching attribute, only functions overloaded - in the context of that class are candidates for overload resolution. In - this sense, overload resolution mirrors the C++ mechanism, where a name - in a derived class ``hides'' all functions with the same name from a base - class. -

      - -

    • Within a name-space context (extension class or module), overloaded - functions are tried in the same order they were - def()ed. The first function whose signature can be made to - match each argument passed is the one which is ultimately called. - This means in particular that you cannot overload the same function on - both ``int'' and ``float'' because Python - automatically converts either of the two types into the other one. - If the ``float'' overload is found first, it is used - also used for arguments of type ``int'' as well, and the - ``int'' version of the function is never invoked. -
    - -

    - Next: Inheritance - Previous: Overridable Virtual Functions - Up: Top -

    - © Copyright David Abrahams 2001. 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. -

    - Updated: Mar 6, 2001 -

    - diff --git a/doc/overriding.html b/doc/overriding.html deleted file mode 100644 index 085d5a7f..00000000 --- a/doc/overriding.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - Overridable Virtual Functions - - c++boost.gif (8819 bytes) - -

    Overridable Virtual Functions

    - -

    - In the previous example we exposed a simple - C++ class in Python and showed that we could write a subclass. We even - redefined one of the functions in our derived class. Now we will learn - how to make the function behave virtually when called from C++. - - -

    Example

    - -

    In this example, it is assumed that hello::greet() is a virtual -member function: - -

    -class hello
    -{
    - public:
    -    hello(const std::string& country) { this->country = country; }
    -    virtual std::string greet() const { return "Hello from " + country; }
    -    virtual ~hello(); // Good practice 
    -    ...
    -};
    -
    - -

    - We'll need a derived class* to help us - dispatch the call to Python. In our derived class, we need the following - elements: - -

      - -
    1. A PyObject* data member (usually - called self) that holds a pointer to the Python object corresponding - to our C++ hello instance. - -
    2. For each exposed constructor of the - base class T, a constructor which takes the same parameters preceded by an initial - PyObject* argument. The initial argument should be stored in the self data - member described above. - -
    3. If the class being wrapped is ever returned by - value from a wrapped function, be sure you do the same for the - T's copy constructor: you'll need a constructor taking arguments - (PyObject*, const T&). - -
    4. An implementation of each virtual function you may - wish to override in Python which uses - callback<return-type>::call_method(self, "name", args...) to call - the Python override. - -
    5. For each non-pure virtual function meant to be - overridable from Python, a static member function (or a free function) taking - a reference or pointer to the T as the first parameter and which - forwards any additional parameters neccessary to the default - implementation of the virtual function. See also this - note if the base class virtual function is private. - -
    - -
    -struct hello_callback : hello
    -{
    -    // hello constructor storing initial self_ parameter
    -    hello_callback(PyObject* self_, const std::string& x) // 2
    -        : hello(x), self(self_) {}
    -
    -    // In case hello is returned by-value from a wrapped function
    -    hello_callback(PyObject* self_, const hello& x) // 3
    -        : hello(x), self(self_) {}
    -
    -    // Override greet to call back into Python
    -    std::string greet() const // 4
    -        { return boost::python::callback<std::string>::call_method(self, "greet"); }
    -
    -    // Supplies the default implementation of greet
    -    static std::string default_greet(const hello& self_) const // 5
    -        { return self_.hello::greet(); }
    - private:
    -    PyObject* self; // 1
    -};
    -
    - -

    - Finally, we add hello_callback to the - class_builder<> declaration in our module initialization - function, and when we define the function, we must tell Boost.Python about the default - implementation: - -

    -// Create the Python type object for our extension class
    -boost::python::class_builder<hello,hello_callback> hello_class(hello, "hello");
    -// Add a virtual member function
    -hello_class.def(&hello::greet, "greet", &hello_callback::default_greet);
    -
    - -

    - Now our Python subclass of hello behaves as expected: - -

    ->>> 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, where the weather is fine! Please come soon!'
    -
    -

    - *You may ask, "Why do we need this derived - class? This could have been designed so that everything gets done right - inside of hello." One of the goals of Boost.Python is to be - minimally intrusive on an existing C++ design. In principle, it should be - possible to expose the interface for a 3rd party library without changing - it. To unintrusively hook into the virtual functions so that a Python - override may be called, we must use a derived class. - -

    Pure Virtual Functions

    - -

    - A pure virtual function with no implementation is actually a lot easier to - deal with than a virtual function with a default implementation. First of - all, you obviously don't need to supply - a default implementation. Secondly, you don't need to call - def() on the extension_class<> instance - for the virtual function. In fact, you wouldn't want to: if the - corresponding attribute on the Python class stays undefined, you'll get an - AttributeError in Python when you try to call the function, - indicating that it should have been implemented. For example: -

    -
    -struct baz {
    -    virtual int pure(int) = 0;
    -    int calls_pure(int x) { return pure(x) + 1000; }
    -};
    -
    -struct baz_callback {
    -    int pure(int x) { boost::python::callback<int>::call_method(m_self, "pure", x); }
    -};
    -
    -BOOST_PYTHON_MODULE_INIT(foobar)
    -{
    -     boost::python::module_builder foobar("foobar");                          
    -     boost::python::class_builder<baz,baz_callback> baz_class("baz");   
    -     baz_class.def(&baz::calls_pure, "calls_pure"); 
    -}
    -
    -
    -

    - Now in Python: -

    -
    ->>> from foobar import baz
    ->>> x = baz()
    ->>> x.pure(1)
    -Traceback (innermost last):
    -  File "<stdin>", line 1, in ?
    -AttributeError: pure
    ->>> x.calls_pure(1)
    -Traceback (innermost last):
    -  File "<stdin>", line 1, in ?
    -AttributeError: pure
    ->>> class mumble(baz):
    -...    def pure(self, x): return x + 1
    -...
    ->>> y = mumble()
    ->>> y.pure(99)
    -100
    ->>> y.calls_pure(99)
    -1100
    -
    - -

    Private Non-Pure Virtual Functions

    - -

    This is one area where some minor intrusiveness on the wrapped library is -required. Once it has been overridden, the only way to call the base class -implementation of a private virtual function is to make the derived class a -friend of the base class. You didn't hear it from me, but most C++ -implementations will allow you to change the declaration of the base class in -this limited way without breaking binary compatibility (though it will certainly -break the ODR). - -


    -

    - Next: Function Overloading - Previous: Exporting Classes - Up: Top -

    - © Copyright David Abrahams 2001. 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. -

    - Updated: Mar 21, 2001 - diff --git a/doc/pickle.html b/doc/pickle.html deleted file mode 100644 index 994a78ab..00000000 --- a/doc/pickle.html +++ /dev/null @@ -1,272 +0,0 @@ - - -Boost.Python Pickle Support - -

    - -c++boost.gif (8819 bytes) - -
    -

    Boost.Python Pickle Support

    - -Pickle is a Python module for object serialization, also known -as persistence, marshalling, or flattening. - -

    -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. - -

    -The Boost Python Library supports the pickle module by emulating the -interface implemented by Jim Fulton's ExtensionClass module that is -included in the -ZOPE -distribution. -This interface is similar to that for regular Python classes as -described in detail in the -Python Library Reference for pickle. - -


    -

    The Boost.Python Pickle Interface

    - -At the user level, the Boost.Python pickle interface involves three special -methods: - -
    -
    -__getinitargs__ -
    - When an instance of a Boost.Python extension class is pickled, the - pickler tests if the instance has a __getinitargs__ 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. - -

    - If __getinitargs__ is not defined, the class constructor - will be called without arguments. - -

    -

    -__getstate__ - -
    - When an instance of a Boost.Python extension class is pickled, the - pickler tests if the instance has a __getstate__ method. - This method should return a Python object representing the state of - the instance. - -

    - If __getstate__ is not defined, the instance's - __dict__ is pickled (if it is not empty). - -

    -

    -__setstate__ - -
    - When an instance of a Boost.Python extension class is restored by the - unpickler, it is first constructed using the result of - __getinitargs__ as arguments (see above). Subsequently the - unpickler tests if the new instance has a __setstate__ - method. If so, this method is called with the result of - __getstate__ (a Python object) as the argument. - -

    - If __setstate__ is not defined, the result of - __getstate__ must be a Python dictionary. The items of this - dictionary are added to the instance's __dict__. - -

    - -If both __getstate__ and __setstate__ are defined, -the Python object returned by __getstate__ need not be a -dictionary. The __getstate__ and __setstate__ methods -can do what they want. - -
    -

    Pitfalls and Safety Guards

    - -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. -However, the author of a Boost.Python extension module might not -anticipate correctly which classes need support for pickle. -Unfortunately, the pickle protocol described above has two important -pitfalls that the end user of a Boost.Python extension module might not -be aware of: - -
    -
    -Pitfall 1: -Both __getinitargs__ and __getstate__ are not defined. - -
    - In this situation the unpickler calls the class constructor without - arguments and then adds the __dict__ that was pickled by - default to that of the new instance. - -

    - However, most C++ classes wrapped with Boost.Python will have member - data that are not restored correctly by this procedure. To alert the - user to this problem, a safety guard is provided. If both - __getinitargs__ and __getstate__ are not defined, - Boost.Python tests if the class has an attribute - __dict_defines_state__. An exception is raised if this - attribute is not defined: - -

    -    RuntimeError: Incomplete pickle support (__dict_defines_state__ not set)
    -
    - - In the rare cases where this is not the desired behavior, the safety - guard can deliberately be disabled. The corresponding C++ code for - this is, e.g.: - -
    -    class_builder<your_class> py_your_class(your_module, "your_class");
    -    py_your_class.dict_defines_state();
    -
    - - It is also possible to override the safety guard at the Python level. - E.g.: - -
    -    import your_bpl_module
    -    class your_class(your_bpl_module.your_class):
    -      __dict_defines_state__ = 1
    -
    - -

    -

    -Pitfall 2: -__getstate__ is defined and the instance's __dict__ is not empty. - -
    - The author of a Boost.Python extension class might provide a - __getstate__ method without considering the possibilities - that: - -

    -

      -
    • - his class is used in Python as a base class. Most likely the - __dict__ of instances of the derived class needs to be - pickled in order to restore the instances correctly. - -

      -

    • - the user adds items to the instance's __dict__ directly. - Again, the __dict__ of the instance then needs to be - pickled. - -
    -

    - - To alert the user to this highly unobvious problem, a safety guard is - provided. If __getstate__ is defined and the instance's - __dict__ is not empty, Boost.Python tests if the class has - an attribute __getstate_manages_dict__. An exception is - raised if this attribute is not defined: - -

    -    RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
    -
    - - To resolve this problem, it should first be established that the - __getstate__ and __setstate__ methods manage the - instances's __dict__ correctly. Note that this can be done - both at the C++ and the Python level. Finally, the safety guard - should intentionally be overridden. E.g. in C++: - -
    -    class_builder<your_class> py_your_class(your_module, "your_class");
    -    py_your_class.getstate_manages_dict();
    -
    - - In Python: - -
    -    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
    -
    -
    - -
    -

    Practical Advice

    - -
      -
    • - Avoid using __getstate__ if the instance can also be - reconstructed by way of __getinitargs__. This automatically - avoids Pitfall 2. - -

      -

    • - If __getstate__ is required, include the instance's - __dict__ in the Python object that is returned. - -
    - -
    -

    Examples

    - -There are three files in boost/libs/python/example that -show how so provide pickle support. - -

    pickle1.cpp

    - - 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 __getinitargs__. - -

    pickle2.cpp

    - - 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 __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 the safety guards - will catch the cases where this assumption is violated. - -

    pickle3.cpp

    - - This example is similar to pickle2.cpp. However, the - object's __dict__ is included in the result of - __getstate__. This requires more code but is unavoidable - if the object's __dict__ is not always empty. - -
    -© Copyright Ralf W. Grosse-Kunstleve 2001. 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. - -

    -Updated: March 21, 2001 -

    diff --git a/doc/pointers.html b/doc/pointers.html deleted file mode 100644 index 11cfd8d9..00000000 --- a/doc/pointers.html +++ /dev/null @@ -1,148 +0,0 @@ - - - Pointers - -
    -

    - c++boost.gif (8819 bytes)Pointers -

    - -

    The Problem With Pointers

    - -

    -In general, raw pointers passed to or returned from functions are problematic -for Boost.Python because pointers have too many potential meanings. Is it an iterator? -A pointer to a single element? An array? When used as a return value, is the -caller expected to manage (delete) the pointed-to object or is the pointer -really just a reference? If the latter, what happens to Python references to the -referent when some C++ code deletes it? -

    -There are a few cases in which pointers are converted automatically: -

      - -
    • Both const- and non-const pointers to wrapped class instances can be passed -to C++ functions. - -
    • Values of type const char* are interpreted as -null-terminated 'C' strings and when passed to or returned from C++ functions are -converted from/to Python strings. - -
    - -

    Can you avoid the problem?

    - -

    My first piece of advice to anyone with a case not covered above is -``find a way to avoid the problem.'' For example, if you have just one -or two functions that return a pointer to an individual const -T, and T is a wrapped class, you may be able to write a ``thin -converting wrapper'' over those two functions as follows: - -

    -const Foo* f(); // original function
    -const Foo& f_wrapper() { return *f(); }
    -  ...
    -my_module.def(f_wrapper, "f");
    -
    -

    -Foo must have a public copy constructor for this technique to work, since Boost.Python -converts const T& values to_python by copying the T -value into a new extension instance. - -

    Dealing with the problem

    - -

    The first step in handling the remaining cases is to figure out what the pointer -means. Several potential solutions are provided in the examples that follow: - -

    Returning a pointer to a wrapped type

    - -

    Returning a const pointer

    - -

    If you have lots of functions returning a const T* for some -wrapped T, you may want to provide an automatic -to_python conversion function so you don't have to write lots of -thin wrappers. You can do this simply as follows: - -

    -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
    -  PyObject* to_python(const Foo* p) {
    -     return to_python(*p); // convert const Foo* in terms of const Foo&
    -  }
    -BOOST_PYTHON_END_CONVERSION_NAMESPACE
    -
    - -

    If you can't (afford to) copy the referent, or the pointer is non-const

    - -

    If the wrapped type doesn't have a public copy constructor, if copying is -extremely costly (remember, we're dealing with Python here), or if the -pointer is non-const and you really need to be able to modify the referent from -Python, you can use the following dangerous trick. Why dangerous? Because python -can not control the lifetime of the referent, so it may be destroyed by your C++ -code before the last Python reference to it disappears: - -

    -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
    -  PyObject* to_python(Foo* p)
    -  {
    -      return boost::python::python_extension_class_converters<Foo>::smart_ptr_to_python(p);
    -  }
    -
    -  PyObject* to_python(const Foo* p)
    -  {
    -      return to_python(const_cast<Foo*>(p));
    -  }
    -BOOST_PYTHON_END_CONVERSION_NAMESPACE
    -
    - -This will cause the Foo* to be treated as though it were an owning smart -pointer, even though it's not. Be sure you don't use the reference for anything -from Python once the pointer becomes invalid, though. Don't worry too much about -the const_cast<> above: Const-correctness is completely lost -to Python anyway! - -

    [In/]Out Parameters and Immutable Types

    - -

    If you have an interface that uses non-const pointers (or references) as -in/out parameters to types which in Python are immutable (e.g. int, string), -there simply is no way to get the same interface in Python. You must -resort to transforming your interface with simple thin wrappers as shown below: -

    -const void f(int* in_out_x); // original function
    -const int f_wrapper(int in_x) { f(in_x); return in_x; }
    -  ...
    -my_module.def(f_wrapper, "f");
    -
    - -

    Of course, [in/]out parameters commonly occur only when there is already a -return value. You can handle this case by returning a Python tuple: -

    -typedef unsigned ErrorCode;
    -const char* f(int* in_out_x); // original function
    - ...
    -#include <boost/python/objects.hpp>
    -const boost::python::tuple f_wrapper(int in_x) { 
    -  const char* s = f(in_x); 
    -  return boost::python::tuple(s, in_x);
    -}
    -  ...
    -my_module.def(f_wrapper, "f");
    -
    -

    Now, in Python: -

    ->>> str,out_x = f(3)
    -
    - -

    - Previous: Enums - Up: Top -

    - © Copyright David Abrahams 2000. 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. -

    - Updated: Nov 26, 2000 -

    - diff --git a/doc/richcmp.html b/doc/richcmp.html deleted file mode 100644 index d9ab7044..00000000 --- a/doc/richcmp.html +++ /dev/null @@ -1,106 +0,0 @@ - - -Rich Comparisons - -
    - -c++boost.gif (8819 bytes) - -
    -

    Rich Comparisons

    - -
    -In Python versions up to and including Python 2.0, support for -implementing comparisons on user-defined classes and extension types -was quite simple. Classes could implement a __cmp__ method -that was given two instances of a class as arguments, and could only -return 0 if they were equal or +1 or -1 if -they were not. The method could not raise an exception or return -anything other than an integer value. -In Python 2.1, Rich Comparisons were added (see -PEP 207). -Python classes can now individually overload each of the <, <=, ->, >=, ==, and != operations. - -

    -For more detailed information, search for "rich comparison" -here. - -

    -Boost.Python supports both automatic overloading and manual overloading -of the Rich Comparison operators. The compile-time support is -independent of the Python version that is used when compiling -Boost.Python extension modules. That is, op_lt for example can -always be used, and the C++ operator< will always be bound -to the Python method __lt__. However, the run-time -behavior will depend on the Python version. - -

    -With Python versions before 2.1, the Rich Comparison operators will not -be called by Python when any of the six comparison operators -(<, <=, ==, !=, ->, >=) is used in an expression. The only way -to access the corresponding methods is to call them explicitly, e.g. -a.__lt__(b). Only with Python versions 2.1 or higher will -expressions like a < b work as expected. - -

    -To support Rich Comparisions, the Python C API was modified between -Python versions 2.0 and 2.1. A new slot was introduced in the -PyTypeObject structure: tp_richcompare. For backwards -compatibility, a flag (Py_TPFLAGS_HAVE_RICHCOMPARE) has to be -set to signal to the Python interpreter that Rich Comparisions are -supported by a particular type. -There is only one flag for all the six comparison operators. -When any of the six operators is wrapped automatically or -manually, Boost.Python will set this flag. Attempts to use comparison -operators at the Python level that are not defined at the C++ level -will then lead to an AttributeError when the Python 2.1 -(or higher) interpreter tries, e.g., a.__lt__(b). That -is, in general all six operators should be supplied. Automatically -wrapped operators and manually wrapped operators can be mixed. For -example:

    -    boost::python::class_builder<code> py_code(this_module, "code");
    -
    -    py_code.def(boost::python::constructor<>());
    -    py_code.def(boost::python::constructor<int>());
    -    py_code.def(boost::python::operators<(  boost::python::op_eq
    -                                          | boost::python::op_ne)>());
    -    py_code.def(NotImplemented, "__lt__");
    -    py_code.def(NotImplemented, "__le__");
    -    py_code.def(NotImplemented, "__gt__");
    -    py_code.def(NotImplemented, "__ge__");
    -
    - -NotImplemented is a simple free function that (currently) has -to be provided by the user. For example:
    -  boost::python::ref
    -  NotImplemented(const code&, const code&) {
    -    return
    -    boost::python::ref(Py_NotImplemented, boost::python::ref::increment_count);
    -  }
    -
    - -See also: - - -
    -© Copyright Nicholas K. Sauter & Ralf W. Grosse-Kunstleve 2001. -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. - -

    -Updated: July 2001 - -

    diff --git a/doc/special.html b/doc/special.html deleted file mode 100644 index d53ec712..00000000 --- a/doc/special.html +++ /dev/null @@ -1,973 +0,0 @@ - - - Special Method and Operator Support - -
    -

    - c++boost.gif (8819 bytes)Special Method and - Operator Support -

    -

    - Overview -

    -

    - Boost.Python supports all of the standard - special method names supported by real Python class instances - except __complex__ (more on the reasons below). In addition, it can quickly and easily expose - suitable C++ functions and operators as Python operators. The following - categories of special method names are supported: -

    - -

    Basic Customization

    - - -

    - Python provides a number of special operators for basic customization of a - class. Only a brief description is provided below; more complete - documentation can be found here. - -

    -
    - __init__(self) -
    - Initialize the class instance. For extension classes not subclassed in - Python, __init__ is defined by - -
        my_class.def(boost::python::constructor<...>())
    - - (see section "A Simple Example Using Boost.Python").

    -

    - __del__(self) -
    - Called when the extension instance is about to be destroyed. For extension classes - not subclassed in Python, __del__ is always defined automatically by - means of the class' destructor. -
    - __repr__(self) -
    - Create a string representation from which the object can be - reconstructed. -
    - __str__(self) -
    - Create a string representation which is suitable for printing. -
    - __lt__(self, other) -
    - __le__(self, other) -
    - __eq__(self, other) -
    - __ne__(self, other) -
    - __gt__(self, other) -
    - __ge__(self, other) -
    - Rich Comparison methods. - New in Python 2.1. - See Rich Comparisons. -
    - __cmp__(self, other) -
    - Three-way compare function. - See Rich Comparisons. -
    - __hash__(self) -
    - Called for the key object for dictionary operations, and by the - built-in function hash(). Should return a 32-bit integer usable as a - hash value for dictionary operations (only allowed if __cmp__ is also - defined) -
    - __nonzero__(self) -
    - called if the object is used as a truth value (e.g. in an if - statement) -
    - __call__ (self[, args...]) -
    -Called when the instance is ``called'' as a function; if this method -is defined, x(arg1, arg2, ...) is a shorthand for -x.__call__(arg1, arg2, ...). -
    - - If we have a suitable C++ function that supports any of these features, - we can export it like any other function, using its Python special name. - For example, suppose that class Foo provides a string - conversion function: -
    -std::string to_string(Foo const& f)
    -{
    -    std::ostringstream s;
    -    s << f;
    -    return s.str();
    -}
    -
    - This function would be wrapped like this: -
    -boost::python::class_builder<Foo> foo_class(my_module, "Foo");
    -foo_class.def(&to_string, "__str__");
    -
    - Note that Boost.Python also supports automatic wrapping of - __str__ and __cmp__. This is explained in the next section and the Table of - Automatically Wrapped Methods. - -

    Numeric Operators

    - -

    - Numeric operators can be exposed manually, by defing C++ - [member] functions that support the standard Python numeric - protocols. This is the same basic technique used to expose - to_string() as __str__() above, and is covered in detail below. Boost.Python also supports - automatic wrapping of numeric operators whenever they have already - been defined in C++. - -

    Exposing C++ Operators Automatically

    - -

    -Supose we wanted to expose a C++ class - BigNum which supports addition. That is, in C++ we can write: -

    -BigNum a, b, c;
    -...
    -c = a + b;
    -
    -

    - To enable the same functionality in Python, we first wrap the - BigNum class as usual: -

    -boost::python::class_builder<BigNum> bignum_class(my_module, "BigNum");
    -bignum_class.def(boost::python::constructor<>());
    -...
    -
    - Then we export the addition operator like this: - -
    -bignum_class.def(boost::python::operators<boost::python::op_add>());
    -
    - - Since BigNum also supports subtraction, multiplication, and division, we - want to export those also. This can be done in a single command by - ``or''ing the operator identifiers together (a complete list of these - identifiers and the corresponding operators can be found in the Table of Automatically Wrapped Methods): -
    -bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>());
    -
    - [Note that the or-expression must be enclosed in parentheses.] - -

    This form of operator definition can be used to wrap unary and - homogeneous binary operators (a homogeneous operator has left and - right operands of the same type). Now suppose that our C++ library also - supports addition of BigNums and plain integers: - -

    -BigNum a, b;
    -int i;
    -...
    -a = b + i;
    -a = i + b;
    -
    - To wrap these heterogeneous operators, we need to specify a different type for - one of the operands. This is done using the right_operand - and left_operand templates: -
    -bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::right_operand<int>());
    -bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::left_operand<int>());
    -
    - Boost.Python uses overloading to register several variants of the same - operation (more on this in the context of - coercion). Again, several operators can be exported at once: -
    -bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(),
    -                 boost::python::right_operand<int>());
    -bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(), 
    -                 boost::python::left_operand<int>());
    -
    - The type of the operand not mentioned is taken from the class being wrapped. In - our example, the class object is bignum_class, and thus the - other operand's type is ``BigNum const&''. You can override - this default by explicitly specifying a type in the - operators template: -
    -bignum_class.def(boost::python::operators<boost::python::op_add, BigNum>(), boost::python::right_operand<int>());
    -
    -

    - Note that automatic wrapping uses the expression - ``left + right'' and can be used uniformly - regardless of whether the C++ operators are supplied as free functions - -

    -BigNum operator+(BigNum, BigNum)
    -
    - - or as member functions - -
    -BigNum::operator+(BigNum).
    -
    - -

    - For the Python built-in functions pow() and - abs(), there is no corresponding C++ operator. Instead, - automatic wrapping attempts to wrap C++ functions of the same name. This - only works if those functions are known in namespace - python. On some compilers (e.g. MSVC) it might be - necessary to add a using declaration prior to wrapping: - -

    -namespace boost { namespace python { 
    -  using my_namespace::pow;
    -  using my_namespace::abs;
    -}
    -
    - -

    Wrapping Numeric Operators Manually

    -

    - In some cases, automatic wrapping of operators may be impossible or - undesirable. Suppose, for example, that the modulo operation for BigNums - is defined by a set of functions called mod(): - -

    -BigNum mod(BigNum const& left, BigNum const& right);
    -BigNum mod(BigNum const& left, int right);
    -BigNum mod(int left, BigNum const& right);
    -
    - -

    - For automatic wrapping of the modulo function, operator%() would be needed. - Therefore, the mod()-functions must be wrapped manually. That is, we have - to export them explicitly with the Python special name "__mod__": - -

    -bignum_class.def((BigNum (*)(BigNum const&, BigNum const&))&mod, "__mod__");
    -bignum_class.def((BigNum (*)(BigNum const&, int))&mod, "__mod__");
    -
    - -

    - The third form of mod() (with int as left operand) cannot - be wrapped directly. We must first create a function rmod() with the - operands reversed: - -

    -BigNum rmod(BigNum const& right, int left)
    -{
    -    return mod(left, right);
    -}
    -
    - - This function must be wrapped under the name "__rmod__" (standing for "reverse mod"): - -
    -bignum_class.def(&rmod,  "__rmod__");
    -
    - - Many of the possible operator names can be found in the Table of Automatically Wrapped Methods. Special treatment is - necessary to export the ternary pow operator. - -

    - Automatic and manual wrapping can be mixed arbitrarily. Note that you - cannot overload the same operator for a given extension class on both - ``int'' and ``float'', because Python implicitly - converts these types into each other. Thus, the overloaded variant - found first (be it ``int`` or ``float'') will be - used for either of the two types. - -

    Inplace Operators

    -

    - Boost.Python can also be used to expose inplace numeric operations - (i.e., += and so forth). These operators must be wrapped - manually, as described in the previous section. For example, suppose - the class BigNum has an operator+=: - -

    -BigNum& operator+= (BigNum const& right);
    -
    - - This can be exposed by first writing a wrapper function: - -
    -BigNum& iadd (BigNum& self, const BigNum& right)
    -{
    -  return self += right;
    -}
    -
    - - and then exposing the wrapper with - -
    -bignum_class.def(&iadd, "__iadd__");
    -
    - - - - -

    Coercion

    - - - Plain Python can only execute operators with identical types on the left - and right hand side. If it encounters an expression where the types of - the left and right operand differ, it tries to coerce these types to a - common type before invoking the actual operator. Implementing good - coercion functions can be difficult if many type combinations must be - supported. -

    - Boost.Python solves this problem the same way that C++ does: with overloading. This technique drastically - simplifies the code neccessary to support operators: you just register - operators for all desired type combinations, and Boost.Python automatically - ensures that the correct function is called in each case; there is no - need for user-defined coercion functions. To enable operator - overloading, Boost.Python provides a standard coercion which is implicitly - registered whenever automatic operator wrapping is used. -

    - If you wrap all operator functions manually, but still want to use - operator overloading, you have to register the standard coercion - function explicitly: - -

    -// this is not necessary if automatic operator wrapping is used
    -bignum_class.def_standard_coerce();
    -
    - - If you encounter a situation where you absolutely need a customized - coercion, you can still define the "__coerce__" operator manually. The signature - of a coercion function should look like one of the following (the first is - the safest): - -
    -boost::python::tuple custom_coerce(boost::python::reference left, boost::python::reference right);
    -boost::python::tuple custom_coerce(PyObject* left, PyObject* right);
    -PyObject* custom_coerce(PyObject* left, PyObject* right);
    -
    - - The resulting tuple must contain two elements which - represent the values of left and right - converted to the same type. Such a function is wrapped as usual: - -
    -// this must be called before any use of automatic operator  
    -// wrapping or a call to some_class.def_standard_coerce()
    -some_class.def(&custom_coerce, "__coerce__");
    -
    - - Note that the standard coercion (defined by use of automatic - operator wrapping on a class_builder or a call to - class_builder::def_standard_coerce()) will never be applied if - a custom coercion function has been registered. Therefore, in - your coercion function you should call - -
    -boost::python::standard_coerce(left, right);
    -
    - - for all cases that you don't want to handle yourself. - -

    The Ternary pow() Operator

    - -

    - In addition to the usual binary pow(x, y) operator (meaning - xy), Python also provides a ternary variant that implements - xy mod z, presumably using a more efficient algorithm than - concatenation of power and modulo operators. Automatic operator wrapping - can only be used with the binary variant. Ternary pow() must - always be wrapped manually. For a homgeneous ternary pow(), - this is done as usual: - -

    -BigNum power(BigNum const& first, BigNum const& second, BigNum const& modulus);
    -typedef BigNum (ternary_function1)(const BigNum&, const BigNum&, const BigNum&);
    -...
    -bignum_class.def((ternary_function1)&power,  "__pow__");
    -
    - - If you want to support this function with non-uniform argument - types, wrapping is a little more involved. Suppose you have to wrap: - -
    -BigNum power(BigNum const& first, int second, int modulus);
    -BigNum power(int first, BigNum const& second, int modulus);
    -BigNum power(int first, int second, BigNum const& modulus);
    -
    - - The first variant can be wrapped as usual: - -
    -typedef BigNum (ternary_function2)(const BigNum&, int, int);
    -bignum_class.def((ternary_function2)&power,  "__pow__");
    -
    - - In the second variant, however, BigNum appears only as second - argument, and in the last one it's the third argument. These functions - must be presented to Boost.Python such that that the BigNum - argument appears in first position: - -
    -BigNum rpower(BigNum const& second, int first, int modulus)
    -{
    -    return power(first, second, modulus);
    -}
    -
    -BigNum rrpower(BigNum const& modulus, int first, int second)
    -{
    -    return power(first, second, modulus);
    -}
    -
    - -

    These functions must be wrapped under the names "__rpow__" and "__rrpow__" - respectively: - -

    -bignum_class.def((ternary_function2)&rpower,  "__rpow__");
    -bignum_class.def((ternary_function2)&rrpower,  "__rrpow__");
    -
    - -Note that "__rrpow__" is an extension not present in plain Python. - -

    Table of Automatically Wrapped Methods

    -

    - Boost.Python can automatically wrap the following - special methods: - -

    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Python Operator Name - - Python Expression - - C++ Operator Id - - C++ Expression Used For Automatic Wrapping
    - with cpp_left = from_python(left, - type<Left>()),
    - cpp_right = from_python(right, - type<Right>()),
    - and cpp_oper = from_python(oper, type<Oper>()) -
    - __add__, __radd__ - - left + right - - op_add - - cpp_left + cpp_right -
    - __sub__, __rsub__ - - left - right - - op_sub - - cpp_left - cpp_right -
    - __mul__, __rmul__ - - left * right - - op_mul - - cpp_left * cpp_right -
    - __div__, __rdiv__ - - left / right - - op_div - - cpp_left / cpp_right -
    - __mod__, __rmod__ - - left % right - - op_mod - - cpp_left % cpp_right -
    - __divmod__, __rdivmod__ - - (quotient, remainder)
    - = divmod(left, right)
    -
    - op_divmod - - cpp_left / cpp_right -
    cpp_left % cpp_right -
    - __pow__, __rpow__ - - pow(left, right)
    - (binary power) -
    - op_pow - - pow(cpp_left, cpp_right) -
    - __rrpow__ - - pow(left, right, modulo)
    - (ternary power modulo) -
    - no automatic wrapping, special treatment - required -
    - __lshift__, __rlshift__ - - left << right - - op_lshift - - cpp_left << cpp_right -
    - __rshift__, __rrshift__ - - left >> right - - op_rshift - - cpp_left >> cpp_right -
    - __and__, __rand__ - - left & right - - op_and - - cpp_left & cpp_right -
    - __xor__, __rxor__ - - left ^ right - - op_xor - - cpp_left ^ cpp_right -
    - __or__, __ror__ - - left | right - - op_or - - cpp_left | cpp_right - -
    - __cmp__, __rcmp__ - - cmp(left, right)
    -
    See Rich Comparisons. -
    - op_cmp - - cpp_left < cpp_right  -
    cpp_right < cpp_left -
    - __lt__ -
    __le__ -
    __eq__ -
    __ne__ -
    __gt__ -
    __ge__ -
    - left < right -
    left <= right -
    left == right -
    left != right -
    left > right -
    left >= right -
    See Rich Comparisons -
    - op_lt -
    op_le -
    op_eq -
    op_ne -
    op_gt -
    op_ge -
    - cpp_left < cpp_right  -
    cpp_left <= cpp_right  -
    cpp_left == cpp_right  -
    cpp_left != cpp_right  -
    cpp_left > cpp_right  -
    cpp_left >= cpp_right  - -
    - __neg__ - - -oper  (unary negation) - - op_neg - - -cpp_oper -
    - __pos__ - - +oper  (identity) - - op_pos - - +cpp_oper -
    - __abs__ - - abs(oper)  (absolute value) - - op_abs - - abs(cpp_oper) -
    - __invert__ - - ~oper  (bitwise inversion) - - op_invert - - ~cpp_oper -
    - __int__ - - int(oper)  (integer conversion) - - op_int - - long(cpp_oper) -
    - __long__ - - long(oper) 
    - (infinite precision integer conversion) -
    - op_long - - PyLong_FromLong(cpp_oper) -
    - __float__ - - float(oper)  (float conversion) - - op_float - - double(cpp_oper) -
    - __str__ - - str(oper)  (string conversion) - - op_str - - std::ostringstream s; s << oper; -
    - __coerce__ - - coerce(left, right) - - usually defined automatically, otherwise - special treatment required -
    - -

    Sequence and Mapping Operators

    - -

    - Sequence and mapping operators let wrapped objects behave in accordance - to Python's iteration and access protocols. These protocols differ - considerably from the ones found in C++. For example, Python's typical - iteration idiom looks like - -

    -for i in S:
    -
    - - while in C++ one writes - -
    -for (iterator i = S.begin(), end = S.end(); i != end; ++i)
    -
    - -

    One could try to wrap C++ iterators in order to carry the C++ idiom into - Python. However, this does not work very well because - -

      -
    1. It leads to - non-uniform Python code (wrapped sequences support a usage different from - Python built-in sequences) and - -
    2. Iterators (e.g. std::vector::iterator) are often implemented as plain C++ - pointers which are problematic for any automatic - wrapping system. -
    - -

    - It is a better idea to support the standard Python - sequence and mapping protocols for your wrapped containers. These - operators have to be wrapped manually because there are no corresponding - C++ operators that could be used for automatic wrapping. The Python - documentation lists the relevant - container operators. In particular, expose __getitem__, __setitem__ - and remember to raise the appropriate Python exceptions - (PyExc_IndexError for sequences, - PyExc_KeyError for mappings) when the requested item is not - present. - -

    - In the following example, we expose std::map<std::size_t,std::string>: -

    -
    -typedef std::map<std::size_t, std::string> StringMap;
    -
    -// A helper function for dealing with errors. Throw a Python exception
    -// if p == m.end().
    -void throw_key_error_if_end(
    -        const StringMap& m, 
    -        StringMap::const_iterator p, 
    -        std::size_t key)
    -{
    -    if (p == m.end())
    -    {
    -        PyErr_SetObject(PyExc_KeyError, boost::python::converters::to_python(key));
    -        boost::python::throw_error_already_set();
    -    }
    -}
    -
    -// Define some simple wrapper functions which match the Python  protocol
    -// for __getitem__, __setitem__, and __delitem__.  Just as in Python, a
    -// free function with a ``self'' first parameter makes a fine class method.
    -
    -const std::string& get_item(const StringMap& self, std::size_t key)
    -{
    -    const StringMap::const_iterator p = self.find(key);
    -    throw_key_error_if_end(self, p, key);
    -    return p->second;
    -}
    -
    -// Sets the item corresponding to key in the map.
    -void StringMapPythonClass::set_item(StringMap& self, std::size_t key, const std::string& value)
    -{
    -    self[key] = value;
    -}
    -
    -// Deletes the item corresponding to key from the map.
    -void StringMapPythonClass::del_item(StringMap& self, std::size_t key)
    -{
    -    const StringMap::iterator p = self.find(key);
    -    throw_key_error_if_end(self, p, key);
    -    self.erase(p);
    -}
    -
    -class_builder<StringMap> string_map(my_module, "StringMap");
    -string_map.def(boost::python::constructor<>());
    -string_map.def(&StringMap::size, "__len__");
    -string_map.def(get_item, "__getitem__");
    -string_map.def(set_item, "__setitem__");
    -string_map.def(del_item, "__delitem__");
    -
    -
    -

    - Then in Python: -

    -
    ->>> m = StringMap()
    ->>> m[1]
    -Traceback (innermost last):
    -  File "<stdin>", line 1, in ?
    -KeyError: 1
    ->>> m[1] = 'hello'
    ->>> m[1]
    -'hello'
    ->>> del m[1]
    ->>> m[1]            # prove that it's gone
    -Traceback (innermost last):
    -  File "<stdin>", line 1, in ?
    -KeyError: 1
    ->>> del m[2]
    -Traceback (innermost last):
    -  File "<stdin>", line 1, in ?
    -KeyError: 2
    ->>> len(m)
    -0
    ->>> m[0] = 'zero'
    ->>> m[1] = 'one'
    ->>> m[2] = 'two'
    ->>> m[3] = 'three'
    ->>> len(m)
    -4
    -
    -
    - -

    Customized Attribute Access

    - -

    - Just like built-in Python classes, Boost.Python extension classes support special - the usual attribute access methods __getattr__, - __setattr__, and __delattr__. - Because writing these functions can - be tedious in the common case where the attributes being accessed are - known statically, Boost.Python checks the special names - -

      -
    • - __getattr__<name>__ -
    • - __setattr__<name>__ -
    • - __delattr__<name>__ -
    - - to provide functional access to the attribute <name>. This - facility can be used from C++ or entirely from Python. For example, the - following shows how we can implement a ``computed attribute'' in Python: -
    -
    ->>> class Range(AnyBoost.PythonExtensionClass):
    -...    def __init__(self, start, end):
    -...        self.start = start
    -...        self.end = end
    -...    def __getattr__length__(self):
    -...        return self.end - self.start
    -...
    ->>> x = Range(3, 9)
    ->>> x.length
    -6
    -
    -
    -

    - Direct Access to Data Members -

    -

    - Boost.Python uses the special - __xxxattr__<name>__ functionality described above - to allow direct access to data members through the following special - functions on class_builder<> and - extension_class<>: -

      -
    • - def_getter(pointer-to-member, name) // - read access to the member via attribute name -
    • - def_setter(pointer-to-member, name) // - write access to the member via attribute name -
    • - def_readonly(pointer-to-member, name) - // read-only access to the member via attribute name -
    • - def_read_write(pointer-to-member, - name) // read/write access to the member via attribute - name -
    -

    - Note that the first two functions, used alone, may produce surprising - behavior. For example, when def_getter() is used, the - default functionality for setattr() and - delattr() remains in effect, operating on items in the extension - instance's name-space (i.e., its __dict__). For that - reason, you'll usually want to stick with def_readonly and - def_read_write. -

    - For example, to expose a std::pair<int,long> we - might write: -

    -
    -typedef std::pair<int,long> Pil;
    -int first(const Pil& x) { return x.first; }
    -long second(const Pil& x) { return x.second; }
    -   ...
    -my_module.def(first, "first");
    -my_module.def(second, "second");
    -
    -class_builder<Pil> pair_int_long(my_module, "Pair");
    -pair_int_long.def(boost::python::constructor<>());
    -pair_int_long.def(boost::python::constructor<int,long>());
    -pair_int_long.def_read_write(&Pil::first, "first");
    -pair_int_long.def_read_write(&Pil::second, "second");
    -
    -
    -

    - Now your Python class has attributes first and - second which, when accessed, actually modify or reflect the - values of corresponding data members of the underlying C++ object. Now - in Python: -

    -
    ->>> x = Pair(3,5)
    ->>> x.first
    -3
    ->>> x.second
    -5
    ->>> x.second = 8
    ->>> x.second
    -8
    ->>> second(x) # Prove that we're not just changing the instance __dict__
    -8
    -
    -
    -

    - And what about __complex__? -

    -

    - That, dear reader, is one problem we don't know how to solve. The - Python source contains the following fragment, indicating the - special-case code really is hardwired: -

    -
    -/* XXX Hack to support classes with __complex__ method */
    -if (PyInstance_Check(r)) { ...
    -
    -
    -

    -Next: A Peek Under the Hood -Previous: Inheritance -Up: Top -

    - © Copyright David Abrahams and Ullrich Köthe 2000. - 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. -

    - Updated: Nov 26, 2000 -

    - diff --git a/doc/under-the-hood.html b/doc/under-the-hood.html deleted file mode 100644 index ee0ecdfb..00000000 --- a/doc/under-the-hood.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - A Peek Under the Hood - -

    - c++boost.gif (8819 bytes) -

    -

    - A Peek Under the Hood -

    -

    - Declaring a class_builder<T> causes the instantiation - of an extension_class<T> to which it forwards all - member function calls and which is doing most of the real work. - extension_class<T> is a subclass of - PyTypeObject, the struct which Python's 'C' API uses - to describe a type. An instance of the - extension_class<> becomes the Python type object - corresponding to hello::world. When we add it to the module it goes into the - module's dictionary to be looked up under the name "world". -

    - Boost.Python uses C++'s template argument deduction mechanism to determine the - types of arguments to functions (except constructors, for which we must - provide an argument list - because they can't be named in C++). Then, it calls the appropriate - overloaded functions PyObject* - to_python(S) and - S'from_python(PyObject*, - type<S>) which convert between any C++ - type S and a PyObject*, the type which represents a - reference to any Python object in its 'C' API. The extension_class<T> - template defines a whole raft of these conversions (for T, T*, - T&, std::auto_ptr<T>, etc.), using the same inline - friend function technique employed by the boost operators - library. -

    - Because the to_python and from_python functions - for a user-defined class are defined by - extension_class<T>, it is important that an instantiation of - extension_class<T> is visible to any code which wraps - a C++ function with a T, T*, const T&, etc. parameter or - return value. In particular, you may want to create all of the classes at - the top of your module's init function, then def the member - functions later to avoid problems with inter-class dependencies. -

    - Next: Building a Module with Boost.Python - Previous: Special Method and Operator Support - Up: Top -

    - © Copyright David Abrahams 2000. 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. -

    - Updated: Nov 26, 2000 - diff --git a/doc/v2/acknowledgments.html b/doc/v2/acknowledgments.html index 071919e3..b2591e6d 100644 --- a/doc/v2/acknowledgments.html +++ b/doc/v2/acknowledgments.html @@ -1,32 +1,85 @@ + + - - - -Boost.Python - Acknowledgments - - - + + + + + Boost.Python - Acknowledgments + + + +
    - - - - -
    -

    -

    -
    -

    Boost.Python

    -

    Acknowledgments

    -
    -


    -{{text}} -
    -

    Revised - - 05 November, 2002 - -

    -

    © Copyright Dave Abrahams - 2002. All Rights Reserved.

    - + + +

    C++ Boost

    + + + +

    Boost.Python

    + +

    Acknowledgments

    + + + +
    + +

    Dave Abrahams is + the architect, designer, and implementor of Boost.Python.

    + +

    Joel de Guzman implemented the default + argument support and wrote the excellent tutorial documentation.

    + +

    Ralf W. + Grosse-Kunstleve implemented the pickle + support, 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 + extensions 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.

    + +

    Achim Domma contributed some + of the Object Wrappers and + HTML templates for this documentation. Dave Hawkes contributed + inspiration for the use of the scope class to simplify module + definition syntax. Pearu Pearson wrote some of the test cases that are in + the current test suite.

    + +

    Martin Casado solved some sticky problems which allow us to build the + Boost.Python shared library for AIX's crazy dynamic linking model.

    + +

    The development of this version of Boost.Python was funded in part by + the Lawrence Livermore National + Laboratories and by the Computational + Crystallography Initiative at Lawrence Berkeley National + Laboratories.

    + +

    Ullrich + Koethe provided the implementation of inheritance and special + method/operator support in the first version of Boost.Python.

    + +

    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.

    +
    + +

    Revised + + 08 October, 2002 + +

    + +

    © Copyright Dave Abrahams 2002. All Rights + Reserved.

    + + diff --git a/doc/v2/callbacks.html b/doc/v2/callbacks.html index f001984d..8c563336 100644 --- a/doc/v2/callbacks.html +++ b/doc/v2/callbacks.html @@ -1,62 +1,85 @@ + + - - - -Boost.Python - Calling Python Functions and Methods - - - + + + + + Boost.Python - Calling Python Functions and Methods + + + +
    - - - - -
    -

    -

    -
    -

    Boost.Python

    -

    Calling Python Functions and Methods

    -
    -
    -

    Contents

    -
    -
    Introduction
    -
    Argument Handling
    -
    Result Handling
    -
    Rationale
    -
    -
    + + +

    C++ Boost

    + -

    Introduction

    -

    -Boost.Python provides two families of function templates, -call and call_method, for -invoking Python functions and methods respectively. The interface for -calling a Python function object (or any Python callable object) looks -like: + +

    Boost.Python

    +

    Calling Python Functions and Methods

    + + + +
    + +

    Contents

    + +
    +
    Introduction
    + +
    Argument Handling
    + +
    Result Handling
    + +
    Rationale
    +
    +
    + +

    Introduction

    + The simplest way to call a Python function from C++, given an object instance f + holding the function, is simply to invoke its function call operator. +
    +f("tea", 4, 2) // In Python: f('tea', 4, 2)
    +
    + And of course, a method of an object instance x can + be invoked by using the function-call operator of the corresponding + attribute: +
    +x.attr("tea")(4, 2); // In Python: x.tea(4, 2)
    +
    + +

    If you don't have an object instance, Boost.Python + provides two families of function templates, call and call_method, for invoking + Python functions and methods respectively on PyObject*s. The + interface for calling a Python function object (or any Python callable + object) looks like:

     call<ResultType>(callable_object, a1, a2... aN);
     
    - -Calling a method of a Python object is similarly easy: - + Calling a method of a Python object is similarly easy:
    -call_method<ResultType>(self_object, "method-name", a1, a2... aN);
    +call_method<ResultType>(self_object, "method-name", a1, a2... aN);
     
    + This comparitively low-level interface is the one you'll use when + implementing C++ virtual functions that can be overridden in Python. +

    Argument Handling

    -

    Argument Handling

    -

    - -Arguments are converted to Python according to their type. By default, -the arguments a1...aN are copied into -new Python objects, but this behavior can be overridden by the use of -ptr() and ref(): - +

    Arguments are converted to Python according to their type. By default, + the arguments a1...aN are copied into + new Python objects, but this behavior can be overridden by the use of + ptr() and ref():

     class X : boost::noncopyable
     {
    @@ -69,178 +92,160 @@ void apply(PyObject* callable, X& x)
        boost::python::call<void>(callable, boost::ref(x));
     }
     
    - -In the table below, x denotes the actual argument -object and cv denotes an optional -cv-qualification: "const", -"volatile", or "const -volatile". + In the table below, x denotes the actual argument + object and cv denotes an optional + cv-qualification: "const", "volatile", + or "const volatile". - - + - + - - + - - + - + +
    Argument Type + Argument TypeBehavior + Behavior
    T cv&
    - T cv + T cv
    The Python argument is created by the same means used - for the return value of a wrapped C++ function returning - T. When - T is a class type, that normally means - *x is copy-constructed into the new Python - object. + The Python argument is created by the same means used for the + return value of a wrapped C++ function returning T. When + T is a class type, that normally means *x + is copy-constructed into the new Python object.
    T* + T*If x == 0, the Python argument will - be None. Otherwise, - the Python argument is created by the same means used for the - return value of a wrapped C++ function returning - T. When - T is a class type, that normally means - *x is copy-constructed into the new Python - object. + If x == 0, the Python argument will be + None. + Otherwise, the Python argument is created by the same means used for + the return value of a wrapped C++ function returning T. + When T is a class type, that normally means + *x is copy-constructed into the new Python object.
    boost::reference_wrapper<T> + boost::reference_wrapper<T>The Python argument contains a pointer to, rather than a - copy of, x.get(). Note: failure to ensure that no - Python code holds a reference to the resulting object beyond - the lifetime of *x.get() may result in a - crash! + The Python argument contains a pointer to, rather than a copy of, + x.get(). Note: failure to ensure that no Python code + holds a reference to the resulting object beyond the lifetime of + *x.get() may result in a crash!
    pointer_wrapper<T> - - If x.get() == 0, the Python - argument will be None. - Otherwise, the Python argument contains a pointer to, rather - than a copy of, *x.get(). Note: failure to ensure - that no Python code holds a reference to the resulting object - beyond the lifetime of *x.get() may result in - a crash! + pointer_wrapper<T>If x.get() == 0, the Python argument will + be None. + Otherwise, the Python argument contains a pointer to, rather than a + copy of, *x.get(). Note: failure to ensure that no + Python code holds a reference to the resulting object beyond the + lifetime of *x.get() may result in a crash!
    -

    Result Handling

    +

    Result Handling

    + In general, call<ResultType>() and + call_method<ResultType>() return + ResultType by exploiting all lvalue and rvalue + from_python converters registered for ResultType and + returning a copy of the result. However, when ResultType 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. -In general, call<ResultType>() and -call_method<ResultType>() return -ResultType by exploiting all lvalue and rvalue -from_python converters registered for ResultType and -returning a copy of the result. However, when -ResultType 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. +

    Rationale

    + In general, to get Python arguments corresponding to + a1...aN, 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. -

    Rationale

    +

    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 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[1].

    -In general, to get Python arguments corresponding to -a1...aN, 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. +

    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 + *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 to None conversion: it's illegal to + dereference a null pointer value.

    -

    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 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[1]. +

    The compromise I've settled on is this:

    -

    -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 -*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 to -None conversion: it's illegal to dereference a null -pointer value. +

      +
    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. -

      +

    3. 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.
    4. +
    -The compromise I've settled on is this: +

    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 call<char + const*>(...) returns.

    -
      -
    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. +

      The old Boost.Python v1 deals with this issue by refusing to compile + any uses of call<char const*>(), 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.

      -
    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. -
    +

    In Boost.Python v2 this is dealt with by:

    -

    -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 call<char -const*>(...) returns. +

      +
    1. lifting the compile-time restriction on const char* callback + returns
    2. -

      -The old Boost.Python v1 deals with this issue by refusing to compile -any uses of call<char const*>(), 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. +

    3. detecting the case when the reference count on the result Python + object is 1 and throwing an exception inside of + call<U>(...) when U is a pointer or + reference type.
    4. +
    + This should be acceptably safe because users have to explicitly specify a + pointer/reference for U in call<U>, and + they will be protected against dangles at runtime, at least long enough + to get out of the call<U>(...) invocation. +
    + [1] 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. -

    +

    Revised + + 17 April, 2002 +

    -In Boost.Python v2 this is dealt with 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 - call<U>(...) when U is a pointer - or reference type. -
    - -This should be acceptably safe because users have to explicitly -specify a pointer/reference for U in -call<U>, and they will be protected against dangles -at runtime, at least long enough to get out of the -call<U>(...) invocation. - -
    - -[1] 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. - -

    Revised - - 17 April, 2002 - -

    -

    © Copyright Dave Abrahams - 2002. All Rights Reserved.

    - +

    © Copyright Dave Abrahams 2002. All Rights + Reserved.

    + + diff --git a/doc/v2/def.html b/doc/v2/def.html index 25a78bf8..d0447930 100644 --- a/doc/v2/def.html +++ b/doc/v2/def.html @@ -52,6 +52,7 @@ in the current scope.

    Functions

    + def
     template <class F>
     void def(char const* name, F f);
    diff --git a/doc/v2/faq.html b/doc/v2/faq.html
    index 7a2811af..d15f536a 100644
    --- a/doc/v2/faq.html
    +++ b/doc/v2/faq.html
    @@ -32,8 +32,8 @@
           
    Is return_internal reference efficient?
    -
    How can I which take C++ containers as - arguments?
    +
    How can I wrap containers which take C++ + containers as arguments?

    Is return_internal reference efficient?

    diff --git a/doc/v2/index.html b/doc/v2/index.html index d1c1c0c0..6f5150fb 100644 --- a/doc/v2/index.html +++ b/doc/v2/index.html @@ -1,43 +1,17 @@ + + - - - -Boost.Python - - - - - - - -
    -

    -

    -
    -

    Boost.Python

    -

    Index

    -
    -
    -

    Contents

    -
    -
    Overview
    -
    Reference
    -
    Configuration Information
    -
    Rationale
    -
    Definitions
    -
    Frequently Asked Questions (FAQs)
    -
    Progress Reports
    -
    Bibliography
    -
    Acknowledgments
    -
    -
    -

    Revised - - 05 November, 2002 - -

    -

    © Copyright Dave Abrahams - 2002. All Rights Reserved.

    - + + + + + + + + + Automatic redirection failed, please go to ../index.html. + + diff --git a/doc/v2/python.html b/doc/v2/python.html new file mode 100644 index 00000000..78706681 --- /dev/null +++ b/doc/v2/python.html @@ -0,0 +1,108 @@ + + + + + + + + + Boost.Python - <boost/python.hpp> + + + + + + + + + +
    +

    C++ Boost

    +
    +

    Boost.Python

    + +

    Header <boost/python.hpp>

    +
    +
    + +

    Contents

    + +
    +
    Introduction
    +
    +
    + +

    Introduction

    + +

    This is a convenience header which #includes all of the public + interface headers that are part of the Boost.Python library

    +
    +# 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>
    +
    + +

    Revised + + 08 October, 2002 + +

    + +

    © Copyright Dave Abrahams 2002. All Rights + Reserved.

    + + + diff --git a/doc/v2/reference.html b/doc/v2/reference.html index 0923a434..fed0e92a 100644 --- a/doc/v2/reference.html +++ b/doc/v2/reference.html @@ -13,7 +13,7 @@ p.c3 {font-style: italic} h2.c2 {text-align: center} h1.c1 {text-align: center} - + @@ -61,6 +61,8 @@
    To/From Python Type Conversion
    Utility and Infrastructure
    + +
    Topics

    @@ -111,6 +113,34 @@ +
    def.hpp
    + +
    +
    +
    Functions
    + +
    +
    +
    def
    +
    +
    +
    +
    + +
    enum.hpp
    + +
    +
    +
    Classes
    + +
    +
    +
    enum_
    +
    +
    +
    +
    +
    errors.hpp
    @@ -136,7 +166,6 @@
    throw_error_already_set
    - @@ -207,7 +236,8 @@
    -
    BOOST_PYTHON_MODULE
    +
    BOOST_PYTHON_MODULE
    @@ -238,6 +268,20 @@ + +
    scope.hpp
    + +
    +
    +
    Classes
    + +
    +
    +
    scope
    +
    +
    +
    +

    Object Wrappers

    @@ -326,6 +370,28 @@ + +
    tuple.hpp
    + +
    +
    +
    Classes
    + +
    +
    +
    tuple
    +
    +
    + +
    Functions
    + +
    +
    +
    make_tuple
    +
    +
    +
    +

    Function Invocation and Creation

    @@ -771,6 +837,8 @@ +
    <boost/python.hpp>
    +
    handle.hpp
    @@ -779,18 +847,17 @@
    -
    handle
    +
    handle
    +
    Functions
    -
    borrowed
    -
    allow_null
    +
    borrowed
    + +
    allow_null
    @@ -818,6 +885,15 @@ + +

    Topics

    + +
    +
    Calling Python Functions and + Methods
    + +
    Pickle Support
    +

    Revised diff --git a/doc/v2/scope.html b/doc/v2/scope.html index 17450645..5a6c4be2 100644 --- a/doc/v2/scope.html +++ b/doc/v2/scope.html @@ -121,15 +121,22 @@ struct X { void f(); - struct Y { int g() { return 0; } }; + 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_<Y>("Y") .def("g", &Y::g) ; @@ -138,9 +145,11 @@ BOOST_PYTHON_MODULE(nested) Interactive Python:

     >>> import nested
    +>>> nested.yes
    +1
     >>> y = nested.X.Y()
     >>> y.g()
    -0
    +42
     

    Revised 03 October, 2002

    diff --git a/example/Attic/project.zip b/example/Attic/project.zip new file mode 100644 index 0000000000000000000000000000000000000000..d863defdb784ca6864f83a6ca22443b65259bda6 GIT binary patch literal 1469 zcmWIWW@Zs#U|`^2aL-z=bNJRCn;-@ThExUy25|-khJvE}tkmQZ{iOW-;u77Y(#)I` zy{yFC;4lt758rb>t3xzAbWR3noDA1E=@II2>b$;QpoiAkGoFDO>vZ%y&pv%x^yxc4 zUnl>k@BD!qLN8pt%&yFu9jCV;DYheN#*RAAx;np&b}kpB7!c0*nYCVr<@xLNO-u|7 zuB;3U{7BC5O3Y2m%t>txiS@tjAW+jk<^Kk+Ul+V?bbRY|TC!w8Q-~ekh-xlMm~)Kl=XCCX%Bmwa zJ??+)J&)AN_8(iU8IzDV_4v92v(_w~TPV$OD&OGBa;Aste>_*2dg_PFg{y5cQ!%Rh;e%O!zHU z=F3kDH@6Qzefsy)th(=i|JmH!B-`b*$vxC-=A2VOmUAN>{}8zTWaDk!$KUtun%1&q|%IrgyH9vOj*qP|t9e>?k zFKqkgr&rZ)=3f@CZ~a^S+L2c_Zrg(XKX1?Vxa&_iygRr-^U9SUF(ID>E`5=h9~v2H z^Y8j1ZnYwte|bH}C*99faoZGAP~-2sW!0nU(Uph0k3XLozOVP?ksFmeq_%bC&wZlx z#<*WBw0E;HU#Oa(=H{Lbd1rAq{wp&~XO}0e=BVKH+tvNuB6N59$@3-acLx1=R(1St z&C%39I}|HonO-?@wsdOR1YDk~87f`weBlK5xqm--J!ejv{Cw-PmbIaqT=qWNSE$sR zZZk>ZT47qup$oiRUE+`U5y^FB)_R@1rIH!yj0_A985tM^P?Kv>X-;afYk+U|VFRAM z;=knOQZ{_O@MYg!w%t5#$7cO55ZZdNU`dkp%U|!))is&pb@uA-W!f6|AXBNo+`Q#t z@SVJEvzgqLW~}OOPfNKk8)5ZJw_4i9PwGOZHJ{3}p3qa)M+Hh1J``L`@Z(8e-}`w+ zOu}`Q+z*`BF7xi4?IFi|j=ktEFYiPJwZ>=D7$fs~L>5fipHV6?r=xoH_8i&c}HD)t{a<}NprJAG4!c6I;i(?P6q^Ws*&im0y- z4c#04)?z_I=HDBFdgp!#ah9!HeV(ObbNh~xzpu*oTdv+ZYgSUC<@wb<$24CU{Etw} zeeUqWA|P8Th<%qr^S>o0Ydo?ng}-Mn|NryDoT4?JW$l|{4{>p_9a#Q*{V+3R&c zGz@bf1!{mdBa;XN?jj4Mhmk>nVOt}Jg`)sNHUwLN1JVjHq#em>Xz_!r8C&!tG@CIa ticqh_TySE5=*I0&kZw>i`tR7yg3uk{&B_LnVPRll_{PA%u#pAC0|1J>SqlIF literal 0 HcmV?d00001 diff --git a/example/project.zip b/example/project.zip new file mode 100644 index 0000000000000000000000000000000000000000..d863defdb784ca6864f83a6ca22443b65259bda6 GIT binary patch literal 1469 zcmWIWW@Zs#U|`^2aL-z=bNJRCn;-@ThExUy25|-khJvE}tkmQZ{iOW-;u77Y(#)I` zy{yFC;4lt758rb>t3xzAbWR3noDA1E=@II2>b$;QpoiAkGoFDO>vZ%y&pv%x^yxc4 zUnl>k@BD!qLN8pt%&yFu9jCV;DYheN#*RAAx;np&b}kpB7!c0*nYCVr<@xLNO-u|7 zuB;3U{7BC5O3Y2m%t>txiS@tjAW+jk<^Kk+Ul+V?bbRY|TC!w8Q-~ekh-xlMm~)Kl=XCCX%Bmwa zJ??+)J&)AN_8(iU8IzDV_4v92v(_w~TPV$OD&OGBa;Aste>_*2dg_PFg{y5cQ!%Rh;e%O!zHU z=F3kDH@6Qzefsy)th(=i|JmH!B-`b*$vxC-=A2VOmUAN>{}8zTWaDk!$KUtun%1&q|%IrgyH9vOj*qP|t9e>?k zFKqkgr&rZ)=3f@CZ~a^S+L2c_Zrg(XKX1?Vxa&_iygRr-^U9SUF(ID>E`5=h9~v2H z^Y8j1ZnYwte|bH}C*99faoZGAP~-2sW!0nU(Uph0k3XLozOVP?ksFmeq_%bC&wZlx z#<*WBw0E;HU#Oa(=H{Lbd1rAq{wp&~XO}0e=BVKH+tvNuB6N59$@3-acLx1=R(1St z&C%39I}|HonO-?@wsdOR1YDk~87f`weBlK5xqm--J!ejv{Cw-PmbIaqT=qWNSE$sR zZZk>ZT47qup$oiRUE+`U5y^FB)_R@1rIH!yj0_A985tM^P?Kv>X-;afYk+U|VFRAM z;=knOQZ{_O@MYg!w%t5#$7cO55ZZdNU`dkp%U|!))is&pb@uA-W!f6|AXBNo+`Q#t z@SVJEvzgqLW~}OOPfNKk8)5ZJw_4i9PwGOZHJ{3}p3qa)M+Hh1J``L`@Z(8e-}`w+ zOu}`Q+z*`BF7xi4?IFi|j=ktEFYiPJwZ>=D7$fs~L>5fipHV6?r=xoH_8i&c}HD)t{a<}NprJAG4!c6I;i(?P6q^Ws*&im0y- z4c#04)?z_I=HDBFdgp!#ah9!HeV(ObbNh~xzpu*oTdv+ZYgSUC<@wb<$24CU{Etw} zeeUqWA|P8Th<%qr^S>o0Ydo?ng}-Mn|NryDoT4?JW$l|{4{>p_9a#Q*{V+3R&c zGz@bf1!{mdBa;XN?jj4Mhmk>nVOt}Jg`)sNHUwLN1JVjHq#em>Xz_!r8C&!tG@CIa ticqh_TySE5=*I0&kZw>i`tR7yg3uk{&B_LnVPRll_{PA%u#pAC0|1J>SqlIF literal 0 HcmV?d00001 diff --git a/include/boost/python.hpp b/include/boost/python.hpp new file mode 100644 index 00000000..dd87d2bc --- /dev/null +++ b/include/boost/python.hpp @@ -0,0 +1,62 @@ +// Copyright David Abrahams 2002. 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. +#ifndef PYTHON_DWA2002810_HPP +# define PYTHON_DWA2002810_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +#endif PYTHON_DWA2002810_HPP diff --git a/include/boost/python/detail/module_init.hpp b/include/boost/python/detail/module_init.hpp deleted file mode 100644 index 5b2366f6..00000000 --- a/include/boost/python/detail/module_init.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright David Abrahams 2002. 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. -#ifdef BOOST_PYTHON_V2 -# error obsolete -#endif -#ifndef MODULE_INIT_DWA2002529_HPP -# define MODULE_INIT_DWA2002529_HPP - -# ifndef BOOST_PYTHON_MODULE_INIT - -# if defined(_WIN32) || defined(__CYGWIN__) - -# define BOOST_PYTHON_MODULE_INIT(name) \ -void init_module_##name(); \ -extern "C" __declspec(dllexport) void init##name() \ -{ \ - boost::python::handle_exception(&init_module_##name); \ -} \ -void init_module_##name() - -# elif defined(_AIX) - -# include -# define BOOST_PYTHON_MODULE_INIT(name) \ -void init_module_##name(); \ -extern "C" \ -{ \ - extern PyObject* _PyImport_LoadDynamicModule(char*, char*, FILE *); \ - void init##name() \ - { \ - boost::python::detail::aix_init_module(_PyImport_LoadDynamicModule, &init_module_##name); \ - } \ -} \ -void init_module_##name() - -# else - -# define BOOST_PYTHON_MODULE_INIT(name) \ -void init_module_##name(); \ -extern "C" void init##name() \ -{ \ - boost::python::handle_exception(&init_module_##name); \ -} \ -void init_module_##name() - -# endif - -# endif - -#endif // MODULE_INIT_DWA2002529_HPP diff --git a/include/boost/python/errors.hpp b/include/boost/python/errors.hpp index 4c47aca8..cd0b3586 100644 --- a/include/boost/python/errors.hpp +++ b/include/boost/python/errors.hpp @@ -46,11 +46,9 @@ inline T* expect_non_null(T* x) return x; } -# ifdef BOOST_PYTHON_V2 // Return source if it is an instance of pytype; throw an appropriate // exception otherwise. BOOST_PYTHON_DECL PyObject* pytype_check(PyTypeObject* pytype, PyObject* source); -# endif }} // namespace boost::python diff --git a/include/boost/python/init.hpp b/include/boost/python/init.hpp index 94d2dd31..882ce756 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -270,13 +270,13 @@ class init : public init_base > typedef typename mpl::fold< required_args , mpl::list0<> - , mpl::push_front + , mpl::push_front<> >::type reversed_required; typedef typename mpl::fold< optional_args , reversed_required - , mpl::push_front + , mpl::push_front<> >::type reversed_args; // Count the maximum number of arguments @@ -310,7 +310,7 @@ namespace detail typedef typename mpl::fold< ReversedArgs , mpl::list0<> - , mpl::push_front + , mpl::push_front<> >::type args; typedef typename ClassT::holder_selector holder_selector_t; diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index df401f85..7087f83a 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -1,555 +1,332 @@ -// (C) Copyright Ullrich Koethe and David Abrahams 2000-2001. Permission to -// copy, use, modify, sell and distribute this software is granted provided -// this copyright notice appears in all copies. This software is provided "as -// is" without express or implied warranty, and with no claim as to its -// suitability for any purpose. -// -// The authors gratefully acknowlege the support of Dragon Systems, Inc., in -// producing this work. -// -// Revision History: -// 23 Jan 2001 - Another stupid typo fix by Ralf W. Grosse-Kunstleve (David Abrahams) -// 20 Jan 2001 - Added a fix from Ralf W. Grosse-Kunstleve (David Abrahams) -#ifndef OPERATORS_UK112000_H_ -# define OPERATORS_UK112000_H_ -# ifdef BOOST_PYTHON_V2 +// Copyright David Abrahams 2002. 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. +#ifndef OPERATORS_DWA2002530_HPP +# define OPERATORS_DWA2002530_HPP -# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include -# else - -# include -# include - -// When STLport is used with native streams, _STL::ostringstream().str() is not -// _STL::string, but std::string. This confuses to_python(), so we'll use -// strstream instead. Also, GCC 2.95.2 doesn't have sstream. -# if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2) -# define BOOST_PYTHON_USE_SSTREAM -# endif - -# if defined(BOOST_PYTHON_USE_SSTREAM) -# include -# else -# include -# endif - -namespace boost { namespace python { - -BOOST_PYTHON_DECL tuple standard_coerce(ref l, ref r); - -namespace detail { - - // helper class for automatic operand type detection - // during operator wrapping. - struct auto_operand {}; -} - -// Define operator ids that can be or'ed together -// (boost::python::op_add | boost::python::op_sub | boost::python::op_mul). -// This allows to wrap several operators in one line. -enum operator_id -{ - op_add = 0x1, - op_sub = 0x2, - op_mul = 0x4, - op_div = 0x8, - op_mod = 0x10, - op_divmod =0x20, - op_pow = 0x40, - op_lshift = 0x80, - op_rshift = 0x100, - op_and = 0x200, - op_xor = 0x400, - op_or = 0x800, - op_neg = 0x1000, - op_pos = 0x2000, - op_abs = 0x4000, - op_invert = 0x8000, - op_int = 0x10000, - op_long = 0x20000, - op_float = 0x40000, - op_str = 0x80000, - op_cmp = 0x100000, - op_gt = 0x200000, - op_ge = 0x400000, - op_lt = 0x800000, - op_le = 0x1000000, - op_eq = 0x2000000, - op_ne = 0x4000000 -}; - -// Wrap the operators given by "which". Usage: -// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>()); -template -struct operators {}; - -// Wrap heterogeneous operators with given left operand type. Usage: -// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), -// boost::python::left_operand()); -template -struct left_operand {}; - -// Wrap heterogeneous operators with given right operand type. Usage: -// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), -// boost::python::right_operand()); -template -struct right_operand {}; +namespace boost { namespace python { namespace detail { - template - struct operand_select + // This is essentially the old v1 to_python(). It will be eliminated + // once the public interface for to_python is settled on. + template + PyObject* convert_result(T const& x) { - template - struct wrapped - { - typedef Specified type; - }; - }; - - template <> - struct operand_select - { - template - struct wrapped - { - typedef const wrapped_type& type; - }; - }; - - template struct define_operator; - - // Base class which grants access to extension_class_base::add_method() to its derived classes - struct add_operator_base - { - protected: - static inline void add_method(extension_class_base* target, function* method, const char* name) - { target->add_method(method, name); } - }; - -// -// choose_op, choose_unary_op, and choose_rop -// -// These templates use "poor man's partial specialization" to generate the -// appropriate add_method() call (if any) for a given operator and argument set. -// -// Usage: -// choose_op<(which & op_add)>::template args::add(ext_class); -// -// (see extension_class<>::def_operators() for more examples). -// - template - struct choose_op - { - template - struct args : add_operator_base - { - static inline void add(extension_class_base* target) - { - typedef define_operator def_op; - add_method(target, - new typename def_op::template operator_function(), - def_op::name()); - } - - }; - }; - - // specialization for 0 has no effect - template <> - struct choose_op<0> - { - template - struct args - { - static inline void add(extension_class_base*) - { - } - - }; - }; - - template - struct choose_unary_op - { - template - struct args : add_operator_base - { - static inline void add(extension_class_base* target) - { - typedef define_operator def_op; - add_method(target, - new typename def_op::template operator_function(), - def_op::name()); - } - - }; - }; - - // specialization for 0 has no effect - template <> - struct choose_unary_op<0> - { - template - struct args - { - static inline void add(extension_class_base*) - { - } - - }; - }; - - template - struct choose_rop - { - template - struct args : add_operator_base - { - static inline void add(extension_class_base* target) - { - typedef define_operator def_op; - add_method(target, - new typename def_op::template roperator_function(), - def_op::rname()); - } - - }; - }; - - // specialization for 0 has no effect - template <> - struct choose_rop<0> - { - template - struct args - { - static inline void add(extension_class_base*) - { - } - - }; - }; - - -// Fully specialize define_operator for all operators defined in operator_id above. -// Every specialization defines one function object for normal operator calls and one -// for operator calls with operands reversed ("__r*__" function variants). -// Specializations for most operators follow a standard pattern: execute the expression -// that uses the operator in question. This standard pattern is realized by the following -// macros so that the actual specialization can be done by just calling a macro. -# define PY_DEFINE_BINARY_OPERATORS(id, oper) \ - template <> \ - struct define_operator \ - { \ - template \ - struct operator_function : function \ - { \ - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ - { \ - tuple args(ref(arguments, ref::increment_count)); \ - \ - return BOOST_PYTHON_CONVERSION::to_python( \ - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) oper \ - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type())); \ - } \ - \ - const char* description() const \ - { return "__" #id "__"; } \ - }; \ - \ - template \ - struct roperator_function : function \ - { \ - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ - { \ - tuple args(ref(arguments, ref::increment_count)); \ - \ - return BOOST_PYTHON_CONVERSION::to_python( \ - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) oper \ - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type())); \ - } \ - \ - const char* description() const \ - { return "__r" #id "__"; } \ - \ - }; \ - \ - static const char * name() { return "__" #id "__"; } \ - static const char * rname() { return "__r" #id "__"; } \ + return converter::arg_to_python(x).release(); } -# define PY_DEFINE_UNARY_OPERATORS(id, oper) \ - template <> \ - struct define_operator \ - { \ - template \ - struct operator_function : function \ - { \ - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ - { \ - tuple args(ref(arguments, ref::increment_count)); \ - \ - return BOOST_PYTHON_CONVERSION::to_python( \ - oper(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); \ - } \ - \ - const char* description() const \ - { return "__" #id "__"; } \ - }; \ - \ - static const char * name() { return "__" #id "__"; } \ - } - - PY_DEFINE_BINARY_OPERATORS(add, +); - PY_DEFINE_BINARY_OPERATORS(sub, -); - PY_DEFINE_BINARY_OPERATORS(mul, *); - PY_DEFINE_BINARY_OPERATORS(div, /); - PY_DEFINE_BINARY_OPERATORS(mod, %); - PY_DEFINE_BINARY_OPERATORS(lshift, <<); - PY_DEFINE_BINARY_OPERATORS(rshift, >>); - PY_DEFINE_BINARY_OPERATORS(and, &); - PY_DEFINE_BINARY_OPERATORS(xor, ^); - PY_DEFINE_BINARY_OPERATORS(or, |); - PY_DEFINE_BINARY_OPERATORS(gt, >); - PY_DEFINE_BINARY_OPERATORS(ge, >=); - PY_DEFINE_BINARY_OPERATORS(lt, <); - PY_DEFINE_BINARY_OPERATORS(le, <=); - PY_DEFINE_BINARY_OPERATORS(eq, ==); - PY_DEFINE_BINARY_OPERATORS(ne, !=); - - PY_DEFINE_UNARY_OPERATORS(neg, -); - PY_DEFINE_UNARY_OPERATORS(pos, +); - PY_DEFINE_UNARY_OPERATORS(abs, abs); - PY_DEFINE_UNARY_OPERATORS(invert, ~); - PY_DEFINE_UNARY_OPERATORS(int, long); - PY_DEFINE_UNARY_OPERATORS(long, PyLong_FromLong); - PY_DEFINE_UNARY_OPERATORS(float, double); - -# undef PY_DEFINE_BINARY_OPERATORS -# undef PY_DEFINE_UNARY_OPERATORS - -// Some operators need special treatment, e.g. because there is no corresponding -// expression in C++. These are specialized manually. - -// pow(): Manual specialization needed because an error message is required if this -// function is called with three arguments. The "power modulo" operator is not -// supported by define_operator, but can be wrapped manually (see special.html). - template <> - struct define_operator + // Operator implementation template declarations. The nested apply + // declaration here keeps MSVC6 happy. + template struct operator_l { - template - struct operator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const - { - tuple args(ref(arguments, ref::increment_count)); - - if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type) - { - PyErr_SetString(PyExc_TypeError, "expected 2 arguments, got 3"); - throw_argument_error(); - } - - return BOOST_PYTHON_CONVERSION::to_python( - pow(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()), - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()))); - } - - const char* description() const - { return "__pow__"; } - - }; - - template - struct roperator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const - { - tuple args(ref(arguments, ref::increment_count)); - - if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type) - { - PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()"); - throw_argument_error(); - } - - return BOOST_PYTHON_CONVERSION::to_python( - pow(BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()), - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); - } - - const char* description() const - { return "__rpow__"; } - - }; - - static const char * name() { return "__pow__"; } - static const char * rname() { return "__rpow__"; } + template struct apply; }; - -// divmod(): Manual specialization needed because we must actually call two operators and -// return a tuple containing both results - template <> - struct define_operator - { - template - struct operator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const - { - tuple args(ref(arguments, ref::increment_count)); - PyObject * res = PyTuple_New(2); - - PyTuple_SET_ITEM(res, 0, - BOOST_PYTHON_CONVERSION::to_python( - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) / - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()))); - PyTuple_SET_ITEM(res, 1, - BOOST_PYTHON_CONVERSION::to_python( - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) % - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()))); - - return res; - } - - const char* description() const - { return "__divmod__"; } - - }; - - template - struct roperator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const - { - tuple args(ref(arguments, ref::increment_count)); - PyObject * res = PyTuple_New(2); - - PyTuple_SET_ITEM(res, 0, - BOOST_PYTHON_CONVERSION::to_python( - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) / - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); - PyTuple_SET_ITEM(res, 1, - BOOST_PYTHON_CONVERSION::to_python( - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) % - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); - - return res; - } - - const char* description() const - { return "__rdivmod__"; } - - }; - - static const char * name() { return "__divmod__"; } - static const char * rname() { return "__rdivmod__"; } - }; - -// cmp(): Manual specialization needed because there is no three-way compare in C++. -// It is implemented by two one-way comparisons with operators reversed in the second. - template <> - struct define_operator - { - template - struct operator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const - { - tuple args(ref(arguments, ref::increment_count)); - - return BOOST_PYTHON_CONVERSION::to_python( - (BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) < - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type())) ? - - 1 : - (BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) < - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type())) ? - 1 : - 0) ; - } - - const char* description() const - { return "__cmp__"; } - - }; - - template - struct roperator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const - { - tuple args(ref(arguments, ref::increment_count)); - - return BOOST_PYTHON_CONVERSION::to_python( - (BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) < - BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type())) ? - - 1 : - (BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) < - BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type())) ? - 1 : - 0) ; - } - - const char* description() const - { return "__rcmp__"; } - - }; - - static const char * name() { return "__cmp__"; } - static const char * rname() { return "__rcmp__"; } - }; - -# ifndef BOOST_PYTHON_USE_SSTREAM - class unfreezer { - public: - unfreezer(std::ostrstream& s) : m_stream(s) {} - ~unfreezer() { m_stream.freeze(false); } - private: - std::ostrstream& m_stream; - }; -# endif -// str(): Manual specialization needed because the string conversion does not follow -// the standard pattern relized by the macros. - template <> - struct define_operator + template struct operator_r { - template - struct operator_function : function - { - PyObject* do_call(PyObject* arguments, PyObject*) const - { - tuple args(ref(arguments, ref::increment_count)); - -// When STLport is used with native streams, _STL::ostringstream().str() is not -// _STL::string, but std::string. -# ifdef BOOST_PYTHON_USE_SSTREAM - std::ostringstream s; - s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()); - return BOOST_PYTHON_CONVERSION::to_python(s.str()); -# else - std::ostrstream s; - s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) << char(); - auto unfreezer unfreeze(s); - return BOOST_PYTHON_CONVERSION::to_python(const_cast(s.str())); -# endif - } - - const char* description() const - { return "__str__"; } - - }; - - static const char * name() { return "__str__"; } + template struct apply; }; + template struct operator_1 + { + template struct apply; + }; -} // namespace detail + // MSVC6 doesn't want us to do this sort of inheritance on a nested + // class template, so we use this layer of indirection to avoid + // ::template<...> on the nested apply functions below + template + struct operator_l_inner + : operator_l::template apply + {}; + + template + struct operator_r_inner + : operator_r::template apply + {}; + + template + struct operator_1_inner + : operator_1::template apply + {}; + + // Define three different binary_op templates which take care of + // these cases: + // self op self + // self op R + // L op self + // + // The inner apply metafunction is used to adjust the operator to + // the class type being defined. Inheritance of the outer class is + // simply used to provide convenient access to the operation's + // name(). + + // self op self + template + struct binary_op : operator_l + { + template + struct apply : operator_l_inner + { + }; + }; + + // self op R + template + struct binary_op_l : operator_l + { + template + struct apply : operator_l_inner + { + }; + }; + + // L op self + template + struct binary_op_r : operator_r + { + template + struct apply : operator_r_inner + { + }; + }; + + template + struct unary_op : operator_1 + { + template + struct apply : operator_1_inner + { + }; + }; + + // This type is what actually gets returned from operators used on + // self_t + template + struct operator_ + : mpl::if_< + is_same + , typename mpl::if_< + is_same + , binary_op + , binary_op_l::type> + >::type + , typename mpl::if_< + is_same + , unary_op + , binary_op_r::type> + >::type + >::type + { + }; +} + +# define BOOST_PYTHON_BINARY_OPERATION(id, rid, expr) \ +namespace detail \ +{ \ + template <> \ + struct operator_l \ + { \ + template \ + struct apply \ + { \ + static inline PyObject* execute(L const& l, R const& r) \ + { \ + return detail::convert_result(expr); \ + } \ + }; \ + static char const* name() { return "__" #id "__"; } \ + }; \ + \ + template <> \ + struct operator_r \ + { \ + template \ + struct apply \ + { \ + static inline PyObject* execute(R const& r, L const& l) \ + { \ + return detail::convert_result(expr); \ + } \ + }; \ + static char const* name() { return "__" #rid "__"; } \ + }; \ +} + +# define BOOST_PYTHON_BINARY_OPERATOR(id, rid, op) \ +BOOST_PYTHON_BINARY_OPERATION(id, rid, l op r) \ +namespace self_ns \ +{ \ + template \ + inline detail::operator_ \ + operator##op(L const&, R const&) \ + { \ + return detail::operator_(); \ + } \ +} + +BOOST_PYTHON_BINARY_OPERATOR(add, radd, +) +BOOST_PYTHON_BINARY_OPERATOR(sub, rsub, -) +BOOST_PYTHON_BINARY_OPERATOR(mul, rmul, *) +BOOST_PYTHON_BINARY_OPERATOR(div, rdiv, /) +BOOST_PYTHON_BINARY_OPERATOR(mod, rmod, %) +BOOST_PYTHON_BINARY_OPERATOR(lshift, rlshift, <<) +BOOST_PYTHON_BINARY_OPERATOR(rshift, rrshift, >>) +BOOST_PYTHON_BINARY_OPERATOR(and, rand, &) +BOOST_PYTHON_BINARY_OPERATOR(xor, rxor, ^) +BOOST_PYTHON_BINARY_OPERATOR(or, ror, |) +BOOST_PYTHON_BINARY_OPERATOR(gt, lt, >) +BOOST_PYTHON_BINARY_OPERATOR(ge, le, >=) +BOOST_PYTHON_BINARY_OPERATOR(lt, gt, <) +BOOST_PYTHON_BINARY_OPERATOR(le, ge, <=) +BOOST_PYTHON_BINARY_OPERATOR(eq, eq, ==) +BOOST_PYTHON_BINARY_OPERATOR(ne, ne, !=) +# undef BOOST_PYTHON_BINARY_OPERATOR + +// pow isn't an operator in C++; handle it specially. +BOOST_PYTHON_BINARY_OPERATION(pow, rpow, pow(l,r)) +# undef BOOST_PYTHON_BINARY_OPERATION + +namespace self_ns +{ +# ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP + template + inline detail::operator_ + pow(L const&, R const&) + { + return detail::operator_(); + } +# else + // When there's no argument-dependent lookup, we need these + // overloads to handle the case when everything is imported into the + // global namespace. Note that the plain overload below does /not/ + // take const& arguments. This is needed by MSVC6 at least, or it + // complains of ambiguities, since there's no partial ordering. + inline detail::operator_ + pow(self_t, self_t) + { + return detail::operator_(); + } + template + inline detail::operator_ + pow(self_t const&, R const&) + { + return detail::operator_(); + } + template + inline detail::operator_ + pow(L const&, self_t const&) + { + return detail::operator_(); + } +# endif +} + + +# define BOOST_PYTHON_INPLACE_OPERATOR(id, op) \ +namespace detail \ +{ \ + template <> \ + struct operator_l \ + { \ + template \ + struct apply \ + { \ + static inline PyObject* \ + execute(back_reference l, R const& r) \ + { \ + l.get() op r; \ + return python::incref(l.source().ptr()); \ + } \ + }; \ + static char const* name() { return "__" #id "__"; } \ + }; \ +} \ +namespace self_ns \ +{ \ + template \ + inline detail::operator_ \ + operator##op(self_t const&, R const&) \ + { \ + return detail::operator_(); \ + } \ +} + +BOOST_PYTHON_INPLACE_OPERATOR(iadd,+=) +BOOST_PYTHON_INPLACE_OPERATOR(isub,-=) +BOOST_PYTHON_INPLACE_OPERATOR(imul,*=) +BOOST_PYTHON_INPLACE_OPERATOR(idiv,/=) +BOOST_PYTHON_INPLACE_OPERATOR(imod,%=) +BOOST_PYTHON_INPLACE_OPERATOR(ilshift,<<=) +BOOST_PYTHON_INPLACE_OPERATOR(irshift,>>=) +BOOST_PYTHON_INPLACE_OPERATOR(iand,&=) +BOOST_PYTHON_INPLACE_OPERATOR(ixor,^=) +BOOST_PYTHON_INPLACE_OPERATOR(ior,|=) + +# define BOOST_PYTHON_UNARY_OPERATOR(id, op, func_name) \ +namespace detail \ +{ \ + template <> \ + struct operator_1 \ + { \ + template \ + struct apply \ + { \ + static PyObject* execute(T const& x) \ + { \ + return detail::convert_result(op(x)); \ + } \ + }; \ + static char const* name() { return "__" #id "__"; } \ + }; \ +} \ +namespace self_ns \ +{ \ + inline detail::operator_ \ + func_name(self_t const&) \ + { \ + return detail::operator_(); \ + } \ +} +# undef BOOST_PYTHON_INPLACE_OPERATOR + +BOOST_PYTHON_UNARY_OPERATOR(neg, -, operator-) +BOOST_PYTHON_UNARY_OPERATOR(pos, +, operator+) +BOOST_PYTHON_UNARY_OPERATOR(abs, abs, abs) +BOOST_PYTHON_UNARY_OPERATOR(invert, ~, operator~) +BOOST_PYTHON_UNARY_OPERATOR(int, long, int_) +BOOST_PYTHON_UNARY_OPERATOR(long, PyLong_FromLong, long_) +BOOST_PYTHON_UNARY_OPERATOR(float, double, float_) +BOOST_PYTHON_UNARY_OPERATOR(complex, std::complex, complex_) +BOOST_PYTHON_UNARY_OPERATOR(str, lexical_cast, str) +# undef BOOST_PYTHON_UNARY_OPERATOR }} // namespace boost::python -# undef BOOST_PYTHON_USE_SSTREAM -# endif -#endif /* OPERATORS_UK112000_H_ */ +# ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP +using boost::python::self_ns::abs; +using boost::python::self_ns::int_; +using boost::python::self_ns::long_; +using boost::python::self_ns::float_; +using boost::python::self_ns::complex_; +using boost::python::self_ns::str; +using boost::python::self_ns::pow; +# endif + +#endif // OPERATORS_DWA2002530_HPP diff --git a/include/boost/python/operators2.hpp b/include/boost/python/operators2.hpp deleted file mode 100755 index 3f06eb46..00000000 --- a/include/boost/python/operators2.hpp +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright David Abrahams 2002. 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. -#ifndef OPERATORS2_DWA2002530_HPP -# define OPERATORS2_DWA2002530_HPP - -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -namespace boost { namespace python { - -namespace detail -{ - // This is essentially the old v1 to_python(). It will be eliminated - // once the public interface for to_python is settled on. - template - PyObject* convert_result(T const& x) - { - return converter::arg_to_python(x).release(); - } - - // Operator implementation template declarations. The nested apply - // declaration here keeps MSVC6 happy. - template struct operator_l - { - template struct apply; - }; - - template struct operator_r - { - template struct apply; - }; - - template struct operator_1 - { - template struct apply; - }; - - // MSVC6 doesn't want us to do this sort of inheritance on a nested - // class template, so we use this layer of indirection to avoid - // ::template<...> on the nested apply functions below - template - struct operator_l_inner - : operator_l::template apply - {}; - - template - struct operator_r_inner - : operator_r::template apply - {}; - - template - struct operator_1_inner - : operator_1::template apply - {}; - - // Define three different binary_op templates which take care of - // these cases: - // self op self - // self op R - // L op self - // - // The inner apply metafunction is used to adjust the operator to - // the class type being defined. Inheritance of the outer class is - // simply used to provide convenient access to the operation's - // name(). - - // self op self - template - struct binary_op : operator_l - { - template - struct apply : operator_l_inner - { - }; - }; - - // self op R - template - struct binary_op_l : operator_l - { - template - struct apply : operator_l_inner - { - }; - }; - - // L op self - template - struct binary_op_r : operator_r - { - template - struct apply : operator_r_inner - { - }; - }; - - template - struct unary_op : operator_1 - { - template - struct apply : operator_1_inner - { - }; - }; - - // This type is what actually gets returned from operators used on - // self_t - template - struct operator_ - : mpl::if_< - is_same - , typename mpl::if_< - is_same - , binary_op - , binary_op_l::type> - >::type - , typename mpl::if_< - is_same - , unary_op - , binary_op_r::type> - >::type - >::type - { - }; -} - -# define BOOST_PYTHON_BINARY_OPERATION(id, rid, expr) \ -namespace detail \ -{ \ - template <> \ - struct operator_l \ - { \ - template \ - struct apply \ - { \ - static inline PyObject* execute(L const& l, R const& r) \ - { \ - return detail::convert_result(expr); \ - } \ - }; \ - static char const* name() { return "__" #id "__"; } \ - }; \ - \ - template <> \ - struct operator_r \ - { \ - template \ - struct apply \ - { \ - static inline PyObject* execute(R const& r, L const& l) \ - { \ - return detail::convert_result(expr); \ - } \ - }; \ - static char const* name() { return "__" #rid "__"; } \ - }; \ -} - -# define BOOST_PYTHON_BINARY_OPERATOR(id, rid, op) \ -BOOST_PYTHON_BINARY_OPERATION(id, rid, l op r) \ -namespace self_ns \ -{ \ - template \ - inline detail::operator_ \ - operator##op(L const&, R const&) \ - { \ - return detail::operator_(); \ - } \ -} - -BOOST_PYTHON_BINARY_OPERATOR(add, radd, +) -BOOST_PYTHON_BINARY_OPERATOR(sub, rsub, -) -BOOST_PYTHON_BINARY_OPERATOR(mul, rmul, *) -BOOST_PYTHON_BINARY_OPERATOR(div, rdiv, /) -BOOST_PYTHON_BINARY_OPERATOR(mod, rmod, %) -BOOST_PYTHON_BINARY_OPERATOR(lshift, rlshift, <<) -BOOST_PYTHON_BINARY_OPERATOR(rshift, rrshift, >>) -BOOST_PYTHON_BINARY_OPERATOR(and, rand, &) -BOOST_PYTHON_BINARY_OPERATOR(xor, rxor, ^) -BOOST_PYTHON_BINARY_OPERATOR(or, ror, |) -BOOST_PYTHON_BINARY_OPERATOR(gt, lt, >) -BOOST_PYTHON_BINARY_OPERATOR(ge, le, >=) -BOOST_PYTHON_BINARY_OPERATOR(lt, gt, <) -BOOST_PYTHON_BINARY_OPERATOR(le, ge, <=) -BOOST_PYTHON_BINARY_OPERATOR(eq, eq, ==) -BOOST_PYTHON_BINARY_OPERATOR(ne, ne, !=) -# undef BOOST_PYTHON_BINARY_OPERATOR - -// pow isn't an operator in C++; handle it specially. -BOOST_PYTHON_BINARY_OPERATION(pow, rpow, pow(l,r)) -# undef BOOST_PYTHON_BINARY_OPERATION - -namespace self_ns -{ -# ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP - template - inline detail::operator_ - pow(L const&, R const&) - { - return detail::operator_(); - } -# else - // When there's no argument-dependent lookup, we need these - // overloads to handle the case when everything is imported into the - // global namespace. Note that the plain overload below does /not/ - // take const& arguments. This is needed by MSVC6 at least, or it - // complains of ambiguities, since there's no partial ordering. - inline detail::operator_ - pow(self_t, self_t) - { - return detail::operator_(); - } - template - inline detail::operator_ - pow(self_t const&, R const&) - { - return detail::operator_(); - } - template - inline detail::operator_ - pow(L const&, self_t const&) - { - return detail::operator_(); - } -# endif -} - - -# define BOOST_PYTHON_INPLACE_OPERATOR(id, op) \ -namespace detail \ -{ \ - template <> \ - struct operator_l \ - { \ - template \ - struct apply \ - { \ - static inline PyObject* \ - execute(back_reference l, R const& r) \ - { \ - l.get() op r; \ - return python::incref(l.source().ptr()); \ - } \ - }; \ - static char const* name() { return "__" #id "__"; } \ - }; \ -} \ -namespace self_ns \ -{ \ - template \ - inline detail::operator_ \ - operator##op(self_t const&, R const&) \ - { \ - return detail::operator_(); \ - } \ -} - -BOOST_PYTHON_INPLACE_OPERATOR(iadd,+=) -BOOST_PYTHON_INPLACE_OPERATOR(isub,-=) -BOOST_PYTHON_INPLACE_OPERATOR(imul,*=) -BOOST_PYTHON_INPLACE_OPERATOR(idiv,/=) -BOOST_PYTHON_INPLACE_OPERATOR(imod,%=) -BOOST_PYTHON_INPLACE_OPERATOR(ilshift,<<=) -BOOST_PYTHON_INPLACE_OPERATOR(irshift,>>=) -BOOST_PYTHON_INPLACE_OPERATOR(iand,&=) -BOOST_PYTHON_INPLACE_OPERATOR(ixor,^=) -BOOST_PYTHON_INPLACE_OPERATOR(ior,|=) - -# define BOOST_PYTHON_UNARY_OPERATOR(id, op, func_name) \ -namespace detail \ -{ \ - template <> \ - struct operator_1 \ - { \ - template \ - struct apply \ - { \ - static PyObject* execute(T const& x) \ - { \ - return detail::convert_result(op(x)); \ - } \ - }; \ - static char const* name() { return "__" #id "__"; } \ - }; \ -} \ -namespace self_ns \ -{ \ - inline detail::operator_ \ - func_name(self_t const&) \ - { \ - return detail::operator_(); \ - } \ -} -# undef BOOST_PYTHON_INPLACE_OPERATOR - -BOOST_PYTHON_UNARY_OPERATOR(neg, -, operator-) -BOOST_PYTHON_UNARY_OPERATOR(pos, +, operator+) -BOOST_PYTHON_UNARY_OPERATOR(abs, abs, abs) -BOOST_PYTHON_UNARY_OPERATOR(invert, ~, operator~) -BOOST_PYTHON_UNARY_OPERATOR(int, long, int_) -BOOST_PYTHON_UNARY_OPERATOR(long, PyLong_FromLong, long_) -BOOST_PYTHON_UNARY_OPERATOR(float, double, float_) -BOOST_PYTHON_UNARY_OPERATOR(complex, std::complex, complex_) -BOOST_PYTHON_UNARY_OPERATOR(str, lexical_cast, str) -# undef BOOST_PYTHON_UNARY_OPERATOR - -}} // namespace boost::python - -# ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP -using boost::python::self_ns::abs; -using boost::python::self_ns::int_; -using boost::python::self_ns::long_; -using boost::python::self_ns::float_; -using boost::python::self_ns::complex_; -using boost::python::self_ns::str; -using boost::python::self_ns::pow; -# endif - -#endif // OPERATORS2_DWA2002530_HPP - - - - - - - - diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp index 60db3bb8..8c495106 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -25,7 +25,7 @@ namespace // { static registry_t registry; -# ifdef BOOST_PYTHON_DYNAMIC_LIB // this conditional should go away eventually. +# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION static bool builtin_converters_initialized = false; if (!builtin_converters_initialized) { diff --git a/src/errors.cpp b/src/errors.cpp index 05e40658..8cda9f0e 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -10,9 +10,7 @@ #include #include -#ifdef BOOST_PYTHON_V2 -# include -#endif +#include namespace boost { namespace python { @@ -21,10 +19,8 @@ BOOST_PYTHON_DECL bool handle_exception_impl(function0 f) { try { -#ifdef BOOST_PYTHON_V2 if (detail::exception_handler::chain) return detail::exception_handler::chain->handle(f); -#endif f(); return false; } @@ -75,7 +71,6 @@ namespace detail { // needed by void_adaptor (see void_adaptor.hpp) BOOST_PYTHON_DECL PyObject arbitrary_object = { 0 }; -#ifdef BOOST_PYTHON_V2 bool exception_handler::operator()(function0 const& f) const { if (m_next) @@ -110,7 +105,6 @@ BOOST_PYTHON_DECL void register_exception_handler(handler_function const& f) // interpreter exits). new exception_handler(f); } -#endif } // namespace boost::python::detail diff --git a/test/Jamfile b/test/Jamfile index de63e575..7a888842 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -120,8 +120,7 @@ if $(TEST_BIENSTMAN_NON_BUGS) # --- unit tests of library components --- -local UNIT_TEST_PROPERTIES = - [ difference $(PYTHON_PROPERTIES) : BOOST_PYTHON_DYNAMIC_LIB ] BOOST_PYTHON_STATIC_LIB ; +local UNIT_TEST_PROPERTIES = $(PYTHON_PROPERTIES) BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION ; run indirect_traits_test.cpp ; run destroy_test.cpp ; diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp deleted file mode 100644 index e3a756b9..00000000 --- a/test/comprehensive.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and -// distribute this software is granted provided this copyright notice appears -// in all copies. This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -// The author gratefully acknowleges the support of Dragon Systems, Inc., in -// producing this work. - -// Revision History: -// 04 Mar 01 Changed name of extension module so it would work with DebugPython, -// eliminated useless test that aggravated MSVC (David Abrahams) -#include "comprehensive.hpp" -#include -#include // used for portability on broken compilers -#include // for pow() -#include - -#if defined(__sgi) \ - && ( (defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730) \ - && !defined(__GNUC__)) -inline double pow(int x, int y) { return pow(static_cast(x), y); } -#endif - -namespace bpl_test { - -FooCallback::FooCallback(PyObject* self, int x) - : Foo(x), m_self(self) -{ -} - -int FooCallback::add_len(const char* x) const -{ - // Try to call the "add_len" method on the corresponding Python object. - return boost::python::callback::call_method(m_self, "add_len", x); -} - -// A function which Python can call in case bar is not overridden from -// Python. In true Python style, we use a free function taking an initial self -// parameter. This function anywhere needn't be a static member of the callback -// class. The only reason to do it this way is that Foo::add_len is private, and -// FooCallback is already a friend of Foo. -int FooCallback::default_add_len(const Foo* self, const char* x) -{ - // Don't forget the Foo:: qualification, or you'll get an infinite - // recursion! - return self->Foo::add_len(x); -} - -// Since Foo::pure() is pure virtual, we don't need a corresponding -// default_pure(). A failure to override it in Python will result in an -// exception at runtime when pure() is called. -std::string FooCallback::pure() const -{ - return boost::python::callback::call_method(m_self, "pure"); -} - -Foo::PythonClass::PythonClass(boost::python::module_builder& m) - : boost::python::class_builder(m, "Foo") -{ - def(boost::python::constructor()); - def(&Foo::mumble, "mumble"); - def(&Foo::set, "set"); - def(&Foo::call_pure, "call_pure"); - def(&Foo::call_add_len, "call_add_len"); - - // This is the way we add a virtual function that has a default implementation. - def(&Foo::add_len, "add_len", &FooCallback::default_add_len); - - // Since pure() is pure virtual, we are leaving it undefined. - - // And the nested classes. - boost::python::class_builder foo_a(*this, "Foo_A"); - foo_a.def(boost::python::constructor<>()); - foo_a.def(&Foo::Foo_A::mumble, "mumble"); - - boost::python::class_builder foo_b(get_extension_class(), - "Foo_B"); - foo_b.def(boost::python::constructor<>()); - foo_b.def(&Foo::Foo_B::mumble, "mumble"); -} - -BarPythonClass::BarPythonClass(boost::python::module_builder& m) - : boost::python::class_builder(m, "Bar") -{ - def(boost::python::constructor()); - def(&Bar::first, "first"); - def(&Bar::second, "second"); - def(&Bar::pass_baz, "pass_baz"); -} - -BazPythonClass::BazPythonClass(boost::python::module_builder& m) - : boost::python::class_builder(m, "Baz") // optional -{ - def(boost::python::constructor<>()); - def(&Baz::pass_bar, "pass_bar"); - def(&Baz::clone, "clone"); - def(&Baz::create_foo, "create_foo"); - def(&Baz::get_foo_value, "get_foo_value"); - def(&Baz::eat_baz, "eat_baz"); -} - -StringMapPythonClass::StringMapPythonClass(boost::python::module_builder& m) - : boost::python::class_builder(m, "StringMap") -{ - def(boost::python::constructor<>()); - // Some compilers make the target of this function - // pointer the same type as the class in which it is defined (some - // standard library class), instead of StringMap. - def((std::size_t (StringMap::*)()const)&StringMap::size, "__len__"); - - def(&get_item, "__getitem__"); - def(&set_item, "__setitem__"); - def(&del_item, "__delitem__"); -} - -int get_first(const IntPair& p) -{ - return p.first; -} - -void set_first(IntPair& p, int value) -{ - p.first = -value; -} - -void del_first(const IntPair&) -{ - PyErr_SetString(PyExc_AttributeError, "first can't be deleted!"); - boost::python::throw_error_already_set(); -} - -IntPairPythonClass::IntPairPythonClass(boost::python::module_builder& m) - : boost::python::class_builder(m, "IntPair") -{ - def(boost::python::constructor()); - def(&getattr, "__getattr__"); - def(&setattr, "__setattr__"); - def(&delattr, "__delattr__"); - def(&get_first, "__getattr__first__"); - def(&set_first, "__setattr__first__"); - def(&del_first, "__delattr__first__"); -} - -void IntPairPythonClass::setattr(IntPair& x, const std::string& name, int value) -{ - if (name == "second") - { - x.second = value; - } - else - { - PyErr_SetString(PyExc_AttributeError, name.c_str()); - boost::python::throw_error_already_set(); - } -} - -void IntPairPythonClass::delattr(IntPair&, const char*) -{ - PyErr_SetString(PyExc_AttributeError, "Attributes can't be deleted!"); - boost::python::throw_error_already_set(); -} - -int IntPairPythonClass::getattr(const IntPair& p, const std::string& s) -{ - if (s == "second") - { - return p.second; - } - else - { - PyErr_SetString(PyExc_AttributeError, s.c_str()); - boost::python::throw_error_already_set(); - } - return 0; -} - -namespace { namespace file_local { -void throw_key_error_if_end(const StringMap& m, StringMap::const_iterator p, std::size_t key) -{ - if (p == m.end()) - { - PyErr_SetObject(PyExc_KeyError, BOOST_PYTHON_CONVERSION::to_python(key)); - boost::python::throw_error_already_set(); - } -} -}} // namespace ::file_local - -const std::string& StringMapPythonClass::get_item(const StringMap& m, std::size_t key) -{ - const StringMap::const_iterator p = m.find(key); - file_local::throw_key_error_if_end(m, p, key); - return p->second; -} - -void StringMapPythonClass::set_item(StringMap& m, std::size_t key, const std::string& value) -{ - m[key] = value; -} - -void StringMapPythonClass::del_item(StringMap& m, std::size_t key) -{ - const StringMap::iterator p = m.find(key); - file_local::throw_key_error_if_end(m, p, key); - m.erase(p); -} - -// -// Show that polymorphism can work. a DerivedFromFoo object will be passed to -// Python in a smart pointer object. -// -class DerivedFromFoo : public Foo -{ -public: - DerivedFromFoo(int x) : Foo(x) {} - -private: - std::string pure() const - { return "this was never pure!"; } - - int add_len(const char*) const - { return 1000; } -}; - -// -// function implementations -// - -IntPair make_pair(int x, int y) -{ - return std::make_pair(x, y); -} - -const char* Foo::mumble() -{ - return "mumble"; -} - -const char* Foo::Foo_A::mumble() -{ - return "mumble a"; -} - -const char* Foo::Foo_B::mumble() -{ - return "mumble b"; -} - -void Foo::set(long x) -{ - m_x = x; -} - -std::string Foo::call_pure() -{ - return this->pure(); -} - -int Foo::call_add_len(const char* s) const -{ - return this->add_len(s); -} - -int Foo::add_len(const char* s) const // sum the held value and the length of s -{ - return BOOST_CSTD_::strlen(s) + static_cast(m_x); -} - -boost::shared_ptr Baz::create_foo() -{ - return boost::shared_ptr(new DerivedFromFoo(0)); -} - -// Used to check conversion to None -boost::shared_ptr foo_factory(bool create) -{ - return boost::shared_ptr(create ? new DerivedFromFoo(0) : 0); -} - -// Used to check conversion from None -bool foo_ptr_is_null(Foo* p) -{ - return p == 0; -} - -bool foo_shared_ptr_is_null(boost::shared_ptr p) -{ - return p.get() == 0; -} - -// We can accept smart pointer parameters -int Baz::get_foo_value(boost::shared_ptr foo) -{ - return foo->call_add_len(""); -} - -// Show what happens in python when we take ownership from an auto_ptr -void Baz::eat_baz(std::auto_ptr baz) -{ - baz->clone(); // just do something to show that it is valid. -} - -Baz Bar::pass_baz(Baz b) -{ - return b; -} - -std::string stringpair_repr(const StringPair& sp) -{ - return "('" + sp.first + "', '" + sp.second + "')"; -} - -int stringpair_compare(const StringPair& sp1, const StringPair& sp2) -{ - return sp1 < sp2 ? -1 : sp2 < sp1 ? 1 : 0; -} - -boost::python::string range_str(const Range& r) -{ - char buf[200]; - sprintf(buf, "(%d, %d)", r.m_start, r.m_finish); - return boost::python::string(buf); -} - -int range_compare(const Range& r1, const Range& r2) -{ - int d = r1.m_start - r2.m_start; - if (d == 0) - d = r1.m_finish - r2.m_finish; - return d; -} - -long range_hash(const Range& r) -{ - return r.m_start * 123 + r.m_finish; -} - -/************************************************************/ -/* */ -/* some functions to test overloading */ -/* */ -/************************************************************/ - -static std::string testVoid() -{ - return std::string("Hello world!"); -} - -static int testInt(int i) -{ - return i; -} - -static std::string testString(std::string i) -{ - return i; -} - -static int test2(int i1, int i2) -{ - return i1+i2; -} - -static int test3(int i1, int i2, int i3) -{ - return i1+i2+i3; -} - -static int test4(int i1, int i2, int i3, int i4) -{ - return i1+i2+i3+i4; -} - -static int test5(int i1, int i2, int i3, int i4, int i5) -{ - return i1+i2+i3+i4+i5; -} - -/************************************************************/ -/* */ -/* a class to test overloading */ -/* */ -/************************************************************/ - -struct OverloadTest -{ - OverloadTest(): x_(1000) {} - OverloadTest(int x): x_(x) {} - OverloadTest(int x,int y): x_(x+y) { } - OverloadTest(int x,int y,int z): x_(x+y+z) {} - OverloadTest(int x,int y,int z, int a): x_(x+y+z+a) {} - OverloadTest(int x,int y,int z, int a, int b): x_(x+y+z+a+b) {} - - int x() const { return x_; } - void setX(int x) { x_ = x; } - - int p1(int x) { return x; } - int p2(int x, int y) { return x + y; } - int p3(int x, int y, int z) { return x + y + z; } - int p4(int x, int y, int z, int a) { return x + y + z + a; } - int p5(int x, int y, int z, int a, int b) { return x + y + z + a + b; } - private: - int x_; -}; - -static int getX(OverloadTest* u) -{ - return u->x(); -} - - -/************************************************************/ -/* */ -/* classes to test base declarations and conversions */ -/* */ -/************************************************************/ - -struct Dummy -{ - virtual ~Dummy() {} - int dummy_; -}; - -struct Base -{ - virtual int x() const { return 999; }; - virtual ~Base() {} -}; - -// inherit Dummy so that the Base part of Concrete starts at an offset -// otherwise, typecast tests wouldn't be very meaningful -struct Derived1 : public Dummy, public Base -{ - Derived1(int x): x_(x) {} - virtual int x() const { return x_; } - - private: - int x_; -}; - -struct Derived2 : public Dummy, public Base -{ - Derived2(int x): x_(x) {} - virtual int x() const { return x_; } - - private: - int x_; -}; - -static int testUpcast(Base* b) -{ - return b->x(); -} - -static std::auto_ptr derived1Factory(int i) -{ - return std::auto_ptr(i < 0 ? 0 : new Derived1(i)); -} - -static std::auto_ptr derived2Factory(int i) -{ - return std::auto_ptr(new Derived2(i)); -} - -static int testDowncast1(Derived1* d) -{ - return d->x(); -} - -static int testDowncast2(Derived2* d) -{ - return d->x(); -} - -/************************************************************/ -/* */ -/* test classes for interaction of overloading, */ -/* base declarations, and callbacks */ -/* */ -/************************************************************/ - -struct CallbackTestBase -{ - virtual int testCallback(int i) { return callback(i); } - virtual int callback(int i) = 0; - virtual ~CallbackTestBase() {} -}; - -struct CallbackTest : public CallbackTestBase -{ - virtual int callback(int i) { return i + 1; } - virtual std::string callbackString(std::string const & i) { return i + " 1"; } -}; - -struct CallbackTestCallback : public CallbackTest -{ - CallbackTestCallback(PyObject* self) - : m_self(self) - {} - - int callback(int x) - { - return boost::python::callback::call_method(m_self, "callback", x); - } - std::string callbackString(std::string const & x) - { - return boost::python::callback::call_method(m_self, "callback", x); - } - - static int default_callback(CallbackTest* self, int x) - { - return self->CallbackTest::callback(x); - } - static std::string default_callbackString(CallbackTest* self, std::string x) - { - return self->CallbackTest::callbackString(x); - } - - PyObject* m_self; -}; - -int testCallback(CallbackTestBase* b, int i) -{ - return b->testCallback(i); -} - -/************************************************************/ -/* */ -/* test classes for interaction of method lookup */ -/* in the context of inheritance */ -/* */ -/************************************************************/ - -struct A1 { - virtual ~A1() {} - virtual std::string overrideA1() const { return "A1::overrideA1"; } - virtual std::string inheritA1() const { return "A1::inheritA1"; } -}; - -struct A2 { - virtual ~A2() {} - virtual std::string inheritA2() const { return "A2::inheritA2"; } -}; - -struct B1 : A1, A2 { - std::string overrideA1() const { return "B1::overrideA1"; } - virtual std::string overrideB1() const { return "B1::overrideB1"; } -}; - -struct B2 : A1, A2 { - std::string overrideA1() const { return "B2::overrideA1"; } - virtual std::string inheritB2() const { return "B2::inheritB2"; } -}; - -struct C : B1 { - std::string overrideB1() const { return "C::overrideB1"; } -}; - -std::string call_overrideA1(const A1& a) { return a.overrideA1(); } -std::string call_overrideB1(const B1& b) { return b.overrideB1(); } -std::string call_inheritA1(const A1& a) { return a.inheritA1(); } - -std::auto_ptr factoryA1asA1() { return std::auto_ptr(new A1); } -std::auto_ptr factoryB1asA1() { return std::auto_ptr(new B1); } -std::auto_ptr factoryB2asA1() { return std::auto_ptr(new B2); } -std::auto_ptr factoryCasA1() { return std::auto_ptr(new C); } -std::auto_ptr factoryA2asA2() { return std::auto_ptr(new A2); } -std::auto_ptr factoryB1asA2() { return std::auto_ptr(new B1); } -std::auto_ptr factoryB1asB1() { return std::auto_ptr(new B1); } -std::auto_ptr factoryCasB1() { return std::auto_ptr(new C); } - -struct B_callback : B1 { - B_callback(PyObject* self) : m_self(self) {} - - std::string overrideA1() const { return boost::python::callback::call_method(m_self, "overrideA1"); } - std::string overrideB1() const { return boost::python::callback::call_method(m_self, "overrideB1"); } - - static std::string default_overrideA1(B1& x) { return x.B1::overrideA1(); } - static std::string default_overrideB1(B1& x) { return x.B1::overrideB1(); } - - PyObject* m_self; -}; - -struct A_callback : A1 { - A_callback(PyObject* self) : m_self(self) {} - - std::string overrideA1() const { return boost::python::callback::call_method(m_self, "overrideA1"); } - std::string inheritA1() const { return boost::python::callback::call_method(m_self, "inheritA1"); } - - static std::string default_overrideA1(A1& x) { return x.A1::overrideA1(); } - static std::string default_inheritA1(A1& x) { return x.A1::inheritA1(); } - - PyObject* m_self; -}; - -/************************************************************/ -/* */ -/* RawTest */ -/* (test passing of raw arguments to C++) */ -/* */ -/************************************************************/ - -struct RawTest -{ - RawTest(int i) : i_(i) {} - - int i_; -}; - -PyObject* raw(boost::python::tuple const & args, boost::python::dictionary const & keywords); - -int raw1(PyObject* args, PyObject* keywords) -{ - return PyTuple_Size(args) + PyDict_Size(keywords); -} - -int raw2(boost::python::ref args, boost::python::ref keywords) -{ - return PyTuple_Size(args.get()) + PyDict_Size(keywords.get()); -} - - - -/************************************************************/ -/* */ -/* Ratio */ -/* */ -/************************************************************/ - -typedef boost::rational Ratio; - -boost::python::string ratio_str(const Ratio& r) -{ - char buf[200]; - - if (r.denominator() == 1) - sprintf(buf, "%d", r.numerator()); - else - sprintf(buf, "%d/%d", r.numerator(), r.denominator()); - - return boost::python::string(buf); -} - -boost::python::string ratio_repr(const Ratio& r) -{ - char buf[200]; - sprintf(buf, "Rational(%d, %d)", r.numerator(), r.denominator()); - return boost::python::string(buf); -} - -boost::python::tuple ratio_coerce(const Ratio& r1, int r2) -{ - return boost::python::tuple(r1, Ratio(r2)); -} - -// The most reliable way, across compilers, to grab the particular abs function -// we're interested in. -Ratio ratio_abs(const Ratio& r) -{ - return boost::abs(r); -} - -// An experiment, to be integrated into the py_cpp library at some point. -template -struct StandardOps -{ - static T add(const T& x, const T& y) { return x + y; } - static T sub(const T& x, const T& y) { return x - y; } - static T mul(const T& x, const T& y) { return x * y; } - static T div(const T& x, const T& y) { return x / y; } - static T cmp(const T& x, const T& y) { return std::less()(x, y) ? -1 : std::less()(y, x) ? 1 : 0; } -}; - -// This helps us prove that we can now pass non-const reference parameters to constructors -struct Fubar { - Fubar(Foo&) {} - Fubar(int) {} -}; - -/************************************************************/ -/* */ -/* Int */ -/* this class tests operator export */ -/* */ -/************************************************************/ - -#ifndef NDEBUG -int total_Ints = 0; -#endif - -struct Int -{ - explicit Int(int i) : i_(i), j_(0) { -#ifndef NDEBUG - ++total_Ints; -#endif - } - -#ifndef NDEBUG - ~Int() { --total_Ints; } - Int(const Int& rhs) : i_(rhs.i_), j_(rhs.j_) { ++total_Ints; } -#endif - - int i() const { return i_; } - int j() const { return j_; } - - int i_; - int j_; - - Int& operator +=(Int const& r) { ++j_; i_ += r.i_; return *this; } - Int& operator -=(Int const& r) { ++j_; i_ -= r.i_; return *this; } - Int& operator *=(Int const& r) { ++j_; i_ *= r.i_; return *this; } - Int& operator /=(Int const& r) { ++j_; i_ /= r.i_; return *this; } - Int& operator %=(Int const& r) { ++j_; i_ %= r.i_; return *this; } - Int& ipow (Int const& r) { ++j_; - int o=i_; - for (int k=1; k>=(Int const& r) { ++j_; i_ >>= r.i_; return *this; } - Int& operator &=(Int const& r) { ++j_; i_ &= r.i_; return *this; } - Int& operator |=(Int const& r) { ++j_; i_ |= r.i_; return *this; } - Int& operator ^=(Int const& r) { ++j_; i_ ^= r.i_; return *this; } -}; - -Int operator+(Int const & l, Int const & r) { return Int(l.i_ + r.i_); } -Int operator+(Int const & l, int const & r) { return Int(l.i_ + r); } -Int operator+(int const & l, Int const & r) { return Int(l + r.i_); } - -Int operator-(Int const & l, Int const & r) { return Int(l.i_ - r.i_); } -Int operator-(Int const & l, int const & r) { return Int(l.i_ - r); } -Int operator-(int const & l, Int const & r) { return Int(l - r.i_); } -Int operator-(Int const & r) { return Int(- r.i_); } - -Int mul(Int const & l, Int const & r) { return Int(l.i_ * r.i_); } -Int imul(Int const & l, int const & r) { return Int(l.i_ * r); } -Int rmul(Int const & r, int const & l) { return Int(l * r.i_); } - -Int operator/(Int const & l, Int const & r) { return Int(l.i_ / r.i_); } - -Int operator%(Int const & l, Int const & r) { return Int(l.i_ % r.i_); } - -bool operator<(Int const & l, Int const & r) { return l.i_ < r.i_; } -bool operator<(Int const & l, int const & r) { return l.i_ < r; } -bool operator<(int const & l, Int const & r) { return l < r.i_; } - -Int pow(Int const & l, Int const & r) { return Int(static_cast(::pow(l.i_, r.i_))); } -Int powmod(Int const & l, Int const & r, Int const & m) { return Int((int)::pow(l.i_, r.i_) % m.i_); } -Int pow(Int const & l, int const & r) { return Int(static_cast(::pow(l.i_, r))); } - -std::ostream & operator<<(std::ostream & o, Int const & r) { return (o << r.i_); } - -/************************************************************/ -/* */ -/* double tests from Mark Evans() */ -/* */ -/************************************************************/ -double sizelist(boost::python::list list) { return list.size(); } -void vd_push_back(std::vector& vd, const double& x) -{ - vd.push_back(x); -} - -/************************************************************/ -/* */ -/* What if I want to return a pointer? */ -/* */ -/************************************************************/ - -// -// This example exposes the pointer by copying its referent -// -struct Record { - Record(int x) : value(x){} - int value; -}; - -const Record* get_record() -{ - static Record v(1234); - return &v; -} - -} // namespace bpl_test - -namespace boost { namespace python { - template class class_builder; // explicitly instantiate -}} // namespace boost::python - -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -inline PyObject* to_python(const bpl_test::Record* p) -{ - return to_python(*p); -} -BOOST_PYTHON_END_CONVERSION_NAMESPACE - -/************************************************************/ -/* */ -/* Enums and non-method class attributes */ -/* */ -/************************************************************/ - -namespace bpl_test { - -struct EnumOwner -{ - public: - enum enum_type { one = 1, two = 2, three = 3 }; - - EnumOwner(enum_type a1, const enum_type& a2) - : m_first(a1), m_second(a2) {} - - void set_first(const enum_type& x) { m_first = x; } - void set_second(const enum_type& x) { m_second = x; } - - enum_type first() { return m_first; } - enum_type second() { return m_second; } - private: - enum_type m_first, m_second; -}; - -} - -namespace boost { namespace python { - template class enum_as_int_converters; - using bpl_test::pow; -}} // namespace boost::python - -// This is just a way of getting the converters instantiated -//struct EnumOwner_enum_type_Converters -// : boost::python::py_enum_as_int_converters -//{ -//}; - -namespace bpl_test { - -/************************************************************/ -/* */ -/* pickling support */ -/* */ -/************************************************************/ - class world - { - private: - std::string country; - int secret_number; - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - void set_secret_number(int number) { secret_number = number; } - int get_secret_number() const { return secret_number; } - }; - - // Support for pickle. - boost::python::tuple world_getinitargs(const world& w) - { - boost::python::tuple result(1); - result.set_item(0, w.get_country()); - return result; - } - - boost::python::tuple world_getstate(const world& w) - { - boost::python::tuple result(1); - result.set_item(0, w.get_secret_number()); - return result; - } - - void world_setstate(world& w, boost::python::tuple state) - { - if (state.size() != 1) { - PyErr_SetString(PyExc_ValueError, - "Unexpected argument in call to __setstate__."); - boost::python::throw_error_already_set(); - } - - const int number = BOOST_PYTHON_CONVERSION::from_python(state[0].get(), boost::python::type()); - if (number != 42) - w.set_secret_number(number); - } - - // Test plain char converters. - char get_plain_char() { return 'x'; } - std::string use_plain_char(char c) { return std::string(3, c); } - - // This doesn't test anything but the compiler, since it has the same signature as the above. - // Since MSVC is broken and gets the signature wrong, we'll skip it. - std::string use_const_plain_char( -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - const -#endif - char c) { return std::string(5, c); } - - // Test std::complex converters. - std::complex dpolar(double rho, double theta) { - return std::polar(rho, theta); - } - double dreal(const std::complex& c) { return c.real(); } - double dimag(std::complex c) { return c.imag(); } - - // Test std::complex converters. - std::complex fpolar(float rho, float theta) { - return std::polar(rho, theta); - } - double freal(const std::complex& c) { return c.real(); } - double fimag(std::complex c) { return c.imag(); } - - // Wrappers for inplace operators. - Int& int_iadd(Int& self, const Int& r) { self += r; return self; } - Int& int_isub(Int& self, const Int& r) { self -= r; return self; } - Int& int_imul(Int& self, const Int& r) { self *= r; return self; } - Int& int_idiv(Int& self, const Int& r) { self /= r; return self; } - Int& int_imod(Int& self, const Int& r) { self %= r; return self; } - Int& int_ipow(Int& self, const Int& r) { self.ipow (r); return self; } - Int& int_ilshift(Int& self, const Int& r) { self <<= r; return self; } - Int& int_irshift(Int& self, const Int& r) { self >>= r; return self; } - Int& int_iand(Int& self, const Int& r) { self &= r; return self; } - Int& int_ior(Int& self, const Int& r) { self |= r; return self; } - Int& int_ixor(Int& self, const Int& r) { self ^= r; return self; } - -/************************************************************/ -/* */ -/* init the module */ -/* */ -/************************************************************/ - -void init_module(boost::python::module_builder& m) -{ - m.def(get_record, "get_record"); - boost::python::class_builder record_class(m, "Record"); - record_class.def_readonly(&Record::value, "value"); - - m.def(sizelist, "sizelist"); - - boost::python::class_builder > vector_double(m, "vector_double"); - vector_double.def(boost::python::constructor<>()); - vector_double.def(vd_push_back, "push_back"); - - boost::python::class_builder fubar(m, "Fubar"); - fubar.def(boost::python::constructor()); - fubar.def(boost::python::constructor()); - - Foo::PythonClass foo(m); - BarPythonClass bar(m); - BazPythonClass baz(m); - StringMapPythonClass string_map(m); - IntPairPythonClass int_pair(m); - m.def(make_pair, "make_pair"); - CompareIntPairPythonClass compare_int_pair(m); - - boost::python::class_builder string_pair(m, "StringPair"); - string_pair.def(boost::python::constructor()); - string_pair.def_readonly(&StringPair::first, "first"); - string_pair.def_read_write(&StringPair::second, "second"); - string_pair.def(&stringpair_repr, "__repr__"); - string_pair.def(&stringpair_compare, "__cmp__"); - m.def(first_string, "first_string"); - m.def(second_string, "second_string"); - - // This shows the wrapping of a 3rd-party numeric type. - boost::python::class_builder > rational(m, "Rational"); - rational.def(boost::python::constructor()); - rational.def(boost::python::constructor()); - rational.def(boost::python::constructor<>()); - rational.def(StandardOps::add, "__add__"); - rational.def(StandardOps::sub, "__sub__"); - rational.def(StandardOps::mul, "__mul__"); - rational.def(StandardOps::div, "__div__"); - rational.def(StandardOps::cmp, "__cmp__"); - rational.def(ratio_coerce, "__coerce__"); - rational.def(ratio_str, "__str__"); - rational.def(ratio_repr, "__repr__"); - rational.def(ratio_abs, "__abs__"); - - boost::python::class_builder range(m, "Range"); - range.def(boost::python::constructor()); - range.def(boost::python::constructor()); - range.def((std::size_t (Range::*)() const)&Range::length, "__len__"); - range.def((void (Range::*)(std::size_t))&Range::length, "__len__"); - range.def(&Range::operator[], "__getitem__"); - range.def(&Range::slice, "__getslice__"); - range.def(&range_str, "__str__"); - range.def(&range_compare, "__cmp__"); - range.def(&range_hash, "__hash__"); - range.def_readonly(&Range::m_start, "start"); - range.def_readonly(&Range::m_finish, "finish"); - - m.def(&testVoid, "overloaded"); - m.def(&testInt, "overloaded"); - m.def(&testString, "overloaded"); - m.def(&test2, "overloaded"); - m.def(&test3, "overloaded"); - m.def(&test4, "overloaded"); - m.def(&test5, "overloaded"); - - boost::python::class_builder over(m, "OverloadTest"); - over.def(boost::python::constructor<>()); - over.def(boost::python::constructor()); - over.def(boost::python::constructor()); - over.def(boost::python::constructor()); - over.def(boost::python::constructor()); - over.def(boost::python::constructor()); - over.def(boost::python::constructor()); - over.def(&getX, "getX"); - over.def(&OverloadTest::setX, "setX"); - over.def(&OverloadTest::x, "overloaded"); - over.def(&OverloadTest::p1, "overloaded"); - over.def(&OverloadTest::p2, "overloaded"); - over.def(&OverloadTest::p3, "overloaded"); - over.def(&OverloadTest::p4, "overloaded"); - over.def(&OverloadTest::p5, "overloaded"); - - boost::python::class_builder base(m, "Base"); - base.def(&Base::x, "x"); - - boost::python::class_builder derived1(m, "Derived1"); - // this enables conversions between Base and Derived1 - // and makes wrapped methods of Base available - derived1.declare_base(base); - derived1.def(boost::python::constructor()); - - boost::python::class_builder derived2(m, "Derived2"); - // don't enable downcast from Base to Derived2 - derived2.declare_base(base, boost::python::without_downcast); - derived2.def(boost::python::constructor()); - - m.def(&testUpcast, "testUpcast"); - m.def(&derived1Factory, "derived1Factory"); - m.def(&derived2Factory, "derived2Factory"); - m.def(&testDowncast1, "testDowncast1"); - m.def(&testDowncast2, "testDowncast2"); - - boost::python::class_builder callbackTestBase(m, "CallbackTestBase"); - callbackTestBase.def(&CallbackTestBase::testCallback, "testCallback"); - m.def(&testCallback, "testCallback"); - - boost::python::class_builder callbackTest(m, "CallbackTest"); - callbackTest.def(boost::python::constructor<>()); - callbackTest.def(&CallbackTest::callback, "callback", - &CallbackTestCallback::default_callback); - callbackTest.def(&CallbackTest::callbackString, "callback", - &CallbackTestCallback::default_callbackString); - - callbackTest.declare_base(callbackTestBase); - - boost::python::class_builder a1_class(m, "A1"); - a1_class.def(boost::python::constructor<>()); - a1_class.def(&A1::overrideA1, "overrideA1", &A_callback::default_overrideA1); - a1_class.def(&A1::inheritA1, "inheritA1", &A_callback::default_inheritA1); - - boost::python::class_builder a2_class(m, "A2"); - a2_class.def(boost::python::constructor<>()); - a2_class.def(&A2::inheritA2, "inheritA2"); - - boost::python::class_builder b1_class(m, "B1"); - b1_class.declare_base(a1_class); - b1_class.declare_base(a2_class); - - b1_class.def(boost::python::constructor<>()); - b1_class.def(&B1::overrideA1, "overrideA1", &B_callback::default_overrideA1); - b1_class.def(&B1::overrideB1, "overrideB1", &B_callback::default_overrideB1); - - boost::python::class_builder b2_class(m, "B2"); - b2_class.declare_base(a1_class); - b2_class.declare_base(a2_class); - - b2_class.def(boost::python::constructor<>()); - b2_class.def(&B2::overrideA1, "overrideA1"); - b2_class.def(&B2::inheritB2, "inheritB2"); - - m.def(call_overrideA1, "call_overrideA1"); - m.def(call_overrideB1, "call_overrideB1"); - m.def(call_inheritA1, "call_inheritA1"); - - m.def(factoryA1asA1, "factoryA1asA1"); - m.def(factoryB1asA1, "factoryB1asA1"); - m.def(factoryB2asA1, "factoryB2asA1"); - m.def(factoryCasA1, "factoryCasA1"); - m.def(factoryA2asA2, "factoryA2asA2"); - m.def(factoryB1asA2, "factoryB1asA2"); - m.def(factoryB1asB1, "factoryB1asB1"); - m.def(factoryCasB1, "factoryCasB1"); - - boost::python::class_builder rawtest_class(m, "RawTest"); - rawtest_class.def(boost::python::constructor()); - rawtest_class.def_raw(&raw, "raw"); - - m.def_raw(&raw, "raw"); - m.def_raw(&raw1, "raw1"); - m.def_raw(&raw2, "raw2"); - - boost::python::class_builder int_class(m, "Int"); - int_class.def(boost::python::constructor()); - int_class.def(&Int::i, "i"); - int_class.def(&Int::j, "j"); - - // wrap homogeneous operators - int_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub | boost::python::op_neg | - boost::python::op_cmp | boost::python::op_str | boost::python::op_divmod | boost::python::op_pow )>()); - // export non-operator functions as homogeneous operators - int_class.def(&mul, "__mul__"); - int_class.def(&powmod, "__pow__"); - - // wrap heterogeneous operators (lhs: Int const &, rhs: int const &) - int_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub | boost::python::op_cmp | boost::python::op_pow)>(), - boost::python::right_operand()); - // export non-operator function as heterogeneous operator - int_class.def(&imul, "__mul__"); - - // wrap heterogeneous operators (lhs: int const &, rhs: Int const &) - int_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub | boost::python::op_cmp)>(), - boost::python::left_operand()); - // export non-operator function as heterogeneous reverse-argument operator - int_class.def(&rmul, "__rmul__"); - -#if PYTHON_API_VERSION >= 1010 - // inplace operators. - int_class.def(&int_iadd, "__iadd__"); - int_class.def(&int_isub, "__isub__"); - int_class.def(&int_imul, "__imul__"); - int_class.def(&int_idiv, "__idiv__"); - int_class.def(&int_imod, "__imod__"); - int_class.def(&int_ipow, "__ipow__"); - int_class.def(&int_ilshift, "__ilshift__"); - int_class.def(&int_irshift, "__irshift__"); - int_class.def(&int_iand, "__iand__"); - int_class.def(&int_ior, "__ior__"); - int_class.def(&int_ixor, "__ixor__"); -#endif - - - boost::python::class_builder enum_owner(m, "EnumOwner"); - enum_owner.def(boost::python::constructor()); - enum_owner.def(&EnumOwner::set_first, "__setattr__first__"); - enum_owner.def(&EnumOwner::set_second, "__setattr__second__"); - enum_owner.def(&EnumOwner::first, "__getattr__first__"); - enum_owner.def(&EnumOwner::second, "__getattr__second__"); - enum_owner.add(PyInt_FromLong(EnumOwner::one), "one"); - enum_owner.add(PyInt_FromLong(EnumOwner::two), "two"); - enum_owner.add(PyInt_FromLong(EnumOwner::three), "three"); - - // pickling support - - // Create the Python type object for our extension class. - boost::python::class_builder world_class(m, "world"); - - // Add the __init__ function. - world_class.def(boost::python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - world_class.def(&world::get_secret_number, "get_secret_number"); - world_class.def(&world::set_secret_number, "set_secret_number"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - world_class.def(world_getstate, "__getstate__"); - world_class.def(world_setstate, "__setstate__"); - - // Test plain char converters. - m.def(get_plain_char, "get_plain_char"); - m.def(use_plain_char, "use_plain_char"); - m.def(use_const_plain_char, "use_const_plain_char"); - - // Test std::complex converters. - m.def(dpolar, "dpolar"); - m.def(dreal, "dreal"); - m.def(dimag, "dimag"); - - // Test std::complex converters. - m.def(fpolar, "fpolar"); - m.def(freal, "freal"); - m.def(fimag, "fimag"); - - // Test new null-pointer<->None conversions - m.def(foo_factory, "foo_factory"); - m.def(foo_ptr_is_null, "foo_ptr_is_null"); - m.def(foo_shared_ptr_is_null, "foo_shared_ptr_is_null"); -} - -PyObject* raw(const boost::python::tuple& args, const boost::python::dictionary& keywords) -{ - if(args.size() != 2 || keywords.size() != 2) - { - PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); - boost::python::throw_argument_error(); - } - - RawTest* first = BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()); - int second = BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()); - - int third = BOOST_PYTHON_CONVERSION::from_python(keywords[boost::python::string("third")].get(), boost::python::type()); - int fourth = BOOST_PYTHON_CONVERSION::from_python(keywords[boost::python::string("fourth")].get(), boost::python::type()); - - return BOOST_PYTHON_CONVERSION::to_python(first->i_ + second + third + fourth); -} - -BOOST_PYTHON_MODULE(boost_python_test) -{ - boost::python::module_builder boost_python_test("boost_python_test"); - init_module(boost_python_test); - - // Just for giggles, add a raw metaclass. - boost_python_test.add(new boost::python::meta_class); -} - -CompareIntPairPythonClass::CompareIntPairPythonClass(boost::python::module_builder& m) - : boost::python::class_builder(m, "CompareIntPair") -{ - def(boost::python::constructor<>()); - def(&CompareIntPair::operator(), "__call__"); -} - -} // namespace bpl_test - - -#if defined(_WIN32) -# ifdef __MWERKS__ -# pragma ANSI_strict off -# endif -# include -# ifdef __MWERKS__ -# pragma ANSI_strict reset -# endif -extern "C" BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved ); - -# ifdef BOOST_MSVC -extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) -# if BOOST_MSVC > 1200 - throw(...) -# endif -{ - throw; -} -# endif - -#ifndef NDEBUG -namespace boost { namespace python { namespace detail { - extern int total_Dispatchers; -}}} // namespace boost::python::detail -#endif - -BOOL WINAPI DllMain( - HINSTANCE, //hDllInst - DWORD fdwReason, - LPVOID // lpvReserved - ) -{ -# ifdef BOOST_MSVC - _set_se_translator(structured_exception_translator); -#endif - (void)fdwReason; // warning suppression. - -#ifndef NDEBUG - switch(fdwReason) - { - case DLL_PROCESS_DETACH: - assert(bpl_test::total_Ints == 0); - } -#endif - - return 1; -} -#endif // _WIN32 diff --git a/test/comprehensive.hpp b/test/comprehensive.hpp deleted file mode 100644 index 370f7d04..00000000 --- a/test/comprehensive.hpp +++ /dev/null @@ -1,235 +0,0 @@ -// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and -// distribute this software is granted provided this copyright notice appears -// in all copies. This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -// The author gratefully acknowleges the support of Dragon Systems, Inc., in -// producing this work. - -#ifndef BPL_TEST_DWA052200_H_ -# define BPL_TEST_DWA052200_H_ -// -// Example code demonstrating extension class usage -// - -# include -# include -# include -# include -# include -# include -# include -# include - -namespace bpl_test { - -// -// example: Foo, Bar, and Baz are C++ classes we want to wrap. -// - -class Foo // prohibit copying, proving that it doesn't choke - : private boost::noncopyable // our generation of to_python(). -{ - public: // constructor/destructor - Foo(int x) : m_x(x) {} - virtual ~Foo() {} - - public: // non-virtual functions - const char* mumble(); // mumble something - void set(long x); // change the held value - - // These two call virtual functions - std::string call_pure(); // call a pure virtual fuction - int call_add_len(const char* s) const; // virtual function with a default implementation - - // A couple nested classs. - struct Foo_A { const char* mumble(); }; - struct Foo_B { const char* mumble(); }; - - private: - // by default, sum the held value and the length of s - virtual int add_len(const char* s) const; - - // Derived classes can do whatever they want here, but they must do something! - virtual std::string pure() const = 0; - - public: // friend declarations - // If you have private virtual functions such as add_len which you want to - // override in Python and have default implementations, they must be - // accessible by the thing making the def() call on the extension_class (in - // this case, the nested PythonClass itself), and by the C++ derived class - // which is used to cause the Python callbacks (in this case, - // FooCallback). See the definition of FooCallback::add_len() - struct PythonClass; - friend struct PythonClass; - friend class FooCallback; - - private: - int m_x; // the held value -}; - -// -// Bar and Baz have mutually-recursive type conversion dependencies (see -// pass_xxx functions). I've done this to prove that it doesn't cause a -// problem for Python class definitions, which happen later. -// -// Bar and Baz functions are only virtual to increase the likelihood of a crash -// if I inadvertently use a pointer to garbage memory (a likely thing to test -// for considering the amount of type casting needed to translate to and from -// Python). -struct Baz; -struct Bar -{ - Bar(int x, int y) : m_first(x), m_second(y) {} - virtual int first() const { return m_first; } - virtual int second() const { return m_second; } - virtual Baz pass_baz(Baz x); - - int m_first, m_second; -}; - -struct Baz -{ - virtual Bar pass_bar(const Bar& x) { return x; } - - // We can return smart pointers - virtual std::auto_ptr clone() { return std::auto_ptr(new Baz(*this)); } - - // This illustrates creating a polymorphic derived class of Foo - virtual boost::shared_ptr create_foo(); - - // We can accept smart pointer parameters - virtual int get_foo_value(boost::shared_ptr); - - // Show what happens in python when we take ownership from an auto_ptr - virtual void eat_baz(std::auto_ptr); -}; - -typedef std::map StringMap; -typedef std::pair IntPair; - -IntPair make_pair(int, int); - -typedef std::less CompareIntPair; -typedef std::pair StringPair; - -inline std::string first_string(const StringPair& x) -{ - return x.first; -} - -inline std::string second_string(const StringPair& x) -{ - return x.second; -} - -struct Range -{ - Range(int x) - : m_start(x), m_finish(x) {} - - Range(int start, int finish) - : m_start(start), m_finish(finish) {} - - std::size_t length() const - { return m_finish < m_start ? 0 : m_finish - m_start; } - - void length(std::size_t new_length) - { m_finish = m_start + new_length; } - - int operator[](std::size_t n) - { return m_start + n; } - - Range slice(std::size_t start, std::size_t end) - { - if (start > length()) - start = length(); - if (end > length()) - end = length(); - return Range(m_start + start, m_start + end); - } - - int m_start, m_finish; -}; - -//////////////////////////////////////////////////////////////////////// -// // -// Begin wrapping code. Usually this would live in a separate header. // -// // -//////////////////////////////////////////////////////////////////////// - -// Since Foo has virtual functions which we want overriden in Python, we must -// derive FooCallback. -class FooCallback : public Foo -{ - public: - // Note the additional constructor parameter "self", which is needed to - // allow function overriding from Python. - FooCallback(PyObject* self, int x); - - friend struct PythonClass; // give it access to the functions below - - private: // implementations of Foo virtual functions that are overridable in python. - int add_len(const char* x) const; - - // A function which Python can call in case bar is not overridden from - // Python. In true Python style, we use a free function taking an initial - // self parameter. You can put this function anywhere; it needn't be a - // static member of the wrapping class. - static int default_add_len(const Foo* self, const char* x); - - // Since Foo::pure() is pure virtual, we don't need a corresponding - // default_pure(). A failure to override it in Python will result in an - // exception at runtime when pure() is called. - std::string pure() const; - - private: // Required boilerplate if functions will be overridden - PyObject* m_self; // No, we don't want a boost::python::ref here, or we'd get an ownership cycle. -}; - -// Define the Python base class -struct Foo::PythonClass : boost::python::class_builder { PythonClass(boost::python::module_builder&); }; - -// No virtual functions on Bar or Baz which are actually supposed to behave -// virtually from C++, so we'll rely on the library to define a wrapper for -// us. Even so, Python class_t types for each type we're wrapping should be -// _defined_ here in a header where they can be seen by other extension class -// definitions, since it is the definition of the boost::python::class_builder<> that -// causes to_python/from_python conversion functions to be generated. -struct BarPythonClass : boost::python::class_builder { BarPythonClass(boost::python::module_builder&); }; -struct BazPythonClass : boost::python::class_builder { BazPythonClass(boost::python::module_builder&); }; - -struct StringMapPythonClass - : boost::python::class_builder -{ - StringMapPythonClass(boost::python::module_builder&); - - // These static functions implement the right argument protocols for - // implementing the Python "special member functions" for mapping on - // StringMap. Could just as easily be global functions. - static const std::string& get_item(const StringMap& m, std::size_t key); - static void set_item(StringMap& m, std::size_t key, const std::string& value); - static void del_item(StringMap& m, std::size_t key); -}; - -struct IntPairPythonClass - : boost::python::class_builder -{ - IntPairPythonClass(boost::python::module_builder&); - - // The following could just as well be a free function; it implements the - // getattr functionality for IntPair. - static int getattr(const IntPair&, const std::string& s); - static void setattr(IntPair&, const std::string& name, int value); - static void delattr(IntPair&, const char* name); -}; - -struct CompareIntPairPythonClass - : boost::python::class_builder -{ - CompareIntPairPythonClass(boost::python::module_builder&); -}; - -} // namespace bpl_test - -#endif // BPL_TEST_DWA052200_H_ diff --git a/test/comprehensive.py b/test/comprehensive.py deleted file mode 100644 index f64ed661..00000000 --- a/test/comprehensive.py +++ /dev/null @@ -1,1281 +0,0 @@ -r''' -// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and -// distribute this software is granted provided this copyright notice appears -// in all copies. This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -// The author gratefully acknowleges the support of Dragon Systems, Inc., in -// producing this work. - -// Revision History: -// 2001 Nov 01 Python 2.2 pickle problems fixed (rwgk) -// 04 Mar 01 Changed name of extension module so it would work with DebugPython, -// fixed exception message checking to work with Python 2.0 -// (Dave Abrahams) - -Automatic checking of the number and type of arguments. Foo's constructor takes -a single long parameter. - - >>> try: - ... ext = Foo() - ... except TypeError, err: - ... assert re.match(r'function .* exactly 1 argument;? \(?0 given\)?', - ... str(err)) - ... else: - ... print 'no exception' - - >>> try: ext = Foo('foo') - ... except TypeError, err: - ... assert_integer_expected(err) - ... else: - ... print 'no exception' - - >>> ext = Foo(1) - -Call a virtual function. This call takes a trip into C++ where -FooCallback::add_len() looks up the Python "add_len" attribute and finds the -wrapper for FooCallback::default_add_len(), which in turn calls Foo::add_len(). - - >>> ext.add_len('hello') - 6 - >>> ext.set(3) - >>> ext.add_len('hello') - 8 - -Call a pure virtual function which should have been overridden, but was not. - - >>> ext.call_pure() - Traceback (innermost last): - File "", line 1, in ? - AttributeError: pure - -We can subclass Foo. - - >>> class Subclass(Foo): - ... def __init__(self, seq): - ... Foo.__init__(self, len(seq)) - ... - ... def pure(self): - ... return 'not pure anymore!' - ... - ... def get(self): - ... return Foo.add_len(self, '') - ... - ... def add_len(self, s): - ... print 'called add_len()' - ... return self.get() + len(s) - ... - >>> b = Subclass('yippee') - >>> b.get() - 6 - >>> b.mumble() - 'mumble' - >>> b.call_pure() - 'not pure anymore!' - -None corresponds to a NULL pointer or smart pointer - >>> f = foo_factory(1) - >>> f.add_len('xxx') - 1000 - >>> foo_factory(0) is None - 1 - >>> foo_ptr_is_null(None) - 1 - >>> foo_ptr_is_null(f) - 0 - >>> foo_shared_ptr_is_null(None) - 1 - >>> foo_shared_ptr_is_null(f) - 0 - -If no __init__ function is defined, the one from the base class takes effect, just -like in a Python class. - - >>> class DemonstrateInitPassthru(Foo): pass - ... - >>> q = DemonstrateInitPassthru(1) - >>> q.add_len("x") - 2 - -If we don't initialize the base class, we'll get a RuntimeError when we try to -use its methods. The test illustrates the kind of error to expect. - - >>> class BadSubclass(Foo): - ... def __init__(self): pass - ... - >>> barf = BadSubclass() - >>> barf.set(4) - Traceback (innermost last): - ... - RuntimeError: __init__ function for extension class 'Foo' was never called. - -Here we are tesing that the simple definition procedure used in the C++ demo -file for classes without any virtual functions actually worked. - - >>> bar = Bar(3, 4) - >>> bar.first() - 3 - >>> bar.second() - 4 - >>> baz = Baz() - -We can actually return the wrapped classes by value - - >>> baz.pass_bar(bar).first() - 3 - >>> bar.pass_baz(baz) is baz # A copy of the return value is made. - 0 - >>> type(bar.pass_baz(baz)) is type(baz) - 1 - -And, yes, we can multiply inherit from these classes. - - >>> class MISubclass(Subclass, Bar): - ... def __init__(self, s): - ... Subclass.__init__(self, s) - ... Bar.__init__(self, 0, len(s)) - ... - >>> mi = MISubclass('xx') - >>> mi.first() - 0 - >>> mi.second() - 2 - >>> mi.mumble() - 'mumble' - -We can even mulitply inherit from built-in Python classes, even if they are -first in the list of bases - - >>> class RealPythonClass: - ... def real_python_method(self): - ... print 'RealPythonClass.real_python_method()' - ... def other_first(self, other): - ... return other.first() - - >>> class MISubclass2(RealPythonClass, Bar): - ... def new_method(self): - ... print 'MISubclass2.new_method()' - ... bound_function = RealPythonClass().other_first - ... - >>> mi2 = MISubclass2(7, 8) - >>> mi2.first() # we can call inherited member functions from Bar - 7 - >>> mi2.real_python_method() # we can call inherited member functions from RealPythonClass - RealPythonClass.real_python_method() - - >>> mi2.new_method() # we can call methods on the common derived class - MISubclass2.new_method() - - We can call unbound methods from the base class accessed through the derived class - >>> MISubclass2.real_python_method(mi2) - RealPythonClass.real_python_method() - - We have not interfered with ordinary python bound methods - >>> MISubclass2.bound_function(mi2) - 7 - >>> mi2.bound_function() - 7 - -Any object whose class is derived from Bar can be passed to a function expecting -a Bar parameter: - - >>> baz.pass_bar(mi).first() - 0 - -But objects not derived from Bar cannot: - - >>> baz.pass_bar(baz) - Traceback (innermost last): - ... - TypeError: extension class 'Baz' is not convertible into 'Bar'. - -The clone function on Baz returns a smart pointer; we wrap it into an -extension_instance and make it look just like any other Baz obj. - - >>> baz_clone = baz.clone() - >>> baz_clone.pass_bar(mi).first() - 0 - -Functions expecting an std::auto_ptr parameter will not accept a raw Baz - - >>> try: baz.eat_baz(Baz()) - ... except RuntimeError, err: - ... assert re.match("Object of extension class 'Baz' does not wrap <.*>.", - ... str(err)) - ... else: - ... print 'no exception' - -We can pass std::auto_ptr where it is expected - - >>> baz.eat_baz(baz_clone) - -And if the auto_ptr has given up ownership? - - # MSVC6 ships with an outdated auto_ptr that doesn't get zeroed out when it - # gives up ownership. If you are using MSVC6 without the new Dinkumware - # library, SGI STL or the STLport, expect this test to crash unless you put - # --broken-auto-ptr on the command line. - >>> if not '--broken-auto-ptr' in sys.argv: - ... try: baz_clone.clone() - ... except RuntimeError, err: - ... assert re.match('Converting from python, pointer or smart pointer to <.*> is NULL.', str(err)) - ... else: - ... print 'no exeption' - -Polymorphism also works: - - >>> polymorphic_foo = baz.create_foo() - >>> polymorphic_foo.call_pure() - 'this was never pure!' - >>> baz.get_foo_value(polymorphic_foo) - 1000 - -Simple nested class test: - >>> foo_a = Foo.Foo_A() - >>> foo_a.mumble() - 'mumble a' - >>> foo_b = Foo.Foo_B() - >>> foo_b.mumble() - 'mumble b' - -Pickling tests: - - >>> world.__module__ - 'boost_python_test' - >>> world.__safe_for_unpickling__ - 1 - >>> world.__reduce__() - 'world' - >>> reduced = world('Hello').__reduce__() - >>> reduced[0] == world - 1 - >>> reduced[1:] - (('Hello',), (0,)) - >>> import StringIO - >>> import cPickle - >>> pickle = cPickle - >>> for number in (24, 42): - ... wd = world('California') - ... wd.set_secret_number(number) - ... # Dump it out and read it back in. - ... f = StringIO.StringIO() - ... pickle.dump(wd, f) - ... f = StringIO.StringIO(f.getvalue()) - ... wl = pickle.load(f) - ... # - ... 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 - -Pickle safety measures: - >>> r=Rational(3, 4) - >>> r - Rational(3, 4) - >>> try: s=pickle.dumps(r) - ... except RuntimeError, err: print err[0] - ... - Incomplete pickle support (__dict_defines_state__ not set) - >>> r=myrational(3, 4) - >>> r - Rational(3, 4) - >>> s=pickle.dumps(r) - >>> u=pickle.loads(s) - - >>> w = myworld() - >>> w.greet() - 'Hello from anywhere!' - >>> w.__dict__ - {'x': 1} - >>> try: s=pickle.dumps(w) - ... except RuntimeError, err: print err[0] - ... - Incomplete pickle support (__getstate_manages_dict__ not set) - - >>> w = myunsafeworld() - >>> w.greet() - 'Hello from anywhere!' - >>> w.__dict__ - {'x': 1} - >>> s=pickle.dumps(w) - -Special member attributes. Tests courtesy of Barry Scott - - >>> class DerivedFromFoo(Foo): - ... def __init__(self): - ... Foo.__init__( self, 1 ) - ... def fred(self): - ... 'Docs for DerivedFromFoo.fred' - ... print 'Barry.fred' - ... def __del__(self): - ... print 'Deleting DerivedFromFoo' - - >>> class Base: - ... i_am_base = 'yes' - ... def fred(self): - ... 'Docs for Base.fred' - ... pass - - - >>> class DerivedFromBase(Base): - ... i_am_derived_from_base = 'yes' - ... def fred(self): - ... 'Docs for DerivedFromBase.fred' - ... pass - - >>> dir(DerivedFromFoo) - ['__del__', '__doc__', '__init__', '__module__', 'fred'] - - >>> df = DerivedFromFoo() - >>> df.__dict__ - {} - >>> df.fred.__doc__ - 'Docs for DerivedFromFoo.fred' - - >>> db = DerivedFromBase() - >>> db.__dict__ - {} - >>> db.fred.__doc__ - 'Docs for DerivedFromBase.fred' - - >>> import sys - >>> if not sys.__dict__.has_key('version_info') or \ - ... sys.version_info[0] < 2 or ( sys.version_info[0] == 2 and - ... sys.version_info[1] < 2 ): - ... assert dir(df) == [] - ... assert dir(db) == [] - ... assert dir(DerivedFromBase) == [ - ... '__doc__', '__module__', 'fred', 'i_am_derived_from_base'] - ... else: - ... assert dir(df) == [ - ... 'Foo_A', 'Foo_B', '__del__', '__doc__', '__init__', '__module__', 'add_len', - ... 'call_add_len', 'call_pure', 'fred', 'mumble', 'set'] - ... assert dir(db) == ['__doc__', '__module__', 'fred' - ... , 'i_am_base', 'i_am_derived_from_base'] - ... assert dir(DerivedFromBase) == [ - ... '__doc__', '__module__', 'fred', 'i_am_base', 'i_am_derived_from_base'] - -Special member functions in action - >>> del df - Deleting DerivedFromFoo - - # force method table sharing - >>> class DerivedFromStringMap(StringMap): pass - ... - - >>> m = StringMap() - -__getitem__() - >>> m[1] - Traceback (innermost last): - File "", line 1, in ? - KeyError: 1 - -__setitem__() - - >>> m[1] = 'hello' - -__getitem__() - >>> m[1] - 'hello' - -__delitem__() - >>> del m[1] - >>> m[1] # prove that it's gone - Traceback (innermost last): - File "", line 1, in ? - KeyError: 1 - -__delitem__() - >>> del m[2] - Traceback (innermost last): - File "", line 1, in ? - KeyError: 2 - -__length__() - >>> len(m) - 0 - >>> m[3] = 'farther' - >>> len(m) - 1 - -Check for sequence/mapping confusion: - >>> for x in m: - ... print x - ... - Traceback (innermost last): - File "", line 1, in ? - KeyError: 0 - -Check for the ability to pass a non-const reference as a constructor parameter - >>> x = Fubar(Foo(1)) - -Some simple overloading tests: - >>> r = Range(3) - >>> print str(r) - (3, 3) - >>> r.start - 3 - >>> r.finish - 3 - >>> r.__len__() - 0 - >>> r.__len__(4) - >>> r.finish - 7 - >>> try: r = Range('yikes') - ... except TypeError, e: - ... assert re.match( - ... 'No overloaded functions match [(]Range, str[a-z]*[)]\. Candidates are:\n.*\n.*', - ... str(e)) - ... else: print 'no exception' - -Sequence tests: - >>> len(Range(3, 10)) - 7 - - >>> map(lambda x:x, Range(3, 10)) - [3, 4, 5, 6, 7, 8, 9] - - >>> map(lambda x:x, Range(3, 10)[-2:]) - [8, 9] - - >>> map(lambda x:x, Range(3, 10)[:-4]) - [3, 4, 5] - - >>> map(lambda x:x, Range(3, 10)[4:]) - [7, 8, 9] - - >>> map(lambda x:x, Range(3, 10)[4:100]) - [7, 8, 9] - - >>> map(lambda x:x, Range(3, 10)[20:]) - [] - - >>> map(lambda x:x, Range(3, 10)[0:4]) - [3, 4, 5, 6] - -Numeric tests: - >>> x = Rational(2,3) - >>> y = Rational(1,4) - >>> print x + y - 11/12 - >>> print x - y - 5/12 - >>> print x * y - 1/6 - >>> print x / y - 8/3 - >>> print x + 1 # testing coercion - 5/3 - >>> print 1 + x # coercion the other way - 5/3 - -delete non-existent attribute: - del m.foobar - Traceback (innermost last): - File "", line 1, in ? - AttributeError: delete non-existing obj attribute - -Testing __getattr__ and __getattr__: - - >>> n = IntPair(1, 2) - >>> n.first - 1 - >>> n.second - 2 - >>> n.third - Traceback (innermost last): - File "", line 1, in ? - AttributeError: third - -Testing __setattr__ and __setattr__: - >>> n.first = 33 # N.B __setattr__first sets first to - >>> n.first # the negative of its argument. - -33 - >>> n.second = 66 - >>> n.second - 66 - -Testing __delattr__ and __delattr__: - >>> del n.first - Traceback (innermost last): - File "", line 1, in ? - AttributeError: first can't be deleted! - >>> del n.second - Traceback (innermost last): - File "", line 1, in ? - AttributeError: Attributes can't be deleted! - >>> del n.third - Traceback (innermost last): - File "", line 1, in ? - AttributeError: Attributes can't be deleted! - - # Now show that we can override it. - - >>> class IntTriple(IntPair): - ... def __getattr__(self, s): - ... if s in ['first', 'second']: - ... return IntPair.__getattr__(self, s) - ... elif s == 'third': - ... return 3 - ... else: - ... raise AttributeError(s) - ... - ... # Also show that __setattr__ is supported - ... def __setattr__(self, name, value): - ... raise AttributeError('no writable attributes') - ... - >>> p = IntTriple(0, 1) - >>> p.first - 0 - >>> p.second - 1 - >>> p.third - 3 - >>> p.bax - Traceback (innermost last): - File "", line 1, in ? - AttributeError: bax - >>> p.third = 'yes' - Traceback (innermost last): - File "", line 1, in ? - AttributeError: no writable attributes - >>> del p.third - Traceback (innermost last): - File "", line 1, in ? - AttributeError: Attributes can't be deleted! - -demonstrate def_readonly, def_read_write: - >>> sp = StringPair("hello", "world") - >>> sp.first # first is read-only - 'hello' - >>> first_string(sp) # prove that we're not just looking in sp's __dict__ - 'hello' - >>> sp.first = 'hi' # we're not allowed to change it - Traceback (innermost last): - File "", line 1, in ? - AttributeError: 'first' attribute is read-only - >>> first_string(sp) # prove that it hasn't changed - 'hello' - - >>> sp.second # second is read/write - 'world' - >>> second_string(sp) - 'world' - >>> sp.second = 'universe' # set the second attribute - >>> sp.second - 'universe' - >>> second_string(sp) # this proves we didn't just set it in sp's __dict__ - 'universe' - -some __str__ and __repr__ tests: - >>> sp - ('hello', 'universe') - >>> repr(sp) - "('hello', 'universe')" - >>> str(sp) - "('hello', 'universe')" - - Range has a __str__ function but not a __repr__ function - >>> range = Range(5, 20) - >>> str(range) - '(5, 20)' - >>> assert re.match('', repr(range)) - -__hash__ and __cmp__ tests: - # Range has both __hash__ and __cmp__, thus is hashable - >>> colors = { Range(3,4): 'blue', Range(7,9): 'red' } - >>> colors[Range(3,4)] - 'blue' - - # StringPair has only __cmp__ - >>> { StringPair('yo', 'eddy'): 1 } - Traceback (innermost last): - File "", line 1, in ? - TypeError: unhashable type - - # But it can be sorted - >>> stringpairs = [ StringPair('yo', 'eddy'), StringPair('yo', 'betty'), sp ] - >>> stringpairs.sort() - >>> stringpairs - [('hello', 'universe'), ('yo', 'betty'), ('yo', 'eddy')] - -make_pair is a global function in the module. - - >>> couple = make_pair(3,12) - >>> couple.first - 3 - >>> couple.second - 12 - -Testing __call__: - >>> couple2 = make_pair(3, 7) - >>> comparator = CompareIntPair() - >>> comparator(couple, couple) - 0 - >>> comparator(couple, couple2) - 0 - >>> comparator(couple2, couple) - 1 - -Testing overloaded free functions - >>> overloaded() - 'Hello world!' - >>> overloaded(1) - 1 - >>> overloaded('foo') - 'foo' - >>> overloaded(1,2) - 3 - >>> overloaded(1,2,3) - 6 - >>> overloaded(1,2,3,4) - 10 - >>> overloaded(1,2,3,4,5) - 15 - >>> try: overloaded(1, 'foo') - ... except TypeError, err: - ... assert re.match("No overloaded functions match \(int, str[a-z]*\)\. Candidates are:", - ... str(err)) - ... else: - ... print 'no exception' - -Testing overloaded constructors - - >>> over = OverloadTest() - >>> over.getX() - 1000 - >>> over = OverloadTest(1) - >>> over.getX() - 1 - >>> over = OverloadTest(1,1) - >>> over.getX() - 2 - >>> over = OverloadTest(1,1,1) - >>> over.getX() - 3 - >>> over = OverloadTest(1,1,1,1) - >>> over.getX() - 4 - >>> over = OverloadTest(1,1,1,1,1) - >>> over.getX() - 5 - >>> over = OverloadTest(over) - >>> over.getX() - 5 - >>> try: over = OverloadTest(1, 'foo') - ... except TypeError, err: - ... assert re.match("No overloaded functions match \(OverloadTest, int, str[a-z]*\)\. Candidates are:", - ... str(err)) - ... else: - ... print 'no exception' - -Testing overloaded methods - - >>> over.setX(3) - >>> over.overloaded() - 3 - >>> over.overloaded(1) - 1 - >>> over.overloaded(1,1) - 2 - >>> over.overloaded(1,1,1) - 3 - >>> over.overloaded(1,1,1,1) - 4 - >>> over.overloaded(1,1,1,1,1) - 5 - >>> try: over.overloaded(1,'foo') - ... except TypeError, err: - ... assert re.match("No overloaded functions match \(OverloadTest, int, str[a-z]*\)\. Candidates are:", - ... str(err)) - ... else: - ... print 'no exception' - -Testing base class conversions - - >>> testUpcast(over) - Traceback (innermost last): - TypeError: extension class 'OverloadTest' is not convertible into 'Base'. - >>> der1 = Derived1(333) - >>> der1.x() - 333 - >>> testUpcast(der1) - 333 - >>> der1 = derived1Factory(1000) - >>> testDowncast1(der1) - 1000 - >>> testDowncast2(der1) - Traceback (innermost last): - TypeError: extension class 'Base' is not convertible into 'Derived2'. - >>> der2 = Derived2(444) - >>> der2.x() - 444 - >>> testUpcast(der2) - 444 - >>> der2 = derived2Factory(1111) - >>> testDowncast2(der2) - Traceback (innermost last): - TypeError: extension class 'Base' is not convertible into 'Derived2'. - -Testing interaction between callbacks, base declarations, and overloading -- testCallback() calls callback() (within C++) -- callback() is overloaded (in the wrapped class CallbackTest) -- callback() is redefined in RedefineCallback (overloading is simulated by type casing) -- testCallback() should use the redefined callback() - - >>> c = CallbackTest() - >>> c.testCallback(1) - 2 - - >>> try: c.testCallback('foo') - ... except TypeError, err: assert_integer_expected(err) - ... else: print 'no exception' - - >>> c.callback(1) - 2 - >>> c.callback('foo') - 'foo 1' - - >>> import types - >>> class RedefineCallback(CallbackTest): - ... def callback(self, x): - ... if type(x) is types.IntType: - ... return x - 2 - ... else: - ... return CallbackTest.callback(self,x) - ... - >>> r = RedefineCallback() - >>> r.callback(1) - -1 - >>> r.callback('foo') - 'foo 1' - - >>> try: r.testCallback('foo') - ... except TypeError, err: assert_integer_expected(err) - ... else: print 'no exception' - - >>> r.testCallback(1) - -1 - >>> testCallback(r, 1) - -1 - -Regression test for a reference-counting bug thanks to Mark Evans -() - >>> sizelist([]) - 0.0 - >>> sizelist([1, 2, 4]) - 3.0 - -And another for doubles - >>> vector_double().push_back(3.0) - -Tests for method lookup in the context of inheritance -Set up the tests - - >>> a1 = A1() - >>> a2 = A2() - >>> b1 = B1() - >>> b2 = B2() - >>> pa1_a1 = factoryA1asA1() - >>> pb1_a1 = factoryB1asA1() - >>> pb2_a1 = factoryB2asA1() - >>> pc_a1 = factoryCasA1() - >>> pa2_a2 = factoryA2asA2() - >>> pb1_a2 = factoryB1asA2() - >>> pb1_b1 = factoryB1asB1() - >>> pc_b1 = factoryCasB1() - >>> class DA1(A1): - ... def overrideA1(self): - ... return 'DA1.overrideA1' - ... - >>> da1 = DA1() - >>> class DB1(B1): - ... def overrideA1(self): - ... return 'DB1.overrideA1' - ... def overrideB1(self): - ... return 'DB1.overrideB1' - ... - >>> db1 = DB1() - >>> class DB2(B2): pass - ... - >>> db2 = DB2() - -test overrideA1 - - >>> a1.overrideA1() - 'A1::overrideA1' - >>> b1.overrideA1() - 'B1::overrideA1' - >>> b2.overrideA1() - 'B2::overrideA1' - >>> da1.overrideA1() - 'DA1.overrideA1' - >>> db1.overrideA1() - 'DB1.overrideA1' - >>> pa1_a1.overrideA1() - 'A1::overrideA1' - >>> pb1_a1.overrideA1() - 'B1::overrideA1' - >>> pb2_a1.overrideA1() - 'B2::overrideA1' - >>> pb1_b1.overrideA1() - 'B1::overrideA1' - >>> pc_a1.overrideA1() - 'B1::overrideA1' - >>> pc_b1.overrideA1() - 'B1::overrideA1' - -test call_overrideA1 - - >>> call_overrideA1(a1) - 'A1::overrideA1' - >>> call_overrideA1(b1) - 'B1::overrideA1' - >>> call_overrideA1(b2) - 'B2::overrideA1' - >>> call_overrideA1(da1) - 'DA1.overrideA1' - >>> call_overrideA1(db1) - 'DB1.overrideA1' - >>> call_overrideA1(pa1_a1) - 'A1::overrideA1' - >>> call_overrideA1(pb1_a1) - 'B1::overrideA1' - >>> call_overrideA1(pb2_a1) - 'B2::overrideA1' - >>> call_overrideA1(pb1_b1) - 'B1::overrideA1' - >>> call_overrideA1(pc_a1) - 'B1::overrideA1' - >>> call_overrideA1(pc_b1) - 'B1::overrideA1' - -test inheritA1 - - >>> a1.inheritA1() - 'A1::inheritA1' - >>> b1.inheritA1() - 'A1::inheritA1' - >>> b2.inheritA1() - 'A1::inheritA1' - >>> da1.inheritA1() - 'A1::inheritA1' - >>> db1.inheritA1() - 'A1::inheritA1' - >>> pa1_a1.inheritA1() - 'A1::inheritA1' - >>> pb1_a1.inheritA1() - 'A1::inheritA1' - >>> pb2_a1.inheritA1() - 'A1::inheritA1' - >>> pb1_b1.inheritA1() - 'A1::inheritA1' - >>> pc_a1.inheritA1() - 'A1::inheritA1' - >>> pc_b1.inheritA1() - 'A1::inheritA1' - -test call_inheritA1 - - >>> call_inheritA1(a1) - 'A1::inheritA1' - >>> call_inheritA1(b1) - 'A1::inheritA1' - >>> call_inheritA1(b2) - 'A1::inheritA1' - >>> call_inheritA1(da1) - 'A1::inheritA1' - >>> call_inheritA1(db1) - 'A1::inheritA1' - >>> call_inheritA1(pa1_a1) - 'A1::inheritA1' - >>> call_inheritA1(pb1_a1) - 'A1::inheritA1' - >>> call_inheritA1(pb2_a1) - 'A1::inheritA1' - >>> call_inheritA1(pb1_b1) - 'A1::inheritA1' - >>> call_inheritA1(pc_a1) - 'A1::inheritA1' - >>> call_inheritA1(pc_b1) - 'A1::inheritA1' - -test inheritA2 - - >>> a2.inheritA2() - 'A2::inheritA2' - >>> b1.inheritA2() - 'A2::inheritA2' - >>> b2.inheritA2() - 'A2::inheritA2' - >>> db1.inheritA2() - 'A2::inheritA2' - >>> pa2_a2.inheritA2() - 'A2::inheritA2' - >>> pb1_a2.inheritA2() - 'A2::inheritA2' - >>> pb1_b1.inheritA2() - 'A2::inheritA2' - -test overrideB1 - - >>> b1.overrideB1() - 'B1::overrideB1' - >>> db1.overrideB1() - 'DB1.overrideB1' - >>> pb1_b1.overrideB1() - 'B1::overrideB1' - >>> pc_b1.overrideB1() - 'C::overrideB1' - -test call_overrideB1 - - >>> call_overrideB1(b1) - 'B1::overrideB1' - >>> call_overrideB1(db1) - 'DB1.overrideB1' - >>> call_overrideB1(pb1_a1) - 'B1::overrideB1' - >>> call_overrideB1(pc_a1) - 'C::overrideB1' - >>> call_overrideB1(pb1_b1) - 'B1::overrideB1' - >>> call_overrideB1(pc_b1) - 'C::overrideB1' - -test inheritB2 - - >>> b2.inheritB2() - 'B2::inheritB2' - >>> db2.inheritB2() - 'B2::inheritB2' - -========= test the new def_raw() feature ========== - - >>> r = RawTest(1) - >>> raw(r,1,third=1,fourth=1) - 4 - >>> r.raw(1,third=1,fourth=1) - 4 - >>> raw(r,1,third=1,f=1) - Traceback (innermost last): - KeyError: fourth - >>> raw(r,1,third=1) - Traceback (innermost last): - TypeError: wrong number of arguments - >>> raw(r,1) - Traceback (innermost last): - TypeError: wrong number of arguments - >>> raw() - Traceback (innermost last): - TypeError: wrong number of arguments - >>> raw1(1,second=1) - 2 - >>> raw1(1) - 1 - >>> raw1(second=1) - 1 - >>> raw1() - 0 - >>> raw2(1,second=1) - 2 - >>> raw2(1) - 1 - >>> raw2(second=1) - 1 - >>> raw2() - 0 - -========= test export of operators ========== - - >>> i = Int(2) - >>> j = i+i - >>> j.i() - 4 - >>> j = i-i - >>> j.i() - 0 - >>> j = i*i - >>> j.i() - 4 - >>> i>> cmp(i,i) - 0 - >>> k = Int(5) - >>> j = divmod(k, i) - >>> j[0].i() - 2 - >>> j[1].i() - 1 - >>> j = pow(i, k) - >>> j.i() - 32 - >>> j = pow(i, k, k) - >>> j.i() - 2 - >>> j = -i - >>> j.i() - -2 - >>> str(i) - '2' - >>> try: j = i/i - ... except TypeError, err: - ... assert re.match(r'(bad|unsupported) operand type\(s\) for /', - ... str(err)) - ... else: print 'no exception' - - >>> j = abs(i) - Traceback (innermost last): - TypeError: bad operand type for abs() - >>> j = i+1 - >>> j.i() - 3 - >>> j = i-1 - >>> j.i() - 1 - >>> j = i*1 - >>> j.i() - 2 - >>> i<1 - 0 - >>> cmp(i,1) - 1 - >>> j = pow(i, 5) - >>> j.i() - 32 - >>> j = pow(i, 5, k) - Traceback (innermost last): - TypeError: bad operand type(s) for pow() - >>> j = pow(i, 5, 5) - Traceback (innermost last): - TypeError: bad operand type(s) for pow() - >>> j = i/1 - Traceback (innermost last): - TypeError: bad operand type(s) for / - >>> j = 1+i - >>> j.i() - 3 - >>> j = 1-i - >>> j.i() - -1 - >>> j = 1*i - >>> j.i() - 2 - >>> 1>> cmp(1,i) - -1 - >>> j = 1/i - Traceback (innermost last): - TypeError: bad operand type(s) for / - >>> pow(1,i) - Traceback (innermost last): - TypeError: bad operand type(s) for pow() - -Test operator export to a subclass - - # force method table sharing - >>> class IntDerived1(Int): pass - ... - - >>> class IntDerived(Int): - ... def __init__(self, i): - ... Int.__init__(self, i) - ... def __str__(self): - ... return 'IntDerived: ' + str(self.i()) - ... - >>> f = IntDerived(3) - >>> str(f) - 'IntDerived: 3' - >>> j = f * f - >>> j.i() - 9 - >>> j = f * i - >>> j.i() - 6 - >>> j = f * 5 - >>> j.i() - 15 - >>> j = i * f - >>> j.i() - 6 - >>> j = 5 * f - >>> j.i() - 15 - - -========= Prove that the "phantom base class" issue is resolved ========== - - >>> assert pa1_a1.__class__ == A1 - >>> assert pb1_a1.__class__ == A1 - >>> assert pb2_a1.__class__ == A1 - >>> assert pc_a1.__class__ == A1 - >>> assert pa2_a2.__class__ == A2 - >>> assert pb1_a2.__class__ == A2 - >>> assert pb1_b1.__class__ == B1 - >>> assert pc_b1.__class__ == B1 - >>> assert A1 in B1.__bases__ - >>> assert A2 in B1.__bases__ - >>> assert A1 in B2.__bases__ - >>> assert A2 in B2.__bases__ - >>> assert A1 in DA1.__bases__ - >>> assert B1 in DB1.__bases__ - >>> assert B2 in DB2.__bases__ - -=============================================================== -test methodologies for wrapping functions that return a pointer - - >>> get_record().value - 1234 - - In this methodology, the referent is copied - >>> get_record() == get_record() - 0 - -======== Enums and non-method class attributes ============== - >>> eo = EnumOwner(EnumOwner.one, EnumOwner.two) - >>> eo.first - 1 - >>> eo.second - 2 - >>> eo.first = EnumOwner.three - >>> eo.second = EnumOwner.one - >>> eo.first - 3 - >>> eo.second - 1 - -======== test [plain] char converters ============== - >>> get_plain_char() - 'x' - >>> use_plain_char('a') - 'aaa' - >>> use_const_plain_char('b') - 'bbbbb' - -======== test std::complex converters ============== - >>> c = dpolar(3, 5) - >>> type(c) - - >>> '%.3g' % (dreal(c)) - '0.851' - >>> '%.3g' % (dimag(c)) - '-2.88' - >>> '%.3g' % (freal(c)) - '0.851' - >>> '%.3g' % (fimag(c)) - '-2.88' - >>> c = fpolar(7, 13) - >>> type(c) - - >>> '%.3g' % (fimag(c)) - '2.94' - >>> '%.3g' % (freal(c)) - '6.35' - >>> '%.3g' % (dimag(c)) - '2.94' - >>> '%.3g' % (dreal(c)) - '6.35' - >>> '%.3g' % (dreal(3)) - '3' - >>> '%.3g' % (dreal(3L)) - '3' - >>> '%.3g' % (dreal(3.)) - '3' - >>> '%.3g' % (freal(3)) - '3' - >>> '%.3g' % (freal(3L)) - '3' - >>> '%.3g' % (freal(3.)) - '3' - -''' -#' - -__test__ = {} -import sys - -# Inplace ops only exist in python 2.1 or later. -if sys.hexversion >= 0x02010000: - __test__['inplacetests'] = r''' - >>> ii = Int(1) - >>> ii += Int(2) - >>> ii.i() - 3 - >>> ii -= Int(1) - >>> ii.i() - 2 - >>> ii *= Int(3) - >>> ii.i() - 6 - >>> ii /= Int(2) - >>> ii.i() - 3 - >>> ii <<= Int(2) - >>> ii.i() - 12 - >>> ii >>= Int(1) - >>> ii.i() - 6 - >>> ii &= Int(5) - >>> ii.i() - 4 - >>> ii |= Int(9) - >>> ii.i() - 13 - >>> ii ^= Int(7) - >>> ii.i() - 10 - >>> ii %= Int(4) - >>> ii.i() - 2 - >>> ii **= Int(3) - >>> ii.i() - 8 - >>> ii.j() - 11 -''' - -from boost_python_test import * - -# pickle requires these derived classes to be -# at the global scope of the module - -class myrational(Rational): - __dict_defines_state__ = 1 # this is a lie but good enough for testing. - -class myworld(world): - def __init__(self): - world.__init__(self, 'anywhere') - self.x = 1 - -class myunsafeworld(myworld): - __getstate_manages_dict__ = 1 # this is a lie but good enough for testing. - - -def assert_integer_expected(err): - """Handle a common error report which appears differently in Python 1.5.x and 2.0""" - assert isinstance(err, TypeError) - message = str(err) - assert (message == "illegal argument type for built-in operation" - or message == "an integer is required") - -import string -import re -import sys - -def run(args = None): - if args is not None: - sys.argv = args - - import doctest, comprehensive - return doctest.testmod(comprehensive) - -if __name__ == '__main__': - sys.exit(run()[0])