From d5cfa0483a3b6f8017db82af659448e36009fd53 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 9 Oct 2002 16:58:35 +0000 Subject: [PATCH] Clean up Boost.Python v1 flotsam, update documentation, prepare for release [SVN r15829] --- doc/building.html | 434 +++++---- doc/index.html | 233 +---- doc/tutorial/doc/building_hello_world.html | 19 +- doc/tutorial/doc/call_policies.html | 2 +- doc/tutorial/doc/class_data_members.html | 7 +- doc/tutorial/doc/class_virtual_functions.html | 7 +- doc/tutorial/doc/constructors.html | 2 +- doc/tutorial/doc/derived_object_types.html | 27 +- doc/tutorial/doc/quickstart.txt | 54 +- 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/reference.html | 100 +- include/boost/python.hpp | 104 +-- include/boost/python/errors.hpp | 2 - include/boost/python/init.hpp | 18 +- include/boost/python/operators.hpp | 851 +++++++----------- src/converter/registry.cpp | 2 +- src/errors.cpp | 8 +- test/Jamfile | 2 +- 22 files changed, 1102 insertions(+), 1327 deletions(-) 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/index.html b/doc/index.html index fffe13e9..c3090a64 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

    - - -

    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/tutorial/doc/building_hello_world.html b/doc/tutorial/doc/building_hello_world.html index 8595ea56..68094b60 100644 --- a/doc/tutorial/doc/building_hello_world.html +++ b/doc/tutorial/doc/building_hello_world.html @@ -36,26 +36,22 @@ building Boost.Python, check out: building.html. After this brief bjam tutorial, we should have built two DLLs:

    -if you are on Windows, and

    -

    -if you are on Unix.

    +This assumes of course that we are running on Windows.

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

    +/libs/python/example/tutorial. There, you can find:

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

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

    Lets Jam!

    -

    -

    Here is our minimalist Jamfile:

         subproject libs/python/example/tutorial ;
    @@ -103,9 +99,8 @@ Python modules. Example:

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

    +and that we are using Python version 2.2. Be sure not to include a third +number, e.g. not "2.2.1", even if that's the version you have.

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

    @@ -144,10 +139,6 @@ And so on... Finally:

    If all is well, you should now have:

    -if you are on Windows, and

    -

    -if you are on Unix.

    -

    boost_python.dll can be found somewhere in libs\python\build\bin while hello.pyd can be found somewhere in libs\python\example\tutorial\bin. After a successful build, you can just diff --git a/doc/tutorial/doc/call_policies.html b/doc/tutorial/doc/call_policies.html index 194097df..f0decf84 100644 --- a/doc/tutorial/doc/call_policies.html +++ b/doc/tutorial/doc/call_policies.html @@ -142,7 +142,7 @@ or more policies can be composed by chaining. Here's the general syntax:

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

    diff --git a/doc/tutorial/doc/class_data_members.html b/doc/tutorial/doc/class_data_members.html index 39847ba8..4718880c 100644 --- a/doc/tutorial/doc/class_data_members.html +++ b/doc/tutorial/doc/class_data_members.html @@ -56,11 +56,12 @@ Then, in Python:

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

    -    >>> x.name = 'e' # can't change name
    +    >>> x.name = 'e' #can't change name
         Traceback (most recent call last):
           File "<stdin>", line 1, in ?
    -    AttributeError: can't set attribute
    -
    + AttributeError: can't set attribute + +
    diff --git a/doc/tutorial/doc/class_virtual_functions.html b/doc/tutorial/doc/class_virtual_functions.html index 72c3fe3d..dea828c4 100644 --- a/doc/tutorial/doc/class_virtual_functions.html +++ b/doc/tutorial/doc/class_virtual_functions.html @@ -92,16 +92,15 @@ polymorphically fromC++.

    Wrapping Base and the free function call_f:

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

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

    +to instantiate a copy constructor for returning Base objects from +functions.

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

    diff --git a/doc/tutorial/doc/constructors.html b/doc/tutorial/doc/constructors.html
    index 79237526..621387f5 100644
    --- a/doc/tutorial/doc/constructors.html
    +++ b/doc/tutorial/doc/constructors.html
    @@ -64,7 +64,7 @@ expose instead.

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

    +"__init__(...)").

    We can expose additional constructors by passing more init<...>s to the def() member function. Say for example we have another World diff --git a/doc/tutorial/doc/derived_object_types.html b/doc/tutorial/doc/derived_object_types.html index 303774f7..4d08db05 100644 --- a/doc/tutorial/doc/derived_object_types.html +++ b/doc/tutorial/doc/derived_object_types.html @@ -70,21 +70,18 @@ member functions.

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

    -

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

    -

    -Python:

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

    -C++:

    -
    -    dict d(x.attr("__dict__"));  #copies x.__dict__
    -    d['whatever'] = 3;           #modifies the copy
    -
    +
    + + + +
    + Beware the common pitfall of +forgetting that the constructors of most of Python's mutable types +make copies, just as in Python.

    + + dict d(x.attr("__dict__")); # makes a copy of x's dict
    + d['whatever'] = 3; # modifies a copy of x.__dict__ (not the original)
    +

    class_<T> as objects

    Due to the dynamic nature of Boost.Python objects, any class_<T> may also be one of these types! The following code snippet wraps the class diff --git a/doc/tutorial/doc/quickstart.txt b/doc/tutorial/doc/quickstart.txt index a8176ec1..ecf3b87d 100644 --- a/doc/tutorial/doc/quickstart.txt +++ b/doc/tutorial/doc/quickstart.txt @@ -65,15 +65,10 @@ After this brief ['bjam] tutorial, we should have built two DLLs: * boost_python.dll * hello.pyd -if you are on Windows, and - -* libboost_python.so -* hello.so - -if you are on Unix. +This assumes of course that we are running on Windows. The tutorial example can be found in the directory: -[^libs/python/example/tutorial]. There, you can find: +[^/libs/python/example/tutorial]. There, you can find: * hello.cpp * Jamfile @@ -82,13 +77,12 @@ The [^hello.cpp] file is our C++ hello world example. The [^Jamfile] is a minimalist ['bjam] script that builds the DLLs for us. Before anything else, you should have the bjam executable in your boost -directory. Pre-built Boost.Jam executables are available for most +directory. Pre-built Boost.Jam executables are available for some platforms. For example, a pre-built Microsoft Windows bjam executable can be downloaded [@http://boost.sourceforge.net/jam-executables/bin.ntx86/bjam.zip here]. The complete list of bjam pre-built executables can be found [@../../../../../tools/build/index.html#Jam here]. [h2 Lets Jam!] -[$theme/jam.png] Here is our minimalist Jamfile: @@ -147,9 +141,8 @@ Python modules. Example: set PYTHON_VERSION=2.2 The above assumes that the Python installation is in [^c:/dev/tools/python] -and that we are using Python version 2.2. You'll have to tweak this path -appropriately. __note__ Be sure not to include a third number, e.g. [*not] "2.2.1", -even if that's the version you have. +and that we are using Python version 2.2. Be sure not to include a third +number, e.g. [*not] "2.2.1", even if that's the version you have. Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial] where the tutorial [^"hello.cpp"] and the [^"Jamfile"] is situated. @@ -193,13 +186,6 @@ If all is well, you should now have: * boost_python.dll * hello.pyd -if you are on Windows, and - -* libboost_python.so -* hello.so - -if you are on Unix. - [^boost_python.dll] can be found somewhere in [^libs\python\build\bin] while [^hello.pyd] can be found somewhere in [^libs\python\example\tutorial\bin]. After a successful build, you can just @@ -290,7 +276,7 @@ expose instead. [^init()] exposes the constructor taking in a [^std::string] (in Python, constructors are spelled -"[^"__init__"]"). +"[^__init__(...)]"). We can expose additional constructors by passing more [^init<...>]s to the [^def()] member function. Say for example we have another World @@ -340,12 +326,10 @@ Then, in Python: Note that [^name] is exposed as [*read-only] while [^value] is exposed as [*read-write]. -[pre >>> x.name = 'e' # can't change name Traceback (most recent call last): File "", line 1, in ? AttributeError: can't set attribute -] [page:1 Class Properties] @@ -498,15 +482,14 @@ polymorphically ['from] [*C++].] Wrapping [^Base] and the free function [^call_f]: - class_("Base", no_init) + class_("Base", no_init) ; def("call_f", call_f); Notice that we parameterized the [^class_] template with [^BaseWrap] as the second parameter. What is [^noncopyable]? Without it, the library will try -to create code for converting Base return values of wrapped functions to -Python. To do that, it needs Base's copy constructor... which isn't -available, since Base is an abstract class. +to instantiate a copy constructor for returning Base objects from +functions. In Python, let us try to instantiate our [^Base] class: @@ -837,7 +820,7 @@ or more policies can be composed by chaining. Here's the general syntax: policy3 > > Here is the list of predefined call policies. A complete reference detailing -these can be found [@../../v2/reference.html#models_of_call_policies here]. +these can be found [@../../v2/CallPolicies.html here]. * [*with_custodian_and_ward][br] Ties lifetimes of the arguments * [*with_custodian_and_ward_postcall][br] Ties lifetimes of the arguments and results @@ -1024,18 +1007,13 @@ member functions. Demonstrates that you can write the C++ equivalent of [^"format" % x,y,z] in Python, which is useful since there's no easy way to do that in std C++. -__alert__ [*Beware] the common pitfall of forgetting that the constructors -of most of Python's mutable types make copies, just as in Python. +[blurb __alert__ Beware the common pitfall of +forgetting that the constructors of most of Python's mutable types +make copies, just as in Python.[br][br] -Python: - - >>> d = dict(x.__dict__) # copies x.__dict__ - >>> d['whatever'] # modifies the copy - -C++: - - dict d(x.attr("__dict__")); # copies x.__dict__ - d['whatever'] = 3; # modifies the copy + [^dict d(x.attr("__dict__")); # makes a copy of x's dict[br] + '''d['whatever']''' = 3; # modifies a copy of x.__dict__ (not the original)[br]] +] [h2 class_ as objects] 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/reference.html b/doc/v2/reference.html index 0923a434..be866666 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

    @@ -308,8 +352,8 @@
    object
    -
    -
    + + @@ -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,11 +885,20 @@ + +

    Topics

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

    Revised - 3 June, 2002 + 08 October, 2002

    © Copyright -# 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 +# 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/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 1cbefb41..2707f7b7 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -138,16 +138,16 @@ struct init_base init_base(char const* doc_, detail::keyword_range const& keywords_) : m_doc(doc_), m_keywords(keywords_) {} - + init_base(char const* doc_) : m_doc(doc_) {} - + DerivedT const& derived() const { return *static_cast(this); } - + char const* doc_string() const { return m_doc; @@ -162,7 +162,7 @@ struct init_base { return default_call_policies(); } - + private: // data members char const* m_doc; detail::keyword_range m_keywords; @@ -192,7 +192,7 @@ class init_with_call_policies { return this->m_policies; } - + private: // data members CallPoliciesT m_policies; }; @@ -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; @@ -355,7 +355,7 @@ namespace detail if (keywords.second > keywords.first) --keywords.second; - + typename mpl::pop_front::type next; define_class_init_helper::apply(cl, policies, next, doc, keywords); } 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/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..4f554cc4 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -120,7 +120,7 @@ if $(TEST_BIENSTMAN_NON_BUGS) # --- unit tests of library components --- -local UNIT_TEST_PROPERTIES = +local UNIT_TEST_PROPERTIES = $(PYTHON_PROPERTIES) BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION [ difference $(PYTHON_PROPERTIES) : BOOST_PYTHON_DYNAMIC_LIB ] BOOST_PYTHON_STATIC_LIB ; run indirect_traits_test.cpp ;