diff --git a/.ci/faber b/.ci/faber new file mode 100644 index 0000000000..ddb36ddf66 --- /dev/null +++ b/.ci/faber @@ -0,0 +1,7 @@ +# -*- python -*- + +from faber.tools.boost import boostbook +from faber.tools.python import python + +bb = boostbook(prefix='/usr/share/boostbook') +p = python(command='$PYTHON') diff --git a/.github/workflows/deploy-documentation.yml b/.github/workflows/deploy-documentation.yml new file mode 100644 index 0000000000..3c5ffafb70 --- /dev/null +++ b/.github/workflows/deploy-documentation.yml @@ -0,0 +1,37 @@ +name: deploy documentation + +on: [push] + +jobs: + deploy: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - name: setup + run: | + sudo apt-get update + sudo apt-get install \ + libboost-tools-dev \ + python3 \ + python3-numpy \ + python3-sphinx \ + xsltproc \ + docbook-xsl + sudo python3 -m pip install --upgrade pip + sudo python3 -m pip install faber + - name: build + run: | + sed -e "s/\$PYTHON/python3/g" .ci/faber > ~/.faber + faber --builddir=build doc.html + if [ "${GITHUB_REF##*/}" == master ]; then + echo "destination_dir=doc/html" >> $GITHUB_ENV + else + echo "destination_dir=doc/develop/html" >> $GITHUB_ENV + fi + - name: deploy + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: build/doc/html + destination_dir: ${{ env.destination_dir }} + keep_files: true diff --git a/.github/workflows/test-osx.yml b/.github/workflows/test-osx.yml new file mode 100644 index 0000000000..b88b43e5dd --- /dev/null +++ b/.github/workflows/test-osx.yml @@ -0,0 +1,50 @@ +name: Test OSX + +on: [push, pull_request] + +jobs: + build: + runs-on: macOS-latest + + strategy: + fail-fast: false + matrix: + python-version: [3.8.10] + cxx: [clang++] + std: [c++11, c++14] # TODO: c++17 is failing ! + + steps: + - uses: actions/checkout@v5 + - name: setup python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - name: setup prerequisites + run: | + brew install boost + python -m pip install --upgrade pip + python -m pip install setuptools faber + - name: build + run: | + python --version + ${{ matrix.cxx }} --version + brew info boost + faber -v + sed -e "s/\$PYTHON/python/g" .ci/faber > ~/.faber + faber \ + --with-boost-include=$(brew --prefix boost)/include \ + --builddir=build \ + cxx.name=${{ matrix.cxx }} \ + cxxflags=-std=${{ matrix.std }} \ + cppflags=-std=${{ matrix.std }} \ + -j`sysctl -n hw.ncpu` + - name: test + run: | + faber \ + --with-boost-include=$(brew --prefix boost)/include \ + --builddir=build\ + cxx.name=${{ matrix.cxx }} \ + cxxflags=-std=${{ matrix.std }} \ + cppflags=-std=${{ matrix.std }} \ + -j`sysctl -n hw.ncpu` \ + test.report diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml new file mode 100644 index 0000000000..6f94c2d186 --- /dev/null +++ b/.github/workflows/test-ubuntu.yml @@ -0,0 +1,57 @@ +name: Test Ubuntu + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python: [python, python3] + cxx: [g++, clang++] + std: [c++11, c++14, c++17] + include: + # Add the appropriate docker image for each compiler. + # The images from teeks99/boost-python-test already have boost::python + # pre-reqs installed, see: + # https://github.com/teeks99/boost-python-test-docker + - cxx: clang++ + docker-img: teeks99/boost-python-test:clang-21_1.89.0 + - cxx: g++ + docker-img: teeks99/boost-python-test:gcc-15_1.89.0 + + container: + image: ${{ matrix.docker-img }} + + steps: + - uses: actions/checkout@v5 + + - name: setup prerequisites + run: | + # Warning: this is not necessarily the same Python version as the one configured above ! + python3 -m pip install -U faber --break-system-packages + - name: build + run: | + ${{ matrix.python }} --version + ${{ matrix.cxx }} --version + faber -v + sed -e "s/\$PYTHON/${{ matrix.python }}/g" .ci/faber > ~/.faber + faber \ + --with-boost-include=${BOOST_PY_DEPS} \ + --builddir=build \ + cxx.name=${{ matrix.cxx }} \ + cxxflags=-std=${{ matrix.std }} \ + cppflags=-std=${{ matrix.std }} \ + -j`nproc` + - name: test + run: | + faber \ + --with-boost-include=${BOOST_PY_DEPS} \ + --builddir=build \ + cxx.name=${{ matrix.cxx }} \ + cxxflags=-std=${{ matrix.std }} \ + cppflags=-std=${{ matrix.std }} \ + -j`nproc` \ + test.report diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml new file mode 100644 index 0000000000..576e1f4415 --- /dev/null +++ b/.github/workflows/test-windows.yml @@ -0,0 +1,49 @@ +name: Test Windows + +on: [push, pull_request] + +jobs: + build: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python-version: [3.7] + + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - uses: microsoft/setup-msbuild@v2 + - name: setup boost prerequisites + uses: lukka/run-vcpkg@v6 + with: + vcpkgGitCommitId: '88b1071e39f13b632644d9d953738d345a4ac055' + vcpkgDirectory: '${{ runner.workspace }}/vcpkg' + vcpkgTriplet: x64-windows + vcpkgArguments: > + boost-config + boost-core + boost-function + boost-graph + boost-iterator + boost-lexical-cast + boost-mpl + boost-preprocessor + boost-smart-ptr + boost-static-assert + boost-align + - name: setup faber + run: | + python -m pip install --upgrade pip + python -m pip install setuptools faber numpy + faber --info=tools cxx + - name: build + shell: cmd + run: | + faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include=${{ runner.workspace }}\vcpkg\installed\x64-windows\include -j4 + - name: test + shell: cmd + run: | + faber --builddir=build cxx.name=msvc --with-boost-include=${{ runner.workspace }}\vcpkg\installed\x64-windows\include -j4 test.report diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..06ea5d43c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bin.SCons +*.pyc +*~ +\#*\# \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..299ef84e9c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,176 @@ +# Copyright 2020, 2021 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.14...3.20) + +project(boost_python VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +find_package(Python REQUIRED COMPONENTS Development OPTIONAL_COMPONENTS NumPy) + +if(Python_NumPy_FOUND) + message(STATUS "Boost.Python: using Python ${Python_VERSION} with NumPy at ${Python_NumPy_INCLUDE_DIRS}") +else() + message(STATUS "Boost.Python: using Python ${Python_VERSION} without NumPy") +endif() + +# boost_pythonXY + +set(_pyver ${Python_VERSION_MAJOR}${Python_VERSION_MINOR}) +set(_boost_python boost_python${_pyver}) + +add_library(${_boost_python} + src/dict.cpp + src/errors.cpp + src/exec.cpp + src/import.cpp + src/list.cpp + src/long.cpp + src/module.cpp + src/object_operators.cpp + src/object_protocol.cpp + src/slice.cpp + src/str.cpp + src/tuple.cpp + src/wrapper.cpp + src/converter/from_python.cpp + src/converter/registry.cpp + src/converter/type_id.cpp + src/converter/builtin_converters.cpp + src/converter/arg_to_python_base.cpp + src/object/enum.cpp + src/object/class.cpp + src/object/function.cpp + src/object/inheritance.cpp + src/object/life_support.cpp + src/object/pickle_support.cpp + src/object/iterator.cpp + src/object/stl_iterator.cpp + src/object_protocol.cpp + src/object_operators.cpp + src/object/function_doc_signature.cpp +) + +add_library(Boost::python${_pyver} ALIAS ${_boost_python}) + +target_include_directories(${_boost_python} PUBLIC include) + +target_link_libraries(${_boost_python} + PUBLIC + Boost::align + Boost::bind + Boost::config + Boost::conversion + Boost::core + Boost::detail + Boost::foreach + Boost::function + Boost::iterator + Boost::lexical_cast + Boost::mpl + Boost::numeric_conversion + Boost::preprocessor + Boost::smart_ptr + Boost::static_assert + Boost::tuple + Boost::type_traits + Boost::utility + + Python::Module + + PRIVATE + Boost::graph + Boost::integer + Boost::property_map +) + +target_compile_definitions(${_boost_python} + PUBLIC BOOST_PYTHON_NO_LIB + PRIVATE BOOST_PYTHON_SOURCE +) + +if(BUILD_SHARED_LIBS) + target_compile_definitions(${_boost_python} PUBLIC BOOST_PYTHON_DYN_LINK) +else() + target_compile_definitions(${_boost_python} PUBLIC BOOST_PYTHON_STATIC_LINK BOOST_PYTHON_STATIC_LIB) +endif() + +# Boost::python alias + +add_library(boost_python INTERFACE) +add_library(Boost::python ALIAS boost_python) +target_link_libraries(boost_python INTERFACE Boost::python${_pyver}) + +# Installation + +if(BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13) + boost_install(TARGETS ${_boost_python} boost_python VERSION ${BOOST_SUPERPROJECT_VERSION} HEADER_DIRECTORY include) +endif() + +if(Python_NumPy_FOUND) + +# boost_numpyXY + +set(_boost_numpy boost_numpy${_pyver}) + +add_library(${_boost_numpy} + src/numpy/dtype.cpp + src/numpy/matrix.cpp + src/numpy/ndarray.cpp + src/numpy/numpy.cpp + src/numpy/scalars.cpp + src/numpy/ufunc.cpp +) + +add_library(Boost::numpy${_pyver} ALIAS ${_boost_numpy}) + +target_include_directories(${_boost_numpy} PUBLIC include) + +target_link_libraries(${_boost_numpy} + PUBLIC + Boost::config + Boost::core + Boost::detail + Boost::mpl + Boost::python + Boost::smart_ptr + + Python::NumPy +) + +target_compile_definitions(${_boost_numpy} + PUBLIC BOOST_NUMPY_NO_LIB + PRIVATE BOOST_NUMPY_SOURCE +) + +if(BUILD_SHARED_LIBS) + target_compile_definitions(${_boost_numpy} PUBLIC BOOST_NUMPY_DYN_LINK) +else() + target_compile_definitions(${_boost_numpy} PUBLIC BOOST_NUMPY_STATIC_LINK BOOST_NUMPY_STATIC_LIB) +endif() + +# Boost::numpy alias + +add_library(boost_numpy INTERFACE) +add_library(Boost::numpy ALIAS boost_numpy) +target_link_libraries(boost_numpy INTERFACE Boost::numpy${_pyver}) + +# Installation + +if(BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13) + boost_install(TARGETS ${_boost_numpy} boost_numpy VERSION ${BOOST_SUPERPROJECT_VERSION}) +endif() + +endif() + +unset(_pyver) +unset(_boost_python) +unset(_boost_numpy) + +# Testing + +if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + + add_subdirectory(test) + +endif() diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..f57b97505a --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +![logo](https://raw.githubusercontent.com/boostorg/python/develop/doc/images/bpl.png) + +# Synopsis + +[![Join the chat at https://gitter.im/boostorg/python](https://badges.gitter.im/boostorg/python.svg)](https://gitter.im/boostorg/python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Welcome to Boost.Python, a C++ library which enables seamless interoperability between C++ and the Python programming language. The library includes support for: + +* References and Pointers +* Globally Registered Type Coercions +* Automatic Cross-Module Type Conversions +* Efficient Function Overloading +* C++ to Python Exception Translation +* Default Arguments +* Keyword Arguments +* Manipulating Python objects in C++ +* Exporting C++ Iterators as Python Iterators +* Documentation Strings + +See the [Boost.Python](http://boostorg.github.io/python) documentation for details. + +**Hint :** Check out the [development version](http://boostorg.github.io/python/develop) of the documentation to see work in progress. + +# Building ![Test Ubuntu](https://github.com/boostorg/python/workflows/Test%20Ubuntu/badge.svg) ![Test OSX](https://github.com/boostorg/python/workflows/Test%20OSX/badge.svg) ![Test Windows](https://github.com/boostorg/python/workflows/Test%20Windows/badge.svg) + +While Boost.Python is part of the Boost C++ Libraries super-project, and thus can be compiled as part of Boost, it can also be compiled and installed stand-alone, i.e. against a pre-installed Boost package. + +## Prerequisites + +* [Python](http://www.python.org) +* [Boost](http://www.boost.org) +* [Faber](https://stefanseefeld.github.io/faber) + +## Build + +Run + +``` +faber +``` +to build the library. + +## Test + +Run + +``` +faber test.report +``` +to run the tests. + +## Build docs + +Run + +``` +faber doc.html +``` +to build the documentation. diff --git a/build.jam b/build.jam new file mode 100644 index 0000000000..e9eb1a11a2 --- /dev/null +++ b/build.jam @@ -0,0 +1,41 @@ +# Copyright René Ferdinand Rivera Morell 2024 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +require-b2 5.2 ; + +constant boost_dependencies : + /boost/align//boost_align + /boost/bind//boost_bind + /boost/config//boost_config + /boost/conversion//boost_conversion + /boost/core//boost_core + /boost/detail//boost_detail + /boost/foreach//boost_foreach + /boost/function//boost_function + /boost/iterator//boost_iterator + /boost/lexical_cast//boost_lexical_cast + /boost/mpl//boost_mpl + /boost/numeric_conversion//boost_numeric_conversion + /boost/preprocessor//boost_preprocessor + /boost/static_assert//boost_static_assert + /boost/tuple//boost_tuple + /boost/type_traits//boost_type_traits + /boost/utility//boost_utility ; + +project /boost/python + : common-requirements + include + ; + +explicit + [ alias boost_python : build//boost_python ] + [ alias boost_numpy : build//boost_numpy ] + [ alias all : boost_python boost_numpy test ] + ; + +call-if : boost-library python + : install boost_python boost_numpy + ; + diff --git a/build/Attic/python_v1.zip b/build/Attic/python_v1.zip deleted file mode 100644 index 0377a07bb3..0000000000 Binary files a/build/Attic/python_v1.zip and /dev/null differ diff --git a/build/Jamfile b/build/Jamfile new file mode 100644 index 0000000000..c8f9859c64 --- /dev/null +++ b/build/Jamfile @@ -0,0 +1,175 @@ +# Copyright David Abrahams 2001-2006. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import os ; +import indirect ; +import modules ; +import feature ; +import property ; +import python ; + +if ! [ python.configured ] && ! ( --without-python in [ modules.peek : ARGV ] ) +{ + # Attempt default configuration of python + import toolset : using ; + using python ; +} + +if [ python.configured ] || ( --without-python in [ modules.peek : ARGV ] ) +{ + alias config-warning ; +} +else +{ + message config-warning + : "warning: No python installation configured and autoconfiguration" + : "note: failed. See http://www.boost.org/libs/python/doc/building.html" + : "note: for configuration instructions or pass --without-python to" + : "note: suppress this message and silently skip all Boost.Python targets" + ; +} + +constant boost_dependencies_private : + /boost/graph//boost_graph + /boost/integer//boost_integer + /boost/property_map//boost_property_map + /boost/smart_ptr//boost_smart_ptr + ; + +project + : source-location ../src + : common-requirements $(boost_dependencies) + : requirements $(boost_dependencies_private) + ; + +rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } +rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } +local rule eq ( a : b ) { if $(a) = $(b) { return 1 ; } } + +rule tag ( name : type ? : property-set ) +{ + if python-tag in [ RULENAMES $(__name__) ] + { + return [ $(__name__).python-tag $(name) : $(type) : $(property-set) ] ; + } +} + +if [ python.configured ] +{ + +lib boost_python + : # sources + list.cpp + long.cpp + dict.cpp + tuple.cpp + str.cpp + slice.cpp + + converter/from_python.cpp + converter/registry.cpp + converter/type_id.cpp + object/enum.cpp + object/class.cpp + object/function.cpp + object/inheritance.cpp + object/life_support.cpp + object/pickle_support.cpp + errors.cpp + module.cpp + converter/builtin_converters.cpp + converter/arg_to_python_base.cpp + object/iterator.cpp + object/stl_iterator.cpp + object_protocol.cpp + object_operators.cpp + wrapper.cpp + import.cpp + exec.cpp + object/function_doc_signature.cpp + : # requirements + static:BOOST_PYTHON_STATIC_LIB + BOOST_PYTHON_SOURCE + + # On Windows, all code using Python has to link to the Python + # import library. + # + # On *nix we never link libboost_python to libpython. When + # extending Python, all Python symbols are provided by the + # Python interpreter executable. When embedding Python, the + # client executable is expected to explicitly link to + # /python//python (the target representing libpython) itself. + # + # python_for_extensions is a target defined by Boost.Build to + # provide the Python include paths, and on Windows, the Python + # import library, as usage requirements. + [ cond [ python.configured ] : /python//python_for_extensions ] + + # we prevent building when there is no python available + # as it's not possible anyway, and to cause dependents to + # fail to build + [ unless [ python.configured ] : no ] + config-warning + on:BOOST_DEBUG_PYTHON + -@%boostcpp.tag + -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + @tag + @python.require-py + + : # default build + shared + : # usage requirements + static:BOOST_PYTHON_STATIC_LIB + on:BOOST_DEBUG_PYTHON + BOOST_PYTHON_NO_LIB + ; + +} +else +{ + +alias boost_python : config-warning ; + +} + +if [ python.configured ] && [ python.numpy ] +{ + +numpy-include = [ python.numpy-include ] ; +lib boost_numpy + : # sources + numpy/dtype.cpp + numpy/matrix.cpp + numpy/ndarray.cpp + numpy/numpy.cpp + numpy/scalars.cpp + numpy/ufunc.cpp + : # requirements + static:BOOST_NUMPY_STATIC_LIB + BOOST_NUMPY_SOURCE + [ cond [ python.numpy ] : /python//python_for_extensions ] + [ unless [ python.numpy ] : no ] + /python//numpy + boost_python + on:BOOST_DEBUG_PYTHON + -@%boostcpp.tag + -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + @tag + @python.require-py + + : # default build + shared + : # usage requirements + static:BOOST_NUMPY_STATIC_LIB + on:BOOST_DEBUG_PYTHON + BOOST_NUMPY_NO_LIB + ; + +} +else +{ + +alias boost_numpy : config-warning ; + +} diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 deleted file mode 100644 index 32bffb0f72..0000000000 --- a/build/Jamfile.v2 +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright David Abrahams 2001-2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -import os ; -import indirect ; -import modules ; -import feature ; - -import python ; - -if ! [ python.configured ] && ! ( --without-python in [ modules.peek : ARGV ] ) -{ - # Attempt default configuration of python - import toolset : using ; - using python ; -} - -if [ python.configured ] || ( --without-python in [ modules.peek : ARGV ] ) -{ - alias config-warning ; -} -else -{ - message config-warning - : "warning: No python installation configured and autoconfiguration" - : "note: failed. See http://www.boost.org/libs/python/doc/building.html" - : "note: for configuration instructions or pass --without-python to" - : "note: suppress this message and silently skip all Boost.Python targets" - ; -} - -rule find-py3-version -{ - local versions = [ feature.values python ] ; - local py3ver ; - for local v in $(versions) - { - if $(v) >= 3.0 - { - py3ver = $(v) ; - } - } - return $(py3ver) ; -} - -py3-version = [ find-py3-version ] ; - -project boost/python - : source-location ../src - : requirements - -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag - @$(__name__).tag - ; - -rule tag ( name : type ? : property-set ) -{ - local result = $(name) ; - if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB - { - if $(name) = boost_python && $(PYTHON_ID) - { - result = $(result)-$(PYTHON_ID) ; - } - } - - # forward to the boost tagging rule - return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag - $(result) : $(type) : $(property-set) ] ; -} - -rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } -rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } - -rule lib_boost_python ( is-py3 ? ) -{ - - lib [ cond $(is-py3) : boost_python3 : boost_python ] - : # sources - numeric.cpp - list.cpp - long.cpp - dict.cpp - tuple.cpp - str.cpp - slice.cpp - - converter/from_python.cpp - converter/registry.cpp - converter/type_id.cpp - object/enum.cpp - object/class.cpp - object/function.cpp - object/inheritance.cpp - object/life_support.cpp - object/pickle_support.cpp - errors.cpp - module.cpp - converter/builtin_converters.cpp - converter/arg_to_python_base.cpp - object/iterator.cpp - object/stl_iterator.cpp - object_protocol.cpp - object_operators.cpp - wrapper.cpp - import.cpp - exec.cpp - object/function_doc_signature.cpp - : # requirements - static:BOOST_PYTHON_STATIC_LIB - BOOST_PYTHON_SOURCE - - # On Windows, all code using Python has to link to the Python - # import library. - # - # On *nix we never link libboost_python to libpython. When - # extending Python, all Python symbols are provided by the - # Python interpreter executable. When embedding Python, the - # client executable is expected to explicitly link to - # /python//python (the target representing libpython) itself. - # - # python_for_extensions is a target defined by Boost.Build to - # provide the Python include paths, and on Windows, the Python - # import library, as usage requirements. - [ cond [ python.configured ] : /python//python_for_extensions ] - - # we prevent building when there is no python available - # as it's not possible anyway, and to cause dependents to - # fail to build - [ unless [ python.configured ] : no ] - config-warning - - on:BOOST_DEBUG_PYTHON - [ cond $(is-py3) : $(py3-version) ] - : # default build - shared - : # usage requirements - static:BOOST_PYTHON_STATIC_LIB - on:BOOST_DEBUG_PYTHON - ; - -} - -lib_boost_python ; -boost-install boost_python ; - -if $(py3-version) -{ - lib_boost_python yes ; - boost-install boost_python3 ; -} diff --git a/build/python_v1.zip b/build/python_v1.zip deleted file mode 100644 index 0377a07bb3..0000000000 Binary files a/build/python_v1.zip and /dev/null differ diff --git a/doc/Jamfile b/doc/Jamfile index 9b7c8841aa..735ef22e6f 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -1,23 +1,66 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying +# Copyright (c) 2006 Joel de Guzman +# Copyright (c) 2015 Stefan Seefeld +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import boostbook ; +import quickbook ; import docutils ; +import os ; + +path-constant here : . ; +path-constant images : html/images ; + +project python/doc + : requirements + -boost.defaults=Boost + html:boost.defaults=none + html:toc.max.depth=3 + html:toc.section.depth=2 + html:chunk.section.depth=1 + ; -import path ; -sources = building.rst ; -bases = $(sources:S=) ; - -# This is a path relative to the html/ subdirectory where the -# generated output will eventually be moved. -stylesheet = "--stylesheet=../../../rst.css" ; +make numpy : numpy/index.rst : @sphinx-build ; -for local b in $(bases) +if [ os.name ] = NT +{ + actions sphinx-build { chdir "$(>:D)" && make clean && make html} +} +else { - html $(b) : $(b).rst : - - "-gdt --source-url="./$(b).rst" --link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript "$(stylesheet) - ; + actions sphinx-build { make -C "$(>:D)" clean html} } -alias htmls : $(bases) ; -stage . : $(bases) ; +boostbook python : python.qbk + : html:$(here)/html + html:generate.toc="library nop; chapter toc; section toc;" + html:html.stylesheet=boostbook.css + html:boost.image.src=images/boost.png + html:boost.graphics.root=images/ + ; + +boostbook tutorial : tutorial.qbk + : html:$(here)/html/tutorial + html:html.stylesheet=../boostbook.css + html:boost.image.src=../images/boost.png + html:boost.graphics.root=../images/ + ; + +boostbook reference : reference.qbk + : html:$(here)/html/reference + html:html.stylesheet=../boostbook.css + html:boost.image.src=../images/boost.png + html:boost.graphics.root=../images/ + ; + +html article : article.rst + : html + "--link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript --stylesheet=rst.css" + ; + +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease : python tutorial reference numpy article ; +explicit boostrelease ; diff --git a/doc/PyConDC_2003/bpl.html b/doc/PyConDC_2003/bpl.html deleted file mode 100755 index 32b655bd9a..0000000000 --- a/doc/PyConDC_2003/bpl.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - Loading: “Building Hybrid Systems With Boost.Python” - - - - Loading...; if nothing happens, please go to http://www.boost-consulting.com/writing/bpl.html. - - - diff --git a/doc/PyConDC_2003/bpl.pdf b/doc/PyConDC_2003/bpl.pdf deleted file mode 100755 index 09827aff02..0000000000 Binary files a/doc/PyConDC_2003/bpl.pdf and /dev/null differ diff --git a/doc/PyConDC_2003/bpl.txt b/doc/PyConDC_2003/bpl.txt deleted file mode 100644 index d6921b1244..0000000000 --- a/doc/PyConDC_2003/bpl.txt +++ /dev/null @@ -1,5 +0,0 @@ -.. Copyright David Abrahams 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -This file has been moved to http://www.boost-consulting.com/writing/bpl.txt. diff --git a/doc/PyConDC_2003/bpl_mods.txt b/doc/PyConDC_2003/bpl_mods.txt deleted file mode 100644 index d42f00f8b1..0000000000 --- a/doc/PyConDC_2003/bpl_mods.txt +++ /dev/null @@ -1,911 +0,0 @@ -Copyright David Abrahams 2006. Distributed under the Boost -Software License, Version 1.0. (See accompanying -file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -.. This is a comment. Note how any initial comments are moved by - transforms to after the document title, subtitle, and docinfo. - -.. Need intro and conclusion -.. Exposing classes - .. Constructors - .. Overloading - .. Properties and data members - .. Inheritance - .. Operators and Special Functions - .. Virtual Functions -.. Call Policies - -++++++++++++++++++++++++++++++++++++++++++++++ - Introducing Boost.Python (Extended Abstract) -++++++++++++++++++++++++++++++++++++++++++++++ - - -.. bibliographic fields (which also require a transform): - -:Author: David Abrahams -:Address: 45 Walnut Street - Somerville, MA 02143 -:Contact: dave@boost-consulting.com -:organization: `Boost Consulting`_ -:status: This is a "work in progress" -:version: 1 -:copyright: Copyright David Abrahams 2002. All rights reserved - -:Dedication: - - For my girlfriend, wife, and partner Luann - -:abstract: - - This paper describes the Boost.Python library, a system for - C++/Python interoperability. - -.. meta:: - :keywords: Boost,python,Boost.Python,C++ - :description lang=en: C++/Python interoperability with Boost.Python - -.. contents:: Table of Contents -.. section-numbering:: - - -.. _`Boost Consulting`: http://www.boost-consulting.com - -============== - Introduction -============== - -Python and C++ are in many ways as different as two languages could -be: while C++ is usually compiled to machine-code, Python is -interpreted. Python's dynamic type system is often cited as the -foundation of its flexibility, while in C++ static typing is the -cornerstone of its efficiency. C++ has an intricate and difficult -meta-language to support compile-time polymorphism, while Python is -a uniform language with convenient runtime polymorphism. - -Yet for many programmers, these very differences mean that Python and -C++ complement one another perfectly. Performance bottlenecks in -Python programs can be rewritten in C++ for maximal speed, and -authors of powerful C++ libraries choose Python as a middleware -language for its flexible system integration capabilities. -Furthermore, the surface differences mask some strong similarities: - -* 'C'-family control structures (if, while, for...) - -* Support for object-orientation, functional programming, and generic - programming (these are both *multi-paradigm* programming languages.) - -* Comprehensive operator overloading facilities, recognizing the - importance of syntactic variability for readability and - expressivity. - -* High-level concepts such as collections and iterators. - -* High-level encapsulation facilities (C++: namespaces, Python: modules) - to support the design of re-usable libraries. - -* Exception-handling for effective management of error conditions. - -* C++ idioms in common use, such as handle/body classes and - reference-counted smart pointers mirror Python reference semantics. - -Python provides a rich 'C' API for writers of 'C' extension modules. -Unfortunately, using this API directly for exposing C++ type and -function interfaces to Python is much more tedious than it should be. -This is mainly due to the limitations of the 'C' language. Compared to -C++ and Python, 'C' has only very rudimentary abstraction facilities. -Support for exception-handling is completely missing. One important -undesirable consequence is that 'C' extension module writers are -required to manually manage Python reference counts. Another unpleasant -consequence is a very high degree of repetition of similar code in 'C' -extension modules. Of course highly redundant code does not only cause -frustration for the module writer, but is also very difficult to -maintain. - -The limitations of the 'C' API have lead to the development of a -variety of wrapping systems. SWIG_ is probably the most popular package -for the integration of C/C++ and Python. A more recent development is -the SIP_ package, which is specifically designed for interfacing Python -with the Qt_ graphical user interface library. Both SWIG and SIP -introduce a new specialized language for defining the inter-language -bindings. Of course being able to use a specialized language has -advantages, but having to deal with three different languages (Python, -C/C++ and the interface language) also introduces practical and mental -difficulties. The CXX_ package demonstrates an interesting alternative. -It shows that at least some parts of Python's 'C' API can be wrapped -and presented through a much more user-friendly C++ interface. However, -unlike SWIG and SIP, CXX does not include support for wrapping C++ -classes as new Python types. CXX is also no longer actively developed. - -In some respects Boost.Python combines ideas from SWIG and SIP with -ideas from CXX. Like SWIG and SIP, Boost.Python is a system for -wrapping C++ classes as new Python "built-in" types, and C/C++ -functions as Python functions. Like CXX, Boost.Python presents Python's -'C' API through a C++ interface. Boost.Python goes beyond the scope of -other systems with the unique support for C++ virtual functions that -are overrideable in Python, support for organizing extensions as Python -packages with a central registry for inter-language type conversions, -and a convenient mechanism for tying into Python's serialization engine -(pickle). Importantly, all this is achieved without introducing a new -syntax. Boost.Python leverages the power of C++ meta-programming -techniques to introspect about the C++ type system, and presents a -simple, IDL-like C++ interface for exposing C/C++ code in extension -modules. Boost.Python is a pure C++ library, the inter-language -bindings are defined in pure C++, and other than a C++ compiler only -Python itself is required to get started with Boost.Python. Last but -not least, Boost.Python is an unrestricted open source library. There -are no strings attached even for commercial applications. - -.. _SWIG: http://www.swig.org/ -.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php -.. _Qt: http://www.trolltech.com/ -.. _CXX: http://cxx.sourceforge.net/ - -=========================== - Boost.Python Design Goals -=========================== - -The primary goal of Boost.Python is to allow users to expose C++ -classes and functions to Python using nothing more than a C++ -compiler. In broad strokes, the user experience should be one of -directly manipulating C++ objects from Python. - -However, it's also important not to translate all interfaces *too* -literally: the idioms of each language must be respected. For -example, though C++ and Python both have an iterator concept, they are -expressed very differently. Boost.Python has to be able to bridge the -interface gap. - -It must be possible to insulate Python users from crashes resulting -from trivial misuses of C++ interfaces, such as accessing -already-deleted objects. By the same token the library should -insulate C++ users from low-level Python 'C' API, replacing -error-prone 'C' interfaces like manual reference-count management and -raw ``PyObject`` pointers with more-robust alternatives. - -Support for component-based development is crucial, so that C++ types -exposed in one extension module can be passed to functions exposed in -another without loss of crucial information like C++ inheritance -relationships. - -Finally, all wrapping must be *non-intrusive*, without modifying or -even seeing the original C++ source code. Existing C++ libraries have -to be wrappable by third parties who only have access to header files -and binaries. - -========================== - Hello Boost.Python World -========================== - -And now for a preview of Boost.Python, and how it improves on the raw -facilities offered by Python. Here's a function we might want to -expose:: - - char const* greet(unsigned x) - { - static char const* const msgs[] = { "hello", "Boost.Python", "world!" }; - - if (x > 2) - throw std::range_error("greet: index out of range"); - - return msgs[x]; - } - -To wrap this function in standard C++ using the Python 'C' API, we'd -need something like this:: - - extern "C" // all Python interactions use 'C' linkage and calling convention - { - // Wrapper to handle argument/result conversion and checking - PyObject* greet_wrap(PyObject* args, PyObject * keywords) - { - int x; - if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments - { - char const* result = greet(x); // invoke wrapped function - return PyString_FromString(result); // convert result to Python - } - return 0; // error occurred - } - - // Table of wrapped functions to be exposed by the module - static PyMethodDef methods[] = { - { "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" } - , { NULL, NULL, 0, NULL } // sentinel - }; - - // module initialization function - DL_EXPORT init_hello() - { - (void) Py_InitModule("hello", methods); // add the methods to the module - } - } - -Now here's the wrapping code we'd use to expose it with Boost.Python:: - - #include - using namespace boost::python; - BOOST_PYTHON_MODULE(hello) - { - def("greet", greet, "return one of 3 parts of a greeting"); - } - -and here it is in action:: - - >>> import hello - >>> for x in range(3): - ... print hello.greet(x) - ... - hello - Boost.Python - world! - -Aside from the fact that the 'C' API version is much more verbose than -the BPL one, it's worth noting that it doesn't handle a few things -correctly: - -* The original function accepts an unsigned integer, and the Python - 'C' API only gives us a way of extracting signed integers. The - Boost.Python version will raise a Python exception if we try to pass - a negative number to ``hello.greet``, but the other one will proceed - to do whatever the C++ implementation does when converting an - negative integer to unsigned (usually wrapping to some very large - number), and pass the incorrect translation on to the wrapped - function. - -* That brings us to the second problem: if the C++ ``greet()`` - function is called with a number greater than 2, it will throw an - exception. Typically, if a C++ exception propagates across the - boundary with code generated by a 'C' compiler, it will cause a - crash. As you can see in the first version, there's no C++ - scaffolding there to prevent this from happening. Functions wrapped - by Boost.Python automatically include an exception-handling layer - which protects Python users by translating unhandled C++ exceptions - into a corresponding Python exception. - -* A slightly more-subtle limitation is that the argument conversion - used in the Python 'C' API case can only get that integer ``x`` in - *one way*. PyArg_ParseTuple can't convert Python ``long`` objects - (arbitrary-precision integers) which happen to fit in an ``unsigned - int`` but not in a ``signed long``, nor will it ever handle a - wrapped C++ class with a user-defined implicit ``operator unsigned - int()`` conversion. The BPL's dynamic type conversion registry - allows users to add arbitrary conversion methods. - -================== - Library Overview -================== - -This section outlines some of the library's major features. Except as -necessary to avoid confusion, details of library implementation are -omitted. - -------------------------------------------- - The fundamental type-conversion mechanism -------------------------------------------- - -XXX This needs to be rewritten. - -Every argument of every wrapped function requires some kind of -extraction code to convert it from Python to C++. Likewise, the -function return value has to be converted from C++ to Python. -Appropriate Python exceptions must be raised if the conversion fails. -Argument and return types are part of the function's type, and much of -this tedium can be relieved if the wrapping system can extract that -information through introspection. - -Passing a wrapped C++ derived class instance to a C++ function -accepting a pointer or reference to a base class requires knowledge of -the inheritance relationship and how to translate the address of a base -class into that of a derived class. - ------------------- - Exposing Classes ------------------- - -C++ classes and structs are exposed with a similarly-terse interface. -Given:: - - struct World - { - void set(std::string msg) { this->msg = msg; } - std::string greet() { return msg; } - std::string msg; - }; - -The following code will expose it in our extension module:: - - #include - BOOST_PYTHON_MODULE(hello) - { - class_("World") - .def("greet", &World::greet) - .def("set", &World::set) - ; - } - -Although this code has a certain pythonic familiarity, people -sometimes find the syntax bit confusing because it doesn't look like -most of the C++ code they're used to. All the same, this is just -standard C++. Because of their flexible syntax and operator -overloading, C++ and Python are great for defining domain-specific -(sub)languages -(DSLs), and that's what we've done in BPL. To break it down:: - - class_("World") - -constructs an unnamed object of type ``class_`` and passes -``"World"`` to its constructor. This creates a new-style Python class -called ``World`` in the extension module, and associates it with the -C++ type ``World`` in the BPL type conversion registry. We might have -also written:: - - class_ w("World"); - -but that would've been more verbose, since we'd have to name ``w`` -again to invoke its ``def()`` member function:: - - w.def("greet", &World::greet) - -There's nothing special about the location of the dot for member -access in the original example: C++ allows any amount of whitespace on -either side of a token, and placing the dot at the beginning of each -line allows us to chain as many successive calls to member functions -as we like with a uniform syntax. The other key fact that allows -chaining is that ``class_<>`` member functions all return a reference -to ``*this``. - -So the example is equivalent to:: - - class_ w("World"); - w.def("greet", &World::greet); - w.def("set", &World::set); - -It's occasionally useful to be able to break down the components of a -Boost.Python class wrapper in this way, but the rest of this paper -will tend to stick to the terse syntax. - -For completeness, here's the wrapped class in use: - ->>> import hello ->>> planet = hello.World() ->>> planet.set('howdy') ->>> planet.greet() -'howdy' - -Constructors -============ - -Since our ``World`` class is just a plain ``struct``, it has an -implicit no-argument (nullary) constructor. Boost.Python exposes the -nullary constructor by default, which is why we were able to write: - ->>> planet = hello.World() - -However, well-designed classes in any language may require constructor -arguments in order to establish their invariants. Unlike Python, -where ``__init__`` is just a specially-named method, In C++ -constructors cannot be handled like ordinary member functions. In -particular, we can't take their address: ``&World::World`` is an -error. The library provides a different interface for specifying -constructors. Given:: - - struct World - { - World(std::string msg); // added constructor - ... - -we can modify our wrapping code as follows:: - - class_("World", init()) - ... - -of course, a C++ class may have additional constructors, and we can -expose those as well by passing more instances of ``init<...>`` to -``def()``:: - - class_("World", init()) - .def(init()) - ... - -Boost.Python allows wrapped functions, member functions, and -constructors to be overloaded to mirror C++ overloading. - -Data Members and Properties -=========================== - -Any publicly-accessible data members in a C++ class can be easily -exposed as either ``readonly`` or ``readwrite`` attributes:: - - class_("World", init()) - .def_readonly("msg", &World::msg) - ... - -and can be used directly in Python: - ->>> planet = hello.World('howdy') ->>> planet.msg -'howdy' - -This does *not* result in adding attributes to the ``World`` instance -``__dict__``, which can result in substantial memory savings when -wrapping large data structures. In fact, no instance ``__dict__`` -will be created at all unless attributes are explicitly added from -Python. BPL owes this capability to the new Python 2.2 type system, -in particular the descriptor interface and ``property`` type. - -In C++, publicly-accessible data members are considered a sign of poor -design because they break encapsulation, and style guides usually -dictate the use of "getter" and "setter" functions instead. In -Python, however, ``__getattr__``, ``__setattr__``, and since 2.2, -``property`` mean that attribute access is just one more -well-encapsulated syntactic tool at the programmer's disposal. BPL -bridges this idiomatic gap by making Python ``property`` creation -directly available to users. So if ``msg`` were private, we could -still expose it as attribute in Python as follows:: - - class_("World", init()) - .add_property("msg", &World::greet, &World::set) - ... - -The example above mirrors the familiar usage of properties in Python -2.2+: - ->>> class World(object): -... __init__(self, msg): -... self.__msg = msg -... def greet(self): -... return self.__msg -... def set(self, msg): -... self.__msg = msg -... msg = property(greet, set) - -Operators and Special Functions -=============================== - -The ability to write arithmetic operators for user-defined types that -C++ and Python both allow the definition of has been a major factor in -the popularity of both languages for scientific computing. The -success of packages like NumPy attests to the power of exposing -operators in extension modules. In this example we'll wrap a class -representing a position in a large file:: - - class FilePos { /*...*/ }; - - // Linear offset - FilePos operator+(FilePos, int); - FilePos operator+(int, FilePos); - FilePos operator-(FilePos, int); - - // Distance between two FilePos objects - int operator-(FilePos, FilePos); - - // Offset with assignment - FilePos& operator+=(FilePos&, int); - FilePos& operator-=(FilePos&, int); - - // Comparison - bool operator<(FilePos, FilePos); - -The wrapping code looks like this:: - - class_("FilePos") - .def(self + int()) // __add__ - .def(int() + self) // __radd__ - .def(self - int()) // __sub__ - - .def(self - self) // __sub__ - - .def(self += int()) // __iadd__ - .def(self -= int()) // __isub__ - - .def(self < self); // __lt__ - ; - -The magic is performed using a simplified application of "expression -templates" [VELD1995]_, a technique originally developed by for -optimization of high-performance matrix algebra expressions. The -essence is that instead of performing the computation immediately, -operators are overloaded to construct a type *representing* the -computation. In matrix algebra, dramatic optimizations are often -available when the structure of an entire expression can be taken into -account, rather than processing each operation "greedily". -Boost.Python uses the same technique to build an appropriate Python -callable object based on an expression involving ``self``, which is -then added to the class. - -Inheritance -=========== - -C++ inheritance relationships can be represented to Boost.Python by adding -an optional ``bases<...>`` argument to the ``class_<...>`` template -parameter list as follows:: - - class_ >("Derived") - ... - -This has two effects: - -1. When the ``class_<...>`` is created, Python type objects - corresponding to ``Base1`` and ``Base2`` are looked up in the BPL - registry, and are used as bases for the new Python ``Derived`` type - object [#mi]_, so methods exposed for the Python ``Base1`` and - ``Base2`` types are automatically members of the ``Derived`` type. - Because the registry is global, this works correctly even if - ``Derived`` is exposed in a different module from either of its - bases. - -2. C++ conversions from ``Derived`` to its bases are added to the - Boost.Python registry. Thus wrapped C++ methods expecting (a - pointer or reference to) an object of either base type can be - called with an object wrapping a ``Derived`` instance. Wrapped - member functions of class ``T`` are treated as though they have an - implicit first argument of ``T&``, so these conversions are - necessary to allow the base class methods to be called for derived - objects. - -Of course it's possible to derive new Python classes from wrapped C++ -class instances. Because Boost.Python uses the new-style class -system, that works very much as for the Python built-in types. There -is one significant detail in which it differs: the built-in types -generally establish their invariants in their ``__new__`` function, so -that derived classes do not need to call ``__init__`` on the base -class before invoking its methods : - ->>> class L(list): -... def __init__(self): -... pass -... ->>> L().reverse() ->>> - -Because C++ object construction is a one-step operation, C++ instance -data cannot be constructed until the arguments are available, in the -``__init__`` function: - ->>> class D(SomeBPLClass): -... def __init__(self): -... pass -... ->>> D().some_bpl_method() -Traceback (most recent call last): - File "", line 1, in ? -TypeError: bad argument type for built-in operation - -This happened because Boost.Python couldn't find instance data of type -``SomeBPLClass`` within the ``D`` instance; ``D``'s ``__init__`` -function masked construction of the base class. It could be corrected -by either removing ``D``'s ``__init__`` function or having it call -``SomeBPLClass.__init__(...)`` explicitly. - -Virtual Functions -================= - -Deriving new types in Python from extension classes is not very -interesting unless they can be used polymorphically from C++. In -other words, Python method implementations should appear to override -the implementation of C++ virtual functions when called *through base -class pointers/references from C++*. Since the only way to alter the -behavior of a virtual function is to override it in a derived class, -the user must build a special derived class to dispatch a polymorphic -class' virtual functions:: - - // - // interface to wrap: - // - class Base - { - public: - virtual int f(std::string x) { return 42; } - virtual ~Base(); - }; - - int calls_f(Base const& b, std::string x) { return b.f(x); } - - // - // Wrapping Code - // - - // Dispatcher class - struct BaseWrap : Base - { - // Store a pointer to the Python object - BaseWrap(PyObject* self_) : self(self_) {} - PyObject* self; - - // Default implementation, for when f is not overridden - int f_default(std::string x) { return this->Base::f(x); } - // Dispatch implementation - int f(std::string x) { return call_method(self, "f", x); } - }; - - ... - def("calls_f", calls_f); - class_("Base") - .def("f", &Base::f, &BaseWrap::f_default) - ; - -Now here's some Python code which demonstrates: - ->>> class Derived(Base): -... def f(self, s): -... return len(s) -... ->>> calls_f(Base(), 'foo') -42 ->>> calls_f(Derived(), 'forty-two') -9 - -Things to notice about the dispatcher class: - -* The key element which allows overriding in Python is the - ``call_method`` invocation, which uses the same global type - conversion registry as the C++ function wrapping does to convert its - arguments from C++ to Python and its return type from Python to C++. - -* Any constructor signatures you wish to wrap must be replicated with - an initial ``PyObject*`` argument - -* The dispatcher must store this argument so that it can be used to - invoke ``call_method`` - -* The ``f_default`` member function is needed when the function being - exposed is not pure virtual; there's no other way ``Base::f`` can be - called on an object of type ``BaseWrap``, since it overrides ``f``. - -Admittedly, this formula is tedious to repeat, especially on a project -with many polymorphic classes; that it is necessary reflects -limitations in C++'s compile-time reflection capabilities. Several -efforts are underway to write front-ends for Boost.Python which can -generate these dispatchers (and other wrapping code) automatically. -If these are successful it will mark a move away from wrapping -everything directly in pure C++ for many of our users. - ---------------- - Serialization ---------------- - -*Serialization* is the process of converting objects in memory to a -form that can be stored on disk or sent over a network connection. The -serialized object (most often a plain string) can be retrieved and -converted back to the original object. A good serialization system will -automatically convert entire object hierarchies. Python's standard -``pickle`` module is such a system. It leverages the language's strong -runtime introspection facilities for serializing practically arbitrary -user-defined objects. With a few simple and unintrusive provisions this -powerful machinery can be extended to also work for wrapped C++ objects. -Here is an example:: - - #include - - struct World - { - World(std::string a_msg) : msg(a_msg) {} - std::string greet() const { return msg; } - std::string msg; - }; - - #include - using namespace boost::python; - - struct World_picklers : pickle_suite - { - static tuple - getinitargs(World const& w) { return make_tuple(w.greet()); } - }; - - BOOST_PYTHON_MODULE(hello) - { - class_("World", init()) - .def("greet", &World::greet) - .def_pickle(World_picklers()) - ; - } - -Now let's create a ``World`` object and put it to rest on disk:: - - >>> import hello - >>> import pickle - >>> a_world = hello.World("howdy") - >>> pickle.dump(a_world, open("my_world", "w")) - -In a potentially *different script* on a potentially *different -computer* with a potentially *different operating system*:: - - >>> import pickle - >>> resurrected_world = pickle.load(open("my_world", "r")) - >>> resurrected_world.greet() - 'howdy' - -Of course the ``cPickle`` module can also be used for faster -processing. - -Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol -defined in the standard Python documentation. There is a one-to-one -correspondence between the standard pickling methods (``__getinitargs__``, -``__getstate__``, ``__setstate__``) and the functions defined by the -user in the class derived from ``pickle_suite`` (``getinitargs``, -``getstate``, ``setstate``). The ``class_::def_pickle()`` member function -is used to establish the Python bindings for all user-defined functions -simultaneously. Correct signatures for these functions are enforced at -compile time. Non-sensical combinations of the three pickle functions -are also rejected at compile time. These measures are designed to -help the user in avoiding obvious errors. - -Enabling serialization of more complex C++ objects requires a little -more work than is shown in the example above. Fortunately the -``object`` interface (see next section) greatly helps in keeping the -code manageable. - ------------------- - Object interface ------------------- - -Experienced extension module authors will be familiar with the 'C' view -of Python objects, the ubiquitous ``PyObject*``. Most if not all Python -'C' API functions involve ``PyObject*`` as arguments or return type. A -major complication is the raw reference counting interface presented to -the 'C' programmer. E.g. some API functions return *new references* and -others return *borrowed references*. It is up to the extension module -writer to properly increment and decrement reference counts. This -quickly becomes cumbersome and error prone, especially if there are -multiple execution paths. - -Boost.Python provides a type ``object`` which is essentially a high -level wrapper around ``PyObject*``. ``object`` automates reference -counting as much as possible. It also provides the facilities for -converting arbitrary C++ types to Python objects and vice versa. -This significantly reduces the learning effort for prospective -extension module writers. - -Creating an ``object`` from any other type is extremely simple:: - - object o(3); - -``object`` has templated interactions with all other types, with -automatic to-python conversions. It happens so naturally that it's -easily overlooked. - -The ``extract`` class template can be used to convert Python objects -to C++ types:: - - double x = extract(o); - -All registered user-defined conversions are automatically accessible -through the ``object`` interface. With reference to the ``World`` class -defined in previous examples:: - - object as_python_object(World("howdy")); - World back_as_c_plus_plus_object = extract(as_python_object); - -If a C++ type cannot be converted to a Python object an appropriate -exception is thrown at runtime. Similarly, an appropriate exception is -thrown if a C++ type cannot be extracted from a Python object. -``extract`` provides facilities for avoiding exceptions if this is -desired. - -The ``object::attr()`` member function is available for accessing -and manipulating attributes of Python objects. For example:: - - object planet(World()); - planet.attr("set")("howdy"); - -``planet.attr("set")`` returns a callable ``object``. ``"howdy"`` is -converted to a Python string object which is then passed as an argument -to the ``set`` method. - -The ``object`` type is accompanied by a set of derived types -that mirror the Python built-in types such as ``list``, ``dict``, -``tuple``, etc. as much as possible. This enables convenient -manipulation of these high-level types from C++:: - - dict d; - d["some"] = "thing"; - d["lucky_number"] = 13; - list l = d.keys(); - -This almost looks and works like regular Python code, but it is pure C++. - -================= - Thinking hybrid -================= - -For many applications runtime performance considerations are very -important. This is particularly true for most scientific applications. -Often the performance considerations dictate the use of a compiled -language for the core algorithms. Traditionally the decision to use a -particular programming language is an exclusive one. Because of the -practical and mental difficulties of combining different languages many -systems are written in just one language. This is quite unfortunate -because the price payed for runtime performance is typically a -significant overhead due to static typing. For example, our experience -shows that developing maintainable C++ code is typically much more -time-consuming and requires much more hard-earned working experience -than developing useful Python code. A related observation is that many -compiled packages are augmented by some type of rudimentary scripting -layer. These ad hoc solutions clearly show that many times a compiled -language alone does not get the job done. On the other hand it is also -clear that a pure Python implementation is too slow for numerically -intensive production code. - -Boost.Python enables us to *think hybrid* when developing new -applications. Python can be used for rapidly prototyping a -new application. Python's ease of use and the large pool of standard -libraries give us a head start on the way to a first working system. If -necessary, the working procedure can be used to discover the -rate-limiting algorithms. To maximize performance these can be -reimplemented in C++, together with the Boost.Python bindings needed to -tie them back into the existing higher-level procedure. - -Of course, this *top-down* approach is less attractive if it is clear -from the start that many algorithms will eventually have to be -implemented in a compiled language. Fortunately Boost.Python also -enables us to pursue a *bottom-up* approach. We have used this approach -very successfully in the development of a toolbox for scientific -applications (scitbx) that we will describe elsewhere. The toolbox -started out mainly as a library of C++ classes with Boost.Python -bindings, and for a while the growth was mainly concentrated on the C++ -parts. However, as the toolbox is becoming more complete, more and more -newly added functionality can be implemented in Python. We expect this -trend to continue, as illustrated qualitatively in this figure: - -.. image:: python_cpp_mix.png - -This figure shows the ratio of newly added C++ and Python code over -time as new algorithms are implemented. We expect this ratio to level -out near 70% Python. The increasing ability to solve new problems -mostly with the easy-to-use Python language rather than a necessarily -more arcane statically typed language is the return on the investment -of learning how to use Boost.Python. The ability to solve some problems -entirely using only Python will enable a larger group of people to -participate in the rapid development of new applications. - -============= - Conclusions -============= - -The examples in this paper illustrate that Boost.Python enables -seamless interoperability between C++ and Python. Importantly, this is -achieved without introducing a third syntax: the Python/C++ interface -definitions are written in pure C++. This avoids any problems with -parsing the C++ code to be interfaced to Python, yet the interface -definitions are concise and maintainable. Freed from most of the -development-time penalties of crossing a language boundary, software -designers can take full advantage of two rich and complimentary -language environments. In practice it turns out that some things are -very difficult to do with pure Python/C (e.g. an efficient array -library with an intuitive interface in the compiled language) and -others are very difficult to do with pure C++ (e.g. serialization). -If one has the luxury of being able to design a software system as a -hybrid system from the ground up there are many new ways of avoiding -road blocks in one language or the other. - -.. I'm not ready to give up on all of this quite yet - -.. Perhaps one day we'll have a language with the simplicity and - expressive power of Python and the compile-time muscle of C++. Being - able to take advantage of all of these facilities without paying the - mental and development-time penalties of crossing a language barrier - would bring enormous benefits. Until then, interoperability tools - like Boost.Python can help lower the barrier and make the benefits of - both languages more accessible to both communities. - -=========== - Footnotes -=========== - -.. [#mi] For hard-core new-style class/extension module writers it is - worth noting that the normal requirement that all extension classes - with data form a layout-compatible single-inheritance chain is - lifted for Boost.Python extension classes. Clearly, either - ``Base1`` or ``Base2`` has to occupy a different offset in the - ``Derived`` class instance. This is possible because the wrapped - part of BPL extension class instances is never assumed to have a - fixed offset within the wrapper. - -=========== - Citations -=========== - -.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report, - Vol. 7 No. 5 June 1995, pp. 26-31. - http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html diff --git a/doc/PyConDC_2003/default.css b/doc/PyConDC_2003/default.css deleted file mode 100644 index f8109bbd33..0000000000 --- a/doc/PyConDC_2003/default.css +++ /dev/null @@ -1,188 +0,0 @@ -/* -:Author: David Goodger -:Contact: goodger@users.sourceforge.net -:copyright: This stylesheet has been placed in the public domain. - -boostinspect:nolicense - -Default cascading style sheet for the HTML output of Docutils. -*/ - -.first { - margin-top: 0 } - -.last { - margin-bottom: 0 } - -a.toc-backref { - text-decoration: none ; - color: black } - -dd { - margin-bottom: 0.5em } - -div.abstract { - margin: 2em 5em } - -div.abstract p.topic-title { - font-weight: bold ; - text-align: center } - -div.attention, div.caution, div.danger, div.error, div.hint, -div.important, div.note, div.tip, div.warning { - margin: 2em ; - border: medium outset ; - padding: 1em } - -div.attention p.admonition-title, div.caution p.admonition-title, -div.danger p.admonition-title, div.error p.admonition-title, -div.warning p.admonition-title { - color: red ; - font-weight: bold ; - font-family: sans-serif } - -div.hint p.admonition-title, div.important p.admonition-title, -div.note p.admonition-title, div.tip p.admonition-title { - font-weight: bold ; - font-family: sans-serif } - -div.dedication { - margin: 2em 5em ; - text-align: center ; - font-style: italic } - -div.dedication p.topic-title { - font-weight: bold ; - font-style: normal } - -div.figure { - margin-left: 2em } - -div.footer, div.header { - font-size: smaller } - -div.system-messages { - margin: 5em } - -div.system-messages h1 { - color: red } - -div.system-message { - border: medium outset ; - padding: 1em } - -div.system-message p.system-message-title { - color: red ; - font-weight: bold } - -div.topic { - margin: 2em } - -h1.title { - text-align: center } - -h2.subtitle { - text-align: center } - -hr { - width: 75% } - -ol.simple, ul.simple { - margin-bottom: 1em } - -ol.arabic { - list-style: decimal } - -ol.loweralpha { - list-style: lower-alpha } - -ol.upperalpha { - list-style: upper-alpha } - -ol.lowerroman { - list-style: lower-roman } - -ol.upperroman { - list-style: upper-roman } - -p.caption { - font-style: italic } - -p.credits { - font-style: italic ; - font-size: smaller } - -p.label { - white-space: nowrap } - -p.topic-title { - font-weight: bold } - -pre.address { - margin-bottom: 0 ; - margin-top: 0 ; - font-family: serif ; - font-size: 100% } - -pre.line-block { - font-family: serif ; - font-size: 100% } - -pre.literal-block, pre.doctest-block { - margin-left: 2em ; - margin-right: 2em ; - background-color: #eeeeee } - -span.classifier { - font-family: sans-serif ; - font-style: oblique } - -span.classifier-delimiter { - font-family: sans-serif ; - font-weight: bold } - -span.interpreted { - font-family: sans-serif } - -span.option-argument { - font-style: italic } - -span.pre { - white-space: pre } - -span.problematic { - color: red } - -table { - margin-top: 0.5em ; - margin-bottom: 0.5em } - -table.citation { - border-left: solid thin gray ; - padding-left: 0.5ex } - -table.docinfo { - margin: 2em 4em } - -table.footnote { - border-left: solid thin black ; - padding-left: 0.5ex } - -td, th { - padding-left: 0.5em ; - padding-right: 0.5em ; - vertical-align: top } - -th.docinfo-name, th.field-name { - font-weight: bold ; - text-align: left ; - white-space: nowrap } - -h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { - font-size: 100% } - -tt { - background-color: #eeeeee } - -ul.auto-toc { - list-style-type: none } diff --git a/doc/PyConDC_2003/python_cpp_mix.jpg b/doc/PyConDC_2003/python_cpp_mix.jpg deleted file mode 100755 index 755a9605b8..0000000000 Binary files a/doc/PyConDC_2003/python_cpp_mix.jpg and /dev/null differ diff --git a/doc/article.rst b/doc/article.rst new file mode 100644 index 0000000000..521f04f4f4 --- /dev/null +++ b/doc/article.rst @@ -0,0 +1,947 @@ ++++++++++++++++++++++++++++++++++++++++++++ + Building Hybrid Systems with Boost.Python ++++++++++++++++++++++++++++++++++++++++++++ + +:Author: David Abrahams +:Contact: dave@boost-consulting.com +:organization: `Boost Consulting`_ +:date: 2003-05-14 + +:Author: Ralf W. Grosse-Kunstleve + +:copyright: Copyright David Abrahams and Ralf W. Grosse-Kunstleve 2003. All rights reserved + +.. contents:: Table of Contents + +.. _`Boost Consulting`: http://www.boost-consulting.com + +========== + Abstract +========== + +Boost.Python is an open source C++ library which provides a concise +IDL-like interface for binding C++ classes and functions to +Python. Leveraging the full power of C++ compile-time introspection +and of recently developed metaprogramming techniques, this is achieved +entirely in pure C++, without introducing a new syntax. +Boost.Python's rich set of features and high-level interface make it +possible to engineer packages from the ground up as hybrid systems, +giving programmers easy and coherent access to both the efficient +compile-time polymorphism of C++ and the extremely convenient run-time +polymorphism of Python. + +============== + Introduction +============== + +Python and C++ are in many ways as different as two languages could +be: while C++ is usually compiled to machine-code, Python is +interpreted. Python's dynamic type system is often cited as the +foundation of its flexibility, while in C++ static typing is the +cornerstone of its efficiency. C++ has an intricate and difficult +compile-time meta-language, while in Python, practically everything +happens at runtime. + +Yet for many programmers, these very differences mean that Python and +C++ complement one another perfectly. Performance bottlenecks in +Python programs can be rewritten in C++ for maximal speed, and +authors of powerful C++ libraries choose Python as a middleware +language for its flexible system integration capabilities. +Furthermore, the surface differences mask some strong similarities: + +* 'C'-family control structures (if, while, for...) + +* Support for object-orientation, functional programming, and generic + programming (these are both *multi-paradigm* programming languages.) + +* Comprehensive operator overloading facilities, recognizing the + importance of syntactic variability for readability and + expressivity. + +* High-level concepts such as collections and iterators. + +* High-level encapsulation facilities (C++: namespaces, Python: modules) + to support the design of re-usable libraries. + +* Exception-handling for effective management of error conditions. + +* C++ idioms in common use, such as handle/body classes and + reference-counted smart pointers mirror Python reference semantics. + +Given Python's rich 'C' interoperability API, it should in principle +be possible to expose C++ type and function interfaces to Python with +an analogous interface to their C++ counterparts. However, the +facilities provided by Python alone for integration with C++ are +relatively meager. Compared to C++ and Python, 'C' has only very +rudimentary abstraction facilities, and support for exception-handling +is completely missing. 'C' extension module writers are required to +manually manage Python reference counts, which is both annoyingly +tedious and extremely error-prone. Traditional extension modules also +tend to contain a great deal of boilerplate code repetition which +makes them difficult to maintain, especially when wrapping an evolving +API. + +These limitations have lead to the development of a variety of wrapping +systems. SWIG_ is probably the most popular package for the +integration of C/C++ and Python. A more recent development is SIP_, +which was specifically designed for interfacing Python with the Qt_ +graphical user interface library. Both SWIG and SIP introduce their +own specialized languages for customizing inter-language bindings. +This has certain advantages, but having to deal with three different +languages (Python, C/C++ and the interface language) also introduces +practical and mental difficulties. The CXX_ package demonstrates an +interesting alternative. It shows that at least some parts of +Python's 'C' API can be wrapped and presented through a much more +user-friendly C++ interface. However, unlike SWIG and SIP, CXX does +not include support for wrapping C++ classes as new Python types. + +The features and goals of Boost.Python_ overlap significantly with +many of these other systems. That said, Boost.Python attempts to +maximize convenience and flexibility without introducing a separate +wrapping language. Instead, it presents the user with a high-level +C++ interface for wrapping C++ classes and functions, managing much of +the complexity behind-the-scenes with static metaprogramming. +Boost.Python also goes beyond the scope of earlier systems by +providing: + +* Support for C++ virtual functions that can be overridden in Python. + +* Comprehensive lifetime management facilities for low-level C++ + pointers and references. + +* Support for organizing extensions as Python packages, + with a central registry for inter-language type conversions. + +* A safe and convenient mechanism for tying into Python's powerful + serialization engine (pickle). + +* Coherence with the rules for handling C++ lvalues and rvalues that + can only come from a deep understanding of both the Python and C++ + type systems. + +The key insight that sparked the development of Boost.Python is that +much of the boilerplate code in traditional extension modules could be +eliminated using C++ compile-time introspection. Each argument of a +wrapped C++ function must be extracted from a Python object using a +procedure that depends on the argument type. Similarly the function's +return type determines how the return value will be converted from C++ +to Python. Of course argument and return types are part of each +function's type, and this is exactly the source from which +Boost.Python deduces most of the information required. + +This approach leads to *user guided wrapping*: as much information is +extracted directly from the source code to be wrapped as is possible +within the framework of pure C++, and some additional information is +supplied explicitly by the user. Mostly the guidance is mechanical +and little real intervention is required. Because the interface +specification is written in the same full-featured language as the +code being exposed, the user has unprecedented power available when +she does need to take control. + +.. _Python: http://www.python.org/ +.. _SWIG: http://www.swig.org/ +.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php +.. _Qt: http://www.trolltech.com/ +.. _CXX: http://cxx.sourceforge.net/ +.. _Boost.Python: http://www.boost.org/libs/python/doc + +=========================== + Boost.Python Design Goals +=========================== + +The primary goal of Boost.Python is to allow users to expose C++ +classes and functions to Python using nothing more than a C++ +compiler. In broad strokes, the user experience should be one of +directly manipulating C++ objects from Python. + +However, it's also important not to translate all interfaces *too* +literally: the idioms of each language must be respected. For +example, though C++ and Python both have an iterator concept, they are +expressed very differently. Boost.Python has to be able to bridge the +interface gap. + +It must be possible to insulate Python users from crashes resulting +from trivial misuses of C++ interfaces, such as accessing +already-deleted objects. By the same token the library should +insulate C++ users from low-level Python 'C' API, replacing +error-prone 'C' interfaces like manual reference-count management and +raw ``PyObject`` pointers with more-robust alternatives. + +Support for component-based development is crucial, so that C++ types +exposed in one extension module can be passed to functions exposed in +another without loss of crucial information like C++ inheritance +relationships. + +Finally, all wrapping must be *non-intrusive*, without modifying or +even seeing the original C++ source code. Existing C++ libraries have +to be wrappable by third parties who only have access to header files +and binaries. + +========================== + Hello Boost.Python World +========================== + +And now for a preview of Boost.Python, and how it improves on the raw +facilities offered by Python. Here's a function we might want to +expose:: + + char const* greet(unsigned x) + { + static char const* const msgs[] = { "hello", "Boost.Python", "world!" }; + + if (x > 2) + throw std::range_error("greet: index out of range"); + + return msgs[x]; + } + +To wrap this function in standard C++ using the Python 'C' API, we'd +need something like this:: + + extern "C" // all Python interactions use 'C' linkage and calling convention + { + // Wrapper to handle argument/result conversion and checking + PyObject* greet_wrap(PyObject* args, PyObject * keywords) + { + int x; + if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments + { + char const* result = greet(x); // invoke wrapped function + return PyString_FromString(result); // convert result to Python + } + return 0; // error occurred + } + + // Table of wrapped functions to be exposed by the module + static PyMethodDef methods[] = { + { "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" } + , { NULL, NULL, 0, NULL } // sentinel + }; + + // module initialization function + DL_EXPORT init_hello() + { + (void) Py_InitModule("hello", methods); // add the methods to the module + } + } + +Now here's the wrapping code we'd use to expose it with Boost.Python:: + + #include + using namespace boost::python; + BOOST_PYTHON_MODULE(hello) + { + def("greet", greet, "return one of 3 parts of a greeting"); + } + +and here it is in action:: + + >>> import hello + >>> for x in range(3): + ... print hello.greet(x) + ... + hello + Boost.Python + world! + +Aside from the fact that the 'C' API version is much more verbose, +it's worth noting a few things that it doesn't handle correctly: + +* The original function accepts an unsigned integer, and the Python + 'C' API only gives us a way of extracting signed integers. The + Boost.Python version will raise a Python exception if we try to pass + a negative number to ``hello.greet``, but the other one will proceed + to do whatever the C++ implementation does when converting an + negative integer to unsigned (usually wrapping to some very large + number), and pass the incorrect translation on to the wrapped + function. + +* That brings us to the second problem: if the C++ ``greet()`` + function is called with a number greater than 2, it will throw an + exception. Typically, if a C++ exception propagates across the + boundary with code generated by a 'C' compiler, it will cause a + crash. As you can see in the first version, there's no C++ + scaffolding there to prevent this from happening. Functions wrapped + by Boost.Python automatically include an exception-handling layer + which protects Python users by translating unhandled C++ exceptions + into a corresponding Python exception. + +* A slightly more-subtle limitation is that the argument conversion + used in the Python 'C' API case can only get that integer ``x`` in + *one way*. PyArg_ParseTuple can't convert Python ``long`` objects + (arbitrary-precision integers) which happen to fit in an ``unsigned + int`` but not in a ``signed long``, nor will it ever handle a + wrapped C++ class with a user-defined implicit ``operator unsigned + int()`` conversion. Boost.Python's dynamic type conversion + registry allows users to add arbitrary conversion methods. + +================== + Library Overview +================== + +This section outlines some of the library's major features. Except as +neccessary to avoid confusion, details of library implementation are +omitted. + +------------------ + Exposing Classes +------------------ + +C++ classes and structs are exposed with a similarly-terse interface. +Given:: + + struct World + { + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +The following code will expose it in our extension module:: + + #include + BOOST_PYTHON_MODULE(hello) + { + class_("World") + .def("greet", &World::greet) + .def("set", &World::set) + ; + } + +Although this code has a certain pythonic familiarity, people +sometimes find the syntax bit confusing because it doesn't look like +most of the C++ code they're used to. All the same, this is just +standard C++. Because of their flexible syntax and operator +overloading, C++ and Python are great for defining domain-specific +(sub)languages +(DSLs), and that's what we've done in Boost.Python. To break it down:: + + class_("World") + +constructs an unnamed object of type ``class_`` and passes +``"World"`` to its constructor. This creates a new-style Python class +called ``World`` in the extension module, and associates it with the +C++ type ``World`` in the Boost.Python type conversion registry. We +might have also written:: + + class_ w("World"); + +but that would've been more verbose, since we'd have to name ``w`` +again to invoke its ``def()`` member function:: + + w.def("greet", &World::greet) + +There's nothing special about the location of the dot for member +access in the original example: C++ allows any amount of whitespace on +either side of a token, and placing the dot at the beginning of each +line allows us to chain as many successive calls to member functions +as we like with a uniform syntax. The other key fact that allows +chaining is that ``class_<>`` member functions all return a reference +to ``*this``. + +So the example is equivalent to:: + + class_ w("World"); + w.def("greet", &World::greet); + w.def("set", &World::set); + +It's occasionally useful to be able to break down the components of a +Boost.Python class wrapper in this way, but the rest of this article +will stick to the terse syntax. + +For completeness, here's the wrapped class in use: :: + + >>> import hello + >>> planet = hello.World() + >>> planet.set('howdy') + >>> planet.greet() + 'howdy' + +Constructors +============ + +Since our ``World`` class is just a plain ``struct``, it has an +implicit no-argument (nullary) constructor. Boost.Python exposes the +nullary constructor by default, which is why we were able to write: :: + + >>> planet = hello.World() + +However, well-designed classes in any language may require constructor +arguments in order to establish their invariants. Unlike Python, +where ``__init__`` is just a specially-named method, In C++ +constructors cannot be handled like ordinary member functions. In +particular, we can't take their address: ``&World::World`` is an +error. The library provides a different interface for specifying +constructors. Given:: + + struct World + { + World(std::string msg); // added constructor + ... + +we can modify our wrapping code as follows:: + + class_("World", init()) + ... + +of course, a C++ class may have additional constructors, and we can +expose those as well by passing more instances of ``init<...>`` to +``def()``:: + + class_("World", init()) + .def(init()) + ... + +Boost.Python allows wrapped functions, member functions, and +constructors to be overloaded to mirror C++ overloading. + +Data Members and Properties +=========================== + +Any publicly-accessible data members in a C++ class can be easily +exposed as either ``readonly`` or ``readwrite`` attributes:: + + class_("World", init()) + .def_readonly("msg", &World::msg) + ... + +and can be used directly in Python: :: + + >>> planet = hello.World('howdy') + >>> planet.msg + 'howdy' + +This does *not* result in adding attributes to the ``World`` instance +``__dict__``, which can result in substantial memory savings when +wrapping large data structures. In fact, no instance ``__dict__`` +will be created at all unless attributes are explicitly added from +Python. Boost.Python owes this capability to the new Python 2.2 type +system, in particular the descriptor interface and ``property`` type. + +In C++, publicly-accessible data members are considered a sign of poor +design because they break encapsulation, and style guides usually +dictate the use of "getter" and "setter" functions instead. In +Python, however, ``__getattr__``, ``__setattr__``, and since 2.2, +``property`` mean that attribute access is just one more +well-encapsulated syntactic tool at the programmer's disposal. +Boost.Python bridges this idiomatic gap by making Python ``property`` +creation directly available to users. If ``msg`` were private, we +could still expose it as attribute in Python as follows:: + + class_("World", init()) + .add_property("msg", &World::greet, &World::set) + ... + +The example above mirrors the familiar usage of properties in Python +2.2+: :: + + >>> class World(object): + ... __init__(self, msg): + ... self.__msg = msg + ... def greet(self): + ... return self.__msg + ... def set(self, msg): + ... self.__msg = msg + ... msg = property(greet, set) + +Operator Overloading +==================== + +The ability to write arithmetic operators for user-defined types has +been a major factor in the success of both languages for numerical +computation, and the success of packages like NumPy_ attests to the +power of exposing operators in extension modules. Boost.Python +provides a concise mechanism for wrapping operator overloads. The +example below shows a fragment from a wrapper for the Boost rational +number library:: + + class_ >("rational_int") + .def(init()) // constructor, e.g. rational_int(3,4) + .def("numerator", &rational::numerator) + .def("denominator", &rational::denominator) + .def(-self) // __neg__ (unary minus) + .def(self + self) // __add__ (homogeneous) + .def(self * self) // __mul__ + .def(self + int()) // __add__ (heterogenous) + .def(int() + self) // __radd__ + ... + +The magic is performed using a simplified application of "expression +templates" [VELD1995]_, a technique originally developed for +optimization of high-performance matrix algebra expressions. The +essence is that instead of performing the computation immediately, +operators are overloaded to construct a type *representing* the +computation. In matrix algebra, dramatic optimizations are often +available when the structure of an entire expression can be taken into +account, rather than evaluating each operation "greedily". +Boost.Python uses the same technique to build an appropriate Python +method object based on expressions involving ``self``. + +.. _NumPy: http://www.pfdubois.com/numpy/ + +Inheritance +=========== + +C++ inheritance relationships can be represented to Boost.Python by adding +an optional ``bases<...>`` argument to the ``class_<...>`` template +parameter list as follows:: + + class_ >("Derived") + ... + +This has two effects: + +1. When the ``class_<...>`` is created, Python type objects + corresponding to ``Base1`` and ``Base2`` are looked up in + Boost.Python's registry, and are used as bases for the new Python + ``Derived`` type object, so methods exposed for the Python ``Base1`` + and ``Base2`` types are automatically members of the ``Derived`` + type. Because the registry is global, this works correctly even if + ``Derived`` is exposed in a different module from either of its + bases. + +2. C++ conversions from ``Derived`` to its bases are added to the + Boost.Python registry. Thus wrapped C++ methods expecting (a + pointer or reference to) an object of either base type can be + called with an object wrapping a ``Derived`` instance. Wrapped + member functions of class ``T`` are treated as though they have an + implicit first argument of ``T&``, so these conversions are + neccessary to allow the base class methods to be called for derived + objects. + +Of course it's possible to derive new Python classes from wrapped C++ +class instances. Because Boost.Python uses the new-style class +system, that works very much as for the Python built-in types. There +is one significant detail in which it differs: the built-in types +generally establish their invariants in their ``__new__`` function, so +that derived classes do not need to call ``__init__`` on the base +class before invoking its methods : :: + + >>> class L(list): + ... def __init__(self): + ... pass + ... + >>> L().reverse() + >>> + +Because C++ object construction is a one-step operation, C++ instance +data cannot be constructed until the arguments are available, in the +``__init__`` function: :: + + >>> class D(SomeBoostPythonClass): + ... def __init__(self): + ... pass + ... + >>> D().some_boost_python_method() + Traceback (most recent call last): + File "", line 1, in ? + TypeError: bad argument type for built-in operation + +This happened because Boost.Python couldn't find instance data of type +``SomeBoostPythonClass`` within the ``D`` instance; ``D``'s ``__init__`` +function masked construction of the base class. It could be corrected +by either removing ``D``'s ``__init__`` function or having it call +``SomeBoostPythonClass.__init__(...)`` explicitly. + +Virtual Functions +================= + +Deriving new types in Python from extension classes is not very +interesting unless they can be used polymorphically from C++. In +other words, Python method implementations should appear to override +the implementation of C++ virtual functions when called *through base +class pointers/references from C++*. Since the only way to alter the +behavior of a virtual function is to override it in a derived class, +the user must build a special derived class to dispatch a polymorphic +class' virtual functions:: + + // + // interface to wrap: + // + class Base + { + public: + virtual int f(std::string x) { return 42; } + virtual ~Base(); + }; + + int calls_f(Base const& b, std::string x) { return b.f(x); } + + // + // Wrapping Code + // + + // Dispatcher class + struct BaseWrap : Base + { + // Store a pointer to the Python object + BaseWrap(PyObject* self_) : self(self_) {} + PyObject* self; + + // Default implementation, for when f is not overridden + int f_default(std::string x) { return this->Base::f(x); } + // Dispatch implementation + int f(std::string x) { return call_method(self, "f", x); } + }; + + ... + def("calls_f", calls_f); + class_("Base") + .def("f", &Base::f, &BaseWrap::f_default) + ; + +Now here's some Python code which demonstrates: :: + + >>> class Derived(Base): + ... def f(self, s): + ... return len(s) + ... + >>> calls_f(Base(), 'foo') + 42 + >>> calls_f(Derived(), 'forty-two') + 9 + +Things to notice about the dispatcher class: + +* The key element which allows overriding in Python is the + ``call_method`` invocation, which uses the same global type + conversion registry as the C++ function wrapping does to convert its + arguments from C++ to Python and its return type from Python to C++. + +* Any constructor signatures you wish to wrap must be replicated with + an initial ``PyObject*`` argument + +* The dispatcher must store this argument so that it can be used to + invoke ``call_method`` + +* The ``f_default`` member function is needed when the function being + exposed is not pure virtual; there's no other way ``Base::f`` can be + called on an object of type ``BaseWrap``, since it overrides ``f``. + +Deeper Reflection on the Horizon? +================================= + +Admittedly, this formula is tedious to repeat, especially on a project +with many polymorphic classes. That it is neccessary reflects some +limitations in C++'s compile-time introspection capabilities: there's +no way to enumerate the members of a class and find out which are +virtual functions. At least one very promising project has been +started to write a front-end which can generate these dispatchers (and +other wrapping code) automatically from C++ headers. + +Pyste_ is being developed by Bruno da Silva de Oliveira. It builds on +GCC_XML_, which generates an XML version of GCC's internal program +representation. Since GCC is a highly-conformant C++ compiler, this +ensures correct handling of the most-sophisticated template code and +full access to the underlying type system. In keeping with the +Boost.Python philosophy, a Pyste interface description is neither +intrusive on the code being wrapped, nor expressed in some unfamiliar +language: instead it is a 100% pure Python script. If Pyste is +successful it will mark a move away from wrapping everything directly +in C++ for many of our users. It will also allow us the choice to +shift some of the metaprogram code from C++ to Python. We expect that +soon, not only our users but the Boost.Python developers themselves +will be "thinking hybrid" about their own code. + +.. _`GCC_XML`: http://www.gccxml.org/HTML/Index.html +.. _`Pyste`: http://www.boost.org/libs/python/pyste + +--------------- + Serialization +--------------- + +*Serialization* is the process of converting objects in memory to a +form that can be stored on disk or sent over a network connection. The +serialized object (most often a plain string) can be retrieved and +converted back to the original object. A good serialization system will +automatically convert entire object hierarchies. Python's standard +``pickle`` module is just such a system. It leverages the language's strong +runtime introspection facilities for serializing practically arbitrary +user-defined objects. With a few simple and unintrusive provisions this +powerful machinery can be extended to also work for wrapped C++ objects. +Here is an example:: + + #include + + struct World + { + World(std::string a_msg) : msg(a_msg) {} + std::string greet() const { return msg; } + std::string msg; + }; + + #include + using namespace boost::python; + + struct World_picklers : pickle_suite + { + static tuple + getinitargs(World const& w) { return make_tuple(w.greet()); } + }; + + BOOST_PYTHON_MODULE(hello) + { + class_("World", init()) + .def("greet", &World::greet) + .def_pickle(World_picklers()) + ; + } + +Now let's create a ``World`` object and put it to rest on disk:: + + >>> import hello + >>> import pickle + >>> a_world = hello.World("howdy") + >>> pickle.dump(a_world, open("my_world", "w")) + +In a potentially *different script* on a potentially *different +computer* with a potentially *different operating system*:: + + >>> import pickle + >>> resurrected_world = pickle.load(open("my_world", "r")) + >>> resurrected_world.greet() + 'howdy' + +Of course the ``cPickle`` module can also be used for faster +processing. + +Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol +defined in the standard Python documentation. Like a __getinitargs__ +function in Python, the pickle_suite's getinitargs() is responsible for +creating the argument tuple that will be use to reconstruct the pickled +object. The other elements of the Python pickling protocol, +__getstate__ and __setstate__ can be optionally provided via C++ +getstate and setstate functions. C++'s static type system allows the +library to ensure at compile-time that nonsensical combinations of +functions (e.g. getstate without setstate) are not used. + +Enabling serialization of more complex C++ objects requires a little +more work than is shown in the example above. Fortunately the +``object`` interface (see next section) greatly helps in keeping the +code manageable. + +------------------ + Object interface +------------------ + +Experienced 'C' language extension module authors will be familiar +with the ubiquitous ``PyObject*``, manual reference-counting, and the +need to remember which API calls return "new" (owned) references or +"borrowed" (raw) references. These constraints are not just +cumbersome but also a major source of errors, especially in the +presence of exceptions. + +Boost.Python provides a class ``object`` which automates reference +counting and provides conversion to Python from C++ objects of +arbitrary type. This significantly reduces the learning effort for +prospective extension module writers. + +Creating an ``object`` from any other type is extremely simple:: + + object s("hello, world"); // s manages a Python string + +``object`` has templated interactions with all other types, with +automatic to-python conversions. It happens so naturally that it's +easily overlooked:: + + object ten_Os = 10 * s[4]; // -> "oooooooooo" + +In the example above, ``4`` and ``10`` are converted to Python objects +before the indexing and multiplication operations are invoked. + +The ``extract`` class template can be used to convert Python objects +to C++ types:: + + double x = extract(o); + +If a conversion in either direction cannot be performed, an +appropriate exception is thrown at runtime. + +The ``object`` type is accompanied by a set of derived types +that mirror the Python built-in types such as ``list``, ``dict``, +``tuple``, etc. as much as possible. This enables convenient +manipulation of these high-level types from C++:: + + dict d; + d["some"] = "thing"; + d["lucky_number"] = 13; + list l = d.keys(); + +This almost looks and works like regular Python code, but it is pure +C++. Of course we can wrap C++ functions which accept or return +``object`` instances. + +================= + Thinking hybrid +================= + +Because of the practical and mental difficulties of combining +programming languages, it is common to settle a single language at the +outset of any development effort. For many applications, performance +considerations dictate the use of a compiled language for the core +algorithms. Unfortunately, due to the complexity of the static type +system, the price we pay for runtime performance is often a +significant increase in development time. Experience shows that +writing maintainable C++ code usually takes longer and requires *far* +more hard-earned working experience than developing comparable Python +code. Even when developers are comfortable working exclusively in +compiled languages, they often augment their systems by some type of +ad hoc scripting layer for the benefit of their users without ever +availing themselves of the same advantages. + +Boost.Python enables us to *think hybrid*. Python can be used for +rapidly prototyping a new application; its ease of use and the large +pool of standard libraries give us a head start on the way to a +working system. If necessary, the working code can be used to +discover rate-limiting hotspots. To maximize performance these can +be reimplemented in C++, together with the Boost.Python bindings +needed to tie them back into the existing higher-level procedure. + +Of course, this *top-down* approach is less attractive if it is clear +from the start that many algorithms will eventually have to be +implemented in C++. Fortunately Boost.Python also enables us to +pursue a *bottom-up* approach. We have used this approach very +successfully in the development of a toolbox for scientific +applications. The toolbox started out mainly as a library of C++ +classes with Boost.Python bindings, and for a while the growth was +mainly concentrated on the C++ parts. However, as the toolbox is +becoming more complete, more and more newly added functionality can be +implemented in Python. + +.. image:: images/python_cpp_mix.png + +This figure shows the estimated ratio of newly added C++ and Python +code over time as new algorithms are implemented. We expect this +ratio to level out near 70% Python. Being able to solve new problems +mostly in Python rather than a more difficult statically typed +language is the return on our investment in Boost.Python. The ability +to access all of our code from Python allows a broader group of +developers to use it in the rapid development of new applications. + +===================== + Development history +===================== + +The first version of Boost.Python was developed in 2000 by Dave +Abrahams at Dragon Systems, where he was privileged to have Tim Peters +as a guide to "The Zen of Python". One of Dave's jobs was to develop +a Python-based natural language processing system. Since it was +eventually going to be targeting embedded hardware, it was always +assumed that the compute-intensive core would be rewritten in C++ to +optimize speed and memory footprint [#proto]_. The project also wanted to +test all of its C++ code using Python test scripts [#test]_. The only +tool we knew of for binding C++ and Python was SWIG_, and at the time +its handling of C++ was weak. It would be false to claim any deep +insight into the possible advantages of Boost.Python's approach at +this point. Dave's interest and expertise in fancy C++ template +tricks had just reached the point where he could do some real damage, +and Boost.Python emerged as it did because it filled a need and +because it seemed like a cool thing to try. + +This early version was aimed at many of the same basic goals we've +described in this paper, differing most-noticeably by having a +slightly more cumbersome syntax and by lack of special support for +operator overloading, pickling, and component-based development. +These last three features were quickly added by Ullrich Koethe and +Ralf Grosse-Kunstleve [#feature]_, and other enthusiastic contributors arrived +on the scene to contribute enhancements like support for nested +modules and static member functions. + +By early 2001 development had stabilized and few new features were +being added, however a disturbing new fact came to light: Ralf had +begun testing Boost.Python on pre-release versions of a compiler using +the EDG_ front-end, and the mechanism at the core of Boost.Python +responsible for handling conversions between Python and C++ types was +failing to compile. As it turned out, we had been exploiting a very +common bug in the implementation of all the C++ compilers we had +tested. We knew that as C++ compilers rapidly became more +standards-compliant, the library would begin failing on more +platforms. Unfortunately, because the mechanism was so central to the +functioning of the library, fixing the problem looked very difficult. + +Fortunately, later that year Lawrence Berkeley and later Lawrence +Livermore National labs contracted with `Boost Consulting`_ for support +and development of Boost.Python, and there was a new opportunity to +address fundamental issues and ensure a future for the library. A +redesign effort began with the low level type conversion architecture, +building in standards-compliance and support for component-based +development (in contrast to version 1 where conversions had to be +explicitly imported and exported across module boundaries). A new +analysis of the relationship between the Python and C++ objects was +done, resulting in more intuitive handling for C++ lvalues and +rvalues. + +The emergence of a powerful new type system in Python 2.2 made the +choice of whether to maintain compatibility with Python 1.5.2 easy: +the opportunity to throw away a great deal of elaborate code for +emulating classic Python classes alone was too good to pass up. In +addition, Python iterators and descriptors provided crucial and +elegant tools for representing similar C++ constructs. The +development of the generalized ``object`` interface allowed us to +further shield C++ programmers from the dangers and syntactic burdens +of the Python 'C' API. A great number of other features including C++ +exception translation, improved support for overloaded functions, and +most significantly, CallPolicies for handling pointers and +references, were added during this period. + +In October 2002, version 2 of Boost.Python was released. Development +since then has concentrated on improved support for C++ runtime +polymorphism and smart pointers. Peter Dimov's ingenious +``boost::shared_ptr`` design in particular has allowed us to give the +hybrid developer a consistent interface for moving objects back and +forth across the language barrier without loss of information. At +first, we were concerned that the sophistication and complexity of the +Boost.Python v2 implementation might discourage contributors, but the +emergence of Pyste_ and several other significant feature +contributions have laid those fears to rest. Daily questions on the +Python C++-sig and a backlog of desired improvements show that the +library is getting used. To us, the future looks bright. + +.. _`EDG`: http://www.edg.com + +============= + Conclusions +============= + +Boost.Python achieves seamless interoperability between two rich and +complimentary language environments. Because it leverages template +metaprogramming to introspect about types and functions, the user +never has to learn a third syntax: the interface definitions are +written in concise and maintainable C++. Also, the wrapping system +doesn't have to parse C++ headers or represent the type system: the +compiler does that work for us. + +Computationally intensive tasks play to the strengths of C++ and are +often impossible to implement efficiently in pure Python, while jobs +like serialization that are trivial in Python can be very difficult in +pure C++. Given the luxury of building a hybrid software system from +the ground up, we can approach design with new confidence and power. + +=========== + Citations +=========== + +.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report, + Vol. 7 No. 5 June 1995, pp. 26-31. + http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html + +=========== + Footnotes +=========== + +.. [#proto] In retrospect, it seems that "thinking hybrid" from the + ground up might have been better for the NLP system: the + natural component boundaries defined by the pure python + prototype turned out to be inappropriate for getting the + desired performance and memory footprint out of the C++ core, + which eventually caused some redesign overhead on the Python + side when the core was moved to C++. + +.. [#test] We also have some reservations about driving all C++ + testing through a Python interface, unless that's the only way + it will be ultimately used. Any transition across language + boundaries with such different object models can inevitably + mask bugs. + +.. [#feature] These features were expressed very differently in v1 of + Boost.Python diff --git a/doc/boost.css b/doc/boost.css deleted file mode 100644 index 6c3e9808ea..0000000000 --- a/doc/boost.css +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright David Abrahams 2006. Distributed under the Boost - Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -*/ -H1 -{ - FONT-SIZE: 200% - COLOR: #00007f -} -H2 -{ - FONT-SIZE: 150%; -} -H3 -{ - FONT-SIZE: 125%; -} -H4 -{ - FONT-SIZE: 108%; -} -BODY -{ - FONT-SIZE: 100%; - BACKGROUND-COLOR: #ffffff -} -PRE -{ - MARGIN-LEFT: 2pc; - FONT-SIZE: 80%; - BACKGROUND-COLOR: #dfffff -} -CODE -{ - FONT-SIZE: 95%; - white-space: pre -} -.index -{ - TEXT-ALIGN: left -} -.page-index -{ - TEXT-ALIGN: left -} -.definition -{ - TEXT-ALIGN: left -} -.footnote -{ - FONT-SIZE: 66%; - VERTICAL-ALIGN: super; - TEXT-DECORATION: none -} -.function-semantics -{ - CLEAR: left -} -.metafunction-semantics -{ - CLEAR: left -} diff --git a/doc/boostbook.css b/doc/boostbook.css new file mode 100644 index 0000000000..28f8935991 --- /dev/null +++ b/doc/boostbook.css @@ -0,0 +1,716 @@ + +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= +Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= +Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= +Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 9pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= +Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= +Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= +Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= +Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= +Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= +Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= +Table of contents +=============================================================================*/ + + div.toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + +/*============================================================================= +Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= +Suppress margins in tables +=============================================================================*/ + + table th > *:first-child, + table td > *:first-child + { + margin-top: 0; + } + + table th > *:last-child, + table td > *:last-child + { + margin-bottom: 0; + } + +/*============================================================================= +Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= +Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= +Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= +Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Links */ + a, a .keyword, a .identifier, a .special, a .preprocessor + a .char, a .comment, a .string, a .number + { + color: #005a9c; + } + + a:visited, a:visited .keyword, a:visited .identifier, + a:visited .special, a:visited .preprocessor a:visited .char, + a:visited .comment, a:visited .string, a:visited .number + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= +Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; +} + +sup { +bottom: 1ex; +} + +sub { +top: .5ex; +} + +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ diff --git a/doc/building.html b/doc/building.html deleted file mode 100644 index e2c48847f1..0000000000 --- a/doc/building.html +++ /dev/null @@ -1,636 +0,0 @@ - - - - - - -Boost C++ Libraries: Boost.Python Build and Test HOWTO - - - -
-

Boost.Python Build and Test HOWTO

- - - - - - -
-

1   Requirements

-

Boost.Python requires Python 2.21 or newer.

-
-
-

2   Background

-

There are two basic models for combining C++ and Python:

-
    -
  • extending, in which the end-user launches the Python interpreter -executable and imports Python “extension modules” written in C++. -Think of taking a library written in C++ and giving it a Python -interface so Python programmers can use it. From Python, these -modules look just like regular Python modules.
  • -
  • embedding, in which the end-user launches a program written -in C++ that in turn invokes the Python interpreter as a library -subroutine. Think of adding scriptability to an existing -application.
  • -
-

The key distinction between extending and embedding is the location -of the C++ main() function: in the Python interpreter executable, -or in some other program, respectively. Note that even when -embedding Python in another program, extension modules are often -the best way to make C/C++ functionality accessible to Python -code, so the use of extension modules is really at the heart of -both models.

-

Except in rare cases, extension modules are built as -dynamically-loaded libraries with a single entry point, which means -you can change them without rebuilding either the other extension -modules or the executable containing main().

-
-
-

3   No-Install Quickstart

-

There is no need to “install Boost” in order to get started using -Boost.Python. These instructions use Boost.Build projects, -which will build those binaries as soon as they're needed. Your -first tests may take a little longer while you wait for -Boost.Python to build, but doing things this way will save you from -worrying about build intricacies like which library binaries to use -for a specific compiler configuration and figuring out the right -compiler options to use yourself.

- -
-

Note

-

Of course it's possible to use other build systems to -build Boost.Python and its extensions, but they are not -officially supported by Boost. Moreover 99% of all “I can't -build Boost.Python” problems come from trying to use another -build system without first following these instructions.

-

If you want to use another system anyway, we suggest that you -follow these instructions, and then invoke bjam with the

-
--a -ofilename
-
-

options to dump the build commands it executes to a file, so -you can see what your alternate build system needs to do.

-
- -
-

3.1   Basic Procedure

-
    -
  1. Get Boost; see sections 1 and 2 [Unix/Linux, Windows] of the -Boost Getting Started Guide.

    -
  2. -
  3. Get the bjam build driver. See section 5 [Unix/Linux, -Windows] of the Boost Getting Started Guide.

    -
  4. -
  5. cd into the libs/python/example/quickstart/ directory of your -Boost installation, which contains a small example project.

    -
  6. -
  7. Invoke bjam. Replace the “stage“ argument from the -example invocation from section 5 of the Getting Started -Guide with “test,“ to build all the test targets. Also add -the argument “--verbose-test” to see the output generated by -the tests when they are run.

    -

    On Windows, your bjam invocation might look something like:

    -
    -C:\boost_1_34_0\…\quickstart> bjam toolset=msvc --verbose-test test
    -
    -

    and on Unix variants, perhaps,

    -
    -~/boost_1_34_0/…/quickstart$ bjam toolset=gcc --verbose-test test
    -
    -
  8. -
-
-

Note to Windows Users

-

For the sake of concision, the rest of this guide will use -unix-style forward slashes in pathnames instead of the -backslashes with which you may be more familiar. The forward -slashes should work everywhere except in Command Prompt -windows, where you should use backslashes.

-
-

If you followed this procedure successfully, you will have built an -extension module called extending and tested it by running a -Python script called test_extending.py. You will also have -built and run a simple application called embedding that embeds -python.

-
-
-

3.2   In Case of Trouble

-

If you're seeing lots of compiler and/or linker error messages, -it's probably because Boost.Build is having trouble finding your -Python installation. You might want to pass the ---debug-configuration option to bjam the first few times -you invoke it, to make sure that Boost.Build is correctly locating -all the parts of your Python installation. If it isn't, consider -Configuring Boost.Build as detailed below.

-

If you're still having trouble, Someone on one of the following -mailing lists may be able to help:

- -
-
-

3.3   In Case Everything Seemed to Work

-

Rejoice! If you're new to Boost.Python, at this point it might be -a good idea to ignore build issues for a while and concentrate on -learning the library by going through the tutorial and perhaps -some of the reference documentation, trying out what you've -learned about the API by modifying the quickstart project.

-
-
-

3.4   Modifying the Example Project

-

If you're content to keep your extension module forever in one -source file called extending.cpp, inside your Boost -distribution, and import it forever as extending, then you can -stop here. However, it's likely that you will want to make a few -changes. There are a few things you can do without having to learn -Boost.Build in depth.

-

The project you just built is specified in two files in the current -directory: boost-build.jam, which tells bjam where it can -find the interpreted code of the Boost build system, and -Jamroot, which describes the targets you just built. These -files are heavily commented, so they should be easy to modify. -Take care, however, to preserve whitespace. Punctuation such as -; will not be recognized as intended by bjam if it is not -surrounded by whitespace.

-
-

Relocate the Project

-

You'll probably want to copy this project elsewhere so you can -change it without modifying your Boost distribution. To do that, -simply

-
    -
  1. copy the entire libs/python/example/quickstart/ directory -into a new directory.
  2. -
  3. In the new copies of boost-build.jam and Jamroot, locate -the relative path near the top of the file that is clearly -marked by a comment, and edit that path so that it refers to the -same directory your Boost distribution as it referred to when -the file was in its original location in the -libs/python/example/quickstart/ directory.
  4. -
-

For example, if you moved the project from -/home/dave/boost_1_34_0/libs/python/example/quickstart to -/home/dave/my-project, you could change the first path in -boost-build.jam from

-
-../../../../tools/build/v2
-
-

to

-
-/home/dave/boost_1_34_0/tools/build/v2
-
-

and change the first path in Jamroot from

-
-../../../..
-
-

to

-
-/home/dave/boost_1_34_0
-
-
-
-

Add New or Change Names of Existing Source Files

-

The names of additional source files involved in building your -extension module or embedding application can be listed in -Jamroot right alongside extending.cpp or embedding.cpp -respectively. Just be sure to leave whitespace around each -filename:

-
-… file1.cpp file2.cpp file3.cpp …
-
-

Naturally, if you want to change the name of a source file you can -tell Boost.Build about it by editing the name in Jamroot.

-
-
-

Change the Name of your Extension Module

-

The name of the extension module is determined by two things:

-
    -
  1. the name in Jamroot immediately following python-extension, and
  2. -
  3. the name passed to BOOST_PYTHON_MODULE in extending.cpp.
  4. -
-

To change the name of the extension module from extending to -hello, you'd edit Jamroot, changing

-
-python-extension extending : extending.cpp ;
-
-

to

-
-python-extension hello : extending.cpp ;
-
-

and you'd edit extending.cpp, changing

-
-BOOST_PYTHON_MODULE(extending)
-
-

to

-
-BOOST_PYTHON_MODULE(hello)
-
-
-
-
-
-

4   Installing Boost.Python on your System

-

Since Boost.Python is a separately-compiled (as opposed to -header-only) library, its user relies on the services of a -Boost.Python library binary.

-

If you need a regular installation of the Boost.Python library -binaries on your system, the Boost Getting Started Guide will -walk you through the steps of creating one. If building binaries -from source, you might want to supply the --with-python -argument to bjam (or the --with-libraries=python argument -to configure), so only the Boost.Python binary will be built, -rather than all the Boost binaries.

-
-
-

5   Configuring Boost.Build

-

As described in the Boost.Build reference manual, a file called -user-config.jam in your home directory6 is used to -specify the tools and libraries available to the build system. You -may need to create or edit user-config.jam to tell Boost.Build -how to invoke Python, #include its headers, and link with its -libraries.

-
-

Users of Unix-Variant OSes

-

If you are using a unix-variant OS and you ran Boost's -configure script, it may have generated a -user-config.jam for you.4 If your configure/make sequence was successful and Boost.Python binaries -were built, your user-config.jam file is probably already -correct.

-
-

If you have one fairly “standard” python installation for your -platform, you might not need to do anything special to describe it. If -you haven't configured python in user-config.jam (and you don't -specify --without-python on the Boost.Build command line), -Boost.Build will automatically execute the equivalent of

-
-import toolset : using ;
-using python ;
-
-

which automatically looks for Python in the most likely places. -However, that only happens when using the Boost.Python project file -(e.g. when referred to by another project as in the quickstart -method). If instead you are linking against separately-compiled -Boost.Python binaries, you should set up a user-config.jam file -with at least the minimal incantation above.

-
-

5.1   Python Configuration Parameters

-

If you have several versions of Python installed, or Python is -installed in an unusual way, you may want to supply any or all of -the following optional parameters to using python.

-
-
version
-
the version of Python to use. Should be in Major.Minor -format, for example, 2.3. Do not include the subminor -version (i.e. not 2.5.1). If you have multiple Python -versions installed, the version will usually be the only -configuration argument required.
-
cmd-or-prefix
-
preferably, a command that invokes a Python interpreter. -Alternatively, the installation prefix for Python libraries and -header files. Only use the alternative formulation if there is -no appropriate Python executable available.
-
includes
-
the #include paths for Python headers. Normally the correct -path(s) will be automatically deduced from version and/or -cmd-or-prefix.
-
libraries
-
the path to Python library binaries. On MacOS/Darwin, -you can also pass the path of the Python framework. Normally the -correct path(s) will be automatically deduced from version -and/or cmd-or-prefix.
-
condition
-
if specified, should be a set of Boost.Build -properties that are matched against the build configuration when -Boost.Build selects a Python configuration to use. See examples -below for details.
-
extension-suffix
-
A string to append to the name of extension -modules before the true filename extension. You almost certainly -don't need to use this. Usually this suffix is only used when -targeting a Windows debug build of Python, and will be set -automatically for you based on the value of the -<python-debugging> feature. However, at least one Linux -distribution (Ubuntu Feisty Fawn) has a specially configured -python-dbg package that claims to use such a suffix.
-
-
-
-

5.2   Examples

-

Note that in the examples below, case and especially whitespace are -significant.

-
    -
  • If you have both python 2.5 and python 2.4 installed, -user-config.jam might contain:

    -
    -using python : 2.5 ;  # Make both versions of Python available
    -
    -using python : 2.4 ;  # To build with python 2.4, add python=2.4
    -                      # to your command line.
    -
    -

    The first version configured (2.5) becomes the default. To build -against python 2.4, add python=2.4 to the bjam command line.

    -
  • -
  • If you have python installed in an unusual location, you might -supply the path to the interpreter in the cmd-or-prefix -parameter:

    -
    -using python : : /usr/local/python-2.6-beta/bin/python ;
    -
    -
  • -
  • If you have a separate build of Python for use with a particular -toolset, you might supply that toolset in the condition -parameter:

    -
    -using python ;  # use for most toolsets
    -
    -# Use with Intel C++ toolset
    -using python
    -     : # version
    -     : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix
    -     : # includes
    -     : # libraries
    -     : <toolset>intel # condition
    -     ;
    -
    -
  • -
  • If you have downloaded the Python sources and built both the -normal and the “python debugging” builds from source on -Windows, you might see:

    -
    -using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ;
    -using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d
    -  : # includes
    -  : # libs
    -  : <python-debugging>on ;
    -
    -
  • -
  • You can set up your user-config.jam so a bjam built under Windows -can build/test both Windows and Cygwin python extensions. Just pass -<target-os>cygwin in the condition parameter -for the cygwin python installation:

    -
    -# windows installation
    -using python ;
    -
    -# cygwin installation
    -using python : : c:\\cygwin\\bin\\python2.5 : : : <target-os>cygwin ;
    -
    -

    when you put target-os=cygwin in your build request, it should build -with the cygwin version of python:5

    -
    -

    bjam target-os=cygwin toolset=gcc

    -
    -

    This is supposed to work the other way, too (targeting windows -python with a Cygwin bjam) but it seems as though the support in -Boost.Build's toolsets for building that way is broken at the -time of this writing.

    -
  • -
  • Note that because of the way Boost.Build currently selects target -alternatives, you might have be very explicit in your build -requests. For example, given:

    -
    -using python : 2.5 ; # a regular windows build
    -using python : 2.4 : : : : <target-os>cygwin ;
    -
    -

    building with

    -
    -bjam target-os=cygwin
    -
    -

    will yield an error. Instead, you'll need to write:

    -
    -bjam target-os=cygwin/python=2.4
    -
    -
  • -
-
-
-
-

6   Choosing a Boost.Python Library Binary

-

If—instead of letting Boost.Build construct and link with the right -libraries automatically—you choose to use a pre-built Boost.Python -library, you'll need to think about which one to link with. The -Boost.Python binary comes in both static and dynamic flavors. Take -care to choose the right flavor for your application.2

-
-

6.1   The Dynamic Binary

-

The dynamic library is the safest and most-versatile choice:

-
    -
  • A single copy of the library code is used by all extension -modules built with a given toolset.3
  • -
  • The library contains a type conversion registry. Because one -registry is shared among all extension modules, instances of a -class exposed to Python in one dynamically-loaded extension -module can be passed to functions exposed in another such module.
  • -
-
-
-

6.2   The Static Binary

-

It might be appropriate to use the static Boost.Python library in -any of the following cases:

-
    -
  • You are extending python and the types exposed in your -dynamically-loaded extension module don't need to be used by any -other Boost.Python extension modules, and you don't care if the -core library code is duplicated among them.
  • -
  • You are embedding python in your application and either:
      -
    • You are targeting a Unix variant OS other than MacOS or AIX, -where the dynamically-loaded extension modules can “see” the -Boost.Python library symbols that are part of the executable.
    • -
    • Or, you have statically linked some Boost.Python extension -modules into your application and you don't care if any -dynamically-loaded Boost.Python extension modules are able to -use the types exposed by your statically-linked extension -modules (and vice-versa).
    • -
    -
  • -
-
-
-
-

7   #include Issues

-
    -
  1. If you should ever have occasion to #include "python.h" -directly in a translation unit of a program using Boost.Python, -use #include "boost/python/detail/wrap_python.hpp" instead. -It handles several issues necessary for use with Boost.Python, -one of which is mentioned in the next section.
  2. -
  3. Be sure not to #include any system headers before -wrap_python.hpp. This restriction is actually imposed by -Python, or more properly, by Python's interaction with your -operating system. See -http://docs.python.org/ext/simpleExample.html for details.
  4. -
-
-
-

8   Python Debugging Builds

-

Python can be built in a special “python debugging” configuration -that adds extra checks and instrumentation that can be very useful -for developers of extension modules. The data structures used by -the debugging configuration contain additional members, so a -Python executable built with python debugging enabled cannot be -used with an extension module or library compiled without it, and -vice-versa.

-

Since pre-built “python debugging” versions of the Python -executable and libraries are not supplied with most distributions -of Python,7 and we didn't want to force our users -to build them, Boost.Build does not automatically enable python -debugging in its debug build variant (which is the default). -Instead there is a special build property called -python-debugging that, when used as a build property, will -define the right preprocessor symbols and select the right -libraries to link with.

-

On unix-variant platforms, the debugging versions of Python's data -structures will only be used if the symbol Py_DEBUG is defined. -On many windows compilers, when extension modules are built with -the preprocessor symbol _DEBUG, Python defaults to force -linking with a special debugging version of the Python DLL. Since -that symbol is very commonly used even when Python is not present, -Boost.Python temporarily undefines _DEBUG when Python.h -is #included from boost/python/detail/wrap_python.hpp - unless -BOOST_DEBUG_PYTHON is defined. The upshot is that if you want -“python debugging”and you aren't using Boost.Build, you should make -sure BOOST_DEBUG_PYTHON is defined, or python debugging will be -suppressed.

-
-
-

9   Testing Boost.Python

-

To run the full test suite for Boost.Python, invoke bjam in the -libs/python/test subdirectory of your Boost distribution.

-
-
-

10   Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users

-

If you are using a version of Python prior to 2.4.1 with a MinGW -prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to -create a MinGW-compatible version of the Python library; the one -shipped with Python will only work with a Microsoft-compatible -linker. Follow the instructions in the “Non-Microsoft” section of -the “Building Extensions: Tips And Tricks” chapter in Installing -Python Modules to create libpythonXX.a, where XX -corresponds to the major and minor version numbers of your Python -installation.

-
- - - - - -
[1]Note that although we tested earlier versions of -Boost.Python with Python 2.2, and we don't think we've done -anything to break compatibility, this release of Boost.Python -may not have been tested with versions of Python earlier than -2.4, so we're not 100% sure that python 2.2 and 2.3 are -supported.
- - - - - -
[2]

Information about how to identify the -static and dynamic builds of Boost.Python:

- -
- - - - - -
[3]Because of the way most *nix platforms -share symbols among dynamically-loaded objects, I'm not certain -that extension modules built with different compiler toolsets -will always use different copies of the Boost.Python library -when loaded into the same Python instance. Not using different -libraries could be a good thing if the compilers have compatible -ABIs, because extension modules built with the two libraries -would be interoperable. Otherwise, it could spell disaster, -since an extension module and the Boost.Python library would -have different ideas of such things as class layout. I would -appreciate someone doing the experiment to find out what -happens.
- - - - - -
[4]configure overwrites the existing -user-config.jam in your home directory -(if any) after making a backup of the old version.
- - - - - -
[5]Note that the <target-os>cygwin feature is -different from the <flavor>cygwin subfeature of the gcc -toolset, and you might need handle both explicitly if you also -have a MinGW GCC installed.
- - - - - -
[6]

Windows users, your home directory can be -found by typing:

-
-ECHO %HOMEDRIVE%%HOMEPATH%
-
-

into a command prompt window.

-
- - - - - -
[7]On Unix and similar platforms, a debugging -python and associated libraries are built by adding ---with-pydebug when configuring the Python build. On -Windows, the debugging version of Python is generated by -the "Win32 Debug" target of the Visual Studio project in the -PCBuild subdirectory of a full Python source code distribution. -
-
-
- - - diff --git a/doc/building.qbk b/doc/building.qbk new file mode 100644 index 0000000000..c19ba7cfdd --- /dev/null +++ b/doc/building.qbk @@ -0,0 +1,566 @@ +[chapter Building and Testing + [quickbook 1.7] + [authors [Abrahams, David]] + [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] + [id building] +] +[/ Copyright David Abrahams 2006. Distributed under the Boost + / Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) + /] + +[section Requirements] + +Boost.Python requires [@http://www.python.org/2.2 Python 2.2] +[footnote Note that although we tested earlier versions of Boost.Python + with Python 2.2, and we don't *think* we've done anything to break + compatibility, this release of Boost.Python may not have been tested + with versions of Python earlier than 2.4, so we're not 100% sure that + python 2.2 and 2.3 are supported.] *or* [@http://www.python.org newer]. + +[endsect] +[section Background] + +There are two basic models for combining C++ and Python: + +* [@http://www.python.org/doc/current/ext/intro.html extending], + in which the end-user launches the Python interpreter + executable and imports Python “extension modules” written in C++. + Think of taking a library written in C++ and giving it a Python + interface so Python programmers can use it. From Python, these + modules look just like regular Python modules. + +* [@http://www.python.org/doc/current/ext/embedding.html embedding], + in which the end-user launches a program written + in C++ that in turn invokes the Python interpreter as a library + subroutine. Think of adding scriptability to an existing + application. + +The key distinction between extending and embedding is the location +of the C++ `main()` function: in the Python interpreter executable, +or in some other program, respectively. Note that even when +embedding Python in another program, [@http://www.python.org/doc/current/ext/extending-with-embedding.html extension modules are often +the best way to make C/C++ functionality accessible to Python +code], so the use of extension modules is really at the heart of +both models. + +Except in rare cases, extension modules are built as +dynamically-loaded libraries with a single entry point, which means +you can change them without rebuilding either the other extension +modules or the executable containing `main()`. + +[endsect] +[section No-Install Quickstart] + +There is no need to “install Boost” in order to get started using +Boost.Python. These instructions use _bb_ projects, +which will build those binaries as soon as they're needed. Your +first tests may take a little longer while you wait for +Boost.Python to build, but doing things this way will save you from +worrying about build intricacies like which library binaries to use +for a specific compiler configuration and figuring out the right +compiler options to use yourself. + +[note Of course it's possible to use other build systems to + build Boost.Python and its extensions, but they are not + officially supported by Boost. Moreover *99% of all “I can't + build Boost.Python” problems come from trying to use another + build system* without first following these instructions. + + If you want to use another system anyway, we suggest that you + follow these instructions, and then invoke `bjam` with the + + `-a -o`\ /filename/ + + options to dump the build commands it executes to a file, so + you can see what your alternate build system needs to do.] + +[section Basic Procedure] + +1. Get Boost; see sections 1 and 2 of the _gsg_. + +2. Get the `bjam` build driver. See section 5 of the _gsg_. + +3. cd into the `example/quickstart/` directory of your + Boost.Python installation, which contains a small example project. + +4. Invoke `bjam`. Replace the “\ `stage`\ “ argument from the + example invocation from section 5 of the _gsg_ with “\ `test`\ ,“ to + build all the test targets. Also add the argument “\ `--verbose-test`\ ” + to see the output generated by the tests when they are run. + On Windows, your `bjam` invocation might look something like: + `` + C:\\...\\quickstart> bjam toolset=msvc --verbose-test test + `` + and on Unix variants, perhaps, + `` + .../quickstart$ bjam toolset=gcc --verbose-test test + `` + +[note For the sake of concision, the rest of this guide will use + unix-style forward slashes in pathnames instead of the + backslashes with which Windows users may be more familiar. The forward + slashes should work everywhere except in + [@http://www.boost.org/more/getting_started/windows.html#command-prompt + Command Prompt] windows, where you should use backslashes.] + +If you followed this procedure successfully, you will have built an +extension module called `extending` and tested it by running a +Python script called `test_extending.py`. You will also have +built and run a simple application called `embedding` that embeds +python. + +[endsect] +[section In Case of Trouble] + +If you're seeing lots of compiler and/or linker error messages, +it's probably because Boost.Build is having trouble finding your +Python installation. You might want to pass the +`--debug-configuration` option to `bjam` the first few times +you invoke it, to make sure that Boost.Build is correctly locating +all the parts of your Python installation. If it isn't, consider +[link building.configuring_boost_build Configuring Boost.Build] +as detailed below. + +If you're still having trouble, Someone on one of the following +mailing lists may be able to help: + +* The _bb_list_ for issues related to Boost.Build +* The _bp_list_ for issues specifically related to Boost.Python + +[endsect] +[section In Case Everything Seemed to Work] + +Rejoice! If you're new to Boost.Python, at this point it might be +a good idea to ignore build issues for a while and concentrate on +learning the library by going through the _tutorial_ and perhaps +some of the _reference_, trying out what you've +learned about the API by modifying the quickstart project. + +[endsect] +[section Modifying the Example Project] + +If you're content to keep your extension module forever in one +source file called `extending.cpp`, inside your Boost.Python +distribution, and import it forever as `extending`, then you can +stop here. However, it's likely that you will want to make a few +changes. There are a few things you can do without having to learn +_bb_ in depth. + +The project you just built is specified in two files in the current +directory: `boost-build.jam`, which tells `bjam` where it can +find the interpreted code of the Boost build system, and +`Jamroot`, which describes the targets you just built. These +files are heavily commented, so they should be easy to modify. +Take care, however, to preserve whitespace. Punctuation such as +`;` will not be recognized as intended by `bjam` if it is not +surrounded by whitespace. + +[section Relocate the Project] + +You'll probably want to copy this project elsewhere so you can +change it without modifying your Boost distribution. To do that, +simply + +a. copy the entire `example/quickstart/` directory + into a new directory. + +b. In the new copies of `boost-build.jam` and `Jamroot`, locate + the relative path near the top of the file that is clearly + marked by a comment, and edit that path so that it refers to the + same directory your Boost distribution as it referred to when + the file was in its original location in the + `example/quickstart/` directory. + +For example, if you moved the project from +`/home/dave/boost_1_34_0/libs/python/example/quickstart` to +`/home/dave/my-project`, you could change the first path in +`boost-build.jam` from +`` + ../../../../tools/build/src +`` +to +`` + /home/dave/boost_1_34_0/tools/build/src +`` +and change the first path in `Jamroot` from +`` + ../../../.. +`` +to +`` + /home/dave/boost_1_34_0 +`` + +[endsect] +[section Add New or Change Names of Existing Source Files] + +The names of additional source files involved in building your +extension module or embedding application can be listed in +`Jamroot` right alongside `extending.cpp` or `embedding.cpp` +respectively. Just be sure to leave whitespace around each +filename: +`` + … file1.cpp file2.cpp file3.cpp … +`` +Naturally, if you want to change the name of a source file you can +tell Boost.Build about it by editing the name in `Jamroot`. + +[endsect] +[section Change the Name of your Extension Module] + +The name of the extension module is determined by two things: + +# the name in `Jamroot` immediately following `python-extension`, and +# the name passed to `BOOST_PYTHON_MODULE` in `extending.cpp`. + +To change the name of the extension module from `extending` to +`hello`, you'd edit `Jamroot`, changing +`` + python-extension extending : extending.cpp ; +`` +to +`` + python-extension hello : extending.cpp ; +`` +and you'd edit extending.cpp, changing + +`` + BOOST_PYTHON_MODULE(extending) +`` +to +`` + BOOST_PYTHON_MODULE(hello) +`` +[endsect] +[endsect] +[endsect] +[section Installing Boost.Python on your System] + +Since Boost.Python is a separately-compiled (as opposed to +`header-only`) library, its user relies on the services of a +Boost.Python library binary. + +If you need a regular installation of the Boost.Python library +binaries on your system, the _gsg_ will +walk you through the steps of creating one. If building binaries +from source, you might want to supply the `--with-python` +argument to `bjam` (or the `--with-libraries=python` argument +to `configure`), so only the Boost.Python binary will be built, +rather than all the Boost binaries. + +[endsect] +[section Configuring Boost.Build] + +As described in the [@http://www.boost.org/build/doc/html/bbv2/overview/configuration.html Boost.Build Reference Manual], a file called +`user-config.jam` in your home directory is used to +specify the tools and libraries available to the build system. You +may need to create or edit `user-config.jam` to tell Boost.Build +how to invoke Python, `#include` its headers, and link with its +libraries. + +[note If you are using a unix-variant OS and you ran Boost's + `configure` script, it may have generated a + `user-config.jam` for you. [footnote `configure` overwrites the existing + `user-config.jam` in your home directory (if any) after making a backup of + the old version.] If your `configure`\ /\ `make` sequence was successful and + Boost.Python binaries were built, your `user-config.jam` file is probably already + correct.] + +If you have one fairly “standard” python installation for your +platform, you might not need to do anything special to describe it. If +you haven't configured python in `user-config.jam` (and you don't +specify `--without-python` on the Boost.Build command line), +Boost.Build will automatically execute the equivalent of + +`` + import toolset : using ; + using python ; +`` +which automatically looks for Python in the most likely places. +However, that only happens when using the Boost.Python project file +(e.g. when referred to by another project as in the quickstart +method). If instead you are linking against separately-compiled +Boost.Python binaries, you should set up a `user-config.jam` file +with at least the minimal incantation above. + +[section Python Configuration Parameters] + +If you have several versions of Python installed, or Python is +installed in an unusual way, you may want to supply any or all of +the following optional parameters to `using python`. + +[variablelist + [[version] + + [the version of Python to use. Should be in Major.Minor + format, for example, `2.3`. Do not include the subminor + version (i.e. *not* `2.5.1`). If you have multiple Python + versions installed, the version will usually be the only + configuration argument required.]] + + [[cmd-or-prefix] + + [preferably, a command that invokes a Python interpreter. + Alternatively, the installation prefix for Python libraries and + header files. Only use the alternative formulation if there is + no appropriate Python executable available.]] + + [[*includes*] + + [the `#include` paths for Python headers. Normally the correct + path(s) will be automatically deduced from `version` and/or + `cmd-or-prefix`.]] + + [[*libraries*] + + [the path to Python library binaries. On MacOS/Darwin, + you can also pass the path of the Python framework. Normally the + correct path(s) will be automatically deduced from `version` + and/or `cmd-or-prefix`.]] + + [[*condition*] + + [if specified, should be a set of Boost.Build + properties that are matched against the build configuration when + Boost.Build selects a Python configuration to use. See examples + below for details.]] + + [[*extension-suffix*] + + [A string to append to the name of extension + modules before the true filename extension. You almost certainly + don't need to use this. Usually this suffix is only used when + targeting a Windows debug build of Python, and will be set + automatically for you based on the value of the + [link building.python_debugging_builds ] feature. + However, at least one Linux distribution (Ubuntu Feisty Fawn) has + a specially configured [@https://wiki.ubuntu.com/PyDbgBuilds ] + package that claims to use such a suffix.]] + ] + +[endsect] +[section Examples] + +Note that in the examples below, case and *especially whitespace* are +significant. + +* If you have both python 2.5 and python 2.4 installed, + `user-config.jam` might contain + + `` + using python : 2.5 ; # Make both versions of Python available + using python : 2.4 ; # To build with python 2.4, add python=2.4 + # to your command line. + `` + The first version configured (2.5) becomes the default. To build + against python 2.4, add `python=2.4` to the `bjam` command line. + +* If you have python installed in an unusual location, you might + supply the path to the interpreter in the `cmd-or-prefix` + parameter: + + `` + using python : : /usr/local/python-2.6-beta/bin/python ; + `` + +* If you have a separate build of Python for use with a particular + toolset, you might supply that toolset in the `condition` + parameter: + + `` + using python ; # use for most toolsets + + # Use with Intel C++ toolset + using python + : # version + : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix + : # includes + : # libraries + : intel # condition + ; + `` + +* If you have downloaded the Python sources and built both the + normal and the [link building.python_debugging_builds "python debugging"] + builds from source on Windows, you might see: + + `` + using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; + using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d + : # includes + : # libs + : on ; + `` +* You can set up your user-config.jam so a bjam built under Windows + can build/test both Windows and Cygwin_ python extensions. Just pass + `cygwin` in the `condition` parameter + for the cygwin python installation: + + `` + # windows installation + using python ; + + # cygwin installation + using python : : c:\\cygwin\\bin\\python2.5 : : : cygwin ; + `` + when you put target-os=cygwin in your build request, it should build + with the cygwin version of python: [#flavor]_ + + `` + bjam target-os=cygwin toolset=gcc + `` + This is supposed to work the other way, too (targeting windows + python with a [@http://cygwin.com Cygwin] bjam) but it seems as though the support in + Boost.Build's toolsets for building that way is broken at the + time of this writing. + +* Note that because of [@http://zigzag.cs.msu.su/boost.build/wiki/AlternativeSelection + the way Boost.Build currently selects target alternatives], you might have be very + explicit in your build requests. For example, given: + + `` + using python : 2.5 ; # a regular windows build + using python : 2.4 : : : : cygwin ; + `` + building with + `` + bjam target-os=cygwin + `` + + will yield an error. Instead, you'll need to write + + `` + bjam target-os=cygwin/python=2.4 + `` + +[endsect] +[endsect] +[section Choosing a Boost.Python Library Binary] + +If—instead of letting Boost.Build construct and link with the right +libraries automatically—you choose to use a pre-built Boost.Python +library, you'll need to think about which one to link with. The +Boost.Python binary comes in both static and dynamic flavors. Take +care to choose the right flavor for your application. [footnote +Information about how to identify the static and dynamic builds of Boost.Python on +[@http://boost.org/more/getting_started/windows.html#library-naming Windows] / +[@http://boost.org/more/getting_started/unix-variants.html#library-naming Unix variants]] + +[section The Dynamic Binary] + +The dynamic library is the safest and most-versatile choice: + +* A single copy of the library code is used by all extension + modules built with a given toolset. [footnote Because of the way most \*nix platforms + share symbols among dynamically-loaded objects, I'm not certain + that extension modules built with different compiler toolsets + will always use different copies of the Boost.Python library + when loaded into the same Python instance. Not using different + libraries could be a good thing if the compilers have compatible + ABIs, because extension modules built with the two libraries + would be interoperable. Otherwise, it could spell disaster, + since an extension module and the Boost.Python library would + have different ideas of such things as class layout. I would + appreciate someone doing the experiment to find out what + happens.] + +* The library contains a type conversion registry. Because one + registry is shared among all extension modules, instances of a + class exposed to Python in one dynamically-loaded extension + module can be passed to functions exposed in another such module. + +[endsect] +[section The Static Binary] + +It might be appropriate to use the static Boost.Python library in +any of the following cases: + +* You are _extending_ python and the types exposed in your + dynamically-loaded extension module don't need to be used by any + other Boost.Python extension modules, and you don't care if the + core library code is duplicated among them. + +* You are _embedding_ python in your application and either: + + * You are targeting a Unix variant OS other than MacOS or AIX, + where the dynamically-loaded extension modules can “see” the + Boost.Python library symbols that are part of the executable. + + * Or, you have statically linked some Boost.Python extension + modules into your application and you don't care if any + dynamically-loaded Boost.Python extension modules are able to + use the types exposed by your statically-linked extension + modules (and vice-versa). + +[endsect] +[endsect] +[section `#include` Issues] + +1. If you should ever have occasion to `#include "python.h"` + directly in a translation unit of a program using Boost.Python, + use `#include "boost/python/detail/wrap_python.hpp"` instead. + It handles several issues necessary for use with Boost.Python, + one of which is mentioned in the next section. + +2. Be sure not to `#include` any system headers before + `wrap_python.hpp`. This restriction is actually imposed by + Python, or more properly, by Python's interaction with your + operating system. See + [@http://docs.python.org/ext/simpleExample.html] for details. + +[endsect] +[section Python Debugging Builds] + +Python can be built in a special “python debugging” configuration +that adds extra checks and instrumentation that can be very useful +for developers of extension modules. The data structures used by +the debugging configuration contain additional members, so *a +Python executable built with python debugging enabled cannot be +used with an extension module or library compiled without it, and +vice-versa.* + +Since pre-built “python debugging” versions of the Python +executable and libraries are not supplied with most distributions +of Python, [footnote On Unix and similar platforms, a debugging python and associated libraries are built by adding --with-pydebug when configuring the Python build. On Windows, the debugging version of Python is generated by the "Win32 Debug" target of the Visual Studio project in the PCBuild subdirectory of a full Python source code distribution.] and we didn't want to force our users +to build them, Boost.Build does not automatically enable python +debugging in its `debug` build variant (which is the default). +Instead there is a special build property called +`python-debugging` that, when used as a build property, will +define the right preprocessor symbols and select the right +libraries to link with. + +On unix-variant platforms, the debugging versions of Python's data +structures will only be used if the symbol `Py_DEBUG` is defined. +On many windows compilers, when extension modules are built with +the preprocessor symbol `_DEBUG`, Python defaults to force +linking with a special debugging version of the Python DLL. Since +that symbol is very commonly used even when Python is not present, +Boost.Python temporarily undefines `_DEBUG` when `Python.h` +is #included from `boost/python/detail/wrap_python.hpp` - unless +`BOOST_DEBUG_PYTHON` is defined. The upshot is that if you want +“python debugging”and you aren't using Boost.Build, you should make +sure `BOOST_DEBUG_PYTHON` is defined, or python debugging will be +suppressed. + +[endsect] +[section Testing Boost.Python] + +To run the full test suite for Boost.Python, invoke `bjam` in the +`test` subdirectory of your Boost.Python distribution. + +[endsect] +[section Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users] + +If you are using a version of Python prior to 2.4.1 with a MinGW +prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to +create a MinGW-compatible version of the Python library; the one +shipped with Python will only work with a Microsoft-compatible +linker. Follow the instructions in the “Non-Microsoft” section of +the “Building Extensions: Tips And Tricks” chapter in +[@https://docs.python.org/2/install/index.html Installing Python Modules] +to create `libpythonXX.a`, where `XX` corresponds to the major and minor +version numbers of your Python installation. + +[endsect] diff --git a/doc/building.rst b/doc/building.rst deleted file mode 100644 index 1e2c7d42f2..0000000000 --- a/doc/building.rst +++ /dev/null @@ -1,680 +0,0 @@ -.. Copyright David Abrahams 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at -.. http://www.boost.org/LICENSE_1_0.txt) - -============================================== - |(logo)|__ Boost.Python Build and Test HOWTO -============================================== - -.. |(logo)| image:: ../../../boost.png - :alt: Boost C++ Libraries: - :class: boost-logo - -__ ../index.html - - -.. section-numbering:: - :depth: 2 - -.. contents:: Contents - :depth: 2 - :class: sidebar small - -.. |newer| replace:: *newer* - -Requirements -============ - -Boost.Python requires `Python 2.2`_ [#2.2]_ *or* |newer|__. - -.. _Python 2.2: http://www.python.org/2.2 -__ http://www.python.org - -Background -========== - -There are two basic models for combining C++ and Python: - -- extending_, in which the end-user launches the Python interpreter - executable and imports Python “extension modules” written in C++. - Think of taking a library written in C++ and giving it a Python - interface so Python programmers can use it. From Python, these - modules look just like regular Python modules. - -- embedding_, in which the end-user launches a program written - in C++ that in turn invokes the Python interpreter as a library - subroutine. Think of adding scriptability to an existing - application. - -.. _extending: http://www.python.org/doc/current/ext/intro.html -.. _embedding: http://www.python.org/doc/current/ext/embedding.html - -The key distinction between extending and embedding is the location -of the C++ ``main()`` function: in the Python interpreter executable, -or in some other program, respectively. Note that even when -embedding Python in another program, `extension modules are often -the best way to make C/C++ functionality accessible to Python -code`__, so the use of extension modules is really at the heart of -both models. - -__ http://www.python.org/doc/current/ext/extending-with-embedding.html - -Except in rare cases, extension modules are built as -dynamically-loaded libraries with a single entry point, which means -you can change them without rebuilding either the other extension -modules or the executable containing ``main()``. - -.. _quickstart: - -No-Install Quickstart -===================== - -There is no need to “install Boost” in order to get started using -Boost.Python. These instructions use Boost.Build_ projects, -which will build those binaries as soon as they're needed. Your -first tests may take a little longer while you wait for -Boost.Python to build, but doing things this way will save you from -worrying about build intricacies like which library binaries to use -for a specific compiler configuration and figuring out the right -compiler options to use yourself. - -.. .. raw:: html - -
- -.. Note:: Of course it's possible to use other build systems to - build Boost.Python and its extensions, but they are not - officially supported by Boost. Moreover **99% of all “I can't - build Boost.Python” problems come from trying to use another - build system** without first following these instructions. - - If you want to use another system anyway, we suggest that you - follow these instructions, and then invoke ``bjam`` with the - - .. parsed-literal:: - - ``-a -o``\ *filename* - - options to dump the build commands it executes to a file, so - you can see what your alternate build system needs to do. - -.. .. raw:: html - -
- -.. _Boost.Build: ../../../tools/build/index.html - -Basic Procedure ---------------- - -1. Get Boost; see sections 1 and 2 [`Unix/Linux`__, `Windows`__\ ] of the - Boost `Getting Started Guide`_. - - __ ../../../more/getting_started/unix-variants.html#get-boost - __ ../../../more/getting_started/windows.html#get-boost - -2. Get the ``bjam`` build driver. See section 5 [`Unix/Linux`__, - `Windows`__\ ] of the Boost `Getting Started Guide`_. - - __ ../../../more/getting_started/unix-variants.html#prepare-to-use-a-boost-library-binary - __ ../../../more/getting_started/windows.html#prepare-to-use-a-boost-library-binary - - -3. cd into the ``libs/python/example/quickstart/`` directory of your - Boost installation, which contains a small example project. - -4. Invoke ``bjam``. Replace the “\ ``stage``\ “ argument from the - example invocation from section 5 of the `Getting Started - Guide`_ with “\ ``test``\ ,“ to build all the test targets. Also add - the argument “\ ``--verbose-test``\ ” to see the output generated by - the tests when they are run. - - On Windows, your ``bjam`` invocation might look something like: - - .. parsed-literal:: - - C:\\boost_1_34_0\\…\\quickstart> **bjam toolset=msvc --verbose-test test** - - and on Unix variants, perhaps, - - .. parsed-literal:: - - ~/boost_1_34_0/…/quickstart$ **bjam toolset=gcc --verbose-test test** - -.. Admonition:: Note to Windows Users - - For the sake of concision, the rest of this guide will use - unix-style forward slashes in pathnames instead of the - backslashes with which you may be more familiar. The forward - slashes should work everywhere except in `Command Prompt`_ - windows, where you should use backslashes. - - .. _Command Prompt: ../../../more/getting_started/windows.html#command-prompt - -If you followed this procedure successfully, you will have built an -extension module called ``extending`` and tested it by running a -Python script called ``test_extending.py``. You will also have -built and run a simple application called ``embedding`` that embeds -python. - -.. _Getting Started Guide: ../../../more/getting_started/index.html - -In Case of Trouble ------------------- - -If you're seeing lots of compiler and/or linker error messages, -it's probably because Boost.Build is having trouble finding your -Python installation. You might want to pass the -``--debug-configuration`` option to ``bjam`` the first few times -you invoke it, to make sure that Boost.Build is correctly locating -all the parts of your Python installation. If it isn't, consider -`Configuring Boost.Build`_ as detailed below. - -If you're still having trouble, Someone on one of the following -mailing lists may be able to help: - -* The `Boost.Build mailing list`__ for issues related to Boost.Build -* The Python `C++ Sig`__ for issues specifically related to Boost.Python - -__ http://www.boost.org/more/mailing_lists.htm#jamboost -__ http://www.boost.org/more/mailing_lists.htm#cplussig - -In Case Everything Seemed to Work ---------------------------------- - -Rejoice! If you're new to Boost.Python, at this point it might be -a good idea to ignore build issues for a while and concentrate on -learning the library by going through the tutorial_ and perhaps -some of the `reference documentation`_, trying out what you've -learned about the API by modifying the quickstart project. - -.. _reference documentation: v2/reference.html -.. _tutorial: tutorial/index.html - -Modifying the Example Project ------------------------------ - -If you're content to keep your extension module forever in one -source file called |extending.cpp|_, inside your Boost -distribution, and import it forever as ``extending``, then you can -stop here. However, it's likely that you will want to make a few -changes. There are a few things you can do without having to learn -Boost.Build_ in depth. - -The project you just built is specified in two files in the current -directory: |boost-build.jam|_, which tells ``bjam`` where it can -find the interpreted code of the Boost build system, and -|Jamroot|_, which describes the targets you just built. These -files are heavily commented, so they should be easy to modify. -Take care, however, to preserve whitespace. Punctuation such as -``;`` will not be recognized as intended by ``bjam`` if it is not -surrounded by whitespace. - -.. |boost-build.jam| replace:: ``boost-build.jam`` -.. _boost-build.jam: ../example/quickstart/boost-build.jam - -.. |Jamroot| replace:: ``Jamroot`` -.. _Jamroot: ../example/quickstart/Jamroot - -.. |extending.cpp| replace:: ``extending.cpp`` -.. _extending.cpp: ../example/quickstart/extending.cpp - -Relocate the Project -.................... - -You'll probably want to copy this project elsewhere so you can -change it without modifying your Boost distribution. To do that, -simply - -a. copy the entire ``libs/python/example/quickstart/`` directory - into a new directory. - -b. In the new copies of |boost-build.jam|_ and |Jamroot|_, locate - the relative path near the top of the file that is clearly - marked by a comment, and edit that path so that it refers to the - same directory your Boost distribution as it referred to when - the file was in its original location in the - ``libs/python/example/quickstart/`` directory. - -For example, if you moved the project from -``/home/dave/boost_1_34_0/libs/python/example/quickstart`` to -``/home/dave/my-project``, you could change the first path in -|boost-build.jam|_ from - -.. parsed-literal:: - - **../../../..**\ /tools/build/v2 - -to - -.. parsed-literal:: - - **/home/dave/boost_1_34_0**\ /tools/build/v2 - -and change the first path in |Jamroot|_ from - -.. parsed-literal:: - - **../../../..** - -to - -.. parsed-literal:: - - **/home/dave/boost_1_34_0** - -Add New or Change Names of Existing Source Files -................................................ - -The names of additional source files involved in building your -extension module or embedding application can be listed in -|Jamroot|_ right alongside ``extending.cpp`` or ``embedding.cpp`` -respectively. Just be sure to leave whitespace around each -filename:: - - … file1.cpp file2.cpp file3.cpp … - -Naturally, if you want to change the name of a source file you can -tell Boost.Build about it by editing the name in |Jamroot|_. - -Change the Name of your Extension Module -........................................ - -The name of the extension module is determined by two things: - -1. the name in |Jamroot|_ immediately following ``python-extension``, and -2. the name passed to ``BOOST_PYTHON_MODULE`` in |extending.cpp|_. - -To change the name of the extension module from ``extending`` to -``hello``, you'd edit |Jamroot|_, changing - -.. parsed-literal:: - - python-extension **extending** : extending.cpp ; - -to - -.. parsed-literal:: - - python-extension **hello** : extending.cpp ; - -and you'd edit extending.cpp, changing - -.. parsed-literal:: - - BOOST_PYTHON_MODULE(\ **extending**\ ) - -to - -.. parsed-literal:: - - BOOST_PYTHON_MODULE(\ **hello**\ ) - -Installing Boost.Python on your System -====================================== - -Since Boost.Python is a separately-compiled (as opposed to -`header-only`_) library, its user relies on the services of a -Boost.Python library binary. - -.. _header-only: ../../../more/getting_started/windows.html#header-only-libraries - -If you need a regular installation of the Boost.Python library -binaries on your system, the Boost `Getting Started Guide`_ will -walk you through the steps of creating one. If building binaries -from source, you might want to supply the ``--with-python`` -argument to ``bjam`` (or the ``--with-libraries=python`` argument -to ``configure``), so only the Boost.Python binary will be built, -rather than all the Boost binaries. - - -Configuring Boost.Build -======================= - -As described in the `Boost.Build reference manual`__, a file called -``user-config.jam`` in your home directory [#home-dir]_ is used to -specify the tools and libraries available to the build system. You -may need to create or edit ``user-config.jam`` to tell Boost.Build -how to invoke Python, ``#include`` its headers, and link with its -libraries. - -__ http://www.boost.orgdoc/html/bbv2/advanced.html#bbv2.advanced.configuration - -.. Admonition:: Users of Unix-Variant OSes - - If you are using a unix-variant OS and you ran Boost's - ``configure`` script, it may have generated a - ``user-config.jam`` for you. [#overwrite]_ If your ``configure``\ - /\ ``make`` sequence was successful and Boost.Python binaries - were built, your ``user-config.jam`` file is probably already - correct. - -If you have one fairly “standard” python installation for your -platform, you might not need to do anything special to describe it. If -you haven't configured python in ``user-config.jam`` (and you don't -specify ``--without-python`` on the Boost.Build command line), -Boost.Build will automatically execute the equivalent of :: - - import toolset : using ; - using python ; - -which automatically looks for Python in the most likely places. -However, that only happens when using the Boost.Python project file -(e.g. when referred to by another project as in the quickstart_ -method). If instead you are linking against separately-compiled -Boost.Python binaries, you should set up a ``user-config.jam`` file -with at least the minimal incantation above. - -Python Configuration Parameters -------------------------------- - -If you have several versions of Python installed, or Python is -installed in an unusual way, you may want to supply any or all of -the following optional parameters to ``using python``. - -version - the version of Python to use. Should be in Major.Minor - format, for example, ``2.3``. Do not include the subminor - version (i.e. *not* ``2.5.1``). If you have multiple Python - versions installed, the version will usually be the only - configuration argument required. - -cmd-or-prefix - preferably, a command that invokes a Python interpreter. - Alternatively, the installation prefix for Python libraries and - header files. Only use the alternative formulation if there is - no appropriate Python executable available. - -includes - the ``#include`` paths for Python headers. Normally the correct - path(s) will be automatically deduced from ``version`` and/or - ``cmd-or-prefix``. - -libraries - the path to Python library binaries. On MacOS/Darwin, - you can also pass the path of the Python framework. Normally the - correct path(s) will be automatically deduced from ``version`` - and/or ``cmd-or-prefix``. - -condition - if specified, should be a set of Boost.Build - properties that are matched against the build configuration when - Boost.Build selects a Python configuration to use. See examples - below for details. - -extension-suffix - A string to append to the name of extension - modules before the true filename extension. You almost certainly - don't need to use this. Usually this suffix is only used when - targeting a Windows debug build of Python, and will be set - automatically for you based on the value of the - |python-debugging|_ feature. However, at least one Linux - distribution (Ubuntu Feisty Fawn) has a specially configured - `python-dbg`__ package that claims to use such a suffix. - -.. |python-debugging| replace:: ```` - -__ https://wiki.ubuntu.com/PyDbgBuilds - - -Examples --------- - -Note that in the examples below, case and *especially whitespace* are -significant. - -- If you have both python 2.5 and python 2.4 installed, - ``user-config.jam`` might contain:: - - using python : 2.5 ; # Make both versions of Python available - - using python : 2.4 ; # To build with python 2.4, add python=2.4 - # to your command line. - - The first version configured (2.5) becomes the default. To build - against python 2.4, add ``python=2.4`` to the ``bjam`` command line. - -- If you have python installed in an unusual location, you might - supply the path to the interpreter in the ``cmd-or-prefix`` - parameter:: - - using python : : /usr/local/python-2.6-beta/bin/python ; - -- If you have a separate build of Python for use with a particular - toolset, you might supply that toolset in the ``condition`` - parameter:: - - using python ; # use for most toolsets - - # Use with Intel C++ toolset - using python - : # version - : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix - : # includes - : # libraries - : intel # condition - ; - - -- If you have downloaded the Python sources and built both the - normal and the “\ `python debugging`_\ ” builds from source on - Windows, you might see:: - - using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; - using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d - : # includes - : # libs - : on ; - -- You can set up your user-config.jam so a bjam built under Windows - can build/test both Windows and Cygwin_ python extensions. Just pass - ``cygwin`` in the ``condition`` parameter - for the cygwin python installation:: - - # windows installation - using python ; - - # cygwin installation - using python : : c:\\cygwin\\bin\\python2.5 : : : cygwin ; - - when you put target-os=cygwin in your build request, it should build - with the cygwin version of python: [#flavor]_ - - bjam target-os=cygwin toolset=gcc - - This is supposed to work the other way, too (targeting windows - python with a Cygwin_ bjam) but it seems as though the support in - Boost.Build's toolsets for building that way is broken at the - time of this writing. - -- Note that because of `the way Boost.Build currently selects target - alternatives`__, you might have be very explicit in your build - requests. For example, given:: - - using python : 2.5 ; # a regular windows build - using python : 2.4 : : : : cygwin ; - - building with :: - - bjam target-os=cygwin - - will yield an error. Instead, you'll need to write:: - - bjam target-os=cygwin/python=2.4 - -.. _Cygwin: http://cygwin.com - -__ http://zigzag.cs.msu.su/boost.build/wiki/AlternativeSelection - -Choosing a Boost.Python Library Binary -====================================== - -If—instead of letting Boost.Build construct and link with the right -libraries automatically—you choose to use a pre-built Boost.Python -library, you'll need to think about which one to link with. The -Boost.Python binary comes in both static and dynamic flavors. Take -care to choose the right flavor for your application. [#naming]_ - -The Dynamic Binary ------------------- - -The dynamic library is the safest and most-versatile choice: - -- A single copy of the library code is used by all extension - modules built with a given toolset. [#toolset-specific]_ - -- The library contains a type conversion registry. Because one - registry is shared among all extension modules, instances of a - class exposed to Python in one dynamically-loaded extension - module can be passed to functions exposed in another such module. - -The Static Binary ------------------ - -It might be appropriate to use the static Boost.Python library in -any of the following cases: - -- You are extending_ python and the types exposed in your - dynamically-loaded extension module don't need to be used by any - other Boost.Python extension modules, and you don't care if the - core library code is duplicated among them. - -- You are embedding_ python in your application and either: - - - You are targeting a Unix variant OS other than MacOS or AIX, - where the dynamically-loaded extension modules can “see” the - Boost.Python library symbols that are part of the executable. - - - Or, you have statically linked some Boost.Python extension - modules into your application and you don't care if any - dynamically-loaded Boost.Python extension modules are able to - use the types exposed by your statically-linked extension - modules (and vice-versa). - -``#include`` Issues -=================== - -1. If you should ever have occasion to ``#include "python.h"`` - directly in a translation unit of a program using Boost.Python, - use ``#include "boost/python/detail/wrap_python.hpp"`` instead. - It handles several issues necessary for use with Boost.Python, - one of which is mentioned in the next section. - -2. Be sure not to ``#include`` any system headers before - ``wrap_python.hpp``. This restriction is actually imposed by - Python, or more properly, by Python's interaction with your - operating system. See - http://docs.python.org/ext/simpleExample.html for details. - -.. _python-debugging: -.. _python debugging: - -Python Debugging Builds -======================= - -Python can be built in a special “python debugging” configuration -that adds extra checks and instrumentation that can be very useful -for developers of extension modules. The data structures used by -the debugging configuration contain additional members, so **a -Python executable built with python debugging enabled cannot be -used with an extension module or library compiled without it, and -vice-versa.** - -Since pre-built “python debugging” versions of the Python -executable and libraries are not supplied with most distributions -of Python, [#get-debug-build]_ and we didn't want to force our users -to build them, Boost.Build does not automatically enable python -debugging in its ``debug`` build variant (which is the default). -Instead there is a special build property called -``python-debugging`` that, when used as a build property, will -define the right preprocessor symbols and select the right -libraries to link with. - -On unix-variant platforms, the debugging versions of Python's data -structures will only be used if the symbol ``Py_DEBUG`` is defined. -On many windows compilers, when extension modules are built with -the preprocessor symbol ``_DEBUG``, Python defaults to force -linking with a special debugging version of the Python DLL. Since -that symbol is very commonly used even when Python is not present, -Boost.Python temporarily undefines _DEBUG when Python.h -is #included from ``boost/python/detail/wrap_python.hpp`` - unless -``BOOST_DEBUG_PYTHON`` is defined. The upshot is that if you want -“python debugging”and you aren't using Boost.Build, you should make -sure ``BOOST_DEBUG_PYTHON`` is defined, or python debugging will be -suppressed. - -Testing Boost.Python -==================== - -To run the full test suite for Boost.Python, invoke ``bjam`` in the -``libs/python/test`` subdirectory of your Boost distribution. - -Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users -======================================================= - -If you are using a version of Python prior to 2.4.1 with a MinGW -prior to 3.0.0 (with binutils-2.13.90-20030111-1), you will need to -create a MinGW-compatible version of the Python library; the one -shipped with Python will only work with a Microsoft-compatible -linker. Follow the instructions in the “Non-Microsoft” section of -the “Building Extensions: Tips And Tricks” chapter in `Installing -Python Modules`__ to create ``libpythonXX.a``, where ``XX`` -corresponds to the major and minor version numbers of your Python -installation. - -__ http://www.python.org/doc/current/inst/index.html - ------------------------------ - -.. [#2.2] Note that although we tested earlier versions of - Boost.Python with Python 2.2, and we don't *think* we've done - anything to break compatibility, this release of Boost.Python - may not have been tested with versions of Python earlier than - 2.4, so we're not 100% sure that python 2.2 and 2.3 are - supported. - -.. [#naming] Information about how to identify the - static and dynamic builds of Boost.Python: - - * `on Windows`__ - * `on Unix variants`__ - - __ ../../../more/getting_started/windows.html#library-naming - __ ../../../more/getting_started/unix-variants.html#library-naming - -.. [#toolset-specific] Because of the way most \*nix platforms - share symbols among dynamically-loaded objects, I'm not certain - that extension modules built with different compiler toolsets - will always use different copies of the Boost.Python library - when loaded into the same Python instance. Not using different - libraries could be a good thing if the compilers have compatible - ABIs, because extension modules built with the two libraries - would be interoperable. Otherwise, it could spell disaster, - since an extension module and the Boost.Python library would - have different ideas of such things as class layout. I would - appreciate someone doing the experiment to find out what - happens. - -.. [#overwrite] ``configure`` overwrites the existing - ``user-config.jam`` in your home directory - (if any) after making a backup of the old version. - -.. [#flavor] Note that the ``cygwin`` feature is - different from the ``cygwin`` subfeature of the ``gcc`` - toolset, and you might need handle both explicitly if you also - have a MinGW GCC installed. - -.. [#home-dir] Windows users, your home directory can be - found by typing:: - - ECHO %HOMEDRIVE%%HOMEPATH% - - into a `command prompt`_ window. - -.. [#get-debug-build] On Unix and similar platforms, a debugging - python and associated libraries are built by adding - ``--with-pydebug`` when configuring the Python build. On - Windows, the debugging version of Python is generated by - the "Win32 Debug" target of the Visual Studio project in the - PCBuild subdirectory of a full Python source code distribution. diff --git a/doc/configuration.qbk b/doc/configuration.qbk new file mode 100644 index 0000000000..49b97de072 --- /dev/null +++ b/doc/configuration.qbk @@ -0,0 +1,83 @@ +[chapter Configuration + [quickbook 1.7] + [authors [Abrahams, David]] + [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] + [id configuration] +] + + +[section Configuration] + +[section Introduction] +[*Boost.Python] uses several configuration macros in ``, as well as configuration macros meant to be supplied by the application. These macros are documented here. + +[endsect] +[section Application Defined Macros] + +These are the macros that may be defined by an application using Boost.Python. Note that if you extend a strict interpretation of the C++ standard to cover dynamic libraries, using different values of these macros when compiling different libraries (including extension modules and the Boost.Python library itself) is a violation of the [link odr ODR]. However, we know of no C++ implementations on which this particular violation is detectable or causes any problems. + +[table + [[Macro][Default][Meaning]] + [[BOOST_PYTHON_MAX_ARITY] + [15] + [The maximum arity of any function, member function, + or constructor to be wrapped, invocation of a + Boost.Python function wich is specified as taking + arguments x1, x2,...Xn. This includes, in particular, + callback mechanisms such as object::operator()(...) or call_method(... ).]] + [[BOOST_PYTHON_MAX_BASES][10] + [The maximum number of template arguments to the + `bases<...>` class template, which is used to specify + the bases of a wrapped C++ class..]] + [[BOOST_PYTHON_STATIC_MODULE] + [ /not defined/ ] + [If defined, prevents your module initialization + function from being treated as an exported symbol + on platforms which support that distinction in-code]] + [[BOOST_PYTHON_ENABLE_CDECL] + [ /not defined/ ] + [If defined, allows functions using the `__cdecl` + calling convention to be wrapped.]] + [[BOOST_PYTHON_ENABLE_STDCALL] + [ /not defined/ ] + [If defined, allows functions using the `__stdcall` + calling convention to be wrapped.]] + [[BOOST_PYTHON_ENABLE_FASTCALL] + [ /not defined/ ] + [If defined, allows functions using the `__fastcall` + calling convention to be wrapped.]] +] +[endsect] +[section Library Defined Defined Macros] +These macros are defined by *Boost.Python* and are implementation details of interest only to implementors and those porting to new platforms. +[table + [[Macro][Default][Meaning]] + [[BOOST_PYTHON_TYPE_ID_NAME][ /not defined/ ] + [If defined, this indicates that the type_info comparison across + shared library boundaries does not work on this platform. + In other words, if shared-lib-1 passes `typeid(T)` to a function + in shared-lib-2 which compares it to `typeid(T)`, that comparison + may return `false`. If this macro is #defined, Boost.Python uses + and compares `typeid(T).name()` instead of using and comparing + the `std::type_info` objects directly.]] + [[BOOST_PYTHON_NO_PY_SIGNATURES][ /not defined/ ] + [If defined for a module no pythonic signatures are generated for + the docstrings of the module functions, and no python type is + associated with any of the converters registered by the module. + This also reduces the binary size of the module by about 14% + (gcc compiled). + If defined for the boost_python runtime library, the default for + the `docstring_options.enable_py_signatures()` is set to `false`.]] + [[BOOST_PYTHON_SUPPORTS_PY_SIGNATURES] + [ /defined/ if `BOOST_PYTHON_NO_PY_SIGNATURES` is /undefined/ ] + [This macro is defined to enable a smooth transition from older + Boost.Python versions which do not support pythonic signatures. + For example usage see here.]] + [[BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE][ /not defined/ ] + [If defined the python type of `__init__` method "self" parameters + is properly generated, otherwise object is used. It is undefined by + default because it increases the binary size of the module by about + 14% (gcc compiled).]] +] +[endsect] +[endsect] diff --git a/doc/fabscript b/doc/fabscript new file mode 100644 index 0000000000..bd8be7a363 --- /dev/null +++ b/doc/fabscript @@ -0,0 +1,83 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from faber.tools.xslt import xsltflags +from faber.tools.boost import quickbook, boostbook +from faber.artefacts import html +from glob import glob as G +from os import makedirs +from os.path import relpath, dirname, exists +from shutil import copyfile + + +def glob(pattern): + prefix = srcdir + '/' + p = len(prefix)+1 + return [f[p:] for f in G(prefix + pattern)] + + +class make_html(action): + + def __init__(self): + action.__init__(self, 'make_html', self.process) + + def map(self, fs): + return boostbook.html.map(fs) + + def process(self, target, source): + boostbook.html(target, source[0:1]) + for s in source[1:]: + t = target[0]._filename + relpath(s._filename, srcdir) + d = dirname(t) + if not exists(d): + makedirs(d) + copyfile(s._filename, t) + + +sphinx_build = action('sphinx-build', 'sphinx-build -b html $(>) $(<)') +rst2html = action('rst2html', 'rst2html --trim-footnote-reference-space --footnote-references=superscript --stylesheet=$(>:D)/rst.css $(>) $(<)') + +python_bbk = rule(quickbook.process, 'python.bbk', 'python.qbk', + dependencies=['release_notes.qbk', + 'building.qbk', + 'configuration.qbk', + 'suport.qbk', + 'faq.qbk', + 'glossary.qbk']) +tutorial_bbk = rule(quickbook.process, 'tutorial.bbk', 'tutorial.qbk') +reference_bbk = rule(quickbook.process, 'reference.bbk', 'reference.qbk') + +python_db = rule(boostbook.db, 'python.db', python_bbk) +tutorial_db = rule(boostbook.db, 'tutorial.db', tutorial_bbk) +reference_db = rule(boostbook.db, 'reference.db', reference_bbk) + +python = html.dir(make_html(), 'html', [python_db, 'boostbook.css'] + glob('/images/*.*') + glob('/images/callouts/*.*'), + features=xsltflags('--stringparam generate.toc "library nop; chaper toc; section toc;"', + '--stringparam html.stylesheet boostbook.css', + '--stringparam boost.image.src images/bpl.png', + '--stringparam boost.graphics.root images/', + '--stringparam boost.defaults none', + '--param toc.max.depth 3', + '--param toc.section.depth 2', + '--param chunk.section.depth 1')) +tutorial = html.dir(boostbook.html, 'html/tutorial', tutorial_db, dependencies=[python], + features=xsltflags('--stringparam html.stylesheet ../boostbook.css', + '--stringparam boost.image.src ../images/bpl.png', + '--stringparam boost.graphics.root ../images/')) +reference = html.dir(boostbook.html, 'html/reference', reference_db, dependencies=[python], + features=xsltflags('--stringparam html.stylesheet ../boostbook.css', + '--stringparam boost.image.src ../images/bpl.png', + '--stringparam boost.graphics.root ../images/')) +numpy = rule(sphinx_build, 'html/numpy', 'numpy', attrs=always, dependencies=[python]) + +article = rule(rst2html, 'html/article.html', 'article.rst') + +html = alias('html', [python, tutorial, reference, numpy, article]) + +default = html diff --git a/doc/faq.qbk b/doc/faq.qbk new file mode 100644 index 0000000000..fce67dce0a --- /dev/null +++ b/doc/faq.qbk @@ -0,0 +1,736 @@ +[chapter Frequently Asked Questions (FAQs) + [quickbook 1.7] + [id faq] +] + +[section How can I wrap a function which takes a function pointer as an argument?] + +If what you're trying to do is something like this: +`` + typedef boost::function funcptr; + + void foo(funcptr fp) + { + fp("hello,world!"); + } + + BOOST_PYTHON_MODULE(test) + { + def("foo",foo); + } +`` + +And then: + +`` +>>> def hello(s): +... print s +... +>>> foo(hello) +hello, world! +`` +The short answer is: "you can't". This is not a +Boost.Python limitation so much as a limitation of C++. The +problem is that a Python function is actually data, and the only +way of associating data with a C++ function pointer is to store it +in a static variable of the function. The problem with that is +that you can only associate one piece of data with every C++ +function, and we have no way of compiling a new C++ function +on-the-fly for every Python function you decide to pass +to `foo`. In other words, this could work if the C++ +function is always going to invoke the /same/ Python +function, but you probably don't want that. + +If you have the luxury of changing the C++ code you're +wrapping, pass it an `object` instead and call that; +the overloaded function call operator will invoke the Python +function you pass it behind the `object`. + +[endsect] +[section I'm getting the "attempt to return dangling reference" error. + What am I doing wrong?] + +That exception is protecting you from causing a nasty crash. It usually +happens in response to some code like this: +`` + period const &get_floating_frequency() const + { + return boost::python::call_method( + m_self,"get_floating_frequency"); + } +`` +And you get: +`` + ReferenceError: Attempt to return dangling reference to object of type: + class period +`` + +In this case, the Python method invoked by `call_method` +constructs a new Python object. You're trying to return a reference to a +C++ object (an instance of `class period`) contained within +and owned by that Python object. Because the called method handed back a +brand new object, the only reference to it is held for the duration of +`get_floating_frequency()` above. When the function returns, +the Python object will be destroyed, destroying the instance of +`class period`, and leaving the returned reference dangling. +That's already undefined behavior, and if you try to do anything with +that reference you're likely to cause a crash. Boost.Python detects this +situation at runtime and helpfully throws an exception instead of letting +you do that. + +[endsect] +[section Is `return_internal_reference` efficient?] + +[*Q:] /I have an object composed of 12 doubles. A `const&` to +this object is returned by a member function of another class. From the +viewpoint of using the returned object in Python I do not care if I get +a copy or a reference to the returned object. In Boost.Python I have the +choice of using `copy_const_reference` or `return_internal_reference`. +Are there considerations that would lead me to prefer one over the other, +such as size of generated code or memory overhead?/ + +[*A:] `copy_const_reference` will make an instance with storage +for one of your objects, `size = base_size + 12 * sizeof(double)`. +`return_internal_reference` will make an instance with storage for a +pointer to one of your objects, `size = base_size + sizeof(void*)`. +However, it will also create a weak reference object which goes in the +source object's weakreflist and a special callback object to manage the +lifetime of the internally-referenced object. My guess? +`copy_const_reference` is your friend here, resulting in less overall +memory use and less fragmentation, also probably fewer total +cycles. + +[endsect] +[section How can I wrap functions which take C++ containers as arguments?] + +Ralf W. Grosse-Kunstleve provides these notes: + +# Using the regular `class_<>` wrapper: + `` + class_ >("std_vector_double") + .def(...) + ... + ; + `` + This can be moved to a template so that several types (`double`, `int`, + `long`, etc.) can be wrapped with the same code. This technique is used + in the file `scitbx/include/scitbx/array_family/boost_python/flex_wrapper.h` + in the "scitbx" package. The file could easily be modified for + wrapping `std::vector<>` instantiations. + This type of C++/Python binding is most suitable for containers + that may contain a large number of elements (>10000). + +# Using custom rvalue converters. Boost.Python "rvalue converters" + match function signatures such as: + `` + void foo(std::vector const &array); // pass by const-reference + void foo(std::vector array); // pass by value + `` + Some custom rvalue converters are implemented in the file + `scitbx/include/scitbx/boost_python/container_conversions.h` + This code can be used to convert from C++ container types such as + `std::vector<>` or `std::list<>` to Python tuples and vice + versa. A few simple examples can be found in the file + `scitbx/array_family/boost_python/regression_test_module.cpp` + Automatic C++ container <-> Python tuple conversions are most + suitable for containers of moderate size. These converters generate + significantly less object code compared to alternative 1 above. + +A disadvantage of using alternative 2 is that operators such as +arithmetic +,-,*,/,% are not available. It would be useful to have custom +rvalue converters that convert to a "math_array" type instead of tuples. +This is currently not implemented but is possible within the framework of +Boost.Python V2 as it will be released in the next couple of weeks. [ed.: +this was posted on 2002/03/10] + +It would also be useful to also have "custom lvalue converters" such +as `std::vector<>` <-> Python list. These converters would +support the modification of the Python list from C++. For example: + +C++: +`` + void foo(std::vector &array) + { + for(std::size_t i=0;i<array.size();i++) { + array[i] *= 2; + } + } +`` +Python: [python] +`` + >>> l = [1, 2, 3] + >>> foo(l) + >>> print l + [2, 4, 6] +`` +Custom lvalue converters require changes to the Boost.Python core library +and are currently not available. + +P.S.: + +The "scitbx" files referenced above are available via anonymous +CVS: +`` + cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login + cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx +`` + +[endsect] +[section fatal error C1204:Compiler limit:internal structure overflow] + +[*Q:] /I get this error message when compiling a large source file. What can I do?/ + +[*A:] You have two choices: + +# Upgrade your compiler (preferred) + +# Break your source file up into multiple translation units. + + `my_module.cpp`: [c++] + + `` + ... + void more_of_my_module(); + BOOST_PYTHON_MODULE(my_module) + { + def("foo", foo); + def("bar", bar); + ... + more_of_my_module(); + } + `` + `more_of_my_module.cpp`: + `` + void more_of_my_module() + { + def("baz", baz); + ... + } + `` + If you find that a `class_<...>` declaration + can't fit in a single source file without triggering the error, you + can always pass a reference to the `class_` object to a + function in another source file, and call some of its member + functions (e.g. `.def(...)`) in the auxilliary source + file: + + `more_of_my_class.cpp`: + `` + void more_of_my_class(class<my_class>& x) + { + x + .def("baz", baz) + .add_property("xx", &my_class::get_xx, &my_class::set_xx) + ; + ... + } + `` + +[endsect] +[section How do I debug my Python extensions?] + +Greg Burley gives the following answer for Unix GCC users: + +[:Once you have created a boost python extension for your c++ library or + class, you may need to debug the code. Afterall this is one of the + reasons for wrapping the library in python. An expected side-effect or + benefit of using BPL is that debugging should be isolated to the c++ + library that is under test, given that python code is minimal and + boost::python either works or it doesn't. (ie. While errors can occur + when the wrapping method is invalid, most errors are caught by the + compiler ;-). + + The basic steps required to initiate a gdb session to debug a c++ + library via python are shown here. Note, however that you should start + the gdb session in the directory that contains your BPL my_ext.so + module. + + `` + (gdb) target exec python + (gdb) run + >>> from my_ext import * + >>> [C-c] + (gdb) break MyClass::MyBuggyFunction + (gdb) cont + >>> pyobj = MyClass() + >>> pyobj.MyBuggyFunction() + Breakpoint 1, MyClass::MyBuggyFunction ... + Current language: auto; currently c++ + (gdb) do debugging stuff + `` +] + +Greg's approach works even better using Emacs' "gdb" +command, since it will show you each line of source as you step through it. + +On *Windows*, my favorite debugging solution is the debugger that +comes with Microsoft Visual C++ 7. This debugger seems to work with code +generated by all versions of Microsoft and Metrowerks toolsets; it's rock +solid and "just works" without requiring any special tricks from the +user. + +Raoul Gough has provided the following for gdb on Windows: + +[:gdb support for Windows DLLs has improved lately, so it is + now possible to debug Python extensions using a few + tricks. Firstly, you will need an up-to-date gdb with support + for minimal symbol extraction from a DLL. Any gdb from version 6 + onwards, or Cygwin gdb-20030214-1 and onwards should do. A + suitable release will have a section in the gdb.info file under + Configuration - Native - Cygwin Native - + Non-debug DLL symbols. Refer to that info section for more + details of the procedures outlined here. + + Secondly, it seems necessary to set a breakpoint in the + Python interpreter, rather than using ^C to break execution. A + good place to set this breakpoint is PyOS_Readline, which will + stop execution immediately before reading each interactive + Python command. You have to let Python start once under the + debugger, so that it loads its own DLL, before you can set the + breakpoint: + + `` + $ gdb python + GNU gdb 2003-09-02-cvs (cygwin-special) + [...] + + (gdb) run + Starting program: /cygdrive/c/Python22/python.exe + Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32 + Type "help", "copyright", "credits" or "license" for more information. + >>> ^Z + + + Program exited normally. + (gdb) break *&PyOS_Readline + Breakpoint 1 at 0x1e04eff0 + (gdb) run + Starting program: /cygdrive/c/Python22/python.exe + Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32 + Type "help", "copyright", "credits" or "license" for more information. + + Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline () + from /cygdrive/c/WINNT/system32/python22.dll + (gdb) cont + Continuing. + >>> from my_ext import * + + Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline () + from /cygdrive/c/WINNT/system32/python22.dll + (gdb) # my_ext now loaded (with any debugging symbols it contains) + `` +] + +[h2 Debugging extensions through Boost.Build] + +If you are launching your extension module tests with _bb_ using the +`boost-python-runtest` rule, you can ask it to launch your +debugger for you by adding "--debugger=/debugger/" to your bjam +command-line: +`` + bjam -sTOOLS=vc7.1 "--debugger=devenv /debugexe" test + bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test +`` +It can also be extremely useful to add the `-d+2` option when +you run your test, because Boost.Build will then show you the exact +commands it uses to invoke it. This will invariably involve setting up +PYTHONPATH and other important environment variables such as +LD_LIBRARY_PATH which may be needed by your debugger in order to get +things to work right. + +[endsect] +[section Why doesn't my `*=` operator work?] + +[*Q:] ['I have exported my class to python, with many overloaded +operators. it works fine for me except the `*=` +operator. It always tells me "can't multiply sequence with non int +type". If I use `p1.__imul__(p2)` instead of +`p1 *= p2`, it successfully executes my code. What's +wrong with me?] + +[*A:] There's nothing wrong with you. This is a bug in Python + 2.2. You can see the same effect in Pure Python (you can learn a lot + about what's happening in Boost.Python by playing with new-style + classes in Pure Python). +`` +>>> class X(object): +... def __imul__(self, x): +... print 'imul' +... +>>> x = X() +>>> x *= 1 +`` +To cure this problem, all you need to do is upgrade your Python to +version 2.2.1 or later. + +[endsect] +[section Does Boost.Python work with Mac OS X?] + +It is known to work under 10.2.8 and 10.3 using +Apple's gcc 3.3 compiler: +``gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1493)`` +Under 10.2.8 get the August 2003 gcc update (free at [@http://connect.apple.com]). +Under 10.3 get the Xcode Tools v1.0 (also free). + +Python 2.3 is required. The Python that ships with 10.3 is +fine. Under 10.2.8 use these commands to install Python +as a framework: +``./configure --enable-framework +make +make frameworkinstall`` + +The last command requires root privileges because the target +directory is `/Library/Frameworks/Python.framework/Versions/2.3`. +However, the installation does not interfere with the Python +version that ships with 10.2.8. + +It is also crucial to increase the `stacksize` before +starting compilations, e.g.: +``limit stacksize 8192k`` +If the `stacksize` is too small the build might crash with +internal compiler errors. + +Sometimes Apple's compiler exhibits a bug by printing an error +like the following while compiling a +`boost::python::class_` +template instantiation: +`` + .../inheritance.hpp:44: error: cannot + dynamic_cast `p' (of type `struct cctbx::boost_python::::add_pair* + ') to type `void*' (source type is not polymorphic) +`` + +We do not know a general workaround, but if the definition of +`your_type` can be modified the following was found +to work in all cases encountered so far: +`` + struct your_type + { + // before defining any member data + #if defined(__MACH__) && defined(__APPLE_CC__) && __APPLE_CC__ == 1493 + bool dummy_; + #endif + // now your member data, e.g. + double x; + int j; + // etc. + }; +`` +[endsect] +[section How can I find the existing PyObject that holds a C++ object?] + +[: "I am wrapping a function that always returns a pointer to an + already-held C++ object."] + +One way to do that is to hijack the mechanisms used for wrapping a class +with virtual functions. If you make a wrapper class with an initial +PyObject* constructor argument and store that PyObject* as "self", you +can get back to it by casting down to that wrapper type in a thin wrapper +function. For example: +`` + class X { X(int); virtual ~X(); ... }; + X* f(); // known to return Xs that are managed by Python objects + + + // wrapping code + + struct X_wrap : X + { + X_wrap(PyObject* self, int v) : self(self), X(v) {} + PyObject* self; + }; + + handle<> f_wrap() + { + X_wrap* xw = dynamic_cast(f()); + assert(xw != 0); + return handle<>(borrowed(xw->self)); + } + + ... + + def("f", f_wrap()); + class_("X", init()) + ... + ; +`` + +Of course, if X has no virtual functions you'll have to use +`static_cast` instead of `dynamic_cast` with no +runtime check that it's valid. This approach also only works if the +`X` object was constructed from Python, because +`X`\ s constructed from C++ are of course never +`X_wrap` objects. + +Another approach to this requires you to change your C++ code a bit; +if that's an option for you it might be a better way to go. work we've +been meaning to get to anyway. When a `shared_ptr` is +converted from Python, the shared_ptr actually manages a reference to the +containing Python object. When a shared_ptr is converted back to +Python, the library checks to see if it's one of those "Python object +managers" and if so just returns the original Python object. So you could +just write `object(p)` to get the Python object back. To +exploit this you'd have to be able to change the C++ code you're wrapping +so that it deals with shared_ptr instead of raw pointers. + +There are other approaches too. The functions that receive the Python +object that you eventually want to return could be wrapped with a thin +wrapper that records the correspondence between the object address and +its containing Python object, and you could have your f_wrap function +look in that mapping to get the Python object out. + +[endsect] +[section How can I wrap a function which needs to take ownership of a raw pointer?] + +[*Q:] Part of an API that I'm wrapping goes something like this: + +`` + struct A {}; struct B { void add( A* ); } + where B::add() takes ownership of the pointer passed to it. +`` + +However: + +`` + a = mod.A() + b = mod.B() + b.add( a ) + del a + del b + # python interpreter crashes + # later due to memory corruption. +`` + +Even binding the lifetime of a to b via `with_custodian_and_ward` doesn't prevent +the python object a from ultimately trying to delete the object it's pointing to. +Is there a way to accomplish a 'transfer-of-ownership' of a wrapped C++ object? + +--Bruce Lowery + +Yes: Make sure the C++ object is held by auto_ptr: +`` + class_ >("A") + ... + ; +`` +Then make a thin wrapper function which takes an auto_ptr parameter: +`` + void b_insert(B &b, std::auto_ptr a) + { + b.insert(a.get()); + a.release(); + } +`` +Wrap that as B.add. Note that pointers returned via `manage_new_object` +will also be held by `auto_ptr`, so this transfer-of-ownership +will also work correctly. + +[endsect] +[section Compilation takes too much time and eats too much memory! + What can I do to make it faster?] + +Please refer to the `Reducing Compiling Time` section in the _tutorial_. + +[endsect] +[section How do I create sub-packages using Boost.Python?] + +Please refer to the `Creating Packages` section in the _tutorial_. + +[endsect] +[section error C2064: term does not evaluate to a function taking 2 arguments] + +/Niall Douglas provides these notes:/ + +If you see Microsoft Visual C++ 7.1 (MS Visual Studio .NET 2003) issue +an error message like the following it is most likely due to a bug +in the compiler: +`` + boost\boost\python\detail\invoke.hpp(76): + error C2064: term does not evaluate to a function taking 2 arguments" +`` +This message is triggered by code like the following: +`` + #include + + using namespace boost::python; + + class FXThread + { + public: + bool setAutoDelete(bool doso) throw(); + }; + + void Export_FXThread() + { + class_< FXThread >("FXThread") + .def("setAutoDelete", &FXThread::setAutoDelete) + ; + } +`` +The bug is related to the `throw()` modifier. +As a workaround cast off the modifier. E.g.: +`` + .def("setAutoDelete", (bool (FXThread::*)(bool)) &FXThread::setAutoDelete) +`` +(The bug has been reported to Microsoft.) + +[endsect] +[section How can I automatically convert my custom string type to and from a Python string?] + +/Ralf W. Grosse-Kunstleve provides these notes:/ + +Below is a small, self-contained demo extension module that shows +how to do this. Here is the corresponding trivial test: +`` + import custom_string + assert custom_string.hello() == "Hello world." + assert custom_string.size("california") == 10 +`` +If you look at the code you will find: + +* A custom `to_python` converter (easy): + `custom_string_to_python_str` + +*A custom lvalue converter (needs more code): + `custom_string_from_python_str` + +The custom converters are registered in the global Boost.Python +registry near the top of the module initialization function. Once +flow control has passed through the registration code the automatic +conversions from and to Python strings will work in any module +imported in the same process. + +`` + #include + #include + #include + + namespace sandbox { namespace { + + class custom_string + { + public: + custom_string() {} + custom_string(std::string const &value) : value_(value) {} + std::string const &value() const { return value_; } + private: + std::string value_; + }; + + struct custom_string_to_python_str + { + static PyObject* convert(custom_string const &s) + { + return boost::python::incref(boost::python::object(s.value()).ptr()); + } + }; + + struct custom_string_from_python_str + { + custom_string_from_python_str() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PyString_Check(obj_ptr)) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + const char* value = PyString_AsString(obj_ptr); + if (value == 0) boost::python::throw_error_already_set(); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage*) + data)->storage.bytes; + new (storage) custom_string(value); + data->convertible = storage; + } + }; + + custom_string hello() { return custom_string("Hello world."); } + + std::size_t size(custom_string const &s) { return s.value().size(); } + + void init_module() + { + using namespace boost::python; + + boost::python::to_python_converter< + custom_string, + custom_string_to_python_str>(); + + custom_string_from_python_str(); + + def("hello", hello); + def("size", size); + } + + }} // namespace sandbox:: + + BOOST_PYTHON_MODULE(custom_string) + { + sandbox::init_module(); + } +`` +[endsect] +[section Why is my automatic to-python conversion not being found?] + +/Niall Douglas provides these notes:/ + +If you define custom converters similar to the ones +shown above the `def_readonly()` and `def_readwrite()` +member functions provided by `boost::python::class_` for +direct access to your member data will not work as expected. +This is because `def_readonly("bar",&foo::bar)` is +equivalent to: + +`` + .add_property("bar", make_getter(&foo::bar, return_internal_reference())) +`` +Similarly, `def_readwrite("bar",&foo::bar)` is +equivalent to: + +`` + .add_property("bar", make_getter(&foo::bar, return_internal_reference()), + make_setter(&foo::bar, return_internal_reference()) +`` +In order to define return value policies compatible with the +custom conversions replace `def_readonly()` and +`def_readwrite()` by `add_property()`. E.g.: + +`` + .add_property("bar", make_getter(&foo::bar, return_value_policy()), + make_setter(&foo::bar, return_value_policy())) +`` + +[endsect] +[section Is Boost.Python thread-aware/compatible with multiple interpreters?] + +/Niall Douglas provides these notes:/ + +The quick answer to this is: no. + +The longer answer is that it can be patched to be so, but it's +complex. You will need to add custom lock/unlock wrapping of every +time your code enters Boost.Python (particularly every virtual +function override) plus heavily modify +`boost/python/detail/invoke.hpp` with custom unlock/lock +wrapping of every time Boost.Python enters your code. You must +furthermore take care to /not/ unlock/lock when Boost.Python +is invoking iterator changes via `invoke.hpp`. + +There is a patched `invoke.hpp` posted on the C++-SIG +mailing list archives and you can find a real implementation of all +the machinery necessary to fully implement this in the TnFOX +project at [@http://sourceforge.net/projects/tnfox/ this] +SourceForge project location. + +[endsect] \ No newline at end of file diff --git a/doc/glossary.qbk b/doc/glossary.qbk new file mode 100644 index 0000000000..eaea9709f3 --- /dev/null +++ b/doc/glossary.qbk @@ -0,0 +1,38 @@ +[chapter Glossary + [quickbook 1.7] + [id glossary] +] + +[variablelist +[[arity [#arity]] + [The number of argumnts accepted by a function or member function. + Unless otherwise specified, the hidden `this` argument to member + functions is not counted when specifying arity.]] +[[ntbs [#ntbs]] + [Null-Terminated Byte String, or 'C'-string. C++ string literals are *ntbs*\ es. + An *ntbs* must never be null.]] +[[raise [#raise]] + [Exceptions in Python are "raised", not "thrown", as they are in C++. + When this documentation says that some Python exception is "raised" in + the context of C++ code, it means that the corresponding Python exception + is set via the [@http://www.python.org/doc/current/api/exceptionHandling.html Python/'C' API], + and `throw_error_already_set()` is called.]] +[[POD [#pod]] + [A technical term from the C++ standard. Short for "Plain Ol'Data": + A POD-struct is an aggregate class that has no non-static data members + of type pointer to member, non-POD-struct, non-POD-union (or array of such + types) or reference, and has no user-defined copy assign- ment operator and + no user-defined destructor. Similarly, a POD-union is an aggregate union that + has no non-static data members of type pointer to member, non-POD-struct, + non-POD-union (or array of such types) or reference, and has no + user-defined copy assignment operator and no user-defined destructor. A + POD class is a class that is either a POD-struct or a POD-union. An + aggregate is an array or a class (clause 9) with no user-declared + constructors (12.1), no private or protected non-static data members + (clause 11), no base classes (clause 10), and no virtual functions + (10.3).]] +[[ODR [#odr]] + [The "One Definition Rule", which says that any entity in a C++ program must have + the same definition in all translation units (object files) which make up a program.]] +] + diff --git a/doc/html/boost.css b/doc/html/boost.css new file mode 100644 index 0000000000..986c4050fa --- /dev/null +++ b/doc/html/boost.css @@ -0,0 +1,66 @@ +/*============================================================================= + Copyright 2002 William E. Kempf + Distributed under the Boost Software License, Version 1.0. (See accompany- + ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +H1 +{ + FONT-SIZE: 200%; + COLOR: #00008B; +} +H2 +{ + FONT-SIZE: 150%; +} +H3 +{ + FONT-SIZE: 125%; +} +H4 +{ + FONT-SIZE: 108%; +} +BODY +{ + FONT-SIZE: 100%; + BACKGROUND-COLOR: #ffffff; + COLOR: #000000; +} +PRE +{ + MARGIN-LEFT: 2em; + FONT-FAMILY: Courier, + monospace; +} +CODE +{ + FONT-FAMILY: Courier, + monospace; +} +CODE.as_pre +{ + white-space: pre; +} +.index +{ + TEXT-ALIGN: left; +} +.page-index +{ + TEXT-ALIGN: left; +} +.definition +{ + TEXT-ALIGN: left; +} +.footnote +{ + FONT-SIZE: 66%; + VERTICAL-ALIGN: super; + TEXT-DECORATION: none; +} +.function-semantics +{ + CLEAR: left; +} \ No newline at end of file diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css new file mode 100644 index 0000000000..d42b3c022f --- /dev/null +++ b/doc/html/boostbook.css @@ -0,0 +1,700 @@ + +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= +Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= +Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= +Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 9pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= +Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= +Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= +Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= +Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= +Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= +Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= +Table of contents +=============================================================================*/ + + div.toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + +/*============================================================================= +Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= +Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= +Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= +Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= +Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Links */ + a, a .keyword, a .identifier, a .special, a .preprocessor + a .char, a .comment, a .string, a .number + { + color: #005a9c; + } + + a:visited, a:visited .keyword, a:visited .identifier, + a:visited .special, a:visited .preprocessor a:visited .char, + a:visited .comment, a:visited .string, a:visited .number + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= +Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; +} + +sup { +bottom: 1ex; +} + +sub { +top: .5ex; +} + +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ diff --git a/doc/html/docutils.css b/doc/html/docutils.css new file mode 100644 index 0000000000..620cf86102 --- /dev/null +++ b/doc/html/docutils.css @@ -0,0 +1,275 @@ +/* +:Author: David Goodger +:Contact: goodger@python.org +:Date: $Date$ +:Revision: $Revision$ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin-left: 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left { + clear: left } + +img.align-right { + clear: right } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid 1px black; + margin-left: 1px } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +ul.auto-toc { + list-style-type: none } diff --git a/doc/tutorial/doc/html/images/alert.png b/doc/html/images/alert.png old mode 100755 new mode 100644 similarity index 100% rename from doc/tutorial/doc/html/images/alert.png rename to doc/html/images/alert.png diff --git a/doc/html/images/blank.png b/doc/html/images/blank.png new file mode 100644 index 0000000000..764bf4f0c3 Binary files /dev/null and b/doc/html/images/blank.png differ diff --git a/doc/html/images/boost.png b/doc/html/images/boost.png new file mode 100644 index 0000000000..b4d51fcd5c Binary files /dev/null and b/doc/html/images/boost.png differ diff --git a/doc/html/images/callouts/1.png b/doc/html/images/callouts/1.png new file mode 100644 index 0000000000..6003ad3af4 Binary files /dev/null and b/doc/html/images/callouts/1.png differ diff --git a/doc/html/images/callouts/1.svg b/doc/html/images/callouts/1.svg new file mode 100644 index 0000000000..e2e87dc526 --- /dev/null +++ b/doc/html/images/callouts/1.svg @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/10.png b/doc/html/images/callouts/10.png new file mode 100644 index 0000000000..0426f516a4 Binary files /dev/null and b/doc/html/images/callouts/10.png differ diff --git a/doc/html/images/callouts/10.svg b/doc/html/images/callouts/10.svg new file mode 100644 index 0000000000..4740f587bd --- /dev/null +++ b/doc/html/images/callouts/10.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/11.png b/doc/html/images/callouts/11.png new file mode 100644 index 0000000000..821afc4fa8 Binary files /dev/null and b/doc/html/images/callouts/11.png differ diff --git a/doc/html/images/callouts/11.svg b/doc/html/images/callouts/11.svg new file mode 100644 index 0000000000..09a0b2cf71 --- /dev/null +++ b/doc/html/images/callouts/11.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/12.png b/doc/html/images/callouts/12.png new file mode 100644 index 0000000000..7cec72720f Binary files /dev/null and b/doc/html/images/callouts/12.png differ diff --git a/doc/html/images/callouts/12.svg b/doc/html/images/callouts/12.svg new file mode 100644 index 0000000000..9794044c71 --- /dev/null +++ b/doc/html/images/callouts/12.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/13.png b/doc/html/images/callouts/13.png new file mode 100644 index 0000000000..5b41e02a67 Binary files /dev/null and b/doc/html/images/callouts/13.png differ diff --git a/doc/html/images/callouts/13.svg b/doc/html/images/callouts/13.svg new file mode 100644 index 0000000000..64268bb4fa --- /dev/null +++ b/doc/html/images/callouts/13.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/14.png b/doc/html/images/callouts/14.png new file mode 100644 index 0000000000..de5bdbd3eb Binary files /dev/null and b/doc/html/images/callouts/14.png differ diff --git a/doc/html/images/callouts/14.svg b/doc/html/images/callouts/14.svg new file mode 100644 index 0000000000..469aa97487 --- /dev/null +++ b/doc/html/images/callouts/14.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/15.png b/doc/html/images/callouts/15.png new file mode 100644 index 0000000000..3fd6ac3860 Binary files /dev/null and b/doc/html/images/callouts/15.png differ diff --git a/doc/html/images/callouts/15.svg b/doc/html/images/callouts/15.svg new file mode 100644 index 0000000000..8202233ef0 --- /dev/null +++ b/doc/html/images/callouts/15.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/16.svg b/doc/html/images/callouts/16.svg new file mode 100644 index 0000000000..01d6bf8164 --- /dev/null +++ b/doc/html/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/17.svg b/doc/html/images/callouts/17.svg new file mode 100644 index 0000000000..0a04c5560e --- /dev/null +++ b/doc/html/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/18.svg b/doc/html/images/callouts/18.svg new file mode 100644 index 0000000000..1cb891b34d --- /dev/null +++ b/doc/html/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/19.svg b/doc/html/images/callouts/19.svg new file mode 100644 index 0000000000..e6fbb179fc --- /dev/null +++ b/doc/html/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/2.png b/doc/html/images/callouts/2.png new file mode 100644 index 0000000000..f7c1578846 Binary files /dev/null and b/doc/html/images/callouts/2.png differ diff --git a/doc/html/images/callouts/2.svg b/doc/html/images/callouts/2.svg new file mode 100644 index 0000000000..07d03395d0 --- /dev/null +++ b/doc/html/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/20.svg b/doc/html/images/callouts/20.svg new file mode 100644 index 0000000000..ccbfd40319 --- /dev/null +++ b/doc/html/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/21.svg b/doc/html/images/callouts/21.svg new file mode 100644 index 0000000000..93ec53fdd9 --- /dev/null +++ b/doc/html/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/22.svg b/doc/html/images/callouts/22.svg new file mode 100644 index 0000000000..f48c5f3fd1 --- /dev/null +++ b/doc/html/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/23.svg b/doc/html/images/callouts/23.svg new file mode 100644 index 0000000000..6624212957 --- /dev/null +++ b/doc/html/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/24.svg b/doc/html/images/callouts/24.svg new file mode 100644 index 0000000000..a3d552535f --- /dev/null +++ b/doc/html/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/25.svg b/doc/html/images/callouts/25.svg new file mode 100644 index 0000000000..56614a979a --- /dev/null +++ b/doc/html/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/26.svg b/doc/html/images/callouts/26.svg new file mode 100644 index 0000000000..56faeaca30 --- /dev/null +++ b/doc/html/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/27.svg b/doc/html/images/callouts/27.svg new file mode 100644 index 0000000000..a75c812159 --- /dev/null +++ b/doc/html/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/28.svg b/doc/html/images/callouts/28.svg new file mode 100644 index 0000000000..7f8cf1a350 --- /dev/null +++ b/doc/html/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/29.svg b/doc/html/images/callouts/29.svg new file mode 100644 index 0000000000..cb63adf1fe --- /dev/null +++ b/doc/html/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/3.png b/doc/html/images/callouts/3.png new file mode 100644 index 0000000000..3ff0a93931 Binary files /dev/null and b/doc/html/images/callouts/3.png differ diff --git a/doc/html/images/callouts/3.svg b/doc/html/images/callouts/3.svg new file mode 100644 index 0000000000..918be806f4 --- /dev/null +++ b/doc/html/images/callouts/3.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/30.svg b/doc/html/images/callouts/30.svg new file mode 100644 index 0000000000..dc43ba1e3c --- /dev/null +++ b/doc/html/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/html/images/callouts/4.png b/doc/html/images/callouts/4.png new file mode 100644 index 0000000000..6aa29fc0b4 Binary files /dev/null and b/doc/html/images/callouts/4.png differ diff --git a/doc/html/images/callouts/4.svg b/doc/html/images/callouts/4.svg new file mode 100644 index 0000000000..8eb6a53b3b --- /dev/null +++ b/doc/html/images/callouts/4.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/5.png b/doc/html/images/callouts/5.png new file mode 100644 index 0000000000..36e785867a Binary files /dev/null and b/doc/html/images/callouts/5.png differ diff --git a/doc/html/images/callouts/5.svg b/doc/html/images/callouts/5.svg new file mode 100644 index 0000000000..ca7a9f22f6 --- /dev/null +++ b/doc/html/images/callouts/5.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/6.png b/doc/html/images/callouts/6.png new file mode 100644 index 0000000000..c943676bea Binary files /dev/null and b/doc/html/images/callouts/6.png differ diff --git a/doc/html/images/callouts/6.svg b/doc/html/images/callouts/6.svg new file mode 100644 index 0000000000..783a0b9d77 --- /dev/null +++ b/doc/html/images/callouts/6.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/7.png b/doc/html/images/callouts/7.png new file mode 100644 index 0000000000..20940de30d Binary files /dev/null and b/doc/html/images/callouts/7.png differ diff --git a/doc/html/images/callouts/7.svg b/doc/html/images/callouts/7.svg new file mode 100644 index 0000000000..59b3714b56 --- /dev/null +++ b/doc/html/images/callouts/7.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/8.png b/doc/html/images/callouts/8.png new file mode 100644 index 0000000000..d8e34d4a09 Binary files /dev/null and b/doc/html/images/callouts/8.png differ diff --git a/doc/html/images/callouts/8.svg b/doc/html/images/callouts/8.svg new file mode 100644 index 0000000000..c1803a3c0d --- /dev/null +++ b/doc/html/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/callouts/9.png b/doc/html/images/callouts/9.png new file mode 100644 index 0000000000..abe636072b Binary files /dev/null and b/doc/html/images/callouts/9.png differ diff --git a/doc/html/images/callouts/9.svg b/doc/html/images/callouts/9.svg new file mode 100644 index 0000000000..bc149d3cb2 --- /dev/null +++ b/doc/html/images/callouts/9.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png new file mode 100644 index 0000000000..5b7809ca4a Binary files /dev/null and b/doc/html/images/caution.png differ diff --git a/doc/html/images/caution.svg b/doc/html/images/caution.svg new file mode 100644 index 0000000000..4bd586a08e --- /dev/null +++ b/doc/html/images/caution.svg @@ -0,0 +1,68 @@ + + + + + + Attenzione + + + + pulsante + + + + + Open Clip Art Library + + + + + Architetto Francesco Rollandin + + + + + Architetto Francesco Rollandin + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/draft.png b/doc/html/images/draft.png new file mode 100644 index 0000000000..0084708c9b Binary files /dev/null and b/doc/html/images/draft.png differ diff --git a/doc/tutorial/doc/html/images/home.png b/doc/html/images/home.png old mode 100755 new mode 100644 similarity index 100% rename from doc/tutorial/doc/html/images/home.png rename to doc/html/images/home.png diff --git a/doc/html/images/home.svg b/doc/html/images/home.svg new file mode 100644 index 0000000000..e803a3178f --- /dev/null +++ b/doc/html/images/home.svg @@ -0,0 +1,26 @@ + + + + + + + + +]> + + + + + + + + + + + + + + diff --git a/doc/html/images/important.png b/doc/html/images/important.png new file mode 100644 index 0000000000..12c90f607a Binary files /dev/null and b/doc/html/images/important.png differ diff --git a/doc/html/images/important.svg b/doc/html/images/important.svg new file mode 100644 index 0000000000..dd84f3fe36 --- /dev/null +++ b/doc/html/images/important.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/doc/tutorial/doc/html/images/jam.png b/doc/html/images/jam.png similarity index 100% rename from doc/tutorial/doc/html/images/jam.png rename to doc/html/images/jam.png diff --git a/doc/tutorial/doc/html/images/next.png b/doc/html/images/next.png old mode 100755 new mode 100644 similarity index 100% rename from doc/tutorial/doc/html/images/next.png rename to doc/html/images/next.png diff --git a/doc/html/images/next.svg b/doc/html/images/next.svg new file mode 100644 index 0000000000..75fa83ed8c --- /dev/null +++ b/doc/html/images/next.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/next_disabled.png b/doc/html/images/next_disabled.png new file mode 100644 index 0000000000..10a8c59d7b Binary files /dev/null and b/doc/html/images/next_disabled.png differ diff --git a/doc/html/images/note.png b/doc/html/images/note.png new file mode 100644 index 0000000000..d0c3c645ab Binary files /dev/null and b/doc/html/images/note.png differ diff --git a/doc/html/images/note.svg b/doc/html/images/note.svg new file mode 100644 index 0000000000..648299d26f --- /dev/null +++ b/doc/html/images/note.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + diff --git a/doc/tutorial/doc/html/images/prev.png b/doc/html/images/prev.png old mode 100755 new mode 100644 similarity index 100% rename from doc/tutorial/doc/html/images/prev.png rename to doc/html/images/prev.png diff --git a/doc/html/images/prev.svg b/doc/html/images/prev.svg new file mode 100644 index 0000000000..6d88ffdd0d --- /dev/null +++ b/doc/html/images/prev.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/prev_disabled.png b/doc/html/images/prev_disabled.png new file mode 100644 index 0000000000..ab3c17e02d Binary files /dev/null and b/doc/html/images/prev_disabled.png differ diff --git a/doc/tutorial/doc/html/images/python.png b/doc/html/images/python.png similarity index 100% rename from doc/tutorial/doc/html/images/python.png rename to doc/html/images/python.png diff --git a/doc/PyConDC_2003/python_cpp_mix.png b/doc/html/images/python_cpp_mix.png old mode 100755 new mode 100644 similarity index 100% rename from doc/PyConDC_2003/python_cpp_mix.png rename to doc/html/images/python_cpp_mix.png diff --git a/doc/tutorial/doc/html/images/smiley.png b/doc/html/images/smiley.png similarity index 100% rename from doc/tutorial/doc/html/images/smiley.png rename to doc/html/images/smiley.png diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png new file mode 100644 index 0000000000..5c4aab3bb3 Binary files /dev/null and b/doc/html/images/tip.png differ diff --git a/doc/html/images/tip.svg b/doc/html/images/tip.svg new file mode 100644 index 0000000000..cd437a5e85 --- /dev/null +++ b/doc/html/images/tip.svg @@ -0,0 +1,84 @@ + + + + + + lamp + + + + office + + lamp + + + + + Open Clip Art Library + + + + + Sergio Luiz Araujo Silva + + + + + Public Domain + + + set 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/html/images/toc-blank.png b/doc/html/images/toc-blank.png new file mode 100644 index 0000000000..6ffad17a0c Binary files /dev/null and b/doc/html/images/toc-blank.png differ diff --git a/doc/html/images/toc-minus.png b/doc/html/images/toc-minus.png new file mode 100644 index 0000000000..abbb020c8e Binary files /dev/null and b/doc/html/images/toc-minus.png differ diff --git a/doc/html/images/toc-plus.png b/doc/html/images/toc-plus.png new file mode 100644 index 0000000000..941312ce0d Binary files /dev/null and b/doc/html/images/toc-plus.png differ diff --git a/doc/tutorial/doc/html/images/up.png b/doc/html/images/up.png old mode 100755 new mode 100644 similarity index 100% rename from doc/tutorial/doc/html/images/up.png rename to doc/html/images/up.png diff --git a/doc/html/images/up.svg b/doc/html/images/up.svg new file mode 100644 index 0000000000..d31aa9c809 --- /dev/null +++ b/doc/html/images/up.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/html/images/up_disabled.png b/doc/html/images/up_disabled.png new file mode 100644 index 0000000000..e22bc87121 Binary files /dev/null and b/doc/html/images/up_disabled.png differ diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png new file mode 100644 index 0000000000..1c33db8f34 Binary files /dev/null and b/doc/html/images/warning.png differ diff --git a/doc/html/images/warning.svg b/doc/html/images/warning.svg new file mode 100644 index 0000000000..fc8d7484cb --- /dev/null +++ b/doc/html/images/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + +]> + + + + + + + + + + + + + diff --git a/doc/html/rst.css b/doc/html/rst.css new file mode 100644 index 0000000000..1e2ac12214 --- /dev/null +++ b/doc/html/rst.css @@ -0,0 +1,149 @@ +@import url("boostbook.css"); +@import url("docutils.css"); +/* Copyright David Abrahams 2006. Distributed under the Boost + Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +dl.docutils dt { + font-weight: bold } + +img.boost-logo { + border: none; + vertical-align: middle +} + +pre.literal-block span.concept { + font-style: italic; +} + +.nav { +display: inline; +list-style-type: none; +} + +.prevpage { +padding-top: -5px; +text-align: left; +float: left; +} + +.nextpage { +padding-top: -20px; +text-align: right; +float: right; +} + +div.small { + font-size: smaller } + +h2 a { + font-size: 90%; +} +h3 a { + font-size: 80%; +} +h4 a { + font-size: 70%; +} +h5 a { + font-size: 60%; +} + +dl,table +{ + text-align: left; + font-size: 10pt; + line-height: 1.15; +} + + +/*============================================================================= + Tables +=============================================================================*/ + +/* The only clue docutils gives us that tables are logically tables, + and not, e.g., footnotes, is that they have border="1". Therefore + we're keying off of that. We used to manually patch docutils to + add a "table" class to all logical tables, but that proved much too + fragile. +*/ + + table[border="1"] + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + table[border="1"] + { + padding: 4px; + } + + /* Table Cells */ + table[border="1"] tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + table[border="1"] tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + @media screen + { + + /* Tables */ + table[border="1"] tr td + { + border: 1px solid #DCDCDC; + } + + table[border="1"] tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + pre, + .screen + { + border: 1px solid #DCDCDC; + } + + td pre + td .screen + { + border: 0px + } + + .sidebar pre + { + border: 0px + } + + } + + pre, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td pre, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + diff --git a/doc/images/alert.png b/doc/images/alert.png new file mode 100644 index 0000000000..b4645bc7e7 Binary files /dev/null and b/doc/images/alert.png differ diff --git a/doc/images/blank.png b/doc/images/blank.png new file mode 100644 index 0000000000..764bf4f0c3 Binary files /dev/null and b/doc/images/blank.png differ diff --git a/doc/images/boost.png b/doc/images/boost.png new file mode 100644 index 0000000000..b4d51fcd5c Binary files /dev/null and b/doc/images/boost.png differ diff --git a/doc/images/bpl.png b/doc/images/bpl.png new file mode 100644 index 0000000000..c2d8c69e00 Binary files /dev/null and b/doc/images/bpl.png differ diff --git a/doc/images/bpl.svg b/doc/images/bpl.svg new file mode 100644 index 0000000000..9a72d2c4e3 --- /dev/null +++ b/doc/images/bpl.svg @@ -0,0 +1,224 @@ + +image/svg+xmlBoost.Python + \ No newline at end of file diff --git a/doc/images/callouts/1.png b/doc/images/callouts/1.png new file mode 100644 index 0000000000..6003ad3af4 Binary files /dev/null and b/doc/images/callouts/1.png differ diff --git a/doc/images/callouts/1.svg b/doc/images/callouts/1.svg new file mode 100644 index 0000000000..e2e87dc526 --- /dev/null +++ b/doc/images/callouts/1.svg @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/10.png b/doc/images/callouts/10.png new file mode 100644 index 0000000000..0426f516a4 Binary files /dev/null and b/doc/images/callouts/10.png differ diff --git a/doc/images/callouts/10.svg b/doc/images/callouts/10.svg new file mode 100644 index 0000000000..4740f587bd --- /dev/null +++ b/doc/images/callouts/10.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/11.png b/doc/images/callouts/11.png new file mode 100644 index 0000000000..821afc4fa8 Binary files /dev/null and b/doc/images/callouts/11.png differ diff --git a/doc/images/callouts/11.svg b/doc/images/callouts/11.svg new file mode 100644 index 0000000000..09a0b2cf71 --- /dev/null +++ b/doc/images/callouts/11.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/12.png b/doc/images/callouts/12.png new file mode 100644 index 0000000000..7cec72720f Binary files /dev/null and b/doc/images/callouts/12.png differ diff --git a/doc/images/callouts/12.svg b/doc/images/callouts/12.svg new file mode 100644 index 0000000000..9794044c71 --- /dev/null +++ b/doc/images/callouts/12.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/13.png b/doc/images/callouts/13.png new file mode 100644 index 0000000000..5b41e02a67 Binary files /dev/null and b/doc/images/callouts/13.png differ diff --git a/doc/images/callouts/13.svg b/doc/images/callouts/13.svg new file mode 100644 index 0000000000..64268bb4fa --- /dev/null +++ b/doc/images/callouts/13.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/14.png b/doc/images/callouts/14.png new file mode 100644 index 0000000000..de5bdbd3eb Binary files /dev/null and b/doc/images/callouts/14.png differ diff --git a/doc/images/callouts/14.svg b/doc/images/callouts/14.svg new file mode 100644 index 0000000000..469aa97487 --- /dev/null +++ b/doc/images/callouts/14.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/15.png b/doc/images/callouts/15.png new file mode 100644 index 0000000000..3fd6ac3860 Binary files /dev/null and b/doc/images/callouts/15.png differ diff --git a/doc/images/callouts/15.svg b/doc/images/callouts/15.svg new file mode 100644 index 0000000000..8202233ef0 --- /dev/null +++ b/doc/images/callouts/15.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/16.svg b/doc/images/callouts/16.svg new file mode 100644 index 0000000000..01d6bf8164 --- /dev/null +++ b/doc/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/17.svg b/doc/images/callouts/17.svg new file mode 100644 index 0000000000..0a04c5560e --- /dev/null +++ b/doc/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/18.svg b/doc/images/callouts/18.svg new file mode 100644 index 0000000000..1cb891b34d --- /dev/null +++ b/doc/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/19.svg b/doc/images/callouts/19.svg new file mode 100644 index 0000000000..e6fbb179fc --- /dev/null +++ b/doc/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/2.png b/doc/images/callouts/2.png new file mode 100644 index 0000000000..f7c1578846 Binary files /dev/null and b/doc/images/callouts/2.png differ diff --git a/doc/images/callouts/2.svg b/doc/images/callouts/2.svg new file mode 100644 index 0000000000..07d03395d0 --- /dev/null +++ b/doc/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/20.svg b/doc/images/callouts/20.svg new file mode 100644 index 0000000000..ccbfd40319 --- /dev/null +++ b/doc/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/21.svg b/doc/images/callouts/21.svg new file mode 100644 index 0000000000..93ec53fdd9 --- /dev/null +++ b/doc/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/22.svg b/doc/images/callouts/22.svg new file mode 100644 index 0000000000..f48c5f3fd1 --- /dev/null +++ b/doc/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/23.svg b/doc/images/callouts/23.svg new file mode 100644 index 0000000000..6624212957 --- /dev/null +++ b/doc/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/24.svg b/doc/images/callouts/24.svg new file mode 100644 index 0000000000..a3d552535f --- /dev/null +++ b/doc/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/25.svg b/doc/images/callouts/25.svg new file mode 100644 index 0000000000..56614a979a --- /dev/null +++ b/doc/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/26.svg b/doc/images/callouts/26.svg new file mode 100644 index 0000000000..56faeaca30 --- /dev/null +++ b/doc/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/27.svg b/doc/images/callouts/27.svg new file mode 100644 index 0000000000..a75c812159 --- /dev/null +++ b/doc/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/28.svg b/doc/images/callouts/28.svg new file mode 100644 index 0000000000..7f8cf1a350 --- /dev/null +++ b/doc/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/29.svg b/doc/images/callouts/29.svg new file mode 100644 index 0000000000..cb63adf1fe --- /dev/null +++ b/doc/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/3.png b/doc/images/callouts/3.png new file mode 100644 index 0000000000..3ff0a93931 Binary files /dev/null and b/doc/images/callouts/3.png differ diff --git a/doc/images/callouts/3.svg b/doc/images/callouts/3.svg new file mode 100644 index 0000000000..918be806f4 --- /dev/null +++ b/doc/images/callouts/3.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/30.svg b/doc/images/callouts/30.svg new file mode 100644 index 0000000000..dc43ba1e3c --- /dev/null +++ b/doc/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/images/callouts/4.png b/doc/images/callouts/4.png new file mode 100644 index 0000000000..6aa29fc0b4 Binary files /dev/null and b/doc/images/callouts/4.png differ diff --git a/doc/images/callouts/4.svg b/doc/images/callouts/4.svg new file mode 100644 index 0000000000..8eb6a53b3b --- /dev/null +++ b/doc/images/callouts/4.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/5.png b/doc/images/callouts/5.png new file mode 100644 index 0000000000..36e785867a Binary files /dev/null and b/doc/images/callouts/5.png differ diff --git a/doc/images/callouts/5.svg b/doc/images/callouts/5.svg new file mode 100644 index 0000000000..ca7a9f22f6 --- /dev/null +++ b/doc/images/callouts/5.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/6.png b/doc/images/callouts/6.png new file mode 100644 index 0000000000..c943676bea Binary files /dev/null and b/doc/images/callouts/6.png differ diff --git a/doc/images/callouts/6.svg b/doc/images/callouts/6.svg new file mode 100644 index 0000000000..783a0b9d77 --- /dev/null +++ b/doc/images/callouts/6.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/7.png b/doc/images/callouts/7.png new file mode 100644 index 0000000000..20940de30d Binary files /dev/null and b/doc/images/callouts/7.png differ diff --git a/doc/images/callouts/7.svg b/doc/images/callouts/7.svg new file mode 100644 index 0000000000..59b3714b56 --- /dev/null +++ b/doc/images/callouts/7.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/8.png b/doc/images/callouts/8.png new file mode 100644 index 0000000000..d8e34d4a09 Binary files /dev/null and b/doc/images/callouts/8.png differ diff --git a/doc/images/callouts/8.svg b/doc/images/callouts/8.svg new file mode 100644 index 0000000000..c1803a3c0d --- /dev/null +++ b/doc/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/callouts/9.png b/doc/images/callouts/9.png new file mode 100644 index 0000000000..abe636072b Binary files /dev/null and b/doc/images/callouts/9.png differ diff --git a/doc/images/callouts/9.svg b/doc/images/callouts/9.svg new file mode 100644 index 0000000000..bc149d3cb2 --- /dev/null +++ b/doc/images/callouts/9.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/images/caution.png b/doc/images/caution.png new file mode 100644 index 0000000000..5b7809ca4a Binary files /dev/null and b/doc/images/caution.png differ diff --git a/doc/images/caution.svg b/doc/images/caution.svg new file mode 100644 index 0000000000..4bd586a08e --- /dev/null +++ b/doc/images/caution.svg @@ -0,0 +1,68 @@ + + + + + + Attenzione + + + + pulsante + + + + + Open Clip Art Library + + + + + Architetto Francesco Rollandin + + + + + Architetto Francesco Rollandin + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/draft.png b/doc/images/draft.png new file mode 100644 index 0000000000..0084708c9b Binary files /dev/null and b/doc/images/draft.png differ diff --git a/doc/images/home.png b/doc/images/home.png new file mode 100644 index 0000000000..5584aacb09 Binary files /dev/null and b/doc/images/home.png differ diff --git a/doc/images/home.svg b/doc/images/home.svg new file mode 100644 index 0000000000..e803a3178f --- /dev/null +++ b/doc/images/home.svg @@ -0,0 +1,26 @@ + + + + + + + + +]> + + + + + + + + + + + + + + diff --git a/doc/images/important.png b/doc/images/important.png new file mode 100644 index 0000000000..12c90f607a Binary files /dev/null and b/doc/images/important.png differ diff --git a/doc/images/important.svg b/doc/images/important.svg new file mode 100644 index 0000000000..dd84f3fe36 --- /dev/null +++ b/doc/images/important.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/doc/images/jam.png b/doc/images/jam.png new file mode 100644 index 0000000000..224ed7914b Binary files /dev/null and b/doc/images/jam.png differ diff --git a/doc/images/next.png b/doc/images/next.png new file mode 100644 index 0000000000..59800b4e87 Binary files /dev/null and b/doc/images/next.png differ diff --git a/doc/images/next.svg b/doc/images/next.svg new file mode 100644 index 0000000000..75fa83ed8c --- /dev/null +++ b/doc/images/next.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/images/next_disabled.png b/doc/images/next_disabled.png new file mode 100644 index 0000000000..10a8c59d7b Binary files /dev/null and b/doc/images/next_disabled.png differ diff --git a/doc/images/note.png b/doc/images/note.png new file mode 100644 index 0000000000..d0c3c645ab Binary files /dev/null and b/doc/images/note.png differ diff --git a/doc/images/note.svg b/doc/images/note.svg new file mode 100644 index 0000000000..648299d26f --- /dev/null +++ b/doc/images/note.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/prev.png b/doc/images/prev.png new file mode 100644 index 0000000000..d88a40f923 Binary files /dev/null and b/doc/images/prev.png differ diff --git a/doc/images/prev.svg b/doc/images/prev.svg new file mode 100644 index 0000000000..6d88ffdd0d --- /dev/null +++ b/doc/images/prev.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/images/prev_disabled.png b/doc/images/prev_disabled.png new file mode 100644 index 0000000000..ab3c17e02d Binary files /dev/null and b/doc/images/prev_disabled.png differ diff --git a/doc/images/smiley.png b/doc/images/smiley.png new file mode 100644 index 0000000000..30a77f71ce Binary files /dev/null and b/doc/images/smiley.png differ diff --git a/doc/images/tip.png b/doc/images/tip.png new file mode 100644 index 0000000000..5c4aab3bb3 Binary files /dev/null and b/doc/images/tip.png differ diff --git a/doc/images/tip.svg b/doc/images/tip.svg new file mode 100644 index 0000000000..cd437a5e85 --- /dev/null +++ b/doc/images/tip.svg @@ -0,0 +1,84 @@ + + + + + + lamp + + + + office + + lamp + + + + + Open Clip Art Library + + + + + Sergio Luiz Araujo Silva + + + + + Public Domain + + + set 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/toc-blank.png b/doc/images/toc-blank.png new file mode 100644 index 0000000000..6ffad17a0c Binary files /dev/null and b/doc/images/toc-blank.png differ diff --git a/doc/images/toc-minus.png b/doc/images/toc-minus.png new file mode 100644 index 0000000000..abbb020c8e Binary files /dev/null and b/doc/images/toc-minus.png differ diff --git a/doc/images/toc-plus.png b/doc/images/toc-plus.png new file mode 100644 index 0000000000..941312ce0d Binary files /dev/null and b/doc/images/toc-plus.png differ diff --git a/doc/images/up.png b/doc/images/up.png new file mode 100644 index 0000000000..17d9c3ec49 Binary files /dev/null and b/doc/images/up.png differ diff --git a/doc/images/up.svg b/doc/images/up.svg new file mode 100644 index 0000000000..d31aa9c809 --- /dev/null +++ b/doc/images/up.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/images/up_disabled.png b/doc/images/up_disabled.png new file mode 100644 index 0000000000..e22bc87121 Binary files /dev/null and b/doc/images/up_disabled.png differ diff --git a/doc/images/warning.png b/doc/images/warning.png new file mode 100644 index 0000000000..1c33db8f34 Binary files /dev/null and b/doc/images/warning.png differ diff --git a/doc/images/warning.svg b/doc/images/warning.svg new file mode 100644 index 0000000000..fc8d7484cb --- /dev/null +++ b/doc/images/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + +]> + + + + + + + + + + + + + diff --git a/doc/index.html b/doc/index.html index e600366fec..d52257577e 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,184 +1,13 @@ - - - - - + - - - - - Boost.Python + - - - - - - - - - - - - - - -
-

-

-
-

Boost.Python

- -

Index

-
- -
-

- - Search - -
-
- - - - - -
- - - GooglePowered - - - - - - -
- - -

-
- -
-
- - -

Synopsis

- Welcome to version 2 of Boost.Python, a C++ library which enables - seamless interoperability between C++ and the
Python programming language. The new version - has been rewritten from the ground up, with a more convenient and - flexible interface, and many new capabilities, including support for: - -
    -
  • References and Pointers
  • - -
  • Globally Registered Type Coercions
  • - -
  • Automatic Cross-Module Type Conversions
  • - -
  • Efficient Function Overloading
  • - -
  • C++ to Python Exception Translation
  • - -
  • Default Arguments
  • - -
  • Keyword Arguments
  • - -
  • Manipulating Python objects in C++
  • - -
  • Exporting C++ Iterators as Python Iterators
  • - -
  • Documentation Strings
  • -
- The development of these features was funded in part by grants to Boost Consulting from the Lawrence Livermore National Laboratories - and by the Computational Crystallography - Initiative at Lawrence Berkeley National Laboratories. - -
- -

Contents

- -
-
Tutorial Introduction
- -
Building and Testing
- -
Reference Manual
- -
Suites:
-
- -
- -
Configuration Information
- -
Known Working Platforms and - Compilers
- -
Definitions
- -
Projects using Boost.Python
- -
Support Resources
- -
Frequently Asked Questions (FAQs)
- -
Py++ Boost.Python code generator
- -
Pyste Boost.Python code generator (no longer maintained)
- -
Internals Documentation
- -
News/Change Log
- -
TODO list
- -
LLNL Progress Reports
- -
Acknowledgments
-
-
- -

Articles

- - "Building Hybrid - Systems With Boost Python", by Dave Abrahams and Ralf - W. Grosse-Kunstleve (PDF) - -
- -

Revised - - 26 August, 2003 - -

- -

© Copyright Dave - Abrahams 2002-2003.

+ + Automatic redirection failed, click this + link  
+

� Copyright Stefan Seefeld, 2015

+

Distributed under the Boost Software License, Version 1.0. (See accompanying + file http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/index.qbk b/doc/index.qbk new file mode 100644 index 0000000000..eaf0df9cf3 --- /dev/null +++ b/doc/index.qbk @@ -0,0 +1,19 @@ +[library Boost.Python + [quickbook 1.3] + [authors [Abrahams, David], [Seefeld, Stefan]] + [copyright 2002 2003 2004 2005 2015 David Abrahams, Stefan Seefeld] + [category inter-language support] + [id python] + [purpose + Reflects C++ classes and functions into Python + ] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] +] + +[/ QuickBook Document version 1.3 ] + +[include preface.qbk] diff --git a/doc/internals.html b/doc/internals.html old mode 100755 new mode 100644 diff --git a/doc/internals.rst b/doc/internals.rst old mode 100755 new mode 100644 diff --git a/doc/news.html b/doc/news.html deleted file mode 100644 index da57caeb30..0000000000 --- a/doc/news.html +++ /dev/null @@ -1,371 +0,0 @@ - - - - - - - - - - - - Boost.Python - News/Change Log - - - - - - - - - -
-

-

-
-

Boost.Python

- -

News/Change Log

-
-
- -
- -
Current SVN
-
-
    -
  • Python 3 support:
  • -
      -
    • All the current Boost.Python test cases passed. Extension modules using - Boost.Python expected to support Python 3 smoothly.
    • -
    • Introduced object.contains where x.contains(y) - is equivalent to Python code y in x. - Now dict.has_key is just a wrapper of object.contains. -
    • -
    • When building against Python 3, str.decode will be removed.
    • -
    • When building against Python 3, the original signature of list.sort, which is: -
      void sort(object_cref cmpfunc);
      - will change to: -
      void sort(args_proxy const &args, kwds_proxy const &kwds);
      - - This is because in Python 3 list.sort requires all its arguments be keyword arguments. - So you should call it like this: -
      x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true))));
      - -
    • -
    • According to PEP 3123, - when building Boost.Python against Python older than 2.6, the following macros will - be defined in Boost.Python header: -
      -# define Py_TYPE(o)    (((PyObject*)(o))->ob_type)
      -# define Py_REFCNT(o)  (((PyObject*)(o))->ob_refcnt)
      -# define Py_SIZE(o)    (((PyVarObject*)(o))->ob_size)
      - So extension writers can use these macro directly, to make code clean and compatible with Python 3. -
    • -
    -
-
- -
1.39.0 Release
- -
-
    -
  • Pythonic signatures are now automatically appended to the - docstrings. - -
  • Use docstring_options.hpp header - control the content of docstrings. - -
  • This new feature increases the size of the modules by about 14%. - If this is not acceptable it can be turned off by defining the macro - BOOST_PYTHON_NO_PY_SIGNATURES. Modules compiled with and without the macro - defined are compatible. -
  • -
  • If BOOST_PYTHON_NO_PY_SIGNATURES is undefined, this version defines the - macro BOOST_PYTHON_SUPPORTS_PY_SIGNATURES. This allows writing code that will compile - with older version of Boost.Python (see here). -
  • -
  • By defining BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE, and at a cost - of another 14% size increase, proper pythonic type is generated for the "self" - parameter of the __init__ methods. -
  • - -
  • To support this new feature changes were made to the - to_python_converter.hpp, - default_call_policies, - ResultConverter, - CallPolicies and some others. - Efforts were made not to have interface breaking changes. -
  • - -
-
- -
12 May 2007 - 1.34.0 release
- -
-
    -
  • C++ signatures are now automatically appended to the - docstrings. - -
  • New docstring_options.hpp header to - control the content of docstrings. - -
  • Support for converting void* to/from python, - with opaque_pointer_converter - as the return value policy. Thanks to Niall Douglas for the - initial patch. -
-
- -
19 October 2005 - 1.33.1 release
- -
-
    -
  • wrapper<T> can now be used as expected with a - held type of some-smart-pointer<T>
  • - -
  • The build now assumes Python 2.4 by default, rather than 2.2
  • - -
  • Support Python that's built without Unicode support
  • - -
  • Support for wrapping classes with overloaded address-of - (&) operators
  • -
-
- -
14 August 2005 - 1.33 release
- -
-
    -
  • Support for docstrings on nonstatic properties.
  • - -
  • We now export the client-provided docstrings for - init<optional<> > and - XXX_FUNCTION_OVERLOADS() for only the last - overload.
  • - -
  • Fixed some support for Embedded VC++ 4
  • - -
  • Better support for rvalue from-python conversions of shared_ptr: - always return a pointer that holds the owning python object *unless* - the python object contains a NULL shared_ptr holder of the right - type.
  • - -
  • Support for exposing vector<T*> with the - indexing suite.
  • - -
  • Support for GCC-3.3 on MacOS.
  • - -
  • updated visual studio project build file to include two new files - (slice.cpp and wrapper.cpp)
  • - -
  • Added search feature to the index page.
  • - -
  • Numerous fixes to the tutorial
  • - -
  • Numerous workarounds for MSVC 6 and 7, GCC 2.96, and EDG - 2.45
  • -
-
- -
11 March 2005
- -
-
    -
  • Added a hack that will fool PyDoc into working with Boost.Python, - thanks to Nick Rasmussen
  • -
-
- -
19 November 2004 - 1.32 release
- -
-
    -
  • Updated to use the Boost Software License.
  • - -
  • A new, - better method of wrapping classes with virtual functions has been - implemented.
  • - -
  • Support for upcoming GCC symbol export control features have been - folded in, thanks to Niall Douglas.
  • - -
  • Improved support for std::auto_ptr-like types.
  • - -
  • The Visual C++ bug that makes top-level cv-qualification - of function parameter types part of the function type has been worked - around.
  • - -
  • Components used by other libraries have been moved out of - python/detail and into boost/detail to - improve dependency relationships.
  • - -
  • Miscellaneous bug fixes and compiler workarounds.
  • -
-
- -
8 Sept 2004
- -
Support for Python's Bool type, thanks to Daniel Holth.
- -
11 Sept 2003
- -
-
    -
  • Changed the response to multiple to-python converters being - registered for the same type from a hard error into warning; - Boost.Python now reports the offending type in the message.
  • - -
  • Added builtin std::wstring conversions
  • - -
  • Added std::out_of_range => Python - IndexError exception conversion, thanks to Raoul Gough
  • -
-
- -
9 Sept 2003
- -
Added new str
- -
constructors which take a range of characters, allowing strings - containing nul ('\0') characters.
- -
8 Sept 2003
- -
Added the ability to create methods from function objects (with an - operator()); see the make_function docs for - more info.
- -
10 August 2003
- -
Added the new properties unit tests contributed by - Roman Yakovenko and - documented add_static_property at his urging.
- -
1 August 2003
- -
- Added the new arg class contributed by Nikolay Mladenov which supplies the - ability to wrap functions that can be called with ommitted arguments in - the middle: -
-void f(int x = 0, double y = 3.14, std::string z = std::string("foo"));
-
-BOOST_PYTHON_MODULE(test)
-{
-   def("f", f
-       , (arg("x", 0), arg("y", 3.14), arg("z", "foo")));
-}
- 
-
And in Python: -
->>> import test
->>> f(0, z = "bar")
->>> f(z = "bar", y = 0.0)
-
Thanks, Nikolay! -
- -
22 July 2003
- -
Killed the dreaded "bad argument type for builtin operation" error. - Argument errors now show the actual and expected argument types!
- -
19 July 2003
- -
Added the new return_arg policy from Nikolay Mladenov. Thanks, Nikolay!
- -
18 March, 2003
- -
Gottfried - Ganßauge has contributed opaque pointer support.
- Bruno da Silva de - Oliveira has contributed the exciting Pyste ("Pie-steh") package.
- -
24 February 2003
- -
Finished improved support for boost::shared_ptr. Now any - wrapped object of C++ class X can be converted automatically - to shared_ptr<X>, regardless of how it was wrapped. - The shared_ptr will manage the lifetime of the Python object - which supplied the X, rather than just the X - object itself, and when such a shared_ptr is converted back - to Python, the original Python object will be returned.
- -
19 January 2003
- -
Integrated staticmethod support from Nikolay Mladenov. Thanks, Nikolay!
- -
29 December 2002
- -
Added Visual Studio project file and instructions from Brett Calcott. - Thanks, Brett!
- -
20 December 2002
- -
Added automatic downcasting for pointers, references, and smart - pointers to polymorphic class types upon conversion to python
- -
18 December 2002
- -
Optimized from_python conversions for wrapped classes by putting the - conversion logic in the shared library instead of registering separate - converters for each class in each extension module
- -
19 November 2002
- -
Removed the need for users to cast base class member function - pointers when used as arguments to add_property
- -
13 December 2002
- -
Allow exporting of enum_ values into enclosing - scope.
- Fixed unsigned integer conversions to deal correctly with numbers that - are out-of-range of signed long.
- -
14 November 2002
- -
Auto-detection of class data members wrapped with make_getter
- -
13 November 2002
- -
Full Support for std::auto_ptr<> added.
- -
October 2002
- -
Ongoing updates and improvements to tutorial documentation
- -
10 October 2002
- -
Boost.Python V2 is released!
-
-
- -

Revised - - 19 November 2004 -

- -

© Copyright Dave - Abrahams 2002-2003.

- - diff --git a/doc/numpy/Makefile b/doc/numpy/Makefile new file mode 100644 index 0000000000..f0ffaaea5f --- /dev/null +++ b/doc/numpy/Makefile @@ -0,0 +1,133 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build +HTMLDIR = ../html/numpy + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +all: html + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(HTMLDIR) + @echo + @echo "Build finished. The HTML pages are in $(HTMLDIR)." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BoostNumPy.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BoostNumPy.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/BoostNumPy" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BoostNumPy" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/numpy/_static/boost.css b/doc/numpy/_static/boost.css new file mode 100644 index 0000000000..36c1efd082 --- /dev/null +++ b/doc/numpy/_static/boost.css @@ -0,0 +1,736 @@ + +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= +Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= +Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= +Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 9pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= +Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= +Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= +Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= +Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= +Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= +Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= +Table of contents +=============================================================================*/ + + div.toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + +/*============================================================================= +Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= +Suppress margins in tables +=============================================================================*/ + + table th > *:first-child, + table td > *:first-child + { + margin-top: 0; + } + + table th > *:last-child, + table td > *:last-child + { + margin-bottom: 0; + } + +/*============================================================================= +Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= +Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= +Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= +Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Links */ + a, a .keyword, a .identifier, a .special, a .preprocessor + a .char, a .comment, a .string, a .number + { + color: #005a9c; + } + + a:visited, a:visited .keyword, a:visited .identifier, + a:visited .special, a:visited .preprocessor a:visited .char, + a:visited .comment, a:visited .string, a:visited .number + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= +Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; +} + +sup { +bottom: 1ex; +} + +sub { +top: .5ex; +} + +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ + +/* 2022 fix */ + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + diff --git a/doc/numpy/_static/boost.png b/doc/numpy/_static/boost.png new file mode 100644 index 0000000000..b4d51fcd5c Binary files /dev/null and b/doc/numpy/_static/boost.png differ diff --git a/doc/numpy/_static/bpl.png b/doc/numpy/_static/bpl.png new file mode 100644 index 0000000000..c2d8c69e00 Binary files /dev/null and b/doc/numpy/_static/bpl.png differ diff --git a/doc/numpy/_static/home.png b/doc/numpy/_static/home.png new file mode 100644 index 0000000000..5584aacb09 Binary files /dev/null and b/doc/numpy/_static/home.png differ diff --git a/doc/numpy/_static/next.png b/doc/numpy/_static/next.png new file mode 100644 index 0000000000..59800b4e87 Binary files /dev/null and b/doc/numpy/_static/next.png differ diff --git a/doc/numpy/_static/prev.png b/doc/numpy/_static/prev.png new file mode 100644 index 0000000000..d88a40f923 Binary files /dev/null and b/doc/numpy/_static/prev.png differ diff --git a/doc/numpy/_static/style.css b/doc/numpy/_static/style.css new file mode 100644 index 0000000000..65277d0e7f --- /dev/null +++ b/doc/numpy/_static/style.css @@ -0,0 +1,38 @@ +@import url(boost.css); + +.header h1 a +{ + color: #00507f; + font-size: 200%; + font-style: italic; +} +.header h3 { margin: 1px;} +#contents +{ +/* border-bottom: solid thin black;*/ +} + +.highlight +{ + border: 1px solid #dcdcdc; + background-color: inherit; + padding: 0 1em; + margin: 0 5em; +} +#searchbox +{ + float: right; + width: auto; + margin: 0 2em; +} + +.admonition-title { font-weight: bold;} +.toctree-wrapper +{ + border: 1px solid #dcdcdc; + padding: 1em; + margin: 0 2em; +} +.toctree-wrapper .caption, +.toctree-wrapper .topic-title { font-weight: bold;} + diff --git a/doc/numpy/_static/up.png b/doc/numpy/_static/up.png new file mode 100644 index 0000000000..17d9c3ec49 Binary files /dev/null and b/doc/numpy/_static/up.png differ diff --git a/doc/numpy/_templates/layout.html b/doc/numpy/_templates/layout.html new file mode 100644 index 0000000000..69e1a868c0 --- /dev/null +++ b/doc/numpy/_templates/layout.html @@ -0,0 +1,123 @@ +{%- macro navbar() %} + +{%- endmacro %} + + + + + + {{ metatags }} + {%- if builder != 'htmlhelp' %} + {%- set titlesuffix = docstitle|e %} + {%- set titlesuffix = " - " + titlesuffix %} + {%- endif %} + {{ title|striptags }}{{ titlesuffix }} + {%- if builder == 'web' %} + + {%- for link, type, title in page_links %} + + {%- endfor %} + {%- else %} + + + + {%- endif %} + {%- if builder != 'htmlhelp' %} + + {%- for scriptfile in script_files %} + + {%- endfor %} + + + + {%- if use_opensearch %} + + {%- endif %} + {%- if favicon %} + + {%- endif %} + {%- endif %} +{%- block linktags %} + {%- if hasdoc('about') %} + + {%- endif %} + + + {%- if hasdoc('copyright') %} + + {%- endif %} + + {%- if parents %} + + {%- endif %} + {%- if next %} + + {%- endif %} + {%- if prev %} + + {%- endif %} +{%- endblock %} +{%- block extrahead %} {% endblock %} + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ {%- if pagename != "search" %} + + + {%- endif %} +
+
+
+
+ {%- block top_navbar %}{{ navbar() }}{% endblock %} + {% block body %} {% endblock %} + {%- block bottom_navbar %}{{ navbar() }}{% endblock %} +
+ + diff --git a/doc/numpy/conf.py b/doc/numpy/conf.py new file mode 100644 index 0000000000..23ab678d3a --- /dev/null +++ b/doc/numpy/conf.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8 -*- +# +# Boost.Python NumPy documentation build configuration file, created by +# sphinx-quickstart on Thu Oct 27 09:04:58 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'Boost.Python NumPy extension' +copyright = '2011, Stefan Seefeld' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'default' + +highlight_language = 'c++' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = '_static/bpl.png' + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'BoostPythonNumPydoc' + +html_add_permalinks = False + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'BoostPythonNumPy.tex', 'Boost.Python NumPy Documentation', + 'Stefan Seefeld', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'boostnumpy', 'Boost.Python NumPy Documentation', + ['Stefan Seefeld'], 1) +] diff --git a/doc/numpy/index.rst b/doc/numpy/index.rst new file mode 100644 index 0000000000..bb3b623ee7 --- /dev/null +++ b/doc/numpy/index.rst @@ -0,0 +1,14 @@ +.. Boost.Python NumPy extension documentation master file, created by + sphinx-quickstart on Thu Oct 27 09:04:58 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to the documentation of the Boost.Python NumPy extension! +================================================================= + +.. toctree:: + :maxdepth: 2 + + Tutorial + Reference + diff --git a/doc/numpy/make.bat b/doc/numpy/make.bat new file mode 100644 index 0000000000..7dc41fc395 --- /dev/null +++ b/doc/numpy/make.bat @@ -0,0 +1,171 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set HTMLDIR=../html/numpy +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %HTMLDIR% + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %HTMLDIR%. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\BoostNumPy.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\BoostNumPy.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/doc/numpy/reference/binary_ufunc.rst b/doc/numpy/reference/binary_ufunc.rst new file mode 100644 index 0000000000..0215e5558f --- /dev/null +++ b/doc/numpy/reference/binary_ufunc.rst @@ -0,0 +1,110 @@ +binary_ufunc +============ + +.. contents :: Table of Contents + +A ``binary_ufunc`` is a struct used as an intermediate step to broadcast two arguments so that a C++ function can be converted to a ufunc like function + + ```` contains the ``binary_ufunc`` structure definitions + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + template + + struct binary_ufunc + { + + static object call(TBinaryFunctor & self, + object const & input1, + object const & input2, + object const & output); + + static object make(); + }; + + } + } + } + + +constructors +------------ + +:: + + struct example_binary_ufunc + { + typedef any_valid first_argument_type; + typedef any_valid second_argument_type; + typedef any_valid result_type; + }; + +:Requirements: The ``any_valid`` type must be defined using typedef as a valid C++ type in order to use the struct methods correctly + +:Note: The struct must be exposed as a Python class, and an instance of the class must be created to use the ``call`` method corresponding to the ``__call__`` attribute of the Python object + +accessors +--------- + +:: + + template + static object call(TBinaryFunctor & self, + object const & input, + object const & output); + +:Requires: Typenames ``TBinaryFunctor`` and optionally ``TArgument1`` and ``TArgument2`` for argument type and ``TResult`` for result type + +:Effects: Passes a Python object to the underlying C++ functor after broadcasting its arguments + +:: + + template + static object make(); + +:Requires: Typenames ``TBinaryFunctor`` and optionally ``TArgument1`` and ``TArgument2`` for argument type and ``TResult`` for result type + +:Returns: A Python function object to call the overloaded () operator in the struct (in typical usage) + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + struct BinarySquare + { + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a,double b) const { return (a*a + b*b) ; } + }; + + p::object ud = p::class_ >("BinarySquare").def("__call__", np::binary_ufunc::make()); + p::object inst = ud(); + result_array = inst.attr("__call__")(demo_array,demo_array) ; + std::cout << "Square of list with binary ufunc is " << p::extract (p::str(result_array)) << std::endl ; + diff --git a/doc/numpy/reference/dtype.rst b/doc/numpy/reference/dtype.rst new file mode 100644 index 0000000000..03227116cc --- /dev/null +++ b/doc/numpy/reference/dtype.rst @@ -0,0 +1,92 @@ +dtype +===== + +.. contents :: Table of Contents + +A `dtype`_ is an object describing the type of the elements of an ndarray + +.. _dtype: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html#data-type-objects-dtype + + ```` contains the method calls necessary to generate a python object equivalent to a numpy.dtype from builtin C++ objects, as well as to create custom dtypes from user defined types + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + class dtype : public object + { + static python::detail::new_reference convert(object::object_cref arg, bool align); + public: + + // Convert an arbitrary Python object to a data-type descriptor object. + template + explicit dtype(T arg, bool align=false); + + // Get the built-in numpy dtype associated with the given scalar template type. + template static dtype get_builtin(); + + // Return the size of the data type in bytes. + int get_itemsize() const; + }; + + } + } + } + +constructors +------------ + +:: + + template + explicit dtype(T arg, bool align=false) + +:Requirements: ``T`` must be either : + + * a built-in C++ typename convertible to object + * a valid python object or convertible to object + +:Effects: Constructs an object from the supplied python object / convertible + to object / builtin C++ data type + +:Throws: Nothing + +:: + + template static dtype get_builtin(); + +:Requirements: The typename supplied, ``T`` must be a builtin C++ type also supported by numpy + +:Returns: Numpy dtype corresponding to builtin C++ type + +accessors +--------- + +:: + + int get_itemsize() const; + +:Returns: the size of the data type in bytes. + + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + np::dtype dtype = np::dtype::get_builtin(); + p::tuple for_custom_dtype = p::make_tuple("ha",dtype); + np::dtype custom_dtype = np::dtype(list_for_dtype); + diff --git a/doc/numpy/reference/index.rst b/doc/numpy/reference/index.rst new file mode 100644 index 0000000000..5c0d852dc3 --- /dev/null +++ b/doc/numpy/reference/index.rst @@ -0,0 +1,12 @@ +Boost.Python NumPy extension Reference +====================================== + +.. toctree:: + :maxdepth: 2 + + dtype + ndarray + unary_ufunc + binary_ufunc + multi_iter + diff --git a/doc/numpy/reference/multi_iter.rst b/doc/numpy/reference/multi_iter.rst new file mode 100644 index 0000000000..c1d812ef1c --- /dev/null +++ b/doc/numpy/reference/multi_iter.rst @@ -0,0 +1,94 @@ +multi_iter +========== + +.. contents :: Table of Contents + +A ``multi_iter`` is a Python object, intended to be used as an iterator It should generally only be used in loops. + + ```` contains the class definitions for ``multi_iter`` + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + class multi_iter : public object + { + public: + void next(); + bool not_done() const; + char * get_data(int n) const; + int const get_nd() const; + Py_intptr_t const * get_shape() const; + Py_intptr_t const shape(int n) const; + }; + + + multi_iter make_multi_iter(object const & a1); + multi_iter make_multi_iter(object const & a1, object const & a2); + multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3); + + } + } + } + + +constructors +------------ + +:: + + multi_iter make_multi_iter(object const & a1); + multi_iter make_multi_iter(object const & a1, object const & a2); + multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3); + +:Returns: A Python iterator object broadcasting over one, two or three sequences as supplied + +accessors +--------- + +:: + + void next(); + +:Effects: Increments the iterator + +:: + + bool not_done() const; + +:Returns: boolean value indicating whether the iterator is at its end + +:: + + char * get_data(int n) const; + +:Returns: a pointer to the element of the nth broadcasted array. + +:: + + int const get_nd() const; + +:Returns: the number of dimensions of the broadcasted array expression + +:: + + Py_intptr_t const * get_shape() const; + +:Returns: the shape of the broadcasted array expression as an array of integers. + +:: + + Py_intptr_t const shape(int n) const; + +:Returns: the shape of the broadcasted array expression in the nth dimension. + + diff --git a/doc/numpy/reference/ndarray.rst b/doc/numpy/reference/ndarray.rst new file mode 100644 index 0000000000..1486c73aa6 --- /dev/null +++ b/doc/numpy/reference/ndarray.rst @@ -0,0 +1,382 @@ +ndarray +======= + +.. contents :: Table of Contents + +A `ndarray`_ is an N-dimensional array which contains items of the same type and size, where N is the number of dimensions and is specified in the form of a ``shape`` tuple. Optionally, the numpy ``dtype`` for the objects contained may also be specified. + +.. _ndarray: http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html +.. _dtype: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html#data-type-objects-dtype + + ```` contains the structures and methods necessary to move raw data between C++ and Python and create ndarrays from the data + + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + class ndarray : public object + { + + public: + + enum bitflag + { + NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2, + ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8, + CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8, + FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8, + UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8 + }; + + ndarray view(dtype const & dt) const; + ndarray astype(dtype const & dt) const; + ndarray copy() const; + int const shape(int n) const; + int const strides(int n) const; + char * get_data() const; + dtype get_dtype() const; + python::object get_base() const; + void set_base(object const & base); + Py_intptr_t const * get_shape() const; + Py_intptr_t const * get_strides() const; + int const get_nd() const; + + bitflag const get_flags() const; + + ndarray transpose() const; + ndarray squeeze() const; + ndarray reshape(tuple const & shape) const; + object scalarize() const; + }; + + ndarray zeros(tuple const & shape, dtype const & dt); + ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); + + ndarray empty(tuple const & shape, dtype const & dt); + ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); + + ndarray array(object const & obj); + ndarray array(object const & obj, dtype const & dt); + + template + ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner); + template + ndarray from_data(void const * data, dtype const & dt, Container shape, Container strides, object const & owner); + + ndarray from_object(object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, dtype const & dt,int nd, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, int nd_min, int nd_max,ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE) + + ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) ; + ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b); + + } + + +constructors +------------ + +:: + + ndarray view(dtype const & dt) const; + +:Returns: new ndarray with old ndarray data cast as supplied dtype + +:: + + ndarray astype(dtype const & dt) const; + +:Returns: new ndarray with old ndarray data converted to supplied dtype + +:: + + ndarray copy() const; + +:Returns: Copy of calling ndarray object + +:: + + ndarray transpose() const; + +:Returns: An ndarray with the rows and columns interchanged + +:: + + ndarray squeeze() const; + +:Returns: An ndarray with all unit-shaped dimensions removed + +:: + + ndarray reshape(tuple const & shape) const; + +:Requirements: The new ``shape`` of the ndarray must be supplied as a tuple + +:Returns: An ndarray with the same data but reshaped to the ``shape`` supplied + + +:: + + object scalarize() const; + +:Returns: A scalar if the ndarray has only one element, otherwise it returns the entire array + +:: + + ndarray zeros(tuple const & shape, dtype const & dt); + ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); + +:Requirements: The following parameters must be supplied as required : + + * the ``shape`` or the size of all dimensions, as a tuple + * the ``dtype`` of the data + * the ``nd`` size for a square shaped ndarray + * the ``shape`` Py_intptr_t + +:Returns: A new ndarray with the given shape and data type, with data initialized to zero. + +:: + + ndarray empty(tuple const & shape, dtype const & dt); + ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); + + +:Requirements: The following parameters must be supplied : + + * the ``shape`` or the size of all dimensions, as a tuple + * the ``dtype`` of the data + * the ``shape`` Py_intptr_t + +:Returns: A new ndarray with the given shape and data type, with data left uninitialized. + +:: + + ndarray array(object const & obj); + ndarray array(object const & obj, dtype const & dt); + +:Returns: A new ndarray from an arbitrary Python sequence, with dtype of each element specified optionally + +:: + + template + inline ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner) + +:Requirements: The following parameters must be supplied : + + * the ``data`` which is a generic C++ data container + * the dtype ``dt`` of the data + * the ``shape`` of the ndarray as Python object + * the ``strides`` of each dimension of the array as a Python object + * the ``owner`` of the data, in case it is not the ndarray itself + +:Returns: ndarray with attributes and data supplied + +:Note: The ``Container`` typename must be one that is convertible to a std::vector or python object type + +:: + + ndarray from_object(object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * minimum number of dimensions ``nd_min`` of the ndarray as Python object + * maximum number of dimensions ``nd_max`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray constructed with dimensions and data supplied as parameters + +:: + + inline ndarray from_object(object const & obj, dtype const & dt, int nd, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * number of dimensions ``nd`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray with dimensions ``nd`` x ``nd`` and suplied parameters + +:: + + inline ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE) + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * optional ``flags`` bitflags + +:Returns: Supplied Python object as ndarray + +:: + + ndarray from_object(object const & obj, int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * minimum number of dimensions ``nd_min`` of the ndarray as Python object + * maximum number of dimensions ``nd_max`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray with supplied dimension limits and parameters + +:Note: dtype need not be supplied here + +:: + + inline ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * number of dimensions ``nd`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray of ``nd`` x ``nd`` dimensions constructed from the supplied object + +:: + + inline ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE) + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * optional ``flags`` bitflags + +:Returns: ndarray of same dimensions and dtype as supplied Python object + + +accessors +--------- + +:: + + int const shape(int n) const; + +:Returns: The size of the n-th dimension of the ndarray + +:: + + int const strides(int n) const; + +:Returns: The stride of the nth dimension. + +:: + + char * get_data() const; + +:Returns: Array's raw data pointer as a char + +:Note: This returns char so stride math works properly on it.User will have to reinterpret_cast it. + +:: + + dtype get_dtype() const; + +:Returns: Array's data-type descriptor object (dtype) + + +:: + + object get_base() const; + +:Returns: Object that owns the array's data, or None if the array owns its own data. + + +:: + + void set_base(object const & base); + +:Returns: Set the object that owns the array's data. Exercise caution while using this + + +:: + + Py_intptr_t const * get_shape() const; + +:Returns: Shape of the array as an array of integers + + +:: + + Py_intptr_t const * get_strides() const; + +:Returns: Stride of the array as an array of integers + + +:: + + int const get_nd() const; + +:Returns: Number of array dimensions + + +:: + + bitflag const get_flags() const; + +:Returns: Array flags + +:: + + inline ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) + +:Returns: bitflag logically OR-ed as (a | b) + +:: + + inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b) + +:Returns: bitflag logically AND-ed as (a & b) + + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + p::object tu = p::make_tuple('a','b','c') ; + np::ndarray example_tuple = np::array (tu) ; + + p::list l ; + np::ndarray example_list = np::array (l) ; + + np::dtype dt = np::dtype::get_builtin(); + np::ndarray example_list1 = np::array (l,dt); + + int data[] = {1,2,3,4} ; + p::tuple shape = p::make_tuple(4) ; + p::tuple stride = p::make_tuple(4) ; + p::object own ; + np::ndarray data_ex = np::from_data(data,dt,shape,stride,own); + + uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; + shape = p::make_tuple(3,2) ; + stride = p::make_tuple(4,2) ; + np::dtype dt1 = np::dtype::get_builtin(); + + np::ndarray mul_data_ex = np::from_data(mul_data,dt1, p::make_tuple(3,4),p::make_tuple(4,1),p::object()); + mul_data_ex = np::from_data(mul_data,dt1, shape,stride,p::object()); + diff --git a/doc/numpy/reference/unary_ufunc.rst b/doc/numpy/reference/unary_ufunc.rst new file mode 100644 index 0000000000..eaec034c2d --- /dev/null +++ b/doc/numpy/reference/unary_ufunc.rst @@ -0,0 +1,103 @@ +unary_ufunc +=========== + +.. contents :: Table of Contents + +A ``unary_ufunc`` is a struct used as an intermediate step to broadcast a single argument so that a C++ function can be converted to a ufunc like function + + ```` contains the ``unary_ufunc`` structure definitions + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + template + struct unary_ufunc + { + + static object call(TUnaryFunctor & self, + object const & input, + object const & output) ; + + static object make(); + + }; + } + } + } + + +constructors +------------ + +:: + + struct example_unary_ufunc + { + typedef any_valid_type argument_type; + typedef any_valid_type result_type; + }; + +:Requirements: The ``any_valid`` type must be defined using typedef as a valid C++ type in order to use the struct methods correctly + +:Note: The struct must be exposed as a Python class, and an instance of the class must be created to use the ``call`` method corresponding to the ``__call__`` attribute of the Python object + +accessors +--------- + +:: + + template + static object call(TUnaryFunctor & self, + object const & input, + object const & output); + +:Requires: Typenames ``TUnaryFunctor`` and optionally ``TArgument`` for argument type and ``TResult`` for result type + +:Effects: Passes a Python object to the underlying C++ functor after broadcasting its arguments + +:: + + template + static object make(); + +:Requires: Typenames ``TUnaryFunctor`` and optionally ``TArgument`` for argument type and ``TResult`` for result type + +:Returns: A Python function object to call the overloaded () operator in the struct (in typical usage) + + + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + struct UnarySquare + { + typedef double argument_type; + typedef double result_type; + double operator()(double r) const { return r * r;} + }; + + p::object ud = p::class_ >("UnarySquare").def("__call__", np::unary_ufunc::make()); + p::object inst = ud(); + std::cout << "Square of unary scalar 1.0 is " << p::extract (p::str(inst.attr("__call__")(1.0))) << std::endl ; + diff --git a/doc/numpy/rst.css b/doc/numpy/rst.css new file mode 100644 index 0000000000..afd9a98c31 --- /dev/null +++ b/doc/numpy/rst.css @@ -0,0 +1,149 @@ +@import url("doc/src/boostbook.css"); +@import url("doc/src/docutils.css"); +/* Copyright David Abrahams 2006. Distributed under the Boost + Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +dl.docutils dt { + font-weight: bold } + +img.boost-logo { + border: none; + vertical-align: middle +} + +pre.literal-block span.concept { + font-style: italic; +} + +.nav { +display: inline; +list-style-type: none; +} + +.prevpage { +padding-top: -5px; +text-align: left; +float: left; +} + +.nextpage { +padding-top: -20px; +text-align: right; +float: right; +} + +div.small { + font-size: smaller } + +h2 a { + font-size: 90%; +} +h3 a { + font-size: 80%; +} +h4 a { + font-size: 70%; +} +h5 a { + font-size: 60%; +} + +dl,table +{ + text-align: left; + font-size: 10pt; + line-height: 1.15; +} + + +/*============================================================================= + Tables +=============================================================================*/ + +/* The only clue docutils gives us that tables are logically tables, + and not, e.g., footnotes, is that they have border="1". Therefore + we're keying off of that. We used to manually patch docutils to + add a "table" class to all logical tables, but that proved much too + fragile. +*/ + + table[border="1"] + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + table[border="1"] + { + padding: 4px; + } + + /* Table Cells */ + table[border="1"] tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + table[border="1"] tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + @media screen + { + + /* Tables */ + table[border="1"] tr td + { + border: 1px solid #DCDCDC; + } + + table[border="1"] tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + pre, + .screen + { + border: 1px solid #DCDCDC; + } + + td pre + td .screen + { + border: 0px + } + + .sidebar pre + { + border: 0px + } + + } + + pre, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td pre, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + diff --git a/doc/numpy/tutorial/dtype.rst b/doc/numpy/tutorial/dtype.rst new file mode 100644 index 0000000000..9bea646a65 --- /dev/null +++ b/doc/numpy/tutorial/dtype.rst @@ -0,0 +1,54 @@ +How to use dtypes +================= + +Here is a brief tutorial to show how to create ndarrays with built-in python data types, and extract the types and values of member variables + +Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Next, we create the shape and dtype. We use the get_builtin method to get the numpy dtype corresponding to the builtin C++ dtype +Here, we will create a 3x3 array passing a tuple with (3,3) for the size, and double as the data type :: + + p::tuple shape = p::make_tuple(3, 3); + np::dtype dtype = np::dtype::get_builtin(); + np::ndarray a = np::zeros(shape, dtype); + +Finally, we can print the array using the extract method in the python namespace. +Here, we first convert the variable into a string, and then extract it as a C++ character array from the python string using the template :: + + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + +We can also print the dtypes of the data members of the ndarray by using the get_dtype method for the ndarray :: + + std::cout << "Datatype is:\n" << p::extract(p::str(a.get_dtype())) << std::endl ; + +We can also create custom dtypes and build ndarrays with the custom dtypes + +We use the dtype constructor to create a custom dtype. This constructor takes a list as an argument. + +The list should contain one or more tuples of the format (variable name, variable type) + +So first create a tuple with a variable name and its dtype, double, to create a custom dtype :: + + p::tuple for_custom_dtype = p::make_tuple("ha",dtype) ; + +Next, create a list, and add this tuple to the list. Then use the list to create the custom dtype :: + + p::list list_for_dtype ; + list_for_dtype.append(for_custom_dtype) ; + np::dtype custom_dtype = np::dtype(list_for_dtype) ; + +We are now ready to create an ndarray with dimensions specified by \*shape\* and of custom dtype :: + + np::ndarray new_array = np::zeros(shape,custom_dtype); + } diff --git a/doc/numpy/tutorial/fromdata.rst b/doc/numpy/tutorial/fromdata.rst new file mode 100644 index 0000000000..33bcee4521 --- /dev/null +++ b/doc/numpy/tutorial/fromdata.rst @@ -0,0 +1,56 @@ +How to access data using raw pointers +===================================== + +One of the advantages of the ndarray wrapper is that the same data can be used in both Python and C++ and changes can be made to reflect at both ends. +The from_data method makes this possible. + +Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Create an array in C++ , and pass the pointer to it to the from_data method to create an ndarray:: + + int arr[] = {1,2,3,4,5}; + np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin(), + p::make_tuple(5), + p::make_tuple(sizeof(int)), + p::object()); + +Print the source C++ array, as well as the ndarray, to check if they are the same:: + + std::cout << "C++ array :" << std::endl; + for (int j=0;j<4;j++) + { + std::cout << arr[j] << ' '; + } + std::cout << std::endl + << "Python ndarray :" << p::extract(p::str(py_array)) << std::endl; + +Now, change an element in the Python ndarray, and check if the value changed correspondingly in the source C++ array:: + + py_array[1] = 5 ; + std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl; + for (int j = 0; j < 5; j++) + { + std::cout << arr[j] << ' '; + } + +Next, change an element of the source C++ array and see if it is reflected in the Python ndarray:: + + arr[2] = 8; + std::cout << std::endl + << "Is the change reflected in the Python ndarray ?" << std::endl + << p::extract(p::str(py_array)) << std::endl; + } + +As we can see, the changes are reflected across the ends. This happens because the from_data method passes the C++ array by reference to create the ndarray, and thus uses the same locations for storing data. + diff --git a/doc/numpy/tutorial/index.rst b/doc/numpy/tutorial/index.rst new file mode 100644 index 0000000000..3de2ef5379 --- /dev/null +++ b/doc/numpy/tutorial/index.rst @@ -0,0 +1,12 @@ +Boost.Python NumPy extension Tutorial +===================================== + +.. toctree:: + :maxdepth: 2 + + simple + dtype + ndarray + ufunc + fromdata + diff --git a/doc/numpy/tutorial/ndarray.rst b/doc/numpy/tutorial/ndarray.rst new file mode 100644 index 0000000000..b270da705d --- /dev/null +++ b/doc/numpy/tutorial/ndarray.rst @@ -0,0 +1,99 @@ +Creating ndarrays +================= + +The Boost.Numpy library exposes quite a few methods to create ndarrays. ndarrays can be created in a variety of ways, include empty arrays and zero filled arrays. +ndarrays can also be created from arbitrary python sequences as well as from data and dtypes. + +This tutorial will introduce you to some of the ways in which you can create ndarrays. The methods covered here include creating ndarrays from arbitrary Python sequences, as well as from C++ containers, using both unit and non-unit strides + +First, as before, initialise the necessary namepaces and runtimes :: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Let's now create an ndarray from a simple tuple. We first create a tuple object, and then pass it to the array method, to generate the necessary tuple :: + + p::object tu = p::make_tuple('a','b','c'); + np::ndarray example_tuple = np::array(tu); + +Let's now try the same with a list. We create an empty list, add an element using the append method, and as before, call the array method :: + + p::list l; + l.append('a'); + np::ndarray example_list = np::array (l); + +Optionally, we can also specify a dtype for the array :: + + np::dtype dt = np::dtype::get_builtin(); + np::ndarray example_list1 = np::array (l,dt); + +We can also create an array by supplying data arrays and a few other parameters. + +First,create an integer array :: + + int data[] = {1,2,3,4,5}; + +Create a shape, and strides, needed by the function :: + + p::tuple shape = p::make_tuple(5); + p::tuple stride = p::make_tuple(sizeof(int)); + +Here, shape is (4,) , and the stride is `sizeof(int)``. +A stride is the number of bytes that must be traveled to get to the next desired element while constructing the ndarray. + +The function also needs an owner, to keep track of the data array passed. Passing none is dangerous :: + + p::object own; + +The from_data function takes the data array, datatype,shape,stride and owner as arguments and returns an ndarray :: + + np::ndarray data_ex1 = np::from_data(data,dt, shape,stride,own); + +Now let's print the ndarray we created :: + + std::cout << "Single dimensional array ::" << std::endl + << p::extract(p::str(data_ex)) << std::endl; + +Let's make it a little more interesting. Lets make an 3x2 ndarray from a multi-dimensional array using non-unit strides + +First lets create a 3x4 array of 8-bit integers :: + + uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; + +Now let's create an array of 3x2 elements, picking the first and third elements from each row . For that, the shape will be 3x2. +The strides will be 4x2 i.e. 4 bytes to go to the next desired row, and 2 bytes to go to the next desired column :: + + shape = p::make_tuple(3,2); + stride = p::make_tuple(sizeof(uint8_t)*2,sizeof(uint8_t)); + +Get the numpy dtype for the built-in 8-bit integer data type :: + + np::dtype dt1 = np::dtype::get_builtin(); + +Now lets first create and print out the ndarray as is. +Notice how we can pass the shape and strides in the function directly, as well as the owner. The last part can be done because we don't have any use to +manipulate the "owner" object :: + + np::ndarray mul_data_ex = np::from_data(mul_data, dt1, + p::make_tuple(3,4), + p::make_tuple(4,1), + p::object()); + std::cout << "Original multi dimensional array :: " << std::endl + << p::extract(p::str(mul_data_ex)) << std::endl; + +Now create the new ndarray using the shape and strides and print out the array we created using non-unit strides :: + + mul_data_ex = np::from_data(mul_data, dt1, shape, stride, p::object()); + std::cout << "Selective multidimensional array :: "<(p::str(mul_data_ex)) << std::endl ; + } + +.. note:: The from_data method will throw ``error_already_set`` if the number of elements dictated by the shape and the corresponding strides don't match. diff --git a/doc/numpy/tutorial/simple.rst b/doc/numpy/tutorial/simple.rst new file mode 100644 index 0000000000..889eea114a --- /dev/null +++ b/doc/numpy/tutorial/simple.rst @@ -0,0 +1,41 @@ +A simple tutorial on Arrays +=========================== + +Let's start with a simple tutorial to create and modify arrays. + +Get the necessary headers for numpy components and set up necessary namespaces:: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + +Initialise the Python runtime, and the numpy module. Failure to call these results in segmentation errors:: + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + + +Zero filled n-dimensional arrays can be created using the shape and data-type of the array as a parameter. Here, the shape is 3x3 and the datatype is the built-in float type:: + + p::tuple shape = p::make_tuple(3, 3); + np::dtype dtype = np::dtype::get_builtin(); + np::ndarray a = np::zeros(shape, dtype); + +You can also create an empty array like this :: + + np::ndarray b = np::empty(shape,dtype); + +Print the original and reshaped array. The array a which is a list is first converted to a string, and each value in the list is extracted using extract< >:: + + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + + // Reshape the array into a 1D array + a = a.reshape(p::make_tuple(9)); + // Print it again. + std::cout << "Reshaped array:\n" << p::extract(p::str(a)) << std::endl; + } + diff --git a/doc/numpy/tutorial/ufunc.rst b/doc/numpy/tutorial/ufunc.rst new file mode 100644 index 0000000000..a3571dbc5d --- /dev/null +++ b/doc/numpy/tutorial/ufunc.rst @@ -0,0 +1,120 @@ +Ufuncs +====== + +Ufuncs or universal functions operate on ndarrays element by element, and support array broadcasting, type casting, and other features. + +Lets try and see how we can use the binary and unary ufunc methods + +After the neccessary includes :: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + +Now we create the structs necessary to implement the ufuncs. The typedefs *must* be made as the ufunc generators take these typedefs as inputs and return an error otherwise :: + + struct UnarySquare + { + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * r;} + }; + + struct BinarySquare + { + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a,double b) const { return (a*a + b*b) ; } + }; + +Initialise the Python runtime and the numpy module :: + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Now expose the struct UnarySquare to Python as a class, and let ud be the class object. :: + + p::object ud = p::class_ >("UnarySquare"); + ud.def("__call__", np::unary_ufunc::make()); + +Let inst be an instance of the class ud :: + + p::object inst = ud(); + +Use the "__call__" method to call the overloaded () operator and print the value :: + + std::cout << "Square of unary scalar 1.0 is " << p::extract(p::str(inst.attr("__call__")(1.0))) << std::endl; + +Create an array in C++ :: + + int arr[] = {1,2,3,4} ; + + +..and use it to create the ndarray in Python :: + + np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin(), + p::make_tuple(4), + p::make_tuple(4), + p::object()); + +Print out the demo array :: + + std::cout << "Demo array is " << p::extract(p::str(demo_array)) << std::endl; + +Call the "__call__" method to perform the operation and assign the value to result_array :: + + p::object result_array = inst.attr("__call__")(demo_array); + +Print the resultant array :: + + std::cout << "Square of demo array is " << p::extract(p::str(result_array)) << std::endl; + +Lets try the same with a list :: + + p::list li; + li.append(3); + li.append(7); + +Print out the demo list :: + + std::cout << "Demo list is " << p::extract(p::str(li)) << std::endl; + +Call the ufunc for the list :: + + result_array = inst.attr("__call__")(li); + +And print the list out :: + + std::cout << "Square of demo list is " << p::extract(p::str(result_array)) << std::endl; + +Now lets try Binary ufuncs. Again, expose the struct BinarySquare to Python as a class, and let ud be the class object :: + + ud = p::class_ >("BinarySquare"); + ud.def("__call__", np::binary_ufunc::make()); + +And initialise ud :: + + inst = ud(); + +Print the two input lists :: + + std::cout << "The two input list for binary ufunc are " << std::endl + << p::extract(p::str(demo_array)) << std::endl + << p::extract(p::str(demo_array)) << std::endl; + +Call the binary ufunc taking demo_array as both inputs :: + + result_array = inst.attr("__call__")(demo_array,demo_array); + +And print the output :: + + std::cout << "Square of list with binary ufunc is " << p::extract(p::str(result_array)) << std::endl; + } + diff --git a/doc/preface.qbk b/doc/preface.qbk new file mode 100644 index 0000000000..b04d88e7df --- /dev/null +++ b/doc/preface.qbk @@ -0,0 +1,26 @@ +[preface Introduction +[quickbook 1.6] +] + +[section Synopsis] + +Welcome to version 2 of Boost.Python, a C++ library which enables seamless interoperability between C++ and the Python programming language. The new version has been rewritten from the ground up, with a more convenient and flexible interface, and many new capabilities, including support for: + + * References and Pointers + * Globally Registered Type Coercions + * Automatic Cross-Module Type Conversions + * Efficient Function Overloading + * C++ to Python Exception Translation + * Default Arguments + * Keyword Arguments + * Manipulating Python objects in C++ + * Exporting C++ Iterators as Python Iterators + * Documentation Strings + +The development of these features was funded in part by grants to Boost Consulting from the Lawrence Livermore National Laboratories and by the Computational Crystallography Initiative at Lawrence Berkeley National Laboratories. + +[endsect] +[section Articles] + +"Building Hybrid Systems With Boost Python", by Dave Abrahams and Ralf W. Grosse-Kunstleve (PDF) +[endsect] diff --git a/doc/projects.html b/doc/projects.html deleted file mode 100644 index 05eb52326c..0000000000 --- a/doc/projects.html +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - - - - - - - Boost.Python - Projects using Boost.Python - - - - - - - - - -
-

-

-
-

Boost.Python

- -

Projects using Boost.Python

-
-
- -

Introduction

- -

This is a partial list of projects using Boost.Python. If you are using - Boost.Python as your Python/C++ binding solution, we'd be proud to list - your project on this page. Just post a short description of your project - and how Boost.Python helps you get the job done, and we'll add it to this - page .

-
- -

Data Analysis

- -
-
NeuraLab
- -
Neuralab is a data analysis environment specifically tailored for - neural data from Neuralynx - acquisition systems. Neuralab combines presentation quality graphics, a - numerical analysis library, and the Python scripting engine in a single - application. With Neuralab, Neuralynx users can perform common analysis - tasks with just a few mouse clicks. More advanced users can create custom - Python scripts, which can optionally be assigned to menus and mouse - clicks.
-
- -
-
TSLib - Fortress - Investment Group LLC
- -
- Fortress Investment Group has contracted Boost Consulting to develop core - internal financial analysis tools in C++ and to prepare Python bindings - for them using Boost.Python. - -

Tom Barket of Fortress writes:

- -
- We have a large C++ analytical library specialized for research in - finance and economics, built for speed and mission critical - stability. Yet Python offers us the flexibility to test out new ideas - quickly and increase the productivity of our time versus working in - C++. There are several key features which make Python stand out. Its - elegance, stability, and breadth of resources on the web are all - valuable, but the most important is its extensibility, due to its - open source transparency. Boost.Python makes Python extensibility - extremely simple and straightforward, yet preserves a great deal of - power and control. -
-
-
- -

Educational

- -
-
Kig
- -
-

KDE Interactive Geometry is a high-school level educational tool, - built for the KDE desktop. It is a nice tool to let students work with - geometrical constructions. It is meant to be the most intuitive, yet - featureful application of its kind.

- -

Versions after 0.6.x (will) support objects built by the user - himself in the Python language. The exporting of the relevant internal - API's were done using Boost.Python, which made the process very - easy.

-
-
- -

Enterprise Software

- -
-
OpenWBEM
- -
- The OpenWBEM project is an effort to develop an open-source - implementation of Web Based Enterprise Management suitable for - commercial and non-commercial application - -

Dan Nuffer writes:

- -
- I'm using Boost.Python to wrap the client API of OpenWBEM.This will - make it easier to do rapid prototyping, testing, and scripting when - developing management solutions that use WBEM. -
-
- -
Metafaq
- -
- Metafaq, from Transversal, - Inc., is an enterprise level online knowledge base management - system. - -

Ben Young - writes:

- -
- Boost.Python is used in an automated process to generate python - bindings to our api which is exposed though multiple backends and - frontends. This allows us to write quick tests and bespoke scripts to - perform one off tasks without having to go through the full - compilation cycle. -
-
-
- -

Games

- -
-
Civilization IV
-
- -
- “The fourth game in the PC strategy series that has sold over five - million copies, Sid Meier's Civilization IV is a bold step forward for - the franchise, with spectacular new 3D graphics and all-new single and - multiplayer content. Civilization IV will also set a new standard for - user-modification, allowing gamers to create their own add-ons using - Python and XML. - -

Sid Meier's Civilization IV will be released for PC in late 2005. For - more information please visit http://www.firaxis.com or write kgilmore@firaxis.com

-
- -

Boost.Python is used as the interface layer between the C++ game code - and Python. Python is used for many purposes in the game, including map - generation, interface screens, game events, tools, tutorials, etc. Most - high-level game operations have been exposed to Python in order to give - modders the power they need to customize the game.

- -
- -Mustafa Thamer, Civ4 Lead Programmer -
- -
-
Vega - Strike
- -
- Vega Strike is the 3D - Space Simulator that allows you to trade and bounty hunt in a vast - universe. Players face dangers, decisions, piracy, and aliens. - -

Vega Strike has - decided to base its scripting on python, using boost as the layer - between the class hierarchy in python and the class hierarchy in C++. - The result is a very flexible scripting system that treats units as - native python classes when designing missions or writing AI's.

- -

A large economic and planetary simulation is currently being run in - the background in python and the results are returned back into C++ in - the form of various factions' spaceships appearing near worlds that - they are simulated to be near in python if the player is in the general - neighborhood.

-
-
- -

Graphics

- -
-
OpenSceneGraph - Bindings
- -
Gideon May has created a set - of bindings for OpenSceneGraph, a cross-platform - C++/OpenGL library for the real-time visualization.
-  
- -
HippoDraw
- -
- HippoDraw is a data analysis environment consisting of a canvas upon - which graphs such as histograms, scattter plots, etc, are prsented. It - has a highly interactive GUI interface, but some things you need to do - with scripts. HippoDraw can be run as Python extension module so that - all the manipulation can be done from either Python or the GUI. - -

Before the web page came online, Paul F. Kunz wrote:

- -
- Don't have a web page for the project, but the organization's is - http://www.slac.stanford.edu (the - first web server site in America, I installed it). -
Which was just too cool a piece of trivia to omit.
-   -
- -
IPLT
- -
- Ansgar Philippsen - writes: - -
- IPLT is an image processing library and toolbox for the structural - biology electron microscopy community. I would call it a - budding/evolving project, since it is currently not in production - stage, but rather under heavy development. Python is used as the main - scripting/interaction level, but also for rapid prototyping, since - the underlying C++ class library is pretty much fully exposed via - boost.python (at least the high-level interface). The combined power - of C++ and Python for this project turned out to be just awesome. -

-   -
- -
PythonMagick
- -
PythonMagick binds the GraphicsMagick image manipulation - library to Python.
-  
- -
VPython
- -
- Bruce Sherwood writes: - -
- VPython is an extension for Python that makes it easy to create - navigable 3D animations, which are generated as a side effect of - computational code. VPython is used in education for various - purposes, including teaching physics and programming, but it has also - been used by research scientists to visualize systems or data in 3D. -

-   -
-
- -

Scientific Computing

- -
-
CAMFR
- -
- CAMFR is a photonics and electromagnetics modelling tool. Python is - used for computational steering. - -

Peter Bienstman - writes:

- -
- Thanks for providing such a great tool! -
-
- -
cctbx - Computational - Crystallography Toolbox
- -
- Computational Crystallography is concerned with the derivation of - atomic models of crystal structures, given experimental X-ray - diffraction data. The cctbx is an open-source library of fundamental - algorithms for crystallographic computations. The core algorithms are - implemented in C++ and accessed through higher-level Python interfaces. - -

The cctbx grew together with Boost.Python and is designed from the - ground up as a hybrid Python/C++ system. With one minor exception, - run-time polymorphism is completely handled by Python. C++ compile-time - polymorphism is used to implement performance critical algorithms. The - Python and C++ layers are seamlessly integrated using Boost.Python.

- -

The SourceForge cctbx project is organized in modules to facilitate - use in non-crystallographic applications. The scitbx module implements - a general purpose array family for scientific applications and pure C++ - ports of FFTPACK and the L-BFGS quasi-Newton minimizer.

-
- -
EMSolve
- -
EMSolve is a provably stable, charge conserving, and energy - conserving solver for Maxwell's equations.
-  
- -
Gaudi and RootPython
- -
- Gaudi is a framework for particle physics collision data processing - applications developed in the context of the LHCb and ATLAS experiments - at CERN. - -

Pere Mato Vila writes:

- -
- We are using Boost.Python to provide scripting/interactive capability - to our framework. We have a module called "GaudiPython" implemented - using Boost.Python that allows the interaction with any framework - service or algorithm from python. RootPython also uses Boost.Python - to provide a generic "gateway" between the ROOT framework and python - -

Boost.Python is great. We managed very quickly to interface our - framework to python, which is great language. We are trying to - facilitate to our physicists (end-users) a rapid analysis application - development environment based on python. For that, Boost.Python plays - and essential role.

-
-
- -
ESSS
- -
- ESSS (Engineering Simulation and Scientific Software) is a company that - provides engineering solutions and acts in the brazilian and - south-american market providing products and services related to - Computational Fluid Dynamics and Image Analysis. - -

Bruno da Silva de Oliveira - writes:

- -
- Recently we moved our work from working exclusively with C++ to an - hybrid-language approach, using Python and C++, with Boost.Python - providing the layer between the two. The results are great so far! -
- -

Two projects have been developed so far with this technology:

- -

Simba - provides 3D visualization of geological formations gattered from the - simulation of the evolution of oil systems, allowing the user to - analyse various aspects of the simulation, like deformation, pressure - and fluids, along the time of the simulation.

- -

Aero aims to - construct a CFD with brazilian technology, which involves various - companies and universities. ESSS is responsible for various of the - application modules, including GUI and post-processing of results.

-
- -
PolyBoRi
- -
-

Michael Brickenstein writes:

- -
-

The core of PolyBoRi is a C++ library, which provides - high-level data types for Boolean polynomials and monomials, - exponent vectors, as well as for the underlying polynomial - rings and subsets of the powerset of the Boolean variables. As - a unique approach, binary decision diagrams are used as - internal storage type for polynomial structures. On top of - this C++-library we provide a Python interface. This allows - parsing of complex polynomial systems, as well as sophisticated - and extendable strategies for Gröbner basis computation. - Boost.Python has helped us to create this interface in a - very clean way.

-
-
- -
Pyrap
-
-

Ger van Diepen writes:

- -
-

Pyrap is the python interface to the Radio-Astronomical Package - casacore (casacore.googlecode.com). Astronomers love pyrap because - it makes it easily possible to get their data (observed with - radio-astronomical telescopes like LOFAR, ASKAP, and eVLA) in numpy - arrays and do basic data inspection and manipulation using the many - python packages that are available.

- -

Boost.Python made it quite easily possible to create converters for - the various data types, also for numpy arrays and individual elements - of a numpy array. It's nice they work fully recursively. Mapping C++ - functions to Python was straightforward.

-
-
- -
RDKit: Cheminformatics and Machine Learning Software
- -
- A collection of cheminformatics and machine-learning software - written in C++ and Python. -
-
- -

Systems Libraries

- -
-
Fusion
- -
-

Fusion is a library that supports implementing protocols in C++ for - use with Twisted, allowing control over memory allocation strategies, - fast method calls internally, etc.. Fusion supports TCP, UDP and - multicast, and is implemented using the Boost.Python python - bindings.

- -

Fusion is licensed under the MIT license, and available for download - from http://itamarst.org/software.

-
-
- -

Tools

- -
-
Jayacard
- -
- Jayacard aims at developing a secure portable open source operating - system for contactless smart cards and a complete suite of high quality - development tools to ease smart card OS and application development. - -

The core of the smart card reader management is written in C++ but - all the development tools are written in the friendly Python language. - Boost plays the fundamental role of binding the tools to our core smart - card reader library.

-
-
-
- -

Revised - - 29 May, 2008

- -

© Copyright Dave - Abrahams 2002-2008.

- - diff --git a/doc/python.qbk b/doc/python.qbk new file mode 100644 index 0000000000..b8b0926def --- /dev/null +++ b/doc/python.qbk @@ -0,0 +1,67 @@ +[book Boost.Python + [quickbook 1.6] + [authors [Abrahams, David], [Seefeld, Stefan]] + [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] + [category inter-language support] + [id python] + [purpose + Reflects C++ classes and functions into Python + ] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] +] + +[def _boost_ [@http://www.boost.org Boost]] +[def _bb_ [@http://www.boost.org/build Boost.Build]] +[def _bb_list_ [@http://www.boost.org/more/mailing_lists.htm#jamboost Boost.Build mailing list]] +[def _bp_list_ [@http://www.boost.org/more/mailing_lists.htm#cplussig Boost.Python mailing list]] +[def _tutorial_ [@tutorial/index.html Tutorial]] +[def _reference_ [@reference/index.html Reference Manual]] +[def _gsg_ Boost [@http://www.boost.org/more/getting_started/ Getting Started Guide]] +[def _extending_ [@https://docs.python.org/2/extending/extending.html extending]] +[def _embedding_ [@https://docs.python.org/2/extending/embedding.html embedding]] + +[h2 Synopsis] + +Welcome to Boost.Python, a C++ library which enables seamless interoperability between C++ and the Python programming language. The library includes support for: + +* References and Pointers +* Globally Registered Type Coercions +* Automatic Cross-Module Type Conversions +* Efficient Function Overloading +* C++ to Python Exception Translation +* Default Arguments +* Keyword Arguments +* Manipulating Python objects in C++ +* Exporting C++ Iterators as Python Iterators +* Documentation Strings + +The development of these features was funded in part by grants to `Boost Consulting` from the [@http://www.llnl.gov Lawrence Livermore National Laboratories] and by the [@http://cci.lbl.gov Computational Crystallography Initiative] at Lawrence Berkeley National Laboratories. + +[section Contents] + +* [link rn Release Notes] +* _tutorial_ +* [link building Building and Testing] +* _reference_ +* [link configuration Configuration Information] +* [link glossary Glossary] +* [link support Support Resources] +* [link faq Frequently Asked Questions (FAQs)] +* [@numpy/index.html NumPy Extension Documentation] + +[endsect] + +[h2 Articles] + +[@article.html Building Hybrid Systems With Boost Python], by Dave Abrahams and Ralf W. Grosse-Kunstleve + +[include release_notes.qbk] +[include building.qbk] +[include configuration.qbk] +[include support.qbk] +[include faq.qbk] +[include glossary.qbk] \ No newline at end of file diff --git a/doc/reference.qbk b/doc/reference.qbk new file mode 100644 index 0000000000..ae97393cad --- /dev/null +++ b/doc/reference.qbk @@ -0,0 +1,21 @@ +[book Boost.Python Reference Manual + [quickbook 1.6] + [authors [Abrahams, David], [Seefeld, Stefan]] + [copyright 2002 2003 2004 2005 2015 David Abrahams, Stefan Seefeld] + [id reference] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt] + ] +] + +[include reference/concepts.qbk] +[include reference/components.qbk] +[include reference/objects.qbk] +[include reference/functions.qbk] +[include reference/conversion.qbk] +[include reference/embedding.qbk] +[include reference/utility.qbk] +[include reference/topics.qbk] +[include glossary.qbk] diff --git a/doc/reference/args.qbk b/doc/reference/args.qbk new file mode 100644 index 0000000000..253b165c83 --- /dev/null +++ b/doc/reference/args.qbk @@ -0,0 +1,62 @@ +[section boost/python/args.hpp] +[section Introduction] +Supplies a family of overloaded functions for specifying argument keywords for wrapped C++ functions. +[section keyword-expressions] +A keyword-expression results in an object which holds a sequence of [link ntbs]\ es, and whose type encodes the number of keywords specified. The keyword-expression may contain default values for some or all of the keywords it holds +[endsect] +[endsect] +[section Class `arg`] +The objects of class arg are keyword-expressions holding one keyword ( size one ) +`` +namespace boost { namespace python +{ + struct arg + { + template + arg &operator = (T const &value); + explicit arg (char const *name){elements[0].name = name;} + }; + +}} +`` +[endsect] +[section Class `arg` constructor] +``arg(char const* name);`` +[variablelist +[[Requires][The argument must be a [link ntbs].]] +[[Effects][Constructs an arg object holding a keyword with name name.]] +] +[endsect] +[section Class `arg` operator=] +``template arg &operator = (T const &value);`` +[variablelist +[[Requires][The argument must convertible to python.]] +[[Effects][Assigns default value for the keyword.]] +[[Returns][Reference to `this`.]] +] +[endsect] +[section Keyword-expression operator,] +`` +keyword-expression operator , (keyword-expression, const arg &kw) const +keyword-expression operator , (keyword-expression, const char *name) const; +`` +[variablelist +[[Requires][The argument name must be a [link ntbs].]] +[[Effects][Extends the keyword-expression argument with one more keyword.]] +[[Returns][The extended keyword-expression.]] +] +[endsect] +[section Example] +`` +#include +using namespace boost::python; + +int f(double x, double y, double z=0.0, double w=1.0); + +BOOST_PYTHON_MODULE(xxx) +{ + def("f", f, (arg("x"), "y", arg("z")=0.0, arg("w")=1.0)); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/call.qbk b/doc/reference/call.qbk new file mode 100644 index 0000000000..4003529ef5 --- /dev/null +++ b/doc/reference/call.qbk @@ -0,0 +1,26 @@ +[section boost/python/call.hpp] +[section Introduction] + defines the call family of overloaded function templates, used to invoke Python callable objects from C++. +[endsect] +[section Function `call`] +`` +template +R call(PyObject* callable, A1 const&, A2 const&, ... An const&) +`` +[variablelist +[[Requires][R is a pointer type, reference type, or a complete type with an accessible copy constructor]] +[[Effects][Invokes callable(a1, a2, ...an) in Python, where a1...an are the arguments to call(), converted to Python objects. ]] +[[Returns][The result of the Python call, converted to the C++ type R.]] +[[Rationale][For a complete semantic description and rationale, see this page. ]] +] +[endsect] +[section Example] +The following C++ function applies a Python callable object to its two arguments and returns the result. If a Python exception is raised or the result can't be converted to a double, an exception is thrown. +`` +double apply2(PyObject* func, double x, double y) +{ + return boost::python::call(func, x, y); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/call_method.qbk b/doc/reference/call_method.qbk new file mode 100644 index 0000000000..fcf68667d0 --- /dev/null +++ b/doc/reference/call_method.qbk @@ -0,0 +1,82 @@ +[section boost/python/call_method.hpp] +[section Introduction] + defines the call_method family of overloaded function templates, used to invoke callable attributes of Python objects from C++. +[endsect] +[section Function `call_method`] +`` +template +R call_method(PyObject* self, char const* method, A1 const&, A2 const&, ... An const&) +`` +[variablelist +[[Requires][`R` is a pointer type, reference type, or a complete type with an accessible copy constructor]] +[[Effects][Invokes `self.method(a1, a2, ...an)` in Python, where `a1...an` are the arguments to `call_method()`, converted to Python objects. For a complete semantic description, see this page.]] +[[Returns][The result of the Python call, converted to the C++ type `R`.]] +[[Rationale][`call_method` is critical to implementing C++ virtual functions which are overridable in Python, as shown by the example below.]] +] +[endsect] +[section Example] +The following C++ illustrates the use of `call_method` in wrapping a class with a virtual function that can be overridden in Python: +C++ Module Definition +`` +#include +#include +#include +#include +#include +#include + +// class to be wrapped +class Base +{ + public: + virtual char const* class_name() const { return "Base"; } + virtual ~Base() {}; +}; + +bool is_base(Base* b) +{ + return !std::strcmp(b->class_name(), "Base"); +} + +// Wrapper code begins here +using namespace boost::python; + +// Callback class +class Base_callback : public Base +{ + public: + Base_callback(PyObject* self) : m_self(self) {} + + char const* class_name() const { return call_method(m_self, "class_name"); } + char const* Base_name() const { return Base::class_name(); } + private: + PyObject* const m_self; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + def("is_base", is_base); + + class_("Base") + .def("class_name", &Base_callback::Base_name) + ; + +} +`` +Python code: +`` +>>> from my_module import * +>>> class Derived(Base): +... def __init__(self): +... Base.__init__(self) +... def class_name(self): +... return self.__class__.__name__ +... +>>> is_base(Base()) # calls the class_name() method from C++ +1 +>>> is_base(Derived()) +0 +`` +[endsect] +[endsect] diff --git a/doc/reference/calling.qbk b/doc/reference/calling.qbk new file mode 100644 index 0000000000..5be05d4ed9 --- /dev/null +++ b/doc/reference/calling.qbk @@ -0,0 +1,65 @@ +[section Calling Python Functions and Methods] +[section Introduction] +The simplest way to call a Python function from C++, given an [link object_wrappers.boost_python_object_hpp.class_object `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 [link object_wrappers.boost_python_object_hpp.class_object `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 [link object_wrappers.boost_python_object_hpp.class_object `object`] instance, `Boost.Python` provides two families of function templates, [link function_invocation_and_creation.boost_python_call_hpp.function_call `call`] and [link function_invocation_and_creation.boost_python_call_method_hpp.function_call_method `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(callable_object, a1, a2... aN);`` +Calling a method of a Python object is similarly easy: +``call_method(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. +[endsect] +[section 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 [link function_invocation_and_creation.boost_python_ptr_hpp.functions `ptr()`] and `ref()`: +`` +class X : boost::noncopyable +{ + ... +}; + +void apply(PyObject* callable, X& x) +{ + // Invoke callable, passing a Python object which holds a reference to x + boost::python::call(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". + +[table +[[Argument Type][Behavior]] +[[`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.]] +[[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.]] +[[boost::reference_wrapper][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][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!]] +] +[endsect] +[section Result Handling] +In general, `call()` and call_method() 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. +[endsect] +[section 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. + +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]. + +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. + +The compromise I've settled on is this: + +# 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. +# 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. + +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(...) returns. + +The old Boost.Python v1 deals with this issue by refusing to compile any uses of call(), 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. + +In Boost.Python this is dealt with by: + +# lifting the compile-time restriction on `char const *` callback returns +# detecting the case when the reference count on the result Python object is 1 and throwing an + exception inside of `call(...)` 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`, and they will be protected against dangles at runtime, at least long enough to get out of the `call(...)` invocation. +[endsect] +[endsect] diff --git a/doc/reference/class.qbk b/doc/reference/class.qbk new file mode 100644 index 0000000000..2cdf429921 --- /dev/null +++ b/doc/reference/class.qbk @@ -0,0 +1,308 @@ +[section boost/python/class.hpp] +[section Introduction] +`` defines the interface through which users expose their C++ classes to Python. It declares the `class_` class template, which is parameterized on the class type being exposed. It also exposes the `init`, `optional` and `bases` utility class templates, which are used in conjunction with `class_`. + +`` contains a forward declaration of the `class_` class template. +[endsect] +[section Class template `class_`] +Creates a Python class associated with the C++ type passed as its first parameter. Although it has four template parameters, only the first one is required. The three optional arguments can actually be supplied *in any order*\ ; Boost.Python determines the role of the argument from its type. +[table + [[Template Parameter][Requirements][Semantics][Default]] + [[`T`][A class type.][The class being wrapped][]] + [[Bases] + [A specialization of [link high_level_components.boost_python_class_hpp.class_template_bases_t1_t2_tn bases<...>] which specifies previously-exposed C++ base classes of `T`.] + [Registers `from_python` conversions from wrapped `T` instances to each of its exposed direct and indirect bases. For each polymorphic base `B`, registers conversions from indirectly-held wrapped `B` instances to `T`.][[link high_level_components.boost_python_class_hpp.class_template_bases_t1_t2_tn bases<>]]] + [[HeldType][Must be `T`, a class derived from `T`, or a [link concepts.dereferenceable.concept_requirements Dereferenceable] type for which `pointee::type` is `T` or a class derived from `T`.][Specifies the type that is actually embedded in a Python object wrapping a `T` instance when `T`\ 's constructor is called or when a `T` or `T*` is converted to Python without the use of [link function_invocation_and_creation.boost_python_ptr_hpp.functions ptr], `ref`, or [link concepts.callpolicies Call Policies] such as [link function_invocation_and_creation.models_of_callpolicies.boost_python_return_internal_ref.class_template_return_internal_r return_internal_reference]. More details below.][`T`]] + [[NonCopyable][If supplied, must be `boost::noncopyable`.][Suppresses automatic registration of `to_python` conversions which copy `T` instances. Required when `T` has no publicly-accessible copy constructor.][An unspecified type other than boost::noncopyable.]] +] +[section HeldType Semantics] + +# If HeldType is derived from `T`, its exposed constructor(s) must accept an initial `PyObject*` argument which refers back to the Python object that contains the HeldType instance, as shown in this example. This argument is not included in the [link high_level_components.boost_python_init_hpp.introduction.init_expressions init-expression] passed to [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu def(init_expr)], below, nor is it passed explicitly by users when Python instances of `T` are created. This idiom allows C++ virtual functions which will be overridden in Python to access the Python object so the Python method can be invoked. Boost.Python automatically registers additional converters which allow wrapped instances of `T` to be passed to wrapped C++ functions expecting HeldType arguments. +# Because Boost.Python will always allow wrapped instances of `T` to be passed in place of HeldType arguments, specifying a smart pointer for HeldType allows users to pass Python `T` instances where a smart pointer-to-T is expected. Smart pointers such as `std::auto_ptr<>` or `boost::shared_ptr<>` which contain a nested type `element_type` designating the referent type are automatically supported; additional smart pointer types can be supported by specializing `pointee`. +# As in case 1 above, when HeldType is a smart pointer to a class derived from `T`, the initial `PyObject*` argument must be supplied by all of HeldType's exposed constructors. +# Except in cases 1 and 3, users may optionally specify that T itself gets initialized with a similar initial `PyObject*` argument by specializing [link utility_and_infrastructure.boost_python_has_back_reference_.class_template_has_back_referenc has_back_reference]. + +[endsect] +[section Class template `class_` synopsis] +`` + namespace boost { namespace python + { + template + , class HeldType = T + , class NonCopyable = unspecified + > + class class_ : public object + { + // Constructors with default __init__ + class_(char const* name); + class_(char const* name, char const* docstring); + + // Constructors, specifying non-default __init__ + template + class_(char const* name, Init); + template + class_(char const* name, char const* docstring, Init); + + // Exposing additional __init__ functions + template + class_& def(Init); + + // defining methods + template + class_& def(char const* name, F f); + template + class_& def(char const* name, Fn fn, A1 const&); + template + class_& def(char const* name, Fn fn, A1 const&, A2 const&); + template + class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&); + + // declaring method as static + class_& staticmethod(char const* name); + + // exposing operators + template + class_& def(detail::operator_); + + // Raw attribute modification + template + class_& setattr(char const* name, U const&); + + // exposing data members + template + class_& def_readonly(char const* name, D T::*pm); + + template + class_& def_readwrite(char const* name, D T::*pm); + + // exposing static data members + template + class_& def_readonly(char const* name, D const& d); + template + class_& def_readwrite(char const* name, D& d); + + // property creation + template + void add_property(char const* name, Get const& fget, char const* doc=0); + template + void add_property( + char const* name, Get const& fget, Set const& fset, char const* doc=0); + + template + void add_static_property(char const* name, Get const& fget); + template + void add_static_property(char const* name, Get const& fget, Set const& fset); + + // pickle support + template + self& def_pickle(PickleSuite const&); + self& enable_pickling(); + }; + }} +`` +[endsect] +[section Class template `class_` constructors] +`` + class_(char const* name); + class_(char const* name, char const* docstring); + template + class_(char const* name, Init init_spec); + template + class_(char const* name, char const* docstring, Init init_spec); +`` + +[variablelist + [[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules]. If docstring is supplied, it must be an [link ntbs]. If `init_spec` is supplied, it must be either the special enumeration constant `no_init` or an [link high_level_components.boost_python_init_hpp.introduction.init_expressions init-expression] compatible with `T`.]] + [[Effects][Constructs a `class_` object holding a Boost.Python extension class named name. The named attribute of the [link high_level_components.boost_python_scope_hpp.introduction current scope] is bound to the new extension class. + +* If supplied, the value of docstring is bound to the `__doc__` attribute of the extension class. +* If `init_spec` is `no_init`, a special `__init__` function is generated which always raises a Python exception. Otherwise, `this->def(init_spec)` is called. +* If `init_spec` is not supplied, `this->def(init<>())` is called.]] + [[Rationale][Allowing the user to specify constructor arguments in the `class_<>` constructor helps her to avoid the common run-time errors which result from invoking wrapped member functions without having exposed an `__init__` function which creates the requisite `T` instance. Types which are not default-constructible will cause a compile-time error unless `Init` is supplied. The user must always supply name as there is currently no portable method to derive the text of the class name from its type.]] +] +[endsect] +[section Class template `class_` modifier functions] +`` + template + class_& def(Init init_expr); +`` + +[variablelist + [[Requires][`init_expr` is the result of an [link high_level_components.boost_python_init_hpp.introduction.init_expressions init-expression] compatible with `T`.]] + [[Effects][For each [link high_level_components.boost_python_init_hpp.introduction.init_expressions valid prefix] `P` of `Init`, adds an `__init__(...)` function overload to the extension class accepting P as arguments. Each overload generated constructs an object of HeldType according to the semantics described above, using a copy of init_expr's call policies. If the longest [link high_level_components.boost_python_init_hpp.introduction.init_expressions valid prefix] of Init contains N types and init_expr holds M keywords, an initial sequence of the keywords are used for all but the first N - M arguments of each overload.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose a class' constructor to Python.]] +] +`` + template + class_& def(char const* name, Fn fn); + template + class_& def(char const* name, Fn fn, A1 const& a1); + template + class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2); + template + class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3); +`` +[variablelist + [[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules]. + * If a1 is the result of an [link function_invocation_and_creation.boost_python_overloads_hpp.introduction.overload_dispatch_expressions overload-dispatch-expression], only the second form is allowed and fn must be a pointer to function or pointer to member function whose [link arity] is the same as A1's [link function_invocation_and_creation.boost_python_overloads_hpp.introduction.overload_dispatch_expressions maximum arity]. + + [*Effects:] For each prefix `P` of `Fn`\ 's sequence of argument types, beginning with the one whose length is `A1`\ 's [link function_invocation_and_creation.boost_python_overloads_hpp.introduction.overload_dispatch_expressions minimum arity], adds a `name(...)` method overload to the extension class. Each overload generated invokes a1's call-expression with `P`, using a copy of a1's call policies. If the longest valid prefix of `A1` contains `N` types and a1 holds `M` keywords, an initial sequence of the keywords are used for all but the first `N - M` arguments of each overload. + +* Otherwise, a single method overload is built around fn, which must not be null: + + * If fn is a function pointer, its first argument must be of the form U, U cv&, U cv*, or U cv* const&, where T* is convertible to U*, and a1-a3, if supplied, may be selected in any order from the table below. + * Otherwise, if fn is a member function pointer, its target must be T or one of its public base classes, and a1-a3, if supplied, may be selected in any order from the table below. + * Otherwise, Fn must be [derived from] [link object_wrappers.boost_python_object_hpp.class_object object], and a1-a2, if supplied, may be selcted in any order from the first two rows of the table below. To be useful, fn should be [@http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6 callable]. + [table + [[Mnemonic Name][Requirements/Type properties][Effects]] + [[docstring][Any [link ntbs]][Value will be bound to the __doc__ attribute of the resulting method overload. If an earlier overload supplied a docstring, two newline characters and the new docstring are appended to it.]] + [[policies][A model of [link concepts.callpolicies CallPolicies]][A copy will be used as the call policies of the resulting method overload.]] + [[keywords][The result of a [link function_invocation_and_creation.boost_python_args_hpp.introduction.keyword_expressions keyword-expression] specifying no more arguments than the [link arity] of fn.][A copy will be used as the call policies of the resulting method overload.]] + ] +]] + [[Returns][`*this`]] +] +``class_& staticmethod(char const* name);`` +[variablelist + [[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules], and corresponds to a method whose overloads have all been defined.]] + [[Effects][Replaces the existing named attribute `x` with the result of invoking `staticmethod(x)` in Python. Specifies that the corresponding method is static and therefore no object instance will be passed to it. This is equivalent to the Python statement:]] +] +``setattr(self, name, staticmethod(getattr(self, name)))`` +[variablelist + [[Note][Attempting to invoke def(name,...) after invoking staticmethod(name) will [link raise] a RuntimeError.]] + [[Returns][`*this`]] +] +`` +template +class_& def(detail::operator_); +`` +[variablelist + [[Effects][Adds a Python [@http://www.python.org/doc/ref/specialnames.html special method] as described [link high_level_components.boost_python_operators_hpp here].]] + [[Returns][`*this`]] +] + +`` + template + class_& setattr(char const* name, U const& u); +`` +[variablelist + [[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules].]] + [[Effects][Converts `u` to Python and adds it to the attribute dictionary of the extension class: + ``PyObject_SetAttrString(this->ptr(), name, object(u).ptr());``]] + [[Returns][`*this`]] +] +`` + template + void add_property(char const* name, Get const& fget, char const* doc=0); + template + void add_property( + char const* name, Get const& fget, Set const& fset, char const* doc=0); +`` +[variablelist + [[Requires][name is an [link ntbs] which conform to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules].]] + [[Effects][Creates a new Python [@http://www.python.org/2.2.2/descrintro.html#property property] class instance, passing `object(fget)` (and `object(fset)` in the second form) with an (optional) docstring `doc` to its constructor, then adds that property to the Python class object under construction with the given attribute name.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose functions that can be invoked from Python with attribute access syntax.]] +] +`` + template + void add_static_property(char const* name, Get const& fget); + template + void add_static_property(char const* name, Get const& fget, Set const& fset); +`` +[variablelist + [[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules].]] + [[Effects][Creates a Boost.Python.StaticProperty object, passing `object(fget)` (and `object(fset)` in the second form) to its constructor, then adds that property to the Python class under construction with the given attribute name. StaticProperty is a special subclass of Python's property class which can be called without an initial self argument.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose functions that can be invoked from Python with static attribute access syntax.]] +] +`` + template + class_& def_readonly(char const* name, D T::*pm, char const* doc=0); + template + class_& def_readonly(char const* name, D const& d); +`` +[variablelist + [[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules]. `doc` is also an [link ntbs].]] + [[Effects][``this->add_property(name, make_getter(pm), doc);`` and ``this->add_static_property(name, make_getter(d));`` respectively.]] + [[Returns][`*this`]] + [[Rationale][Allows users to easily expose a class' data member or free variable such that it can be inspected from Python with a natural syntax.]] +] +`` + template + class_& def_readwrite(char const* name, D T::*pm, char const* doc=0); + template + class_& def_readwrite(char const* name, D& d); +`` +[variablelist +[[Effects][``this->add_property(name, make_getter(pm), make_setter(pm), doc);`` and ``this->add_static_property(name, make_getter(d), make_setter(d));`` respectively.]] +[[Returns][`*this`]] +[[Rationale][Allows users to easily expose a class' data or free variable member such that it can be inspected and set from Python with a natural syntax.]] +] +`` + template + class_& def_pickle(PickleSuite const&); +`` +[variablelist +[[Requires][PickleSuite must be publically derived from [link topics.pickle_support.the_pickle_interface pickle_suite].]] +[[Effects][Defines a legal combination of the special attributes and methods: __getinitargs__, __getstate__, __setstate__, __getstate_manages_dict__, __safe_for_unpickling__, __reduce__]] +[[Returns][`*this`]] +[[Rationale][Provides an [link topics.pickle_support.the_pickle_interface easy to use high-level interface] for establishing complete [link topics.pickle_support.the_pickle_interface pickle support] for the wrapped class. The user is protected by compile-time consistency checks.]] +] +``class_& enable_pickling();`` +[variablelist +[[Effects][Defines the __reduce__ method and the __safe_for_unpickling__ attribute.]] +[[Returns][`*this`]] +[[Rationale][Light-weight alternative to def_pickle(). Enables implementation of pickle support from Python.]] +] +[endsect] +[endsect] +[section Class template bases] +An MPL sequence which can be used in class_<...> instantiations indicate a list of base classes. +[section Class template bases synopsis] +`` +namespace boost { namespace python +{ + template + struct bases + {}; +}} +`` +[endsect] +[endsect] +[section Examples] +Given a C++ class declaration: +`` +class Foo : public Bar, public Baz +{ + public: + Foo(int x, char const* y); + Foo(double); + + std::string const& name() { return m_name; } + void name(char const*); + + double value; // public data + private: + ... +}; +`` +A corresponding Boost.Python extension class can be created with: +`` +using namespace boost::python; + +class_ >("Foo", + "This is Foo's docstring." + "It describes our Foo extension class", + + init(args("x","y"), "__init__ docstring") + ) + .def(init()) + .def("get_name", &Foo::get_name, return_internal_reference<>()) + .def("set_name", &Foo::set_name) + .def_readwrite("value", &Foo::value); +`` +[endsect] +[endsect] diff --git a/doc/reference/components.qbk b/doc/reference/components.qbk new file mode 100644 index 0000000000..70a2969a1a --- /dev/null +++ b/doc/reference/components.qbk @@ -0,0 +1,18 @@ +[chapter High Level Components + [quickbook 1.7] +] + +[include class.qbk] +[include def.qbk] +[include def_visitor.qbk] +[include docstring_options.qbk] +[include enum.qbk] +[include errors.qbk] +[include exception_translator.qbk] +[include init.qbk] +[include iterator.qbk] +[include module.qbk] +[include operators.qbk] +[include scope.qbk] +[include stl_iterator.qbk] +[include wrapper.qbk] diff --git a/doc/reference/concepts.qbk b/doc/reference/concepts.qbk new file mode 100644 index 0000000000..bb5db53c1b --- /dev/null +++ b/doc/reference/concepts.qbk @@ -0,0 +1,134 @@ +[chapter Concepts + [quickbook 1.7] +] + +[section CallPolicies] +[section Introduction] + +Models of the CallPolicies concept are used to specialize the behavior of Python callable objects +generated by Boost.Python to wrapped C++ objects like function and member function pointers, +providing three behaviors: + +# `precall` - Python argument tuple management before the wrapped object is invoked +# `result_converter` - C++ return value handling +# `postcall` - Python argument tuple and result management after the wrapped object is invoked +# `extract_return_type` - metafunction for extracting the return type from a given signature type sequence + +[endsect] +[section CallPolicies Composition] + +In order to allow the use of multiple models of CallPolicies in the same callable object, +Boost.Python's CallPolicies class templates provide a chaining interface which allows them to be +recursively composed. This interface takes the form of an optional template parameter, `Base`, which +defaults to `default_call_policies`. By convention, the `precall` function of the `Base` is invoked after +the `precall` function supplied by the `outer` template, and the `postcall` function of the `Base` is invoked +before the `postcall` function of the `outer` template. If a `result_converter` is supplied by the `outer` +template, it replaces any `result_converter` supplied by the `Base`. For an example, see +`return_internal_reference`. + +[endsect] +[section Concept Requirements] +[table + [[Expression][Type][Result/Semantics]] + [[`x.precall(a)`][convertible to `bool`] + [returns `false` and `PyErr_Occurred() != 0` upon failure, `true` otherwise.]] + [[`P::result_converter`][A model of `ResultConverterGenerator`.] + [An MPL unary Metafunction Class used produce the "preliminary" result object.]] + [[`x.postcall(a, r)`][convertible to `PyObject*`] + [`0` and `PyErr_Occurred() != 0` upon failure. Must "conserve references" even in the event of an exception. In other words, if `r` is not returned, its reference count must be decremented; if another existing object is returned, its reference count must be incremented.]] + [[`P::extract_return_type`][A model of Metafunction.] + [An MPL unary Metafunction used extract the return type from a given signature. By default it is derived from `mpl::front`.]] +] +[endsect] +[endsect] +[section Dereferenceable] +[section Introduction] +Instances of a `Dereferenceable` type can be used like a pointer to access an lvalue. +[endsect] +[section Concept Requirements] +In the table below, `T` is a model of Dereferenceable, and `x` denotes an object of type `T`. In addition, all pointers are `Dereferenceable`. +[table + [[Expression][Result][Operational Semantics]] + [[`get_pointer(x)`][convertible to `pointee::type*`] + [`&*x`, or a null pointer ]] +] +[endsect] +[endsect] +[section Extractor] +[section Introduction] +An Extractor is a class which Boost.Python can use to extract C++ objects from Python objects, and is typically used by facilities that define `from_python` conversions for "traditional" Python extension types. +[endsect] +[section Concept Requirements] +In the table below, `X` denotes a model of `Extractor` and `a` denotes an instance of a Python object type. +[table + [[Expression][Type][Semantics]] + [[`X::execute(a)`][non-void] + [Returns the C++ object being extracted. The execute function must not be overloaded.]] + [[`&a.ob_type`][`PyTypeObject**`] + [Points to the `ob_type` field of an object which is layout-compatible with `PyObject`]] +] +[endsect] +[section Notes] +Informally, an Extractor's execute member must be a non-overloaded static function whose single argument is a Python object type. Acceptable Python object types include those publicly (and unambiguously) derived from PyObject, and POD types which are layout-compatible with PyObject. +[endsect] +[endsect] +[section HolderGenerator] +[section Introduction] +A HolderGenerator is a unary metafunction class which returns types suitable for holding instances of its argument in a wrapped C++ class instance. +[endsect] +[section Concept Requirements] +In the table below, `G` denotes an type which models `HolderGenerator`, and `X` denotes a class type. +[table + [[Expression][Requirements]] + [[`G::apply::type`][A concrete subclass of `instance_holder` which can hold objects of type `X`. ]] +] +[endsect] +[endsect] +[section ResultConverter] +[section Introduction] +A ResultConverter for a type `T` is a type whose instances can be used to convert C++ return values of type `T` `to_python`. A ResultConverterGenerator is an MPL unary metafunction class which, given the return type of a C++ function, returns a ResultConverter for that type. ResultConverters in Boost.Python generally inspect library's registry of converters to find a suitable converter, but converters which don't use the registry are also possible. +[endsect] +[section ResultConverter Concept Requirements] +In the table below, `C` denotes a ResultConverter type for a type `R`, `c` denotes an object of type `C`, and `r` denotes an object of type `R`. +[table + [[Expression][Type][Semantics]] + [[`C c`][] + [Constructs a `c` object.]] + [[`c.convertible()`][convertible to `bool`] + [`false` iff no conversion from any `R` value to a Python object is possible.]] + [[`c(r)`][convertible to `PyObject*`] + [A pointer to a Python object corresponding to `r`, or `0` iff `r` could not be converted `to_python`, in which case `PyErr_Occurred` should return non-zero.]] + [[`c.get_pytype()`][`PyTypeObject const *`] + [A pointer to a Python Type object corresponding to result of the conversion, or `0`. Used for documentation generation. If `0` is returned the generated type in the documentation will be object.]] +] +[endsect] +[section ResultConverterGenerator Concept Requirements] +In the table below, `G` denotes a ResultConverterGenerator type and `R` denotes a possible C++ function return type. +[table + [[Expression][Requirements]] + [[`G::apply::type`][A ResultConverter type for `R`.]] +] +[endsect] +[endsect] +[section ObjectWrapper] +[section Introduction] +This page defines two concepts used to describe classes which manage a Python objects, and which are intended to support usage with a Python-like syntax. +[endsect] +[section ObjectWrapper Concept Requirements] +Models of the ObjectWrapper concept have [link object_wrappers.boost_python_object_hpp.class_object object] as a publicly-accessible base class, and are used to supply special construction behavior and/or additional convenient functionality through (often templated) member functions. Except when the return type R is itself an [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper], a member function invocation of the form ``x.some_function(a1, a2,...an)`` always has semantics equivalent to: +``extract(x.attr("some_function")(object(a1), object(a2),...object(an)))()`` (see [link concepts.objectwrapper.caveat caveat] below). +[endsect] +[section TypeWrapper Concept Requirements] +TypeWrapper is a refinement of [link concepts.objectwrapper.objectwrapper_concept_requiremen ObjectWrapper] which is associated with a particular Python type `X`. For a given TypeWrapper `T`, a valid constructor expression ``T(a1, a2,...an)`` builds a new T object managing the result of invoking X with arguments corresponding to ``object(a1), object(a2),...object(an)``. +When used as arguments to wrapped C++ functions, or as the template parameter to [link to_from_python_type_conversion.boost_python_extract_hpp.class_template_extract extract<>], only instances of the associated Python type will be considered a match. +[endsect] +[section Caveat] +The upshot of the special member function invocation rules when the return type is a TypeWrapper is that it is possible for the returned object to manage a Python object of an inappropriate type. This is not usually a serious problem; the worst-case result is that errors will be detected at runtime a little later than they might otherwise be. For an example of how this can occur, note that the [link object_wrappers.boost_python_dict_hpp.class_dict dict] member function `items` returns an object of type [link object_wrappers.boost_python_list_hpp.class_list list]. Now suppose the user defines this `dict` subclass in Python: +`` + >>> class mydict(dict): + ... def items(self): + ... return tuple(dict.items(self)) # return a tuple +`` +Since an instance of `mydict` is also an instance of `dict`, when used as an argument to a wrapped C++ function, [link object_wrappers.boost_python_dict_hpp.class_dict boost::python::dict] can accept objects of Python type `mydict`. Invoking `items()` on this object can result in an instance of [link object_wrappers.boost_python_list_hpp.class_list boost::python::list] which actually holds a Python `tuple`. Subsequent attempts to use `list` methods (e.g. `append`, or any other mutating operation) on this object will raise the same exception that would occur if you tried to do it from Python. +[endsect] +[endsect] diff --git a/doc/reference/conversion.qbk b/doc/reference/conversion.qbk new file mode 100644 index 0000000000..6f6268b496 --- /dev/null +++ b/doc/reference/conversion.qbk @@ -0,0 +1,10 @@ +[chapter To/From Python Type Conversion + [quickbook 1.7] +] + +[include extract.qbk] +[include implicit.qbk] +[include lvalue_from_pytype.qbk] +[include opaque_pointer_converter.qbk] +[include to_python_converter.qbk] +[include register_ptr_to_python.qbk] diff --git a/doc/reference/copy_const_reference.qbk b/doc/reference/copy_const_reference.qbk new file mode 100644 index 0000000000..9217a29675 --- /dev/null +++ b/doc/reference/copy_const_reference.qbk @@ -0,0 +1,58 @@ +[section boost/python/copy_const_reference.hpp] +[section Class `copy_const_reference`] +`copy_const_reference` is a model of [link concepts.resultconverter.resultconvertergenerator_concept ResultConverterGenerator] which can be used to wrap C++ functions returning a reference-to-const type such that the referenced value is copied into a new Python object. +`` +namespace boost { namespace python +{ + struct copy_const_reference + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `copy_const_reference` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U const&` for some `U`.]] +[[Returns][`typedef to_python_value type;`]] +] +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar const& get_bar() const { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_value_policy()) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/copy_non_const_reference.qbk b/doc/reference/copy_non_const_reference.qbk new file mode 100644 index 0000000000..a12d4cfbf8 --- /dev/null +++ b/doc/reference/copy_non_const_reference.qbk @@ -0,0 +1,58 @@ +[section boost/python/copy_non_const_reference.hpp] +[section Class `copy_non_const_reference`] +`copy_non_const_reference` is a model of [link concepts.resultconverter.resultconvertergenerator_concept ResultConverterGenerator] which can be used to wrap C++ functions returning a reference-to-non-const type such that the referenced value is copied into a new Python object. +`` +namespace boost { namespace python +{ + struct copy_non_const_reference + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `copy_non_const_reference` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U &` for some non-const `U`.]] +[[Returns][`typedef to_python_value type`;]] +] +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar& get_bar() { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_value_policy()) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/data_members.qbk b/doc/reference/data_members.qbk new file mode 100644 index 0000000000..8cc9bb7817 --- /dev/null +++ b/doc/reference/data_members.qbk @@ -0,0 +1,98 @@ +[section boost/python/data_members.hpp] +[section Introduction] +`make_getter()` and `make_setter()` are the functions used internally by [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu `class_<>::def_readonly`] and [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu `class_<>::def_readwrite`] to produce Python callable objects which wrap C++ data members. +[endsect] +[section Functions] +`` +template +object make_getter(D C::*pm); + +template +object make_getter(D C::*pm, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of [link concepts.callpolicies `CallPolicies`].]] +[[Effects][Creates a Python callable object which accepts a single argument that can be converted from_python to C*, and returns the corresponding member D member of the C object, converted to_python. If policies is supplied, it will be applied to the function as described here. Otherwise, the library attempts to determine whether D is a user-defined class type, and if so uses return_internal_reference<> +for Policies. Note that this test may inappropriately choose return_internal_reference<> in some cases when D is a smart pointer type. This is a known defect.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +`` +template +object make_getter(D const& d); +template +object make_getter(D const& d, Policies const& policies); + +template +object make_getter(D const* p); +template +object make_getter(D const* p, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which accepts no arguments and returns d or *p, converted to_python on demand. If policies is supplied, it will be applied to the function as described here. Otherwise, the library attempts to determine whether D is a user-defined class type, and if so uses reference_existing_object for Policies.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +`` +template +object make_setter(D C::*pm); + +template +object make_setter(D C::*pm, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which, when called from Python, expects two arguments which can be converted from_python to C* and D const&, respectively, and sets the corresponding D member of the C object. If policies is supplied, it will be applied to the function as described here.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +`` +template +object make_setter(D& d); +template +object make_setter(D& d, Policies const& policies); + +template +object make_setter(D* p); +template +object make_setter(D* p, Policies const& policies); +`` +[variablelist +[[Requires][Policies is a model of CallPolicies.]] +[[Effects][Creates a Python callable object which accepts one argument, which is converted from Python to D const& and written into d or *p, respectively. If policies is supplied, it will be applied to the function as described here.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] +[endsect] +[section Example] +The code below uses make_getter and make_setter to expose a data member as functions: +`` +#include +#include +#include + +struct X +{ + X(int x) : y(x) {} + int y; +}; + +using namespace boost::python; + +BOOST_PYTHON_MODULE_INIT(data_members_example) +{ + class_("X", init()) + .def("get", make_getter(&X::y)) + .def("set", make_setter(&X::y)) + ; +} +`` +It can be used this way in Python: +`` +>>> from data_members_example import * +>>> x = X(1) +>>> x.get() +1 +>>> x.set(2) +>>> x.get() +2 +`` +[endsect] +[endsect] diff --git a/doc/reference/def.qbk b/doc/reference/def.qbk new file mode 100644 index 0000000000..bf92e17c66 --- /dev/null +++ b/doc/reference/def.qbk @@ -0,0 +1,54 @@ +[section boost/python/def.hpp] +[section Introduction] +`def()` is the function which can be used to expose C++ functions and callable objects as Python functions in the [link high_level_components.boost_python_scope_hpp.introduction current scope]. +[endsect] +[section Functions] +`` +template +void def(char const* name, F f); + +template +void def(char const* name, Fn fn, A1 const&); + +template +void def(char const* name, Fn fn, A1 const&, A2 const&); + +template +void def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&); +`` +[variablelist +[[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules]. + +* If `Fn` is [derived from] [link object_wrappers.boost_python_object_hpp.class_object object], it will be added to the [link high_level_components.boost_python_scope_hpp.introduction current scope] as a single overload. To be useful, `fn` should be [@http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6 callable]. +* If `a1` is the result of an [link function_invocation_and_creation.boost_python_overloads_hpp.introduction.overload_dispatch_expressions overload-dispatch-expression], only the second form is allowed and `fn` must be a pointer to function or pointer to member function whose [link arity] is the same as A1's [link function_invocation_and_creation.boost_python_overloads_hpp.introduction.overload_dispatch_expressions maximum arity]. + + [*Effects:] For each prefix `P` of `Fn`\ 's sequence of argument types, beginning with the one whose length is `A1`\ 's [link function_invocation_and_creation.boost_python_overloads_hpp.introduction.overload_dispatch_expressions minimum arity], adds a `name(...)` function overload to the [link high_level_components.boost_python_scope_hpp.introduction current scope]. Each overload generated invokes a1's call-expression with P, using a copy of a1's call policies. If the longest valid prefix of A1 contains N types and a1 holds M keywords, an initial sequence of the keywords are used for all but the first N - M arguments of each overload. + +* Otherwise, fn must be a non-null function or member function pointer, and a single function overload built around fn is added to the current scope. If any of a1-a3 are supplied, they may be selected in any order from the table below. + + [table + [[Mnemonic Name][Requirements/Type properties][Effects]] + [[docstring][Any [link ntbs]][Value will be bound to the `__doc__` attribute of the resulting method overload.]] + [[policies][A model of [link concepts.callpolicies CallPolicies]][A copy will be used as the call policies of the resulting method overload.]] + [[keywords][The result of a [link function_invocation_and_creation.boost_python_args_hpp.introduction.keyword_expressions keyword-expression] specifying no more arguments than the [link arity] of `fn`.][A copy will be used as the call policies of the resulting method overload.]] +] +]] +] +[endsect] +[section Example] +`` +#include +#include +#include + +using namespace boost::python; + +char const* foo(int x, int y) { return "foo"; } + +BOOST_PYTHON_MODULE(def_test) +{ + def("foo", foo, args("x", "y"), "foo's docstring"); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/def_visitor.qbk b/doc/reference/def_visitor.qbk new file mode 100644 index 0000000000..773402a3c0 --- /dev/null +++ b/doc/reference/def_visitor.qbk @@ -0,0 +1,58 @@ +[section boost/python/def_visitor.hpp] +[section Introduction] + provides a generic visitation interface through which the [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel class_] def member functionality can be extended non-intrusively to avoid cluttering the [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel class_] interface. It declares the `def_visitor` class template, which is parameterized on the derived type `DerivedVisitor`, which provides the actual `def` functionality through its `visit` member functions. +[endsect] +[section Class `def_visitor`] +The class `def_visitor` is a base class paramaterized by its derived class. The `def_visitor` class is a protocol class. Its derived class, DerivedVisitor, is expected to have a member function `visit`. The `def_visitor` class is never instantiated directly. Instead, an instance of its subclass, DerivedVisitor, is passed on as an argument to the [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel class_] `def` member function. + +`` +namespace boost { namespace python { + + template + class def_visitor {}; +} +`` + +[variablelist + [[Requires][The client supplied class DerivedVisitor template parameter is expected to: + * be privately derived from def_visitor + * grant friend access to class def_visitor_access + * define either or both visit member functions listed in the table below: + [table + [[Expression][Return Type][Requirements][Effects]] + [[`visitor.visit(cls)`][`void`] + [`cls` is an instance of a [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel class_] being wrapped to Python. `visitor` is a `def_visitor` derived class.] + [A call to `cls.def(visitor)` forwards to this member function.]] + [[`visitor.visit(cls, name, options)`][`void`] + [`cls` is a [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel class_] instance, name is a C string. `visitor` is a `def_visitor` derived class. options is a context specific optional argument.] + [A call to `cls.def(name, visitor)` or `cls.def(name, visitor, options)` forwards to this member function. ]]] + ]] + ] +[endsect] +[section Example] +`` +class X {/*...*/}; + +class my_def_visitor : boost::python::def_visitor +{ + friend class def_visitor_access; + + template + void visit(classT& c) const + { + c.def("foo", &my_def_visitor::foo); + c.def("bar", &my_def_visitor::bar); + } + + static void foo(X& self); + static void bar(X& self); +}; + +BOOST_PYTHON_MODULE(my_ext) +{ + class_("X") + .def(my_def_visitor()); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/default_call_policies.qbk b/doc/reference/default_call_policies.qbk new file mode 100644 index 0000000000..99b969be7d --- /dev/null +++ b/doc/reference/default_call_policies.qbk @@ -0,0 +1,58 @@ +[section boost/python/default_call_policies.hpp] +[section Class `default_call_policies`] +`default_call_policies` is a model of [link concepts.callpolicies `CallPolicies`] with no `precall` or `postcall` behavior and a `result_converter` which handles by-value returns. Wrapped C++ functions and member functions `use default_call_policies` unless otherwise specified. You may find it convenient to derive new models of [link concepts.callpolicies `CallPolicies`] from `default_call_policies`. +`` +namespace boost { namespace python +{ + struct default_call_policies + { + static bool precall(PyObject*); + static PyObject* postcall(PyObject*, PyObject* result); + typedef default_result_converter result_converter; + template struct extract_return_type : mpl::front{}; + }; +}} +`` +[endsect] +[section Class `default_call_policies` static functions] +``bool precall(PyObject*);`` +[variablelist +[[Returns][true]] +[[Throws][nothing]] +] +``PyObject* postcall(PyObject*, PyObject* result);`` +[variablelist +[[Returns][result]] +[[Throws][nothing]] +] +[endsect] +[section Class `default_result_converter`] +default_result_converter is a model of [link concepts.resultconverter.resultconvertergenerator_concept `ResultConverterGenerator`] which can be used to wrap C++ functions returning non-pointer types, `char const*`, and `PyObject*`, by-value. +`` +namespace boost { namespace python +{ + struct default_result_converter + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `default_result_converter` metafunctions] +``template struct apply`` +[variablelist +[[Requires][T is not a reference type. If T is a pointer type, T is const char* or PyObject*. ]] +[[Returns][typedef to_python_value type;]] +] +[endsect] +[section Example] +This example comes from the Boost.Python implementation itself. Because the return_value_policy class template does not implement precall or postcall behavior, its default base class is default_call_policies: +`` +template +struct return_value_policy : Base +{ + typedef Handler result_converter; +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/dict.qbk b/doc/reference/dict.qbk new file mode 100644 index 0000000000..e32d35e4ef --- /dev/null +++ b/doc/reference/dict.qbk @@ -0,0 +1,71 @@ +[section boost/python/dict.hpp] +[section Introduction] +Exposes a [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] for the Python [@http://www.python.org/dev/doc/devel/lib/typesmapping.html `dict`] type. +[endsect] +[section Class `dict`] +Exposes the [@http://www.python.org/dev/doc/devel/lib/typesmapping.html mapping protocol] of Python's built-in `dict` type. The semantics of the constructors and member functions defined below can be fully understood by reading the [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] concept definition. Since `dict` is publicly derived from [link object_wrappers.boost_python_object_hpp.class_object `object`], the public `object` interface applies to `dict` instances as well. +`` +namespace boost { namespace python +{ + class dict : public object + { + dict(); + + template< class T > + dict(T const & data); + + // modifiers + void clear(); + dict copy(); + + template + tuple popitem(); + + template + object setdefault(T const &k); + + template + object setdefault(T1 const & k, T2 const & d); + + void update(object_cref E); + + template< class T > + void update(T const & E); + + // observers + list values() const; + + object get(object_cref k) const; + + template + object get(T const & k) const; + + object get(object_cref k, object_cref d) const; + object get(T1 const & k, T2 const & d) const; + + bool has_key(object_cref k) const; + + template< class T > + bool has_key(T const & k) const; + + list items() const; + object iteritems() const; + object iterkeys() const; + object itervalues() const; + list keys() const; + }; +}} +`` +[endsect] +[section Example] +`` +using namespace boost::python; +dict swap_object_dict(object target, dict d) +{ + dict result = extract(target.attr("__dict__")); + target.attr("__dict__") = d; + return result; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/docstring_options.qbk b/doc/reference/docstring_options.qbk new file mode 100644 index 0000000000..00b5228254 --- /dev/null +++ b/doc/reference/docstring_options.qbk @@ -0,0 +1,213 @@ +[section boost/python/docstring_options.hpp] +[section Introduction] +Boost.Python supports user-defined docstrings with automatic appending of C++ signatures. These features are enabled by default. The class docstring_options is available to selectively suppress the user-defined docstrings, signatures, or both. +[endsect] +[section Class `docstring_options`] +Controls the appearance of docstrings of wrapped functions and member functions for the life-time of the instance. The instances are noncopyable to eliminate the possibility of surprising side effects. + +``namespace boost { namespace python { + + class docstring_options : boost::noncopyable + { + public: + docstring_options(bool show_all=true); + docstring_options(bool show_user_defined, bool show_signatures); + docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); + ~docstring_options(); + void disable_user_defined(); + void enable_user_defined(); + void disable_signatures(); + void enable_signatures(); + void disable_py_signatures(); + void enable_py_signatures(); + void disable_cpp_signatures(); + void enable_cpp_signatures(); + void disable_all(); + void enable_all(); + }; +}} + +`` +[endsect] +[section Class dostring_options constructors] +`` +docstring_options(bool show_all=true); +`` +[variablelist +[[Effects][Constructs a docstring_options object which controls the appearance of function and member-function docstrings defined in the code that follows. If show_all is true, both the user-defined docstrings and the automatically generated Python and C++ signatures are shown. If show_all is false the `__doc__` attributes are `None`.]] +] +`` +docstring_options(bool show_user_defined, bool show_signatures); +`` +[variablelist +[[Effects][Constructs a `docstring_options` object which controls the appearance of function and member-function docstrings defined in the code that follows. Iff `show_user_defined` is `true`, the user-defined docstrings are shown. Iff `show_signatures` is `true`, Python and C++ signatures are automatically added. If both `show_user_defined` and `show_signatures` are `false`, the `__doc__` attributes are `None`.]] +] +`` +docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); +`` +[variablelist +[[Effects][Constructs a `docstring_options` object which controls the appearance of function and member-function docstrings defined in the code that follows. Iff `show_user_defined` is `true`, the user-defined docstrings are shown. Iff `show_py_signatures` is `true`, Python signatures are automatically added. Iff `show_cpp_signatures` is true, C++ signatures are automatically added. If all parameters are `false`, the `__doc__` attributes are `None`.]] +] +[endsect] +[section Class docstring_options destructor] +``~docstring_options();`` +[variablelist +[[Effects][Restores the previous state of the docstring options. In particular, if `docstring_options` instances are in nested C++ scopes the settings effective in the enclosing scope are restored. If the last `docstring_options` instance goes out of scope the default "all on" settings are restored.]]] +[endsect] +[section Class `docstring_options` modifier functions] +`` +void disable_user_defined(); +void enable_user_defined(); +void disable_signatures(); +void enable_signatures(); +void disable_py_signatures(); +void enable_py_signatures(); +void disable_cpp_signatures(); +void enable_cpp_signatures(); +void disable_all(); +void enable_all(); +`` +These member functions dynamically change the appearance of docstrings in the code that follows. The `*_user_defined()` and `*_signatures()` member functions are provided for fine-grained control. The `*_all()` member functions are convenient shortcuts to manipulate all settings simultaneously. +[endsect] +[section Example] +[section Docstring options defined at compile time] +`` +#include +#include +#include + +void foo() {} + +BOOST_PYTHON_MODULE(demo) +{ + using namespace boost::python; + docstring_options doc_options(DEMO_DOCSTRING_SHOW_ALL); + def("foo", foo, "foo doc"); +} +`` +If compiled with `-DDEMO_DOCSTRING_SHOW_ALL=true`: +`` +>>> import demo +>>> print demo.foo.__doc__ +foo() -> None : foo doc +C++ signature: + foo(void) -> void +`` +If compiled with `-DDEMO_DOCSTRING_SHOW_ALL=false`: +`` +>>> import demo +>>> print demo.foo.__doc__ +None +`` +[endsect] +[section Selective suppressions] +`` +#include +#include +#include +#include + +int foo1(int i) { return i; } +int foo2(long l) { return static_cast(l); } +int foo3(float f) { return static_cast(f); } +int foo4(double d) { return static_cast(d); } + +BOOST_PYTHON_MODULE(demo) +{ + using namespace boost::python; + docstring_options doc_options; + def("foo1", foo1, arg("i"), "foo1 doc"); + doc_options.disable_user_defined(); + def("foo2", foo2, arg("l"), "foo2 doc"); + doc_options.disable_signatures(); + def("foo3", foo3, arg("f"), "foo3 doc"); + doc_options.enable_user_defined(); + def("foo4", foo4, arg("d"), "foo4 doc"); + doc_options.enable_py_signatures(); + def("foo5", foo4, arg("d"), "foo5 doc"); + doc_options.disable_py_signatures(); + doc_options.enable_cpp_signatures(); + def("foo6", foo4, arg("d"), "foo6 doc"); +} +`` +Python code: +`` +>>> import demo +>>> print demo.foo1.__doc__ +foo1( (int)i) -> int : foo1 doc +C++ signature: + foo1(int i) -> int +>>> print demo.foo2.__doc__ +foo2( (int)l) -> int : +C++ signature: + foo2(long l) -> int +>>> print demo.foo3.__doc__ +None +>>> print demo.foo4.__doc__ +foo4 doc +>>> print demo.foo5.__doc__ +foo5( (float)d) -> int : foo5 doc +>>> print demo.foo6.__doc__ +foo6 doc +C++ signature: + foo6(double d) -> int +`` +[endsect] +[section Wrapping from multiple C++ scopes] +`` +#include +#include +#include +#include + +int foo1(int i) { return i; } +int foo2(long l) { return static_cast(l); } + +int bar1(int i) { return i; } +int bar2(long l) { return static_cast(l); } + +namespace { + + void wrap_foos() + { + using namespace boost::python; + // no docstring_options here + // -> settings from outer C++ scope are in effect + def("foo1", foo1, arg("i"), "foo1 doc"); + def("foo2", foo2, arg("l"), "foo2 doc"); + } + + void wrap_bars() + { + using namespace boost::python; + bool show_user_defined = true; + bool show_signatures = false; + docstring_options doc_options(show_user_defined, show_signatures); + def("bar1", bar1, arg("i"), "bar1 doc"); + def("bar2", bar2, arg("l"), "bar2 doc"); + } +} + +BOOST_PYTHON_MODULE(demo) +{ + boost::python::docstring_options doc_options(false); + wrap_foos(); + wrap_bars(); +} +`` +Python code: +`` +>>> import demo +>>> print demo.foo1.__doc__ +None +>>> print demo.foo2.__doc__ +None +>>> print demo.bar1.__doc__ +bar1 doc +>>> print demo.bar2.__doc__ +bar2 doc +`` + +[endsect] +[endsect] +[endsect] diff --git a/doc/reference/embedding.qbk b/doc/reference/embedding.qbk new file mode 100644 index 0000000000..77461b9bcd --- /dev/null +++ b/doc/reference/embedding.qbk @@ -0,0 +1,6 @@ +[chapter Embedding + [quickbook 1.7] +] + +[include exec.qbk] +[include import.qbk] diff --git a/doc/reference/enum.qbk b/doc/reference/enum.qbk new file mode 100644 index 0000000000..ece2d298c9 --- /dev/null +++ b/doc/reference/enum.qbk @@ -0,0 +1,107 @@ +[section boost/python/enum.hpp] +[section Introduction] + defines the interface through which users expose their C++ enumeration types to Python. It declares the `enum_` class template, which is parameterized on the enumeration type being exposed. +[endsect] +[section Class template `enum_`] +Creates a Python class derived from Python's `int` type which is associated with the C++ type passed as its first parameter. +`` +namespace boost { namespace python +{ + template + class enum_ : public object + { + enum_(char const* name, char const* doc = 0); + enum_& value(char const* name, T); + enum_& export_values(); + }; +}} +`` +[endsect] +[section Class template `enum_` constructors] +``enum_(char const* name, char const* doc=0);`` +[variablelist +[[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules].]] +[[Effects][Constructs an `enum_` object holding a Python extension type derived from `int` which is named `name`. The named attribute of the [link high_level_components.boost_python_scope_hpp current scope] is bound to the new extension type.]] +] +[endsect] +[section Class template `enum_` modifier functions] +``enum_& value(char const* name, T x);`` +[variablelist +[[Requires][name is an [link ntbs] which conforms to Python's [@http://www.python.org/doc/current/ref/identifiers.html identifier naming rules].]] +[[Effects][adds an instance of the wrapped enumeration type with value x to the type's dictionary as the named attribute.]] +[[Returns][`*this`]] +] +``enum_& export_values();`` +[variablelist +[[Effects][sets attributes in the [link high_level_components.boost_python_scope_hpp current scope] with the same names and values as all enumeration values exposed so far by calling value().]] +[[Returns][`*this`]] +] +[endsect] +[section Example] +C++ module definition +`` +#include +#include +#include + +using namespace boost::python; + +enum color { red = 1, green = 2, blue = 4 }; + +color identity_(color x) { return x; } + +BOOST_PYTHON_MODULE(enums) +{ + enum_("color") + .value("red", red) + .value("green", green) + .export_values() + .value("blue", blue) + ; + + def("identity", identity_); +} +`` +Interactive Python: +`` +>>> from enums import * + +>>> identity(red) +enums.color.red + +>>> identity(color.red) +enums.color.red + +>>> identity(green) +enums.color.green + +>>> identity(color.green) +enums.color.green + +>>> identity(blue) +Traceback (most recent call last): + File "", line 1, in ? +NameError: name 'blue' is not defined + +>>> identity(color.blue) +enums.color.blue + +>>> identity(color(1)) +enums.color.red + +>>> identity(color(2)) +enums.color.green + +>>> identity(color(3)) +enums.color(3) + +>>> identity(color(4)) +enums.color.blue + +>>> identity(1) +Traceback (most recent call last): + File "", line 1, in ? +TypeError: bad argument type for built-in operation +`` +[endsect] +[endsect] diff --git a/doc/reference/errors.qbk b/doc/reference/errors.qbk new file mode 100644 index 0000000000..2103017cba --- /dev/null +++ b/doc/reference/errors.qbk @@ -0,0 +1,142 @@ +[section boost/python/errors.hpp] +[section Introduction] + provides types and functions for managing and translating between Python and C++ exceptions. This is relatively low-level functionality that is mostly used internally by Boost.Python. Users should seldom need it. +[endsect] +[section Class `error_already_set`] +error_already_set is an exception type which can be thrown to indicate that a Python error has occurred. If thrown, the precondition is that [@http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71 PyErr_Occurred()] returns a value convertible to `true`. Portable code shouldn't throw this exception type directly, but should instead use [link high_level_components.boost_python_errors_hpp.functions throw_error_already_set()], below. +`` +namespace boost { namespace python +{ + class error_already_set {}; +}} +`` +[endsect] +[section Functions] +`` +template bool handle_exception(T f) throw(); +void handle_exception() throw(); +`` +[variablelist +[[Requires][The first form requires that the expression function0(f) is valid. The second form requires that a C++ exception is currently being handled (see section 15.1 in the C++ standard).]] +[[Effects][The first form calls f() inside a try block which first attempts to use all registered [link high_level_components.boost_python_exception_translato exception translators]. If none of those translates the exception, the catch clauses then set an appropriate Python exception for the C++ exception caught, returning true if an exception was thrown, false otherwise. The second form passes a function which rethrows the exception currently being handled to the first form.]] +[[Postconditions][No exception is being handled]] +[[Throws][nothing]] +[[Rationale][At inter-language boundaries it is important to ensure that no C++ exceptions escape, since the calling language usually doesn't have the equipment necessary to properly unwind the stack. Use handle_exception to manage exception translation whenever your C++ code is called directly from the Python API. This is done for you automatically by the usual function wrapping facilities: [link function_invocation_and_creation.boost_python_make_function_hpp.functions make_function()], [link function_invocation_and_creation.boost_python_make_function_hpp.functions make_constructor()], [link high_level_components.boost_python_def_hpp.functions def()] and [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu class_::def()]. The second form can be more convenient to use (see the example below), but various compilers have problems when exceptions are rethrown from within an enclosing try block.]] +] +``template T* expect_non_null(T* x);`` +[variablelist +[[Returns][x]] +[[Throws][error_already_set() iff x == 0.]] +[[Rationale][Simplifies error-handling when calling functions in the Python/C API which return 0 on error.]] +] +``void throw_error_already_set();`` +[variablelist +[[Effects][throw error_already_set();]] +[[Rationale][Simplifies error-handling when calling functions in the Python/C API which return 0 on error.]] +] +``void throw_error_already_set();`` +[variablelist +[[Effects][throw error_already_set();]] +[[Rationale][Many platforms and compilers are not able to consistently catch exceptions thrown across shared library boundaries. Using this function from the Boost.Python library ensures that the appropriate catch block in handle_exception() can catch the exception.]] +] +[endsect] +[section Example] +`` +#include +#include +#include +#include + +// Returns a std::string which has the same value as obj's "__name__" +// attribute. +std::string get_name(boost::python::object obj) +{ + // throws if there's no __name__ attribute + PyObject* p = boost::python::expect_non_null( + PyObject_GetAttrString(obj.ptr(), "__name__")); + + char const* s = PyString_AsString(p); + if (s != 0) + Py_DECREF(p); + + // throws if it's not a Python string + std::string result( + boost::python::expect_non_null( + PyString_AsString(p))); + + Py_DECREF(p); // Done with p + + return result; +} + +// +// Demonstrate form 1 of handle_exception +// + +// Place into result a Python Int object whose value is 1 if a and b have +// identical "__name__" attributes, 0 otherwise. +void same_name_impl(PyObject*& result, boost::python::object a, boost::python::object b) +{ + result = PyInt_FromLong( + get_name(a) == get_name(a2)); +} + +object borrowed_object(PyObject* p) +{ + return boost::python::object( + boost::python::handle<>( + boost::python::borrowed(a1))); +} + +// This is an example Python 'C' API interface function +extern "C" PyObject* +same_name(PyObject* args, PyObject* keywords) +{ + PyObject* a1; + PyObject* a2; + PyObject* result = 0; + + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + return 0; + + // Use boost::bind to make an object compatible with + // boost::Function0 + if (boost::python::handle_exception( + boost::bind(same_name_impl, boost::ref(result), borrowed_object(a1), borrowed_object(a2)))) + { + // an exception was thrown; the Python error was set by + // handle_exception() + return 0; + } + + return result; +} + +// +// Demonstrate form 2 of handle_exception. Not well-supported by all +// compilers. +// +extern "C" PyObject* +same_name2(PyObject* args, PyObject* keywords) +{ + PyObject* a1; + PyObject* a2; + PyObject* result = 0; + + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + return 0; + + try { + return PyInt_FromLong( + get_name(borrowed_object(a1)) == get_name(borrowed_object(a2))); + } + catch(...) + { + // If an exception was thrown, translate it to Python + boost::python::handle_exception(); + return 0; + } +} +`` +[endsect] +[endsect] diff --git a/doc/reference/exception_translator.qbk b/doc/reference/exception_translator.qbk new file mode 100644 index 0000000000..e9fb0a899e --- /dev/null +++ b/doc/reference/exception_translator.qbk @@ -0,0 +1,51 @@ +[section boost/python/exception_translator.hpp] +[section Introduction] +As described [link high_level_components.boost_python_errors_hpp.introduction here], it is important to make sure that exceptions thrown by C++ code do not pass into the Python interpreter core. By default, Boost.Python translates all C++ exceptions thrown by wrapped functions and module init functions into Python, but the default translators are extremely limited: most C++ exceptions will appear in Python as a [@http://www.python.org/doc/current/lib/module-exceptions.html RuntimeError] exception whose representation is 'Unidentifiable C++ Exception'. To produce better error messages, users can register additional exception translators as described below. +[endsect] +[section Function `register_exception_translator`] +`` +template +void register_exception_translator(Translate translate); +`` +[variablelist +[[Requires][Translate is CopyConstructible, and the following code must be well-formed: +``void f(ExceptionType x) { translate(x); }``. +The expression `translate(x)` must either throw a C++ exception, or a subsequent call to `PyErr_Occurred()` must return 1. ]] +[[Effects][Adds a copy of translate to the sequence of exception translators tried when Boost.Python catches an exception that is about to pass into Python's core interpreter. The new translator will get "first shot" at translating all exceptions matching the catch clause shown above. Any subsequently-registered translators will be allowed to translate the exception earlier. A translator which cannot translate a given C++ exception can re-throw it, and it will be handled by a translator which was registered earlier (or by the default translator).]] +] +[endsect] +[section Example] +`` +#include +#include +#include +#include + +struct my_exception : std::exception +{ + char const* what() throw() { return "One of my exceptions"; } +}; + +void translate(my_exception const& e) +{ + // Use the Python 'C' API to set up an exception object + PyErr_SetString(PyExc_RuntimeError, e.what()); +} + +void something_which_throws() +{ + ... + throw my_exception(); + ... +} + +BOOST_PYTHON_MODULE(exception_translator_ext) +{ + using namespace boost::python; + register_exception_translator(&translate); + + def("something_which_throws", something_which_throws); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/exec.qbk b/doc/reference/exec.qbk new file mode 100644 index 0000000000..2cd46c45b2 --- /dev/null +++ b/doc/reference/exec.qbk @@ -0,0 +1,84 @@ +[section boost/python/exec.hpp] +[section Introduction] +Exposes a mechanism for embedding the python interpreter into C++ code. +[endsect] +[section Function `eval`] +`` +object eval(str expression, + object globals = object(), + object locals = object()); +`` +[variablelist +[[Effects][Evaluate Python expression from expression in the context specified by the dictionaries globals and locals. ]] +[[Returns][An instance of object which holds the value of the expression.]] +] +[endsect] +[section Function `exec`] +`` +object exec(str code, + object globals = object(), + object locals = object()); +`` +[variablelist +[[Effects][Execute Python source code from code in the context specified by the dictionaries globals and locals. ]] +[[Returns][ An instance of object which holds the result of executing the code. ]] +] +[endsect] +[section Function `exec_file`] +`` +object exec_file(str filename, + object globals = object(), + object locals = object()); +`` +[variablelist +[[Effects][Execute Python source code from the file named by filename in the context specified by the dictionaries globals and locals.]] +[[Returns][An instance of object which holds the result of executing the code. ]] +] +[endsect] +[section Examples] +The following example demonstrates the use of import and exec to define a function in python, and later call it from within C++. + +`` +#include +#include + +using namespace boost::python; + +void greet() +{ + // Retrieve the main module. + object main = import("__main__"); + + // Retrieve the main module's namespace + object global(main.attr("__dict__")); + + // Define greet function in Python. + object result = exec( + "def greet(): \n" + " return 'Hello from Python!' \n", + global, global); + + // Create a reference to it. + object greet = global["greet"]; + + // Call it. + std::string message = extract(greet()); + std::cout << message << std::endl; +} + `` + Instead of embedding the python script into a string, we could also store it in an a file... +`` +def greet(): + return 'Hello from Python!' +`` + ... and execute that instead. + +`` + // ... + // Load the greet function from a file. + object result = exec_file(script, global, global); + // ... +} +`` +[endsect] +[endsect] diff --git a/doc/reference/extract.qbk b/doc/reference/extract.qbk new file mode 100644 index 0000000000..2c8ffcdbdb --- /dev/null +++ b/doc/reference/extract.qbk @@ -0,0 +1,99 @@ +[section boost/python/extract.hpp] +[section Introduction] +Exposes a mechanism for extracting C++ object values from generalized Python objects. Note that `extract<...>` can also be used to "downcast" an [link object_wrappers.boost_python_object_hpp.class_object `object`] to some specific [link concepts.objectwrapper ObjectWrapper]. Because invoking a mutable python type with an argument of the same type (e.g. `list([1,2]`) typically makes a copy of the argument object, this may be the only way to access the [link concepts.objectwrapper ObjectWrapper]\ 's interface on the original object. +[endsect] +[section Class template `extract`] +`extract` can be used to extract a value of an arbitrary C++ type from an instance of [link object_wrappers.boost_python_object_hpp.class_object object]. Two usages are supported: + +# `extract(o)` is a temporary object which is implicitly convertible to `T` (explicit conversion is also available through the object's function-call operator). However, if no conversion is available which can convert o to an object of type `T`, a Python TypeError exception will be raised. +# `extract x(o);` constructs an extractor whose `check()` member function can be used to ask whether a conversion is available without causing an exception to be thrown. + +`` +namespace boost { namespace python +{ + template + struct extract + { + typedef unspecified result_type; + + extract(PyObject*); + extract(object const&); + + result_type operator()() const; + operator result_type() const; + + bool check() const; + }; +}} +`` +[endsect] +[section Class template `extract` constructors and destructor] +`` +extract(PyObject* p); +extract(object const&); +`` +[variablelist +[[Requires][The first form requires that p is non-null.]] +[[Effects][Stores a pointer to the Python object managed by its constructor argument. In particular, the reference count of the object is not incremented. The onus is on the user to be sure it is not destroyed before the extractor's conversion function is called.]] +] +[endsect] +[section Class template `extract` observer functions] +`` +result_type operator()() const; +operator result_type() const; +`` +[variablelist +[[Effects][Converts the stored pointer to result_type, which is either T or T const&. ]] +[[Returns][An object of result_type corresponding to the one referenced by the stored pointer.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set `error_already_set`] and sets a `TypeError` if no such conversion is available. May also emit other unspecified exceptions thrown by the converter which is actually used.]] +] +`` bool check() const;`` +[variablelist +[[Postconditions][None. In particular, note that a return value of true does not preclude an exception being thrown from operator result_type() or operator()().]] +[[Returns][false only if no conversion from the stored pointer to T is available.]] +] +[endsect] +[section Example] +`` +#include +using namespace boost::python; +int Print(str s) +{ + // extract a C string from the Python string object + char const* c_str = extract(s); + + // Print it using printf + std::printf("%s\n", c_str); + + // Get the Python string's length and convert it to an int + return extract(s.attr("__len__")()) +} +`` + The following example shows how extract can be used along with [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel `class_<...>`] to create and access an instance of a wrapped C++ class. +`` +struct X +{ + X(int x) : v(x) {} + int value() { return v; } + private: + int v; +}; + +BOOST_PYTHON_MODULE(extract_ext) +{ + object x_class( + class_("X", init()) + .def("value", &X::value)) + ; + + // Instantiate an X object through the Python interface. + // Its lifetime is now managed by x_obj. + object x_obj = x_class(3); + + // Get a reference to the C++ object out of the Python object + X& x = extract(x_obj); + assert(x.value() == 3); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/function_doc_signature.qbk b/doc/reference/function_doc_signature.qbk new file mode 100644 index 0000000000..992f478cc6 --- /dev/null +++ b/doc/reference/function_doc_signature.qbk @@ -0,0 +1,129 @@ +[section boost/python/function_doc_signature.hpp] +[section Introduction] +Boost.Python supports docstrings with automatic appending of Pythonic and C++ signatures. This feature is implemented by class `function_doc_signature_generator`. The class uses all of the overloads, supplied arg names and default values, as well as the user-defined docstrings, to generate documentation for a given function. +[endsect] +[section Class `function_doc_signature_generator`] +The class has only one public function which returns a list of strings documenting the overloads of a function. +`` +namespace boost { namespace python { namespace objects { + + class function_doc_signature_generator + { + public: + static list function_doc_signatures(function const *f); + }; + +}}} +`` +[endsect] +[section Example] +`` +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + + +struct X +{ + tuple f(int x = 1, double y = 4.25, char const* z = "wow") + { + return make_tuple(x, y, z); + } +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3) + +tuple raw_func(tuple args, dict kw) +{ + return make_tuple(args, kw); +} + +BOOST_PYTHON_MODULE(args_ext) +{ + def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow") + , "This is f's docstring" + ); + + def("raw", raw_function(raw_func)); + + def("f1", f, f_overloads("f1's docstring", args("x", "y", "z"))); + + + class_("X", "This is X's docstring", init<>(args("self"))) + .def("f", &X::f + , "This is X.f's docstring" + , args("self","x", "y", "z")) + + ; + +} +`` +Python code: [python] +`` +>>> import args_ext +>>> help(args_ext) +Help on module args_ext: + +NAME + args_ext + +FILE + args_ext.pyd + +CLASSES + Boost.Python.instance(__builtin__.object) + X + + class X(Boost.Python.instance) + | This is X's docstring + | + | Method resolution order: + | X + | Boost.Python.instance + | __builtin__.object + | + | Methods defined here: + | + | __init__(...) + | __init__( (object)self) -> None : + | C++ signature: + | void __init__(struct _object *) + | + | f(...) + | f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring + | C++ signature: + | class boost::python::tuple f(struct X {lvalue},int,double,char const *) + | + | ................. + | +FUNCTIONS + f(...) + f([ (int)x=1 [, (float)y=4.25 [, (str)z='wow']]]) -> tuple : This is f's docstring + C++ signature: + class boost::python::tuple f([ int=1 [,double=4.25 [,char const *='wow']]]) + + f1(...) + f1([ (int)x [, (float)y [, (str)z]]]) -> tuple : f1's docstring + C++ signature: + class boost::python::tuple f1([ int [,double [,char const *]]]) + + raw(...) + object raw(tuple args, dict kwds) : + C++ signature: + object raw(tuple args, dict kwds) +`` +[endsect] +[endsect] diff --git a/doc/reference/functions.qbk b/doc/reference/functions.qbk new file mode 100644 index 0000000000..40b220cd31 --- /dev/null +++ b/doc/reference/functions.qbk @@ -0,0 +1,35 @@ +[chapter Function Invocation and Creation + [quickbook 1.7] +] + +[include args.qbk] +[include call.qbk] +[include call_method.qbk] +[include data_members.qbk] +[include make_function.qbk] +[include overloads.qbk] +[include ptr.qbk] +[include raw_function.qbk] +[section Function documentation] +[include function_doc_signature.qbk] +[include pytype_function.qbk] +[endsect] +[section Models of CallPolicies] +[include default_call_policies.qbk] +[include return_arg.qbk] +[include return_internal_reference.qbk] +[include return_value_policy.qbk] +[include with_custodian_and_ward.qbk] +[endsect] +[section Models of ResultConverter] +[include to_python_indirect.qbk] +[include to_python_value.qbk] +[endsect] +[section Models of ResultConverterGenerator] +[include copy_const_reference.qbk] +[include copy_non_const_reference.qbk] +[include manage_new_object.qbk] +[include reference_existing_object.qbk] +[include return_by_value.qbk] +[include return_opaque_pointer.qbk] +[endsect] diff --git a/doc/reference/handle.qbk b/doc/reference/handle.qbk new file mode 100644 index 0000000000..c7c63abcd9 --- /dev/null +++ b/doc/reference/handle.qbk @@ -0,0 +1,190 @@ +[section boost/python/handle.hpp] +[section Introduction] + provides class template `handle`, a smart pointer for managing reference-counted Python objects. +[endsect] +[section Class template `handle`] +`handle` is a smart pointer to a Python object type; it holds a pointer of type `T*`, where `T` is its template parameter. T must be either a type derived from `PyObject` or a [link pod POD] type whose initial `sizeof(PyObject)` bytes are layout-compatible with `PyObject`. Use `handle<>` at the boundary between the Python/'C' API and high-level code; prefer object for a generalized interface to Python objects. + +In this document, the term "upcast" refers to an operation which converts a pointer `Y*` to a base class `pointer T*` via `static_cast` if `Y` is derived from `T`, or via C-style cast (`T*`) if it is not. However, in the latter case the "upcast" is ill-formed if the initial `sizeof(PyObject)` bytes of `Y` are not layout-compatible with `PyObject`. + +`` +namespace boost { namespace python +{ + template + class handle + { + typedef unspecified-member-function-pointer bool_type; + + public: // types + typedef T element_type; + + public: // member functions + ~handle(); + + template + explicit handle(detail::borrowed >* p); + + template + explicit handle(null_ok >* p); + + template + explicit handle(detail::borrowed* p); + + template + explicit handle(null_ok* p); + + template + explicit handle(Y* p); + + handle(); + + handle& operator=(handle const& r); + + template + handle& operator=(handle const & r); // never throws + + + template + handle(handle const& r); + + handle(handle const& r); + + T* operator-> () const; + T& operator* () const; + T* get() const; + void reset(); + T* release(); + + operator bool_type() const; // never throws + private: + T* m_p; + }; + + template struct null_ok; + namespace detail { template struct borrowed; } +}} +`` +[section Class template `handle` constructors and destructor] +``virtual ~handle();`` +[variablelist +[[Effects][`Py_XDECREF(upcast(m_p))`]] +] +``template +explicit handle(detail::borrowed >* p); +`` +[variablelist +[[Effects][ +``Py_XINCREF(upcast(p)); +m_p = upcast(p); +`` +]] +] +``template +explicit handle(null_ok >* p);`` +[variablelist +[[Effects][ +``Py_XINCREF(upcast(p)); + m_p = upcast(p); +`` +]] +] +``template +explicit handle(detail::borrowed* p);`` +[variablelist +[[Effects][ +``Py_XINCREF(upcast(p)); + m_p = upcast(expect_non_null(p)); +`` +]] +] +``template +explicit handle(null_ok* p); +`` +[variablelist +[[Effects][`m_p = upcast(p);`]] +] +`` +template +explicit handle(Y* p); +`` +[variablelist +[[Effects][`m_p = upcast(expect_non_null(p));`]] +] +`` +handle(); +`` +[variablelist +[[Effects][`m_p = 0;`]] +] +`` +template +handle(handle const& r); +handle(handle const& r); +`` +[variablelist +[[Effects][m_p = r.m_p; Py_XINCREF(upcast(m_p));]] +] +[endsect] +[section Class template `handle` modifiers] +`` +handle& operator=(handle const& r); +template +handle& operator=(handle const & r); // never throws +`` +[variablelist +[[Effects][`Py_XINCREF(upcast(r.m_p)); Py_XDECREF( upcast(m_p)); m_p = r.m_p;`]] +] +`` +T* release(); +`` +[variablelist +[[Effects][`T* x = m_p; m_p = 0; return x;`]] +] +`` +void reset(); +`` +[variablelist +[[Effects][`*this = handle();`]] +] +[endsect] +[section Class template `handle` observers] +`` +T* operator-> () const; +T* get() const; +`` +[variablelist +[[Returns][`m_p;`]] +] +`` +T& operator* () const; +`` +[variablelist +[[Returns][`*m_p;`]] +] +`` +operator bool_type() const; // never throws +`` +[variablelist +[[Returns][`0` if `m_p == 0`, a pointer convertible to true otherwise.]] +] +[endsect] +[endsect] +[section Function `borrowed`] +`` +template +detail::borrowed* borrowed(T* p) +{ + return (detail::borrowed*)p; +} +`` +[endsect] +[section Function `allow_null`] +`` +template +null_ok* allow_null(T* p) +{ + return (null_ok*)p; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/has_back_reference.qbk b/doc/reference/has_back_reference.qbk new file mode 100644 index 0000000000..f34fc56eda --- /dev/null +++ b/doc/reference/has_back_reference.qbk @@ -0,0 +1,115 @@ +[section boost/python/has_back_reference.hpp] +[section Introduction] + defines the predicate metafunction `has_back_reference<>`, which can be specialized by the user to indicate that a wrapped class instance holds a `PyObject*` corresponding to a Python object. +[endsect] +[section Class template `has_back_reference`] +A unary metafunction whose value is true iff its argument is a `pointer_wrapper<>`. +`` +namespace boost { namespace python +{ + template class has_back_reference + { + typedef mpl::false_ type; + }; +}} +`` + +A metafunction that is inspected by Boost.Python to determine how wrapped classes can be constructed. + +`type::value` is an integral constant convertible to bool of unspecified type. +Specializations may substitute a true-valued integral constant wrapper for type iff for each invocation of `class_::def(init< type-sequence...>())` and the implicitly wrapped copy constructor (unless it is noncopyable), there exists a corresponding constructor `WrappedClass::WrappedClass(PyObject*, type-sequence...)`. If such a specialization exists, the WrappedClass constructors will be called with a "back reference" pointer to the corresponding Python object whenever they are invoked from Python. The easiest way to provide this nested type is to derive the specialization from `mpl::true_`. + +[endsect] +[section Examples] +In C++: +`` +#include +#include +#include +#include +#include + +using namespace boost::python; +using boost::shared_ptr; + +struct X +{ + X(PyObject* self) : m_self(self), m_x(0) {} + X(PyObject* self, int x) : m_self(self), m_x(x) {} + X(PyObject* self, X const& other) : m_self(self), m_x(other.m_x) {} + + handle<> self() { return handle<>(borrowed(m_self)); } + int get() { return m_x; } + void set(int x) { m_x = x; } + + PyObject* m_self; + int m_x; +}; + +// specialize has_back_reference for X +namespace boost { namespace python +{ + template <> + struct has_back_reference + : mpl::true_ + {}; +}} + +struct Y +{ + Y() : m_x(0) {} + Y(int x) : m_x(x) {} + int get() { return m_x; } + void set(int x) { m_x = x; } + + int m_x; +}; + +shared_ptr +Y_self(shared_ptr self) { return self; } + +BOOST_PYTHON_MODULE(back_references) +{ + class_("X") + .def(init()) + .def("self", &X::self) + .def("get", &X::get) + .def("set", &X::set) + ; + + class_ >("Y") + .def(init()) + .def("get", &Y::get) + .def("set", &Y::set) + .def("self", Y_self) + ; +} +`` + The following Python session illustrates that x.self() returns the same Python object on which it is invoked, while y.self() must create a new Python object which refers to the same Y instance. + +In Python: +`` +>>> from back_references import * +>>> x = X(1) +>>> x2 = x.self() +>>> x2 is x +1 +>>> (x.get(), x2.get()) +(1, 1) +>>> x.set(10) +>>> (x.get(), x2.get()) +(10, 10) +>>> +>>> +>>> y = Y(2) +>>> y2 = y.self() +>>> y2 is y +0 +>>> (y.get(), y2.get()) +(2, 2) +>>> y.set(20) +>>> (y.get(), y2.get()) +(20, 20) +`` +[endsect] +[endsect] diff --git a/doc/reference/implicit.qbk b/doc/reference/implicit.qbk new file mode 100644 index 0000000000..67ce162ec6 --- /dev/null +++ b/doc/reference/implicit.qbk @@ -0,0 +1,69 @@ +[section boost/python/implicit.hpp] +[section Introduction] +`implicitly_convertible` allows Boost.Python to implicitly take advantage of a C++ implicit or explicit conversion when matching Python objects to C++ argument types. +[endsect] +[section Function template `implicit_convertible`] +`` +template +void implicitly_convertible(); +`` +[table +[[Parameter][Description]] +[[Source][The source type of the implicit conversion]] +[[Target][The target type of the implicit conversion]] +] +[variablelist +[[Requires][The declaration `Target t(s);`, where s is of type Source, is valid.]] +[[Effects][registers an rvalue `from_python` converter to Target which can succeed for any `PyObject* p` iff there exists any registered converter which can produce Source rvalues]] +[[Rationale][C++ users expect to be able to take advantage of the same sort of interoperability in Python as they do in C++.]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include + +using namespace boost::python; + +struct X +{ + X(int x) : v(x) {} + operator int() const { return v; } + int v; +}; + +int x_value(X const& x) +{ + return x.v; +} + +X make_x(int n) { return X(n); } + +BOOST_PYTHON_MODULE(implicit_ext) +{ + def("x_value", x_value); + def("make_x", make_x); + + class_("X", + init()) + ; + + implicitly_convertible(); + implicitly_convertible(); +} +`` +In Python: +`` +>>> from implicit_ext import * +>>> x_value(X(42)) +42 +>>> x_value(42) +42 +>>> x = make_x(X(42)) +>>> x_value(x) +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/import.qbk b/doc/reference/import.qbk new file mode 100644 index 0000000000..44e3d1ca0c --- /dev/null +++ b/doc/reference/import.qbk @@ -0,0 +1,31 @@ +[section boost/python/import.hpp] +[section Introduction] +Exposes a mechanism for importing python modules. +[endsect] +[section Function `import`] +``object import(str name);`` +[variablelist +[[Effects][Imports the module named by name.]] +[[Returns][An instance of object which holds a reference to the imported module.]] +] +[endsect] +[section Examples] +The following example demonstrates the use of import to access a function in python, and later call it from within C++. +`` +#include +#include + +using namespace boost::python; + +void print_python_version() +{ + // Load the sys module. + object sys = import("sys"); + + // Extract the python version. + std::string version = extract(sys.attr("version")); + std::cout << version << std::endl; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/indexing.qbk b/doc/reference/indexing.qbk new file mode 100644 index 0000000000..4f3a55cbf0 --- /dev/null +++ b/doc/reference/indexing.qbk @@ -0,0 +1,271 @@ +[section Indexing support] +[section Introduction] +Indexing is a `Boost Python` facility for easy exportation of indexable C++ containers to Python. Indexable containers are containers that allow random access through the `operator[]` (e.g. `std::vector`). + +While `Boost Python` has all the facilities needed to expose indexable C++ containers such as the ubiquitous std::vector to Python, the procedure is not as straightforward as we'd like it to be. Python containers do not map easily to C++ containers. Emulating Python containers in C++ (see Python Reference Manual, [@http://www.python.org/doc/current/ref/sequence-types.html Emulating container types]) using `Boost.Python` is non trivial. There are a lot of issues to consider before we can map a C++ container to Python. These involve implementing wrapper functions for the methods `__len__`, `__getitem__`, `__setitem__`, `__delitem__`, `__iter__` and `__contains__`. + +The goals: + +* Make indexable C++ containers behave exactly as one would expect a Python container to behave. +* Provide default reference semantics for container element indexing (`__getitem__`) such that c[i] can be mutable. Require: + + `` + val = c[i] + c[i].m() + val == c[i] + `` + + where m is a non-const (mutating) member function (method). +* Return safe references from `__getitem__` such that subsequent adds and deletes to and from the container will not result in dangling references (will not crash Python). +* Support slice indexes. +* Accept Python container arguments (e.g. `lists`, `tuples`) wherever appropriate. +* Allow for extensibility through re-definable policy classes. +* Provide predefined support for the most common STL and STL-like indexable containers. + +[endsect] +[section The Indexing Interface] +The `indexing_suite` class is the base class for the management of C++ containers intended to be integrated to Python. The objective is make a C++ container look and feel and behave exactly as we'd expect a Python container. The class automatically wraps these special Python methods (taken from the Python reference: Emulating container types): + +[variablelist +[[__len__(self)] + [Called to implement the built-in function `len()`. Should return the length of the object, an integer `>= 0`. Also, an object that doesn't define a `__nonzero__()` method and whose `__len__()` method returns zero is considered to be false in a Boolean context.]] +[[__getitem__(self, key)] +[Called to implement evaluation of `self[key]`. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the `__getitem__()` method. If key is of an inappropriate type, `TypeError` may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. [Note: for loops expect that an IndexError will be raised for illegal indexes to allow proper detection of the end of the sequence.]]] +[[__setitem__(self, key, value)] + [Called to implement assignment to self[key]. Same note as for __getitem__(). This should only be implemented for mappings if the objects support changes to the values for keys, or if new keys can be added, or for sequences if elements can be replaced. The same exceptions should be raised for improper key values as for the __getitem__() method.]] +[[__delitem__(self, key)] + [Called to implement deletion of self[key]. Same note as for __getitem__(). This should only be implemented for mappings if the objects support removal of keys, or for sequences if elements can be removed from the sequence. The same exceptions should be raised for improper key values as for the __getitem__() method.]] +[[__iter__(self)] + [This method is called when an iterator is required for a container. This method should return a new iterator object that can iterate over all the objects in the container. For mappings, it should iterate over the keys of the container, and should also be made available as the method iterkeys(). + +Iterator objects also need to implement this method; they are required to return themselves. For more information on iterator objects, see [@https://docs.python.org/3/library/stdtypes.html#iterator-types Iterator Types] in the [@https://docs.python.org/3/library/index.html Python Library Reference].]] + +[[__contains__(self, item)] + [Called to implement membership test operators. Should return true if item is in self, false otherwise. For mapping objects, this should consider the keys of the mapping rather than the values or the key-item pairs.]] + ] +[endsect] +[section index_suite sub-classes] +The `indexing_suite` is not meant to be used as is. A couple of policy functions must be supplied by subclasses of `indexing_suite`. However, a set of indexing_suite subclasses for the standard indexable STL containers will be provided, In most cases, we can simply use the available predefined suites. In some cases, we can refine the predefined suites to suit our needs. +[section vector_index_suite] +The `vector_indexing_suite` class is a predefined `indexing_suite` derived class designed to wrap `std::vector` (and `std::vector`-like [i.e. a class with `std::vector` interface]) classes. It provides all the policies required by the `indexing_suite`. + +Example usage: +`` +class X {...}; +... +class_ >("XVec") + .def(vector_indexing_suite >()) +; +`` + +XVec is now a full-fledged Python container (see the example in full, along with its python test). +[endsect] +[section map_index_suite] +The `map_indexing_suite` class is a predefined `indexing_suite` derived class designed to wrap `std::map` (and `std::map`-like [i.e. a class with `std::map` interface]) classes. It provides all the policies required by the `indexing_suite`. + +Example usage: + +`` +class X {...}; +... + +class_ >("XMap") + .def(map_indexing_suite >()) +; +`` + +By default indexed elements are returned by proxy. This can be disabled by supplying `true` in the `NoProxy` template parameter. XMap is now a full-fledged Python container (see the example in full, along with its python test). +[endsect] +[endsect] +[section `indexing_suite` class] +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][A class type][ The container type to be wrapped to Python. ][]] +[[DerivedPolicies][A subclass of indexing_suite][ Derived classes provide the policy hooks. See DerivedPolicies below. ][]] +[[NoProxy][A boolean][ By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. ][false]] +[[NoSlice][A boolean][ Do not allow slicing. ][false]] +[[Data][][The container's data type.][Container::value_type]] +[[Index][][The container's index type.][Container::size_type]] +[[Key][][The container's key type.][Container::value_type]] +] +`` +template +class indexing_suite : unspecified +{ +public: + indexing_suite(); // default constructor +} +`` +[section DerivedPolicies] + +Derived classes provide the hooks needed by the indexing_suite: +`` +data_type& +get_item(Container& container, index_type i); + +static object +get_slice(Container& container, index_type from, index_type to); + +static void +set_item(Container& container, index_type i, data_type const& v); + +static void +set_slice( + Container& container, index_type from, + index_type to, data_type const& v +); + +template +static void +set_slice(Container& container, index_type from, + index_type to, Iter first, Iter last +); + +static void +delete_item(Container& container, index_type i); + +static void +delete_slice(Container& container, index_type from, index_type to); + +static size_t +size(Container& container); + +template +static bool +contains(Container& container, T const& val); + +static index_type +convert_index(Container& container, PyObject* i); + +static index_type +adjust_index(index_type current, index_type from, + index_type to, size_type len); +`` + +Most of these policies are self explanatory. However, convert_index and adjust_index deserve some explanation. + +convert_index converts a Python index into a C++ index that the container can handle. For instance, negative indexes in Python, by convention, start counting from the right(e.g. C[-1] indexes the rightmost element in C). convert_index should handle the necessary conversion for the C++ container (e.g. convert -1 to C.size()-1). convert_index should also be able to convert the type of the index (A dynamic Python type) to the actual type that the C++ container expects. + +When a container expands or contracts, held indexes to its elements must be adjusted to follow the movement of data. For instance, if we erase 3 elements, starting from index 0 from a 5 element vector, what used to be at index 4 will now be at index 1: + +`` + [a][b][c][d][e] ---> [d][e] + ^ ^ + 4 1 +`` + +adjust_index takes care of the adjustment. Given a current index, the function should return the adjusted index when data in the container at index from..to is replaced by len elements. +[endsect] +[endsect] +[section class `vector_indexing_suite`] +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][A class type][ The container type to be wrapped to Python. ][]] +[[NoProxy][A boolean][ By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. ][false]] +[[DerivedPolicies][A subclass of indexing_suite][ The vector_indexing_suite may still be derived to further tweak any of the predefined policies. Static polymorphism through CRTP (James Coplien. "Curiously Recurring Template Pattern". C++ Report, Feb. 1995) enables the base indexing_suite class to call policy function of the most derived class ][]] +] +`` +template +class vector_indexing_suite : unspecified_base +{ +public: + + typedef typename Container::value_type data_type; + typedef typename Container::value_type key_type; + typedef typename Container::size_type index_type; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + + data_type& + get_item(Container& container, index_type i); + + static object + get_slice(Container& container, index_type from, index_type to); + + static void + set_item(Container& container, index_type i, data_type const& v); + + static void + set_slice(Container& container, index_type from, + index_type to, data_type const& v); + + template + static void + set_slice(Container& container, index_type from, + index_type to, Iter first, Iter last); + + static void + delete_item(Container& container, index_type i); + + static void + delete_slice(Container& container, index_type from, index_type to); + + static size_t + size(Container& container); + + static bool + contains(Container& container, key_type const& key); + + static index_type + convert_index(Container& container, PyObject* i); + + static index_type + adjust_index(index_type current, index_type from, + index_type to, size_type len); +}; +`` +[endsect] +[section class `map_indexing_suite`] +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][ A class type ][ The container type to be wrapped to Python. ][]] +[[NoProxy][ A boolean ][ By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. ][ false ]] +[[DerivedPolicies][ A subclass of indexing_suite ][ The vector_indexing_suite may still be derived to further tweak any of the predefined policies. Static polymorphism through CRTP (James Coplien. "Curiously Recurring Template Pattern". C++ Report, Feb. 1995) enables the base indexing_suite class to call policy function of the most derived class ][]] +] +`` +template +class map_indexing_suite : unspecified_base +{ +public: + + typedef typename Container::value_type value_type; + typedef typename Container::value_type::second_type data_type; + typedef typename Container::key_type key_type; + typedef typename Container::key_type index_type; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + + static data_type& + get_item(Container& container, index_type i); + + static void + set_item(Container& container, index_type i, data_type const& v); + + static void + delete_item(Container& container, index_type i); + + static size_t + size(Container& container); + + static bool + contains(Container& container, key_type const& key); + + static bool + compare_index(Container& container, index_type a, index_type b); + + static index_type + convert_index(Container& container, PyObject* i); +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/init.qbk b/doc/reference/init.qbk new file mode 100644 index 0000000000..7b5a7c11de --- /dev/null +++ b/doc/reference/init.qbk @@ -0,0 +1,91 @@ +[section boost/python/init.hpp] +[section Introduction] + defines the interface for exposing C++ constructors to Python as extension class `__init__` functions. +[section init-expressions] +An init-expression is used to describe a family of `__init__` methods to be generated for an extension class, and the result has the following properties: +[variablelist +[[docstring][An [link ntbs] whose value will bound to the method's `__doc__` attribute]] +[[keywords][A [link function_invocation_and_creation.boost_python_args_hpp.introduction.keyword_expressions keyword-expression] which will be used to name (a trailing subsequence of) the arguments to the generated `__init__` function(s).]] +[[call_policies][An instance of a model of [link concepts.callpolicies CallPolicies].]] +[[argument_types][An MPL sequence of C++ argument types which will be used to construct the wrapped C++ object. An init expression has one or more valid prefixes which are given by a sequence of prefixes of its argument types.]] +] +[endsect] +[endsect] +[section Class template `init`] +A MPL sequence which can be used to specify a family of one or more __init__ functions. Only the last Ti supplied may be an instantiation of optional<...>. + +`` +namespace boost { namespace python +{ + template + struct init + { + init(char const* doc = 0); + template init(Keywords const& kw, char const* doc = 0); + template init(char const* doc, Keywords const& kw); + + template + unspecified operator[](CallPolicies const& policies) const + }; +}} +`` +[section Class template `init` constructors] +`` +init(char const* doc = 0); +template init(Keywords const& kw, char const* doc = 0); +template init(char const* doc, Keywords const& kw); +`` +[variablelist +[[Requires][If supplied, doc is an [link ntbs]. If supplied, kw is the result of a ]] +[[Effects][The result is an init-expression whose docstring is doc and whose keywords are a reference to kw. If the first form is used, the resulting expression's keywords are empty. The expression's call policies are an instance of [link function_invocation_and_creation.models_of_callpolicies.boost_python_default_call_polici default_call_policies]. If Tn is [link high_level_components.boost_python_init_hpp.class_template_optional optional], the expression's valid prefixes are given by: ``(T1, T2,...Tn-1), (T1, T2,...Tn-1 , U1), (T1, T2,...Tn-1 , U1, U2), ...(T1, T2,...Tn-1 , U1, U2,...Um)``. +Otherwise, the expression has one valid prefix given by the template arguments the user specified. ]] +] +[endsect] +[section Class template `init` observer functions] +`` +template +unspecified operator[](Policies const& policies) const +`` +[variablelist +[[Requires][Policies is a model of [link concepts.callpolicies CallPolicies].]] +[[Effects][Returns a new [link high_level_components.boost_python_init_hpp.introduction.init_expressions init-expression] with all the same properties as the init object except that its call policies are replaced by a reference to policies.]] +] +[endsect] +[endsect] +[section Class template `optional` ] +A MPL sequence which can be used to specify the optional arguments to an __init__ function. +`` +namespace boost { namespace python +{ + template + struct optional {}; +}} +`` +[endsect] +[section Example] +Given the C++ declarations: +`` +class Y; +class X +{ + public: + X(int x, Y* y) : m_y(y) {} + X(double); + private: + Y* m_y; +}; +`` +A corresponing Boost.Python extension class can be created with: +`` +using namespace boost::python; + +class_("X", "This is X's docstring.", + init(args("x","y"), "X.__init__'s docstring")[ + with_custodian_and_ward<1,3>()] + ) + .def(init()) + ; + +`` +[endsect] +[endsect] diff --git a/doc/reference/instance_holder.qbk b/doc/reference/instance_holder.qbk new file mode 100644 index 0000000000..c7c533430a --- /dev/null +++ b/doc/reference/instance_holder.qbk @@ -0,0 +1,92 @@ +[section boost/python/instance_holder.hpp] +[section Introduction] + provides class `instance_holder`, the base class for types which hold C++ instances of wrapped classes. +[endsect] +[section Class template `instance_holder`] +`instance_holder` is an abstract base class whose concrete derived classes hold C++ class instances within their Python object wrappers. To allow multiple inheritance in Python from C++ class wrappers, each such Python object contains a chain of instance_holders. When an `__init__` function for a wrapped C++ class is invoked, a new `instance_holder` instance is created and installed in the Python object using its `install()` function. Each concrete class derived from `instance_holder` must provide a `holds()` implementation which allows Boost.Python to query it for the type(s) it is holding. In order to support the held type's wrapped constructor(s), the class must also provide constructors that can accept an initial `PyObject*` argument referring to the owning Python object, and which forward the rest of their arguments to the constructor of the held type. The initial argument is needed to enable virtual function overriding in Python, and may be ignored, depending on the specific `instance_holder` subclass. +`` +namespace boost { namespace python +{ + class instance_holder : noncopyable + { + public: + // destructor + virtual ~instance_holder(); + + // instance_holder modifiers + void install(PyObject* inst) throw(); + + // instance_holder observers + virtual void* holds(type_info) = 0; + }; +}} +`` +[section Class `intance_holder` destructor] +``virtual ~instance_holder();`` +[variablelist +[[Effects][destroys the object]] +] +[endsect] +[section Class `intance_holder` modifiers] +``void install(PyObject* inst) throw();`` +[variablelist +[[Requires][`inst` is a Python instance of a wrapped C++ class type, or is a type derived from a wrapped C++ class type. ]] +[[Effects][installs the new instance at the head of the Python object's chain of held instances. ]] +[[Throws][nothing]] +] +[endsect] +[section Class `intance_holder` observers] +``virtual void *holds(type_info x) = 0;`` +[variablelist +[[Returns][A pointer to an object of the type described by `x` if `*this` contains such an object, 0 otherwise. ]] +] +[endsect] +[endsect] +[section Examples] +The following is a simplified version of the instance holder template used by Boost.Python to wrap classes held by smart pointers: + +`` +template +struct pointer_holder : instance_holder +{ + // construct from the SmartPtr type + pointer_holder(SmartPtr p) + :m_p(p) + + // Forwarding constructors for the held type + pointer_holder(PyObject*) + :m_p(new Value()) + { + } + + template + pointer_holder(PyObject*,A0 a0) + :m_p(new Value(a0)) + { + } + + template + pointer_holder(PyObject*,A0 a0,A1 a1) + :m_p(new Value(a0,a1)) + { + } + ... + + private: // required holder implementation + void* holds(type_info dst_t) + { + // holds an instance of the SmartPtr type... + if (dst_t == python::type_id()) + return &this->m_p; + + // ...and an instance of the SmartPtr's element_type, if the + // pointer is non-null + return python::type_id() == dst_t ? &*this->m_p : 0; + } + + private: // data members + SmartPtr m_p; +}; + `` +[endsect] +[endsect] diff --git a/doc/reference/iterator.qbk b/doc/reference/iterator.qbk new file mode 100644 index 0000000000..c4ee68e0b9 --- /dev/null +++ b/doc/reference/iterator.qbk @@ -0,0 +1,111 @@ +[section boost/python/iterator.hpp] +[section Introduction] + provides types and functions for creating [@http://www.python.org/doc/current/lib/typeiter.html Python iterators] from C++ Containers and Iterators. Note that if your `class_` supports random-access iterators, implementing [@http://www.python.org/doc/current/ref/sequence-types.html#l2h-128 __getitem__] (also known as the Sequence Protocol) may serve you better than using this facility: Python will automatically create an iterator type for you (see [@http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-35 `iter()`]), and each access can be range-checked, leaving no possiblity of accessing through an invalidated C++ iterator. +[endsect] +[section Class template `iterator`] +Instances of `iterator` hold a reference to a callable Python object which, when invoked from Python, expects a single argument c convertible to C and creates a Python iterator that traverses `[c.begin(), c.end())`. The optional [link concepts.callpolicies CallPolicies] `P` can be used to control how elements are returned during iteration. + +In the table below, c is an instance of Container. + +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[Container][`[c.begin(),c.end()`) is a valid Iterator range.][The result will convert its argument to c and call c.begin() and c.end() to acquire iterators. To invoke Container's const `begin()` and `end()` functions, make it const.][ ]] +[[NextPolicies][A default-constructible model of [link concepts.callpolicies CallPolicies].][Applied to the resulting iterators' `next()` method.][An unspecified model of [link concepts.callpolicies CallPolicies] which always makes a copy of the result of deferencing the underlying C++ iterator]] +] + +`` +namespace boost { namespace python + { + template + struct iterator : object + { + iterator(); + }; + }} +`` +[endsect] +[section Class template iterator constructors] +``iterator()`` + +[variablelist +[[Effects][Initializes its base class with the result of: +``range(&iterators::begin, &iterators::end)``]] +[[Postconditions][`this->get()` points to a Python callable object which creates a Python iterator as described above.]] +[[Rationale][Provides an easy way to create iterators for the common case where a C++ class being wrapped provides `begin()` and `end()`.]] +] +[endsect] +[section Class template `iterators`] +A utility class template which provides a way to reliably call its argument's `begin()` and `end()` member functions. Note that there is no portable way to take the address of a member function of a C++ standard library container, so `iterators<>` can be particularly helpful when wrapping them. + +In the table below, x is an instance of C. +[table +[[Required Valid Expression][Type]] +[[x.begin()][Convertible to C::const_iterator if C is a const type; convertible to C::iterator otherwise.]] +[[x.end()][Convertible to C::const_iterator if C is a const type; convertible to C::iterator otherwise.]] +] +`` +namespace boost { namespace python +{ + template + struct iterators + { + typedef typename C::const_iterator iterator; + static iterator begin(C& x); + static iterator end(C& x); + }; +}} +`` +[endsect] +[section Class template iterators nested types] +If C is a const type,``typedef typename C::const_iterator iterator;`` +Otherwise: ``typedef typename C::iterator iterator;`` +[endsect] +[section Class template iterators static functions] +``static iterator begin(C&);`` +[variablelist [[Returns][`x.begin()`]]] +``static iterator end(C&);`` +[variablelist [[Returns][`x.end()`]]] +[endsect] +[section Functions] +`` +template +object range(Accessor1 start, Accessor2 finish); + +template +object range(Accessor1 start, Accessor2 finish); + +template +object range(Accessor1 start, Accessor2 finish); +`` +[variablelist +[[Requires][ NextPolicies is a default-constructible model of [link concepts.callpolicies CallPolicies].]] +[[Effects][The first form creates a Python callable object which, when invoked, converts its argument to a Target object x, and creates a Python iterator which traverses `[bind(start,_1)(x), bind(finish,_1)(x))`, applying NextPolicies to the iterator's `next()` function. +The second form is identical to the first, except that Target is deduced from Accessor1 as follows: + +# If Accessor1 is a function type, Target is the type of its first argument. +# If Accessor1 is a data member pointer of the form `R (T::*)`, Target is identical to `T`. +# If Accessor1 is a member function pointer of the form `R (T::*)(arguments...) cv-opt`, where cv-opt is an optional cv-qualifier, Target is identical to `T`. + +The third form is identical to the second, except that NextPolicies is an unspecified model of [link concepts.callpolicies CallPolicies] which always makes a copy of the result of deferencing the underlying C++ iterator + +]] +[[Rationale][The use of `boost::bind()` allows C++ iterators to be accessed through functions, member functions or data member pointers. Customization of NextPolicies (e.g. using [link function_invocation_and_creation.models_of_callpolicies.boost_python_return_internal_ref.class_template_return_internal_r return_internal_reference]) is useful when it is expensive to copy sequence elements of a wrapped class type. Customization of Target is useful when Accessor1 is a function object, or when a base class of the intended target type would otherwise be deduced.]] +] +[endsect] +[section Example] +`` +#include +#include + +#include + +using namespace boost::python; +BOOST_PYTHON_MODULE(demo) +{ + class_ >("dvec") + .def("__iter__", iterator >()) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/list.qbk b/doc/reference/list.qbk new file mode 100644 index 0000000000..fd602c1852 --- /dev/null +++ b/doc/reference/list.qbk @@ -0,0 +1,60 @@ +[section boost_python_list.hpp] +[section Introduction] +Exposes a [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] for the Python [@http://www.python.org/doc/current/lib/typesseq-mutable.html list] type. +[endsect] +[section Class `list`] +Exposes the [@http://www.python.org/doc/current/lib/typesseq-mutable.html mapping protocol] of Python's built-in `list` type. The semantics of the constructors and member functions defined below can be fully understood by reading the [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] concept definition. Since `list` is publicly derived from [link object_wrappers.boost_python_object_hpp.class_object `object`], the public `object` interface applies to `list` instances as well.`` +namespace boost { namespace python +{ + class list : public object + { + public: + list(); // new list + + template + explicit list(T const& sequence); + + template + void append(T const& x); + + template + long count(T const& value) const; + + template + void extend(T const& x); + + template + long index(T const& x) const; + + template + void insert(object const& index, T const& x); // insert object before index + + object pop(); // remove and return item at index (default last) + object pop(long index); + object pop(object const& index); + + template + void remove(T const& value); + + void reverse(); // reverse *IN PLACE* + + void sort(); // sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1 + + template + void sort(T const& value); + }; +}} +`` +[endsect] +[section Example] +`` +using namespace boost::python; + +// Return the number of zeroes in the list +long zeroes(list l) +{ + return l.count(0); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/long.qbk b/doc/reference/long.qbk new file mode 100644 index 0000000000..dddc3944e2 --- /dev/null +++ b/doc/reference/long.qbk @@ -0,0 +1,38 @@ +[section boost/python/long.hpp] +[section Introduction] +Exposes a [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] for the Python [@http://www.python.org/doc/current/lib/typesnumeric.html long] integer type. +[endsect] +[section Class `long_`] +Exposes the [@http://www.python.org/doc/current/lib/typesnumeric.html numeric type protocol] of Python's built-in `long` type. The semantics of the constructors and member functions defined below can be fully understood by reading the [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] concept definition. Since `long_` is publicly derived from [link object_wrappers.boost_python_object_hpp.class_object `object`], the public `object` interface applies to `long_` instances as well. +`` +namespace boost { namespace python +{ + class long_ : public object + { + public: + long_(); // new long_ + + template + explicit long_(T const& rhs); + + template + long_(T const& rhs, U const& base); + }; +}} +`` +[endsect] +[section Example] +`` +namespace python = boost::python; + +// compute a factorial without overflowing +python::long_ fact(long n) +{ + if (n == 0) + return python::long_(1); + else + return n * fact(n - 1); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/lvalue_from_pytype.qbk b/doc/reference/lvalue_from_pytype.qbk new file mode 100644 index 0000000000..7b5e907cd8 --- /dev/null +++ b/doc/reference/lvalue_from_pytype.qbk @@ -0,0 +1,120 @@ +[section boost/python/lvalue_from_pytype.hpp] +[section Introduction] + supplies a facility for extracting C++ objects from within Python instances of a given type. This is typically useful for dealing with "traditional" Python extension types. +[endsect] +[section Class template `lvalue_from_pytype`] +Class template lvalue_from_pytype will register from_python converters which, given an object of the given Python type, can extract references and pointers to a particular C++ type. Its template arguments are: + + In the table below, x denotes an object of type PythonObject& +[table +[[Parameter][Requirements][Semantics]] +[[Extractor][a model of [link concepts.extractor `Extractor`] whose execute function returns a reference type.][Extracts the lvalue from the Python object once its type has been confirmed]] +[[python_type][A compile-time constant [@http://www.python.org/doc/2.2/ext/dnt-type-methods.html `PyTypeObject*`]][The Python type of instances convertible by this converter. Python subtypes are also convertible.]] +] +`` +namespace boost { namespace python +{ + template + struct lvalue_from_pytype + { + lvalue_from_pytype(); + }; +}} +`` +[section Class template `lvalue_from_pytype` constructor] +``lvalue_from_pytype();`` +[variablelist +[[Effects][Registers converters which can convert Python objects of the given type to lvalues of the type returned by Extractor::execute.]] +] +[endsect] +[endsect] +[section Class template `extract_identity`] +extract_identity is a model of [link concepts.extractor `Extractor`] which can be used in the common case where the C++ type to be extracted is the same as the Python object type. +`` +namespace boost { namespace python +{ + template + struct extract_identity + { + static InstanceType& execute(InstanceType& c); + }; +}} +`` +[section Class template `extract_identity` static functions] +``InstanceType& execute(InstanceType& c);`` +[variablelist +[[Returns][c]] +] +[endsect] +[endsect] +[section Class template `extract_member`] +`extract_member` is a model of [link concepts.extractor `Extractor`] which can be used in the common case in the common case where the C++ type to be extracted is a member of the Python object. +`` +namespace boost { namespace python +{ + template + struct extract_member + { + static MemberType& execute(InstanceType& c); + }; +}} +`` +[section Class template `extract_member` static functions] +``static MemberType& execute(InstanceType& c);`` +[variablelist +[[Returns][`c.*member`]] +] +[endsect] +[endsect] +[section Example] +This example presumes that someone has implemented the standard noddy example module from the Python documentation, and we want to build a module which manipulates Noddys. Since noddy_NoddyObject is so simple that it carries no interesting information, the example is a bit contrived: it assumes you want to keep track of one particular object for some reason. This module would have to be dynamically linked to the module which defines noddy_NoddyType. + +In C++: +`` +#include +#include +#include +#include + +// definition lifted from the Python docs +typedef struct { + PyObject_HEAD +} noddy_NoddyObject; + +using namespace boost::python; +static handle cache; + +bool is_cached(noddy_NoddyObject* x) +{ + return x == cache.get(); +} + +void set_cache(noddy_NoddyObject* x) +{ + cache = handle(borrowed(x)); +} + +BOOST_PYTHON_MODULE(noddy_cache) +{ + def("is_cached", is_cached); + def("set_cache", set_cache); + + // register Noddy lvalue converter + lvalue_from_pytype,&noddy_NoddyType>(); +} +`` +In Python: +`` +>>> import noddy +>>> n = noddy.new_noddy() +>>> import noddy_cache +>>> noddy_cache.is_cached(n) +0 +>>> noddy_cache.set_cache(n) +>>> noddy_cache.is_cached(n) +1 +>>> noddy_cache.is_cached(noddy.new_noddy()) +0 +`` +[endsect] +[endsect] diff --git a/doc/reference/make_function.qbk b/doc/reference/make_function.qbk new file mode 100644 index 0000000000..78c18237b3 --- /dev/null +++ b/doc/reference/make_function.qbk @@ -0,0 +1,83 @@ +[section boost/python/make_function.hpp] +[section Introduction] +make_function() and make_constructor() are the functions used internally by def() and class_<>::def() to produce Python callable objects which wrap C++ functions and member functions. +[endsect] +[section Functions] +`` +template +object make_function(F f) + +template +object make_function(F f, Policies const& policies) + +template +object make_function(F f, Policies const& policies, KeywordsOrSignature const& ks) + +template +object make_function(F f, Policies const& policies, Keywords const& kw, Signature const& sig) +`` +[variablelist +[[Requires][F is a function pointer or member function pointer type. If policies are supplied, it must be a model of CallPolicies. If kewords are supplied, it must be the result of a keyword-expression specifying no more arguments than the arity of f.]] +[[Effects][Creates a Python callable object which, when called from Python, converts its arguments to C++ and calls f. If F is a pointer-to-member-function type, the target object of the function call (*this) will be taken from the first Python argument, and subsequent Python arguments will be used as the arguments to f. + +* If policies are supplied, it will be applied to the function as described here. +* If keywords are supplied, the keywords will be applied in order to the final arguments of the resulting function. +* If Signature is supplied, it should be an instance of an MPL front-extensible sequence representing the function's return type followed by its argument types. Pass a Signature when wrapping function object types whose signatures can't be deduced, or when you wish to override the types which will be passed to the wrapped function. ]] +[[Returns][An instance of object which holds the new Python callable object.]] +[[Caveats][An argument of pointer type may be 0 if None is passed from Python. An argument type which is a constant reference may refer to a temporary which was created from the Python object for just the duration of the call to the wrapped function, for example a std::vector conjured up by the conversion process from a Python list. Use a non-const reference argument when a persistent lvalue is required. ]] +] +`` +template +object make_constructor(F f) + +template +object make_constructor(F f, Policies const& policies) + +template +object make_constructor(F f, Policies const& policies, KeywordsOrSignature const& ks) + +template +object make_constructor(F f, Policies const& policies, Keywords const& kw, Signature const& sig) +`` +[variablelist +[[Requires][F is a function pointer type. If policies are supplied, it must be a model of CallPolicies. If kewords are supplied, it must be the result of a keyword-expression specifying no more arguments than the arity of f.]] +[[Effects][Creates a Python callable object which, when called from Python, converts its arguments to C++ and calls f.]] +[[Returns][An instance of object which holds the new Python callable object.]] +] + +[endsect] +[section Example] +C++ function exposed below returns a callable object wrapping one of two functions. +`` +#include +#include + +char const* foo() { return "foo"; } +char const* bar() { return "bar"; } + +using namespace boost::python; +object choose_function(bool selector) +{ + if (selector) + return boost::python::make_function(foo); + else + return boost::python::make_function(bar); +} + +BOOST_PYTHON_MODULE(make_function_test) +{ + def("choose_function", choose_function); +} +`` +It can be used this way in Python: +`` +>>> from make_function_test import * +>>> f = choose_function(1) +>>> g = choose_function(0) +>>> f() +'foo' +>>> g() +'bar' +`` +[endsect] +[endsect] diff --git a/doc/reference/manage_new_object.qbk b/doc/reference/manage_new_object.qbk new file mode 100644 index 0000000000..95cc6859c7 --- /dev/null +++ b/doc/reference/manage_new_object.qbk @@ -0,0 +1,56 @@ +[section boost/python/manage_new_object.hpp] +[section Class `manage_new_object`] +`manage_new_object` is a model of [link concepts.resultconverter.resultconvertergenerator_concept ResultConverterGenerator] which can be used to wrap C++ functions which return a pointer to an object allocated with a new-expression, and expect the caller to take responsibility for deleting that object. +`` +namespace boost { namespace python +{ + struct manage_new_object + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `manage_new_object` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U*` for some `U`.]] +[[Returns][`typedef to_python_indirect type;`]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include +#include + + +struct Foo { + Foo(int x) : x(x){} + int get_x() { return x; } + int x; +}; + +Foo* make_foo(int x) { return new Foo(x); } + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + def("make_foo", make_foo, return_value_policy()) + class_("Foo") + .def("get_x", &Foo::get_x) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = make_foo(3) # create a Foo object +>>> f.get_x() +3 +`` +[endsect] +[endsect] diff --git a/doc/reference/module.qbk b/doc/reference/module.qbk new file mode 100644 index 0000000000..31c9fec99c --- /dev/null +++ b/doc/reference/module.qbk @@ -0,0 +1,41 @@ +[section boost/python/module.hpp] +[section Introduction] +This header provides the basic facilities needed to create a Boost.Python extension module. +[endsect] +[section Macros] +`BOOST_PYTHON_MODULE(name)` is used to declare Python [@http://www.python.org/doc/2.2/ext/methodTable.html#SECTION003400000000000000000 module initialization functions]. The name argument must exactly match the name of the module to be initialized, and must conform to Python's [@http://www.python.org/doc/2.2/ref/identifiers.html identifier naming rules]. Where you would normally write + +`` +extern "C" void initname() +{ + ... +} +`` +Boost.Python modules should be initialized with +`` +BOOST_PYTHON_MODULE(name) +{ + ... +} +`` +This macro generates two functions in the scope where it is used: `extern "C" void initname()`, and `void init_module_name()`, whose body must follow the macro invocation. `init_name` passes `init_module_name` to [link high_level_components.boost_python_errors_hpp.functions handle_exception()] so that any C++ exceptions generated are safely processeed. During the body of `init_name`, the [link high_level_components.boost_python_scope_hpp current scope] refers to the module being initialized. +[endsect] +[section Examples] +C++ module definition: +`` +#include + +BOOST_PYTHON_MODULE(xxx) +{ + throw "something bad happened" +} +`` +Interactive Python: +`` +>>> import xxx +Traceback (most recent call last): + File "", line 1, in ? +RuntimeError: Unidentifiable C++ Exception +`` +[endsect] +[endsect] diff --git a/doc/reference/object.qbk b/doc/reference/object.qbk new file mode 100644 index 0000000000..26b4840d5d --- /dev/null +++ b/doc/reference/object.qbk @@ -0,0 +1,574 @@ +[section boost/python/object.hpp] +[section Introduction] +Exposes the generic Python object wrapper class object, and related classes. In order to avoid some potenential problems with argument-dependent lookup and the generalized operators defined on object, all these facilities are defined in namespace boost::python::api, and object is imported into namespace boost::python with a using-declaration. +[endsect] +[section Class `slice_nil`] +`` +class slice_nil; +static const _ = slice_nil(); +`` +A type that can be used to get the effect of leaving out an index in a Python slice expression: +`` +>>> x[:-1] +>>> x[::-1] +`` +C++ equivalent: +`` +x.slice(_,-1) +x[slice(_,_,-1)] +`` +[endsect] +[section Class `const_attribute_policies`] +The policies which are used for proxies representing an attribute access to a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_attribute_policies + { + typedef char const* key_type; + static object get(object const& target, char const* key); + }; +}}} +`` +[endsect] +[section Class `const_attribute_policies` static functions] +`` +static object get(object const& target, char const* key); +`` +[variablelist +[[Requires][key is an [link ntbs].]] +[[Effects][accesses the attribute of target named by key.]] +[[Returns][An object managing the result of the attribute access.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `attribute_policies`] +The policies which are used for proxies representing an attribute access to a mutable object. +`` +namespace boost { namespace python { namespace api +{ + struct attribute_policies : const_attribute_policies + { + static object const& set(object const& target, char const* key, object const& value); + static void del(object const&target, char const* key); + }; +}}} +`` +[endsect] +[section Class `attribute_policies` static functions] +`` +static object const& set(object const& target, char const* key, object const& value); +`` +[variablelist +[[Requires][key is an [link ntbs].]] +[[Effects][sets the attribute of target named by key to value.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +`` +static void del(object const&target, char const* key); +`` +[variablelist +[[Requires][key is an [link ntbs].]] +[[Effects][deletes the attribute of target named by key.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `const_objattribute_policies`] +The policies which are used for proxies representing an attribute access to a const object when the attribute name is given as a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_objattribute_policies + { + typedef object const& key_type; + static object get(object const& target, object const& key); + }; +}}} +`` +[endsect] +[section Class `const_objattribute_policies` static functions] +`` +static object get(object const& target, object const& key); +`` +[variablelist +[[Requires][key is an object holding a string.]] +[[Effects][accesses the attribute of target named by key.]] +[[Returns][An object managing the result of the attribute access.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `objattribute_policies`] +The policies which are used for proxies representing an attribute access to a mutable object when the attribute name is given as a const object. +`` +namespace boost { namespace python { namespace api +{ + struct objattribute_policies : const_objattribute_policies + { + static object const& set(object const& target, object const& key, object const& value); + static void del(object const&target, object const& key); + }; +}}} +`` +[endsect] +[section Class `objattribute_policies` static functions] +`` +static object const& set(object const& target, object const& key, object const& value); +`` +[variablelist +[[Requires][key is an object holding a string.]] +[[Effects][sets the attribute of target named by key to value.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +`` +static void del(object const&target, object const& key); +`` +[variablelist +[[Requires][key is an object holding a string.]] +[[Effects][deletes the attribute of target named by key.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `const_item_policies`] +The policies which are used for proxies representing an item access (via the Python bracket operators []) to a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_item_policies + { + typedef object key_type; + static object get(object const& target, object const& key); + }; +}}} +`` +[endsect] +[section Class `const_item_policies` static functions] +`` +static object get(object const& target, object const& key); +`` +[variablelist +[[Effects][accesses the item of target specified by key.]] +[[Returns][An object managing the result of the item access.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `item_policies`] +The policies which are used for proxies representing an item access (via the Python bracket operators []) to a mutable object. +`` +namespace boost { namespace python { namespace api +{ + struct item_policies : const_item_policies + { + static object const& set(object const& target, object const& key, object const& value); + static void del(object const& target, object const& key); + }; +}}} +`` +[endsect] +[section Class `item_policies` static functions] +`` +static object const& set(object const& target, object const& key, object const& value); +`` +[variablelist +[[Effects][sets the item of target specified by key to value.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +`` +static void del(object const& target, object const& key); +`` +[variablelist +[[Effects][deletes the item of target specified by key.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `const_slice_policies`] +The policies which are used for proxies representing an slice access (via the Python slice notation [x:y]) to a const object. +`` +namespace boost { namespace python { namespace api +{ + struct const_slice_policies + { + typedef std::pair, handle<> > key_type; + static object get(object const& target, key_type const& key); + }; +}}} +`` +[endsect] +[section Class `const_slice_policies` static functions] +`` +static object get(object const& target, key_type const& key); +`` +[variablelist +[[Effects][accesses the slice of target specified by key.]] +[[Returns][An object managing the result of the slice access.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class `slice_policies`] +The policies which are used for proxies representing an slice access to a mutable object. +`` +namespace boost { namespace python { namespace api +{ + struct slice_policies : const_slice_policies + { + static object const& set(object const& target, key_type const& key, object const& value); + static void del(object const& target, key_type const& key); + }; +}}} +`` +[endsect] +[section Class `slice_policies` static functions] +`` +static object const& set(object const& target, key_type const& key, object const& value); +`` +[variablelist +[[Effects][sets the slice of target specified by key to value.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +`` +static void del(object const& target, key_type const& key); +`` +[variablelist +[[Effects][deletes the slice of target specified by key.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] if a Python exception is raised.]] +] +[endsect] +[section Class template `object_operators`] +This is the base class of object and its proxy template used to supply common interface: member functions, and operators which must be defined within the class body. Its template parameter U is expected to be a class derived from object_operators. In practice users should never use this class directly, but it is documented here because it supplies important interface to object and its proxies. +`` +namespace boost { namespace python { namespace api +{ + template + class object_operators + { + public: + // function call + // + object operator()() const; + + template + object operator()(A0 const&) const; + template + object operator()(A0 const&, A1 const&) const; + ... + template + object operator()(A0 const&, A1 const&,...An const&) const; + + detail::args_proxy operator* () const; + object operator()(detail::args_proxy const &args) const; + object operator()(detail::args_proxy const &args, + detail::kwds_proxy const &kwds) const; + + // truth value testing + // + typedef unspecified bool_type; + operator bool_type() const; + + // Attribute access + // + proxy attr(char const*) const; + proxy attr(char const*); + proxy attr(object const&) const; + proxy attr(object const&); + + // item access + // + template + proxy operator[](T const& key) const; + + template + proxy operator[](T const& key); + + // slicing + // + template + proxy slice(T const& start, V const& end) const + + template + proxy slice(T const& start, V const& end); + }; +}}} +`` +[endsect] +[section Class template `object_operators` observer functions] +`` +object operator()() const; +template +object operator()(A0 const&) const; +template +object operator()(A0 const&, A1 const&) const; +... +template +object operator()(A0 const& a1, A1 const& a2,...An const& aN) const; +`` +[variablelist +[[Effects][`call(object(*static_cast(this)).ptr(), a1, a2,...aN)`]] +] +``object operator()(detail::args_proxy const &args) const; `` +[variablelist +[[Effects][`call object with arguments given by the tuple args`]] +] +``object operator()(detail::args_proxy const &args, + detail::kwds_proxy const &kwds) const; + +`` +[variablelist +[[Effects][`call object with arguments given by the tuple args, and named arguments given by the dictionary kwds`]] +] +``operator bool_type() const;`` +[variablelist +[[Effects][Tests truth value of `*this`.]] +[[Returns][`call(object(*static_cast(this)).ptr(), a1, a2,...aN)`]] +] +`` +proxy attr(char const* name) const; +proxy attr(char const* name); +`` +[variablelist +[[Requires][name is an [link ntbs].]] +[[Effects][accesses the named attribute of *this.]] +[[Returns][a proxy object which binds `object(*static_cast(this))` as its target, and name as its key.]] +] +`` +proxy attr(const object& name) const; +proxy attr(const object& name); +`` +[variablelist +[[Requires][name is a object holding a string.]] +[[Effects][accesses the named attribute of `*this`.]] +[[Returns][a proxy object which binds `object(*static_cast(this))` as its target, and name as its key.]] +] +`` +template +proxy operator[](T const& key) const; +template +proxy operator[](T const& key); +`` +[variablelist +[[Effects][accesses the item of `*this` indicated by key.]] +[[Returns][a proxy object which binds `object(*static_cast(this))` as its target, and object(key) as its key.]] +] +`` +template +proxy slice(T const& start; start, V const& finish) const +template +proxy slice(T const& start; start, V const& finish); +`` +[variablelist +[[Effects][accesses the slice of `*this` indicated by `std::make_pair(object(start), object(finish))`.]] +[[Returns][a proxy object which binds `object(*static_cast(this))` as its target, and `std::make_pair(object(start), object(finish))` as its key.]] +] +[endsect] +[section Class `object`] +The intention is that object acts as much like a Python variable as possible. Thus expressions you'd expect to work in Python should generally work in the same way from C++. Most of object's interface is provided by its base class `object_operators`, and the free functions defined in this header. +`` +namespace boost { namespace python { namespace api +{ + class object : public object_operators + { + public: + object(); + object(object const&); + template + explicit object(T const& x); + + ~object(); + + object& operator=(object const&); + PyObject* ptr() const; + bool is_none() const; + }; +}}} +`` +[endsect] +[section Class `object` constructors and destructor] +``object();`` +[variablelist +[[Effects][Constructs an object managing a reference to the Python None object.]] +[[Throws][nothing.]] +] +``template +explicit object(T const& x); +`` +[variablelist +[[Effects][converts x to python and manages a reference to it.]] +[[Throws][[link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] and sets a Python TypeError exception if no such conversion is possible.]] +] +`` +~object(); +`` +[variablelist +[[Effects][decrements the reference count of the internally-held object.]] +] +[endsect] +[section Class `object` modifiers] +``PyObject* ptr() const;`` + +[variablelist +[[Returns] [a pointer to the internally-held Python object.]] +] +``bool is_none() const;`` + +[variablelist +[[Returns] [result of `(ptr() == Py_None)`]] +] +[endsect] +[section Class template `proxy`] +This template is instantiated with various Policies described in this document in order to implement attribute, item, and slice access for object. It stores an object of type Policies::key_type. +`` +namespace boost { namespace python { namespace api +{ + template + class proxy : public object_operators > + { + public: + operator object() const; + + proxy const& operator=(proxy const&) const; + template + inline proxy const& operator=(T const& rhs) const; + + void del() const; + + template + proxy operator+=(R const& rhs); + template + proxy operator-=(R const& rhs); + template + proxy operator*=(R const& rhs); + template + proxy operator/=(R const& rhs); + template + proxy operator%=(R const& rhs); + template + proxy operator<<=(R const& rhs); + template + proxy operator>>=(R const& rhs); + template + proxy operator&=(R const& rhs); + template + proxy operator|=(R const& rhs); + }; +}}} +`` +[endsect] +[section Class template `proxy` observer functions] +``operator object() const;`` +[variablelist +[[Effects][applies `Policies::get(target, key)` with the proxy's target and key objects.]] +] +[endsect] +[section Class template `proxy` modifier functions] +`` +proxy const& operator=(proxy const& rhs) const; +template +inline proxy const& operator=(T const& rhs) const; +`` +[variablelist +[[Effects][ `Policies::set(target, key , object(rhs))` with the proxy's target and key objects.]] +] +`` +template +proxy operator+=(R const& rhs); +template +proxy operator-=(R const& rhs); +template +proxy operator*=(R const& rhs); +template +proxy operator/=(R const& rhs); +template +proxy operator%=(R const& rhs); +template +proxy operator<<=(R const& rhs); +template +proxy operator>>=(R const& rhs); +template +proxy operator&=(R const& rhs); +template +proxy operator|=(R const& rhs); +`` +[variablelist +[[Effects][for a given `operator@=`, `object(*this) @= rhs;`]] +[[Returns][`*this`]] +] +``void del() const;`` +[variablelist +[[Effects][Policies::del(target, key ) with the proxy's target and key objects.]] +] +[endsect] +[section Functions] +`` +template +void del(proxy const& x); +`` +[variablelist +[[Effects][`x.del()`]] +] +`` +template object operator>(L const&l,R const&r); +template object operator>=(L const&l,R const&r); +template object operator<(L const&l,R const&r); +template object operator<=(L const&l,R const&r); +template object operator==(L const&l,R const&r); +template object operator!=(L const&l,R const&r); +`` +[variablelist +[[Effects][returns the result of applying the operator to `object(l)` and `object(r)`, respectively, in Python.]] +] +`` +template object operator+(L const&l,R const&r); +template object operator-(L const&l,R const&r); +template object operator*(L const&l,R const&r); +template object operator/(L const&l,R const&r); +template object operator%(L const&l,R const&r); +template object operator<<(L const&l,R const&r); +template object operator>>(L const&l,R const&r); +template object operator&(L const&l,R const&r); +template object operator^(L const&l,R const&r); +template object operator|(L const&l,R const&r); +`` +[variablelist +[[Effects][returns the result of applying the operator to `object(l)` and `object(r)`, respectively, in Python.]] +] +`` +template object& operator+=(object&l,R const&r); +template object& operator-=(object&l,R const&r); +template object& operator*=(object&l,R const&r); +template object& operator/=(object&l,R const&r); +template object& operator%=(object&l,R const&r); +template object& operator<<=(object&l,R const&r) +template object& operator>>=(object&l,R const&r); +template object& operator&=(object&l,R const&r); +template object& operator^=(object&l,R const&r); +template object& operator|=(object&l,R const&r); +`` +[variablelist +[[Effects][assigns to `l` the result of applying the corresponding Python inplace operator to `l` and `object(r)`, respectively.]] +[[Returns][l]] +] +``long len(object const& obj);`` +[variablelist +[[Effects][`PyObject_Length(obj.ptr())`]] +[[Returns][`len()` of object.]] +] +[endsect] +[section Example] +Python code: +`` +def sum_items(seq): + result = 0 + for x in seq: + result += x + return result +`` +C++ version +`` +object sum_items(object seq) +{ + object result = object(0); + for (int i = 0; i < len(seq); ++i) + result += seq[i]; + return result; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/objects.qbk b/doc/reference/objects.qbk new file mode 100644 index 0000000000..c57b02d03d --- /dev/null +++ b/doc/reference/objects.qbk @@ -0,0 +1,11 @@ +[chapter Object Wrappers + [quickbook 1.7] +] + +[include dict.qbk] +[include list.qbk] +[include long.qbk] +[include object.qbk] +[include str.qbk] +[include slice.qbk] +[include tuple.qbk] diff --git a/doc/reference/opaque_pointer_converter.qbk b/doc/reference/opaque_pointer_converter.qbk new file mode 100644 index 0000000000..c87cd36ac9 --- /dev/null +++ b/doc/reference/opaque_pointer_converter.qbk @@ -0,0 +1,31 @@ +[section boost/python/opaque_pointer_converter.hpp] +[section Introduction] +`opaque<>` registers itself as a converter from Python objects to pointers to undefined types and vice versa. +`` +namespace boost { namespace python +{ + template + struct opaque + { + opaque(); + }; +}} +`` +[endsect] +[section Class template `opaque` constructor] +``opaque();`` +[variablelist +[[Effects][ +* Registers the instance as a [link to_from_python_type_conversion.boost_python_lvalue_from_pytype_.class_template_lvalue_from_pytyp `lvalue_from_pytype`] converter from Python objects into opaque pointers. + The Python Objects created are named after the type pointed to by the opaque pointer being wrapped. +* Registers the instance as a [link to_from_python_type_conversion.boost_python_to_python_converter.class_template_to_python_convert `to_python_converter`] from opaque pointers to Python objects. +]] +] +[note If there is already an instance registered by another module, this instance doesn't try to register again in order to avoid warnings about multiple registrations.] + +[endsect] +[section Macro `BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)`] +This macro must be used to define specializations of the [link utility_and_infrastructure.boost_python_type_id_hpp.functions `type_id`] function which can't be instantiated for incomplete types. +[note The macro must be invoked in every translation unit which uses the opaque converter.] +[endsect] +[endsect] diff --git a/doc/reference/operators.qbk b/doc/reference/operators.qbk new file mode 100644 index 0000000000..8276f68190 --- /dev/null +++ b/doc/reference/operators.qbk @@ -0,0 +1,257 @@ +[section boost/python/operators.hpp] +[section Introduction] + provides types and functions for automatically generating Python [@http://www.python.org/doc/ref/specialnames.html special methods] from the corresponding C++ constructs. Most of these constructs are operator expressions, hence the name. To use the facility, substitute the [link high_level_components.boost_python_operators_hpp.object_self self] object for an object of the class type being wrapped in the expression to be exposed, and pass the result to [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu class_<>::def()]. Much of what is exposed in this header should be considered part of the implementation, so is not documented in detail here. +[endsect] +[section Class `self_ns::self_t`] +`self_ns::self_t` is the actual type of the [link high_level_components.boost_python_operators_hpp.object_self self] object. The library isolates `self_t` in its own namespace, `self_ns`, in order to prevent the generalized operator templates which operate on it from being found by argument-dependent lookup in other contexts. This should be considered an implementation detail, since users should never have to mention `self_t` directly. +`` +namespace boost { namespace python { namespace self_ns { +{ + unspecified-type-declaration self_t; + + // inplace operators + template operator_ operator+=(self_t, T); + template operator_ operator-=(self_t, T); + template operator_ operator*=(self_t, T); + template operator_ operator/=(self_t, T); + template operator_ operator%=(self_t, T); + template operator_ operator>>=(self_t, T); + template operator_ operator<<=(self_t, T); + template operator_ operator&=(self_t, T); + template operator_ operator^=(self_t, T); + template operator_ operator|=(self_t, T); + + // comparisons + template operator_ operator==(L const&, R const&); + template operator_ operator!=(L const&, R const&); + template operator_ operator<(L const&, R const&); + template operator_ operator>(L const&, R const&); + template operator_ operator<=(L const&, R const&); + template operator_ operator>=(L const&, R const&); + + // non-member operations + template operator_ operator+(L const&, R const&); + template operator_ operator-(L const&, R const&); + template operator_ operator*(L const&, R const&); + template operator_ operator/(L const&, R const&); + template operator_ operator%(L const&, R const&); + template operator_ operator>>(L const&, R const&); + template operator_ operator<<(L const&, R const&); + template operator_ operator&(L const&, R const&); + template operator_ operator^(L const&, R const&); + template operator_ operator|(L const&, R const&); + template operator_ pow(L const&, R const&); + + // unary operations + operator_ operator-(self_t); + operator_ operator+(self_t); + operator_ operator~(self_t); + operator_ operator!(self_t); + + // value operations + operator_ int_(self_t); + operator_ long_(self_t); + operator_ float_(self_t); + operator_ complex_(self_t); + operator_ str(self_t); + + operator_ repr(self_t); +}}}; +`` +The tables below describe the methods generated when the results of the expressions described are passed as arguments to [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu class_<>::def()]. `x` is an object of the class type being wrapped. +[section `self_t` inplace operators] +In the table below, If `r` is an object of type [link high_level_components.boost_python_operators_hpp.class_template_other other], `y` is an object of type `T`; otherwise, `y` is an object of the same type as `r`. +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`self += r`][`__iadd__`][`x += y`]] +[[`self -= r`][`__isub__`][`x -= y`]] +[[`self *= r`][`__imul__`][`x *= y`]] +[[`self /= r`][`__idiv__`][`x /= y`]] +[[`self %= r`][`__imod__`][`x %= y`]] +[[`self >>= r`][`__irshift__`][`x >>= y`]] +[[`self <<= r`][`__ilshift__`][`x <<= y`]] +[[`self &= r`][`__iand__`][`x &= y`]] +[[`self ^= r`][`__ixor__`][`x ^= y`]] +[[`self |= r`][`__ior__`][`x |= y`]] +] +[endsect] +[section `self_t` comparison functions] +In the tables below, if `r` is of type [link high_level_components.boost_python_operators_hpp.class_self_ns_self_t self_t], `y` is an object of the same type as `x`; +if `l` or `r` is an object of type [link high_level_components.boost_python_operators_hpp.class_template_other other], `y` is an object of type `T`; +otherwise, `y` is an object of the same type as `l` or `r`. +`l` is never of type [link high_level_components.boost_python_operators_hpp.class_self_ns_self_t self_t]. + +The column of Python Expressions illustrates the expressions that will be supported in Python for objects convertible to the types of x and y. The secondary operation arises due to Python's [@http://www.python.org/doc/ref/customization.html#l2h-89 reflection rules] for rich comparison operators, and are only used when the corresponding operation is not defined as a method of the y object. +[table +[[C++ Expression][Python Method Name][C++ Implementation][Python Expression (primary, secondary)]] +[[`self == r`][`__eq__`][`x == y`][`x == y`, `y == x`]] +[[`l == self`][`__eq__`][`y == x`][`y == x`, `x == y`]] +[[`self != r`][`__ne__`][`x != y`][`x != y`, `y != x`]] +[[`l != self`][`__ne__`][`y != x`][`y != x`, `x != y`]] +[[`self < r`][`__lt__`][`x < y`][`x < y`, `y > x`]] +[[`l < self`][`__gt__`][`y < x`][`y > x`, `x < y`]] +[[`self > r`][`__gt__`][`x > y`][`x > y`, `y < x`]] +[[`l > self`][`__lt__`][`y > x`][`y < x`, `x > y`]] +[[`self <= r`][`__le__`][`x <= y`][`x <= y`, `y >= x`]] +[[`l <= self`][`__ge__`][`y <= x`][`y >= x`, `x <= y`]] +[[`self >= r`][`__ge__`][`x >= y`][`x >= y`, `y <= x`]] +[[`l <= self`][`__le__`][`y >= x`][`y <= x`, `x >= y`]] +] +[endsect] +[section `self_t` non-member operations] +The operations whose names begin with "__r" below will only be called if the left-hand operand does not already support the given operation, as described [@http://www.python.org/doc/current/ref/numeric-types.html#l2h-152 here]. +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`self + r`][`__add__`][`x + y`]] +[[`l + self`][`__radd__`][`y + x`]] +[[`self - r`][`__sub__`][`x - y`]] +[[`l - self`][`__rsub__`][`y - x`]] +[[`self * r`][`__mult__`][`x * y`]] +[[`l * self`][`__rmult__`][`y * x`]] +[[`self / r`][`__div__`][`x / y`]] +[[`l / self`][`__rdiv__`][`y / x`]] +[[`self % r`][`__mod__`][`x % y`]] +[[`l % self`][`__rmod__`][`y % x`]] +[[`self >> r`][`__rshift__`][`x >> y`]] +[[`l >> self`][`__rrshift__`][`y >> x`]] +[[`self << r`][`__lshift__`][`x << y`]] +[[`l << self`][`__rlshift__`][`y << x`]] +[[`self & r`][`__and__`][`x & y`]] +[[`l & self`][`__rand__`][`y & x`]] +[[`self ^ r`][`__xor__`][`x ^ y`]] +[[`l ^ self`][`__rxor__`][`y ^ x`]] +[[`self | r`][`__or__`][`x | y`]] +[[`l | self`][`__ror__`][`y | x`]] +[[`pow(self, r)`][`__pow__`][`x ** y`]] +[[`pow(l, self)`][`__rpow__`][`y ** x`]] +] +[endsect] +[section `self_t` unary operations] +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`-self`][`__neg__`][`-x`]] +[[`+self`][`__pos__`][`+x`]] +[[`~self`][`__invert__`][`~x`]] +[[`not self` or `!self`][`__nonzero__`][`!!x`]] +] +[endsect] +[section `self_t` value operations] +[table +[[C++ Expression][Python Method Name][C++ Implementation]] +[[`int_(self)`][`__int__`][`long(x)`]] +[[`long_(self)`][`__long__`][`PyLong_FromLong(x)`]] +[[`float_(self)`][`__float__`][`double(x)`]] +[[`complex_(self)`][`__complex__`][`std::complex(x)`]] +[[`str(self)`][`__str__`][`lexical_cast(x)`]] +[[`repr(self)`][`__repr__`][`lexical_cast(x)`]] +] +[endsect] +[endsect] +[section Class template `other`] +Instances of `other` can be used in operator expressions with [link high_level_components.boost_python_operators_hpp.object_self self]; the result is equivalent to the same expression with a `T` object in place of `other`. Use `other` to prevent construction of a `T` object in case it is heavyweight, when no constructor is available, or simply for clarity. +`` +namespace boost { namespace python +{ + template + struct other + { + }; +}} +`` +[endsect] +[section Class template `detail::operator_`] +Instantiations of `detail::operator_<>` are used as the return type of operator expressions involving [link high_level_components.boost_python_operators_hpp.object_self self]. This should be considered an implementation detail and is only documented here as a way of showing how the result of self-expressions match calls to [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel.class_template_class_modifier_fu `class_<>::def()`]. +`` +namespace boost { namespace python { namespace detail +{ + template + struct operator_ + { + }; +}}} +`` +[endsect] +[section Object `self`] +`` +namespace boost { namespace python +{ + using self_ns::self; +}} +`` +[endsect] +[section Example] +`` +#include +#include +#include +#include + +struct number + : boost::integer_arithmetic +{ + explicit number(long x_) : x(x_) {} + operator long() const { return x; } + + template + number& operator+=(T const& rhs) + { x += rhs; return *this; } + + template + number& operator-=(T const& rhs) + { x -= rhs; return *this; } + + template + number& operator*=(T const& rhs) + { x *= rhs; return *this; } + + template + number& operator/=(T const& rhs) + { x /= rhs; return *this; } + + template + number& operator%=(T const& rhs) + { x %= rhs; return *this; } + + long x; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(demo) +{ + class_("number", init()) + // interoperate with self + .def(self += self) + .def(self + self) + .def(self -= self) + .def(self - self) + .def(self *= self) + .def(self * self) + .def(self /= self) + .def(self / self) + .def(self %= self) + .def(self % self) + + // Convert to Python int + .def(int_(self)) + + // interoperate with long + .def(self += long()) + .def(self + long()) + .def(long() + self) + .def(self -= long()) + .def(self - long()) + .def(long() - self) + .def(self *= long()) + .def(self * long()) + .def(long() * self) + .def(self /= long()) + .def(self / long()) + .def(long() / self) + .def(self %= long()) + .def(self % long()) + .def(long() % self) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/overloads.qbk b/doc/reference/overloads.qbk new file mode 100644 index 0000000000..819ee680fa --- /dev/null +++ b/doc/reference/overloads.qbk @@ -0,0 +1,97 @@ +[section boost/python/overloads.hpp] +[section Introduction] +Defines facilities for generating families of overloaded Python functions and extension class methods from C++ functions and member functions with default arguments, or from similar families of C++ overloads +[section overload-dispatch-expressions] +An overload-dispatch-expression is used to describe a family of overloaded methods to be generated for an extension class. It has the following properties: +[variablelist +[[docstring][An [link ntbs] whose value will bound to the methods' `__doc__` attribute]] +[[keywords][A [link function_invocation_and_creation.boost_python_args_hpp.introduction.keyword_expressions keyword-expression] which will be used to name (a trailing subsequence of) the arguments to the generated methods.]] +[[call policies][An instance of some type which models CallPolicies.]] +[[minimum arity][The minimum number of arguments to be accepted by a generated method overload.]] +[[maximum arity][The maximum number of arguments to be accepted by a generated method overload.]] +] +[endsect] +[endsect] +[section OverloadDispatcher Concept] +An OverloadDispatcher X is a class which has a minimum arity and a maximum arity, and for which the following following are valid overload-dispatch-expressions, with the same minimum and maximum arity as the OverloadDispatcher. +`` +X() +X(docstring) +X(docstring, keywords) +X(keywords, docstring) +X()[policies] +X(docstring)[policies] +X(docstring, keywords)[policies] +X(keywords, docstring)[policies] +`` +* If policies are supplied, it must be an instance of a type which models [link concepts.callpolicies CallPolicies], and will be used as the result's call policies. Otherwise the result's call policies will be an instance of [link function_invocation_and_creation.models_of_callpolicies.boost_python_default_call_polici `default_call_policies`]. +* If docstring is supplied it must be an [link ntbs], and will be used as the result's docstring. Otherwise the result has an empty docstring. +* If keywords is supplied it must be the result of a [link function_invocation_and_creation.boost_python_args_hpp.introduction.keyword_expressions keyword-expression] whose length is no greater than X's maximum arity, and will be used as the result's keywords. Otherwise the result's keywords will be empty. +[endsect] +[section Macros] +`` +BOOST_PYTHON_FUNCTION_OVERLOADS(name, func_id, min_args, max_args) +`` +Expands to the definition of an OverloadDispatcher called name in the current scope which can be used to generate the following function invocation: +``func_id(a1, a2,...ai);`` +for all `min_args <= i <= max_args`. +`` +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(name, member_name, min_args, max_args) +`` +Expands to the definition of an OverloadDispatcher called name in the current scope which can be used to generate the following function invocation: +``x.member_name(a1, a2,...ai);`` +for all min_args <= i <= max_args, where x is a reference to an object of class type. +[endsect] +[section Example] +`` +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + +struct Y {}; +struct X +{ + Y& f(int x, double y = 4.25, char const* z = "wow") + { + return inner; + } + Y inner; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(f_member_overloads, f, 1, 3) + +BOOST_PYTHON_MODULE(args_ext) +{ + def("f", f, + f_overloads( + args("x", "y", "z"), "This is f's docstring" + )); + + + class_("Y") + ; + + class_("X", "This is X's docstring") + .def("f1", &X::f, + f_member_overloads( + args("x", "y", "z"), "f's docstring" + )[return_internal_reference<>()] + ) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/pickle.qbk b/doc/reference/pickle.qbk new file mode 100644 index 0000000000..23d25ede7c --- /dev/null +++ b/doc/reference/pickle.qbk @@ -0,0 +1,159 @@ +[section Pickle support] +[section Introduction] +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 through the interface as described in detail in the [@https://docs.python.org/2/library/pickle.html Python Library Reference for pickle]. This interface involves the special methods `__getinitargs__`, `__getstate__` and `__setstate__` as described in the following. Note that `Boost.Python` is also fully compatible with Python's cPickle module. +[endsect] +[section The Pickle Interface] +At the user level, the Boost.Python pickle interface involves three special methods: +[variablelist +[[__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 [link object_wrappers.boost_python_tuple_hpp.class_tuple `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, `pickle.load` will call the constructor (`__init__`) without arguments; i.e., the object must be default-constructible.]] +[[__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.]] +[[__setstate__][When an instance of a `Boost.Python` extension class is restored by the unpickler (`pickle.load`), 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.]] +] + +The three special methods described above may be `.def()`\ 'ed individually by the user. However, `Boost.Python` provides an easy to use high-level interface via the `boost::python::pickle_suite` class that also enforces consistency: `__getstate__` and `__setstate__` must be defined as pairs. Use of this interface is demonstrated by the following examples. +[endsect] +[section Example] +There are three files in `python/test` that show how to provide pickle support. +[section 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__`. This is done in the following way: +Definition of the C++ pickle function: +`` +struct world_pickle_suite : boost::python::pickle_suite +{ + static + boost::python::tuple + getinitargs(world const& w) + { + return boost::python::make_tuple(w.get_country()); + } +}; +`` +Establishing the Python binding: +`` +class_("world", args()) + // ... + .def_pickle(world_pickle_suite()) + // ... +`` +[endsect] +[section 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: + +Definition of the C++ pickle functions: +`` +struct world_pickle_suite : boost::python::pickle_suite + { + static + boost::python::tuple + getinitargs(const world& w) + { + // ... + } + + static + boost::python::tuple + getstate(const world& w) + { + // ... + } + + static + void + setstate(world& w, boost::python::tuple state) + { + // ... + } + }; +`` +Establishing the Python bindings for the entire suite: +`` + class_("world", args()) + // ... + .def_pickle(world_pickle_suite()) + // ... + +`` + +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 guard described below will catch the cases where this assumption is violated. +[endsect] +[section pickle3.cpp] +This example is similar to pickle2.cpp. However, the object's `__dict__` is included in the result of `__getstate__`. This requires a little more code but is unavoidable if the object's `__dict__` is not always empty. +[endsect] +[endsect] +[section Pitfall and Safety Guard] +The pickle protocol described above has an important pitfall that the end user of a Boost.Python extension module might not be aware of: + +[*`__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 either at the C++ or the Python level. Finally, the safety guard should intentionally be overridden. E.g. in C++ (from pickle3.cpp): + +`` +struct world_pickle_suite : boost::python::pickle_suite +{ + // ... + + static bool getstate_manages_dict() { return true; } +}; +`` + +Alternatively 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 + +`` +[endsect] +[section Practical Advice] + +* 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. +* Avoid using `__getstate__` if the instance can also be reconstructed by way of `__getinitargs__`. This automatically avoids the pitfall described above. +* If `__getstate__` is required, include the instance's `__dict__` in the Python object that is returned. + +[endsect] +[section Light-weight alternative: pickle support implemented in Python] +The pickle4.cpp example demonstrates an alternative technique for implementing pickle support. First we direct Boost.Python via the class_::enable_pickling() member function to define only the basic attributes required for pickling: + +`` + class_("world", args()) + // ... + .enable_pickling() + // ... +`` +This enables the standard Python pickle interface as described in the Python documentation. By "injecting" a `__getinitargs__` method into the definition of the wrapped class we make all instances pickleable: + +`` + # import the wrapped world class + from pickle4_ext import world + + # definition of __getinitargs__ + def world_getinitargs(self): + return (self.get_country(),) + + # now inject __getinitargs__ (Python is a dynamic language!) + world.__getinitargs__ = world_getinitargs +`` +See also the tutorial section on injecting additional methods from Python. +[endsect] +[endsect] diff --git a/doc/reference/pointee.qbk b/doc/reference/pointee.qbk new file mode 100644 index 0000000000..525ba5d870 --- /dev/null +++ b/doc/reference/pointee.qbk @@ -0,0 +1,47 @@ +[section boost/python/pointee.hpp] +[section Introduction] + introduces a traits metafunction `template pointee` that can be used to extract the "pointed-to" type from the type of a pointer or smart pointer. +[endsect] +[section Class template `pointee`] +`pointee` is used by the [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel `class_<...>`] template to deduce the type being held when a pointer or smart pointer type is used as its HeldType argument. +`` +namespace boost { namespace python +{ + template struct pointee + { + typedef T::element_type type; + }; + + // specialization for pointers + template struct pointee + { + typedef T type; + }; +} +`` +[endsect] +[section Examples] +Given a 3rd-party smart pointer type `smart_pointer`, one might partially specialize `pointee >` so that it can be used as the HeldType for a class wrapper: +`` +#include +#include +#include + +namespace boost { namespace python +{ + template struct pointee > + { + typedef T type; + }; +}} + +BOOST_PYTHON_MODULE(pointee_demo) +{ + class_ >("third_party_class") + .def(...) + ... + ; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/ptr.qbk b/doc/reference/ptr.qbk new file mode 100644 index 0000000000..c39c5ac818 --- /dev/null +++ b/doc/reference/ptr.qbk @@ -0,0 +1,118 @@ +[section boost/python/ptr.hpp] +[section Introduction] + defines the ptr() function template, which allows users to specify how to convert C++ pointer values to python in the context of implementing overridable virtual functions, invoking Python callable objects, or explicitly converting C++ objects to Python. Normally, when passing pointers to Python callbacks, the pointee is copied to ensure that the Python object never holds a dangling reference. To specify that the new Python object should merely contain a copy of a pointer p, the user can pass ptr(p) instead of passing p directly. This interface is meant to mirror the use of boost::ref(), which can be similarly used to prevent copying of referents. + +ptr(p) returns an instance of [link function_invocation_and_creation.boost_python_ptr_hpp.class_template_pointer_wrapper `pointer_wrapper<>`], which can be detected using the [link function_invocation_and_creation.boost_python_ptr_hpp.metafunctions.class_template_is_pointer_wrappe `is_pointer_wrapper<>`] metafunction; [link function_invocation_and_creation.boost_python_ptr_hpp.metafunctions.class_template_unwrap_pointer `unwrap_pointer<>`] is a metafunction which extracts the original pointer type from a `pointer_wrapper<>`. These classes can be thought of as implementation details. +[endsect] +[section Functions] +`` +template +pointer_wrapper ptr(T x); +`` +[variablelist +[[Requires][T is a pointer type.]] +[[Returns][pointer_wrapper(x)]] +[[Throws][nothing.]] +] +[endsect] +[section Class template `pointer_wrapper`] +A "type envelope" which is returned by `ptr()`, used to indicate reference semantics for pointers passed to Python callbacks. +`` +namespace boost { namespace python +{ + template class pointer_wrapper + { + public: + typedef Ptr type; + + explicit pointer_wrapper(Ptr x); + operator Ptr() const; + Ptr get() const; + }; +}} +`` +[endsect] +[section Class template `pointer_wrapper` types] +`` +typedef Ptr type; +`` +The type of the pointer being wrapped. +[endsect] +[section Class template `pointer_wrapper` constructors and destructor] +`` +explicit pointer_wrapper(Ptr x); +`` +[variablelist +[[Requires][`Ptr` is a pointer type]] +[[Effects][Stores `x` in a the `pointer_wrapper<>`. ]] +[[Throws][nothing.]] +] +[endsect] +[section Class template `pointer_wrapper` observer functions] +`` +operator Ptr() const; +Ptr get() const; +`` +[variablelist +[[Returns][a copy of the stored pointer. ]] +[[Rationale][pointer_wrapper is intended to be a stand-in for the actual pointer type, but sometimes it's better to have an explicit way to retrieve the pointer. ]] +] +[endsect] +[section Metafunctions] +[section Class template `is_pointer_wrapper`] +A unary metafunction whose value is true iff its argument is a pointer_wrapper<>. +`` +namespace boost { namespace python +{ + template class is_pointer_wrapper + { + static unspecified value = ...; + }; +}} +`` +[variablelist +[[Returns][`true` iff `T` is a specialization of `pointer_wrapper<>`. +value is an integral constant convertible to bool of unspecified type ]] +] +[endsect] +[section Class template `unwrap_pointer`] +A unary metafunction which extracts the wrapped pointer type from a specialization of pointer_wrapper<>. +`` +namespace boost { namespace python +{ + template class unwrap_pointer + { + typedef unspecified type; + }; +}} +`` +[variablelist +[[Returns][`T::type` if `T` is a specialization of `pointer_wrapper<>`, `T` otherwise ]] +] +[endsect] +[endsect] +[section Example] +This example illustrates the use of ptr() to prevent an object from being copied: +`` +#include +#include + +class expensive_to_copy +{ + ... +}; + +void pass_as_arg(expensive_to_copy* x, PyObject* f) +{ + // call the Python function f, passing a Python object built around + // which refers to *x by-pointer. + // + // *** Note: ensuring that *x outlives the argument to f() is *** + // *** up to the user! Failure to do so could result in a crash! *** + + boost::python::call(f, ptr(x)); +} +... +`` +[endsect] +[endsect] diff --git a/doc/reference/pytype_function.qbk b/doc/reference/pytype_function.qbk new file mode 100644 index 0000000000..18ceff57b2 --- /dev/null +++ b/doc/reference/pytype_function.qbk @@ -0,0 +1,194 @@ +[section boost/python/pytype_function.hpp] +[section Introduction] +To support Pythonic signatures the converters should supply a `get_pytype` function returning a pointer to the associated `PyTypeObject`. See for example [link concepts.resultconverter `ResultConverter`] or [link to_from_python_type_conversion.boost_python_to_python_converter.class_template_to_python_convert.class_template_to_python_convert `to_python_converter`]. The classes in this header file are meant to be used when implmenting `get_pytype`. There are also `_direct` versions of the templates of `class T` which should be used with undecorated type parameter, expected to be in the conversion registry when the module loads. +[endsect] +[section Class `wrap_pytype`] +This template generates a static `get_pytype` member returning the template parameter. +`` +namespace boost { namespace python { namespace converter{ + + template < PyTypeObject const *pytype > + class wrap_pytype + { + public: + static PyTypeObject const *get_pytype(){return pytype; } + }; + +}}} +`` +[endsect] +[section Class `registered_pytype`] +This template should be used with template parameters which are (possibly decorated) types exported to python using [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel `class_`]. The generated a static `get_pytype` member returns the corresponding python type. +`` +namespace boost { namespace python { namespace converter{ + + template < class T > + class registered_pytype + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +`` +[endsect] +[section Class `expected_from_python_type`] +This template generates a static `get_pytype` member which inspects the registered `from_python` converters for the type `T` and returns a matching python type. +`` +namespace boost { namespace python { namespace converter{ + + template < class T > + class expected_from_python_type + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +`` +[endsect] +[section Class `to_python_target_type`] +This template generates a static `get_pytype` member returning the python type to which `T` can be converted. +`` +namespace boost { namespace python { namespace converter{ + + template < class T > + class to_python_target_type + { + public: + static PyTypeObject const *get_pytype(); + }; + +}}} +`` +[endsect] +[section Example] +This example presumes that someone has implemented the standard noddy example module from the Python documentation, and placed the corresponding declarations in "noddy.h". Because `noddy_NoddyObject` is the ultimate trivial extension type, the example is a bit contrived: it wraps a function for which all information is contained in the type of its return value. + +C++ module definition: +`` +#include +#include +#include "noddy.h" + +struct tag {}; +tag make_tag() { return tag(); } + +using namespace boost::python; + +struct tag_to_noddy +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported +: wrap_pytype<&noddy_NoddyType> //inherits get_pytype from wrap_pytype +#endif +{ + static PyObject* convert(tag const& x) + { + return PyObject_New(noddy_NoddyObject, &noddy_NoddyType); + } +}; + +BOOST_PYTHON_MODULE(to_python_converter) +{ + def("make_tag", make_tag); + to_python_converter(); //"true" because tag_to_noddy has member get_pytype +} +`` +The following example registers to and from python converters using the templates expected_from_python_type and to_pyhton_target_type. +`` +#include +#include +#include +#include +#include + +using namespace boost::python; + +struct A +{ +}; + +struct B +{ + A a; + B(const A& a_):a(a_){} +}; + +// Converter from A to python int +struct BToPython +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported + : converter::to_python_target_type //inherits get_pytype +#endif +{ + static PyObject* convert(const B& b) + { + return incref(object(b.a).ptr()); + } +}; + +// Conversion from python int to A +struct BFromPython +{ + BFromPython() + { + boost::python::converter::registry::push_back + ( &convertible + , &construct + , type_id< B >() +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + , &converter::expected_from_python_type::get_pytype//convertible to A can be converted to B +#endif + ); + } + + static void* convertible(PyObject* obj_ptr) + { + extract ex(obj_ptr); + if (!ex.check()) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (converter::rvalue_from_python_storage< B >*)data)-> storage.bytes; + + extract ex(obj_ptr); + new (storage) B(ex()); + data->convertible = storage; + } +}; + + +B func(const B& b) { return b ; } + +BOOST_PYTHON_MODULE(pytype_function_ext) +{ + to_python_converter< B , BToPython +#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported + ,true +#endif + >(); //has get_pytype + BFromPython(); + + class_("A") ; + + def("func", &func); + +} + + + +>>> from pytype_function_ext import * +>>> print func.__doc__ +func( (A)arg1) -> A : + C++ signature: + struct B func(struct B) +`` +[endsect] +[endsect] diff --git a/doc/reference/raw_function.qbk b/doc/reference/raw_function.qbk new file mode 100644 index 0000000000..705428d138 --- /dev/null +++ b/doc/reference/raw_function.qbk @@ -0,0 +1,44 @@ +[section boost/python/raw_function.hpp] +[section Introduction] +`raw_function(...)` is used to convert a function taking a [link object_wrappers.boost_python_tuple_hpp.class_tuple `tuple`] and a [link object_wrappers.boost_python_dict_hpp.class_dict `dict`] into a Python callable object which accepts a variable number of arguments and arbitrary keyword arguments. +[endsect] +[section Function `raw_function`] +`` +template +object raw_function(F f, std::size_t min_args = 0); +`` +[variablelist +[[Requires][f(tuple(), dict()) is well-formed.]] +[[Returns][a callable object which requires at least min_args arguments. When called, the actual non-keyword arguments will be passed in a tuple as the first argument to f, and the keyword arguments will be passed in a dict as the second argument to f. ]] +] +[endsect] +[section Example] +C++: +`` +#include +#include +#include +#include +#include + +using namespace boost::python; + +tuple raw(tuple args, dict kw) +{ + return make_tuple(args, kw); +} + +BOOST_PYTHON_MODULE(raw_test) +{ + def("raw", raw_function(raw)); +} +`` +Python: +`` +>>> from raw_test import * + +>>> raw(3, 4, foo = 'bar', baz = 42) +((3, 4), {'foo': 'bar', 'baz': 42}) +`` +[endsect] +[endsect] diff --git a/doc/reference/reference_existing_object.qbk b/doc/reference/reference_existing_object.qbk new file mode 100644 index 0000000000..e95c8fac5f --- /dev/null +++ b/doc/reference/reference_existing_object.qbk @@ -0,0 +1,75 @@ +[section boost/python/reference_existing_object.hpp] +[section Class `reference_existing_object`] +`reference_existing_object` is a model of [link concepts.resultconverter.resultconvertergenerator_concept ResultConverterGenerator] which can be used to wrap C++ functions which return a reference or pointer to a C++ object. When the wrapped function is called, the value referenced by its return value is not copied. A new Python object is created which contains a pointer to the referent, and no attempt is made to ensure that the lifetime of the referent is at least as long as that of the corresponding Python object. Thus, it can be *highly dangerous* to use `reference_existing_object` without additional lifetime management from such models of [link concepts.callpolicies CallPolicies] as [link function_invocation_and_creation.models_of_callpolicies.boost_python_with_custodian_and_.class_with_custodian_and_ward `with_custodian_and_ward`]. This class is used in the implementation of [link function_invocation_and_creation.models_of_callpolicies.boost_python_return_internal_ref.class_template_return_internal_r `return_internal_reference`]. +`` +namespace boost { namespace python +{ + struct reference_existing_object + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `reference_existing_object` metafunctions] +``template struct apply`` +[variablelist +[[Requires][`T` is `U&` or `U*` for some `U`.]] +[[Returns][`typedef to_python_indirect type;`, where V is a class whose static execute function constructs an instance holder containing an unowned `U*` pointing to the referent of the wrapped function's return value.]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include +#include +#include + +// classes to wrap +struct Singleton +{ + Singleton() : x(0) {} + + int exchange(int n) // set x and return the old value + { + std::swap(n, x); + return n; + } + + int x; +}; + +Singleton& get_it() +{ + static Singleton just_one; + return just_one; +} + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(singleton) +{ + def("get_it", get_it, + return_value_policy()); + + class_("Singleton") + .def("exchange", &Singleton::exchange) + ; +} +`` +Python code: +`` +>>> import singleton +>>> s1 = singleton.get_it() +>>> s2 = singleton.get_it() +>>> id(s1) == id(s2) # s1 and s2 are not the same object +0 +>>> s1.exchange(42) # but they reference the same C++ Singleton +0 +>>> s2.exchange(99) +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/register_ptr_to_python.qbk b/doc/reference/register_ptr_to_python.qbk new file mode 100644 index 0000000000..0c9f72e836 --- /dev/null +++ b/doc/reference/register_ptr_to_python.qbk @@ -0,0 +1,86 @@ +[section boost/python/register_ptr_to_python.hpp] +[section Introduction] + supplies `register_ptr_to_python`, a function template which registers a conversion for smart pointers to Python. The resulting Python object holds a copy of the converted smart pointer, but behaves as though it were a wrapped copy of the pointee. If the pointee type has virtual functions and the class representing its dynamic (most-derived) type has been wrapped, the Python object will be an instance of the wrapper for the most-derived type. More than one smart pointer type for a pointee's class can be registered. + +Note that in order to convert a Python `X` object to a `smart_ptr&` (non-const reference), the embedded C++ object must be held by `smart_ptr`, and that when wrapped objects are created by calling the constructor from Python, how they are held is determined by the HeldType parameter to `class_<...>` instances. +[endsect] +[section Function `register_ptr_to_python`] +`` +template +void register_ptr_to_python() +`` +[variablelist +[[Requires][`P` is [link concepts.dereferenceable Dereferenceable].]] +[[Effects][Allows conversions to-python of P instances. ]] +] +[endsect] +[section Example] +Here is an example of a module that contains a class A with virtual functions and some functions that work with boost::shared_ptr. + +In C++: +`` +struct A +{ + virtual int f() { return 0; } +}; + +shared_ptr New() { return shared_ptr( new A() ); } + +int Ok( const shared_ptr& a ) { return a->f(); } + +int Fail( shared_ptr& a ) { return a->f(); } + +struct A_Wrapper: A +{ + A_Wrapper(PyObject* self_): self(self_) {} + int f() { return call_method(self, "f"); } + int default_f() { return A::f(); } + PyObject* self; +}; + +BOOST_PYTHON_MODULE(register_ptr) +{ + class_("A") + .def("f", &A::f, &A_Wrapper::default_f) + ; + + def("New", &New); + def("Ok", &Call); + def("Fail", &Fail); + + register_ptr_to_python< shared_ptr >(); +} +`` +In Python: +`` +>>> from register_ptr import * +>>> a = A() +>>> Ok(a) # ok, passed as shared_ptr +0 +>>> Fail(a) # passed as shared_ptr&, and was created in Python! +Traceback (most recent call last): + File "", line 1, in ? +TypeError: bad argument type for built-in operation +>>> +>>> na = New() # now "na" is actually a shared_ptr +>>> Ok(a) +0 +>>> Fail(a) +0 +>>> +`` +If shared_ptr is registered as follows: +`` +class_ >("A") + .def("f", &A::f, &A_Wrapper::default_f) +; +`` +There will be an error when trying to convert shared_ptr to shared_ptr: +`` +>>> a = New() +Traceback (most recent call last): +File "", line 1, in ? +TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr +>>> +`` +[endsect] diff --git a/doc/reference/return_arg.qbk b/doc/reference/return_arg.qbk new file mode 100644 index 0000000000..08e6f299cb --- /dev/null +++ b/doc/reference/return_arg.qbk @@ -0,0 +1,91 @@ +[section boost/python/return_arg.hpp] +[section Introduction] +`return_arg` and `return_self` instantiations are models of [link concepts.callpolicies `CallPolicies`] which return the specified argument parameter (usually `*this`) of a wrapped (member) function. +[endsect] +[section Class `return_arg`] +[table +[[Parameter][Requirements][Description][Default]] + [[arg_pos][A positive compile-time constant of type `std::size_t`.][the position of the argument to be returned.][1]] +[[Base][A model of [link concepts.callpolicies `CallPolicies`]][Used for policy composition. Any `result_converter` it supplies will be overridden by `return_arg`, but its `precall` and `postcall` policies are composed as described here [link concepts.callpolicies `CallPolicies`].][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct return_arg : Base + { + static PyObject* postcall(PyObject*, PyObject* result); + struct result_converter{ template struct apply; }; + template struct extract_return_type : mpl::at_c{}; + + }; +}} +`` +[endsect] +[section Class `return_arg` static functions] +``PyObject* postcall(PyObject* args, PyObject* result);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0` and `PyTuple_Size(args) != 0`]] +[[Returns][PyTuple_GetItem(args,arg_pos-1)]] +] +[endsect] +[section Class template `return_self`] +`` +namespace boost { namespace python +{ + template + struct return_self + : return_arg<1,Base> + {}; +}} +`` +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include + +struct Widget +{ + Widget() :sensitive_(true){} + bool get_sensitive() const { return sensitive_; } + void set_sensitive(bool s) { this->sensitive_ = s; } + private: + bool sensitive_; +}; + +struct Label : Widget +{ + Label() {} + + std::string get_label() const { return label_; } + void set_label(const std::string &l){ label_ = l; } + + private: + std::string label_; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(return_self_ext) +{ + class_("Widget") + .def("sensitive", &Widget::get_sensitive) + .def("sensitive", &Widget::set_sensitive, return_self<>()) + ; + + class_ >("Label") + .def("label", &Label::get_label) + .def("label", &Label::set_label, return_self<>()) + ; +} +`` +Python code: +`` +>>> from return_self_ext import * +>>> l1 = Label().label("foo").sensitive(false) +>>> l2 = Label().sensitive(false).label("foo") +`` +[endsect] +[endsect] diff --git a/doc/reference/return_by_value.qbk b/doc/reference/return_by_value.qbk new file mode 100644 index 0000000000..2b8b7887ca --- /dev/null +++ b/doc/reference/return_by_value.qbk @@ -0,0 +1,62 @@ +[section boost/python/return_by_value.hpp] +[section Class `return_by_value`] +`return_by_value` is a model of [link concepts.resultconverter.resultconvertergenerator_concept ResultConverterGenerator] which can be used to wrap C++ functions returning any reference or value type such that the return value is copied into a new Python object. +`` +namespace boost { namespace python +{ + struct return_by_value + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `return_by_value` metafunctions] +``template struct apply`` +[variablelist +[[Returns][`typedef to_python_value type;`]] +] +[endsect] +[section Example] +In C++: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { }; + +Bar global_bar; + +// functions to wrap: +Bar b1(); +Bar& b2(); +Bar const& b3(); + +// Wrapper code +using namespace boost::python; +template +void def_void_function(char const* name, R (*f)()) +{ + def(name, f, return_value_policy()); +} + +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + def_void_function("b1", b1); + def_void_function("b2", b2); + def_void_function("b3", b3); +} +`` +Python code: +`` +>>> from my_module import * +>>> b = b1() # each of these calls +>>> b = b2() # creates a brand +>>> b = b3() # new Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/return_internal_reference.qbk b/doc/reference/return_internal_reference.qbk new file mode 100644 index 0000000000..240ed0ab01 --- /dev/null +++ b/doc/reference/return_internal_reference.qbk @@ -0,0 +1,88 @@ +[section boost/python/return_internal_reference.hpp] +[section Introduction] +`return_internal_reference` instantiations are models of [link concepts.callpolicies `CallPolicies`] which allow pointers and references to objects held internally by a free or member function argument or from the target of a member function to be returned safely without making a copy of the referent. The default for its first template argument handles the common case where the containing object is the target (`*this`) of a wrapped member function. +[endsect] +[section Class template `return_internal_reference`] +[table + [[Parameter][Requirements][Description][Default]] + [[owner_arg][A positive compile-time constant of type `std::size_t`.][The index of the parameter which contains the object to which the reference or pointer is being returned. If used to wrap a member function, parameter 1 is the target object (`*this`). Note that if the target Python object type doesn't support weak references, a Python TypeError exception will be raised when the function being wrapped is called.][]] + [[Base][A model of [link concepts.callpolicies `CallPolicies`]][Used for policy composition. Any `result_converter` it supplies will be overridden by `return_internal_reference`, but its `precall` and `postcall` policies are composed as described here [link concepts.callpolicies `CallPolicies`].][default_call_policies]] +] +`` +namespace boost { namespace python +{ + template + struct return_internal_reference : Base + { + static PyObject* postcall(PyObject*, PyObject* result); + typedef reference_existing_object result_converter; + }; +}} +`` +[endsect] +[section Class `return_internal_reference` static functions] +``PyObject* postcall(PyObject* args, PyObject* result);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0`]] +[[Returns][[link function_invocation_and_creation.models_of_callpolicies.boost_python_with_custodian_and_.class_with_custodian_and_ward_st `with_custodian_and_ward_postcall::postcall(args, result)`]]] +] +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include + +class Bar +{ + public: + Bar(int x) : x(x) {} + int get_x() const { return x; } + void set_x(int x) { this->x = x; } + private: + int x; +}; + +class Foo +{ + public: + Foo(int x) : b(x) {} + + // Returns an internal reference + Bar const& get_bar() const { return b; } + + private: + Bar b; +}; + +using namespace boost::python; +BOOST_PYTHON_MODULE(internal_refs) +{ + class_("Bar", init()) + .def("get_x", &Bar::get_x) + .def("set_x", &Bar::set_x) + ; + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_internal_reference<>()) + ; +} +`` +Python code: +`` +>>> from internal_refs import * +>>> f = Foo(3) +>>> b1 = f.get_bar() +>>> b2 = f.get_bar() +>>> b1.get_x() +3 +>>> b2.get_x() +3 +>>> b1.set_x(42) +>>> b2.get_x() +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/return_opaque_pointer.qbk b/doc/reference/return_opaque_pointer.qbk new file mode 100644 index 0000000000..e87d82b9b7 --- /dev/null +++ b/doc/reference/return_opaque_pointer.qbk @@ -0,0 +1,95 @@ +[section boost/python/return_opaque_pointer.hpp] +[section Class `return_opaqe_pointer`] +return_opaque_pointer is a model of [link concepts.resultconverter.resultconvertergenerator_concept ResultConverterGenerator] which can be used to wrap C++ functions returning pointers to undefined types such that the return value is copied into a new Python object. + +In addition to specifying the `return_opaque_pointer` policy the [link to_from_python_type_conversion.boost_python_opaque_pointer_conv.macro_boost_python_opaque_specia `BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID`] macro must be used to define specializations for the [link utility_and_infrastructure.boost_python_type_id_hpp.functions `type_id`] function on the type pointed to by returned pointer. +`` +namespace boost { namespace python +{ + struct return_opaque_pointer + { + template struct apply; + }; +}} +`` +[endsect] +[section Class `return_opaque_pointer` metafunctions] +``template struct apply`` +[variablelist +[[Returns][`detail::opaque_conversion_holder type;`]] +] +[endsect] +[section Example] +In C++: +`` +# include +# include +# include +# include + +typedef struct opaque_ *opaque; + +opaque the_op = ((opaque) 0x47110815); + +opaque get () { return the_op; } +void use (opaque op) { + if (op != the_op) + throw std::runtime_error (std::string ("failed")); +} + +void failuse (opaque op) { + if (op == the_op) + throw std::runtime_error (std::string ("success")); +} + +BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_) + +namespace bpl = boost::python; + +BOOST_PYTHON_MODULE(opaque_ext) +{ + bpl::def ( + "get", &::get, bpl::return_value_policy()); + bpl::def ("use", &::use); + bpl::def ("failuse", &::failuse); +} +`` +Python code: +`` +""" +>>> from opaque_ext import * +>>> # +>>> # Check for correct conversion +>>> use(get()) +>>> failuse(get()) +Traceback (most recent call last): + ... +RuntimeError: success +>>> # +>>> # Check that there is no conversion from integers ... +>>> use(0) +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +>>> # +>>> # ... and from strings to opaque objects +>>> use("") +Traceback (most recent call last): + ... +TypeError: bad argument type for built-in operation +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) +`` +[endsect] +[endsect] diff --git a/doc/reference/return_value_policy.qbk b/doc/reference/return_value_policy.qbk new file mode 100644 index 0000000000..6c2e394cc3 --- /dev/null +++ b/doc/reference/return_value_policy.qbk @@ -0,0 +1,59 @@ +[section boost/python/return_value_policy.hpp] +[section Introduction] +return_value_policy instantiations are simply models of [link concepts.callpolicies `CallPolicies`] which are composed of a [link concepts.resultconverter.resultconvertergenerator_concept `ResultConverterGenerator`] and optional `Base` [link concepts.callpolicies `CallPolicies`]. +[endsect] +[section Class template `return_value_policy`] +[table +[[Parameter][Requirements][Default]] + [[ResultConverterGenerator][A model of [link concepts.resultconverter.resultconvertergenerator_concept `ResultConverterGenerator`]][]] +[[Base][A model of [link concepts.callpolicies `CallPolicies`]][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct return_value_policy : Base + { + typedef ResultConverterGenerator result_converter; + }; +}} +`` +[endsect] +[section Example] +C++ module definition: +`` +#include +#include +#include +#include + +// classes to wrap +struct Bar { int x; } + +struct Foo { + Foo(int x) : { b.x = x; } + Bar const& get_bar() const { return b; } + private: + Bar b; +}; + +// Wrapper code +using namespace boost::python; +BOOST_PYTHON_MODULE(my_module) +{ + class_("Bar"); + + class_("Foo", init()) + .def("get_bar", &Foo::get_bar + , return_value_policy()) + ; +} +`` +Python code: +`` +>>> from my_module import * +>>> f = Foo(3) # create a Foo object +>>> b = f.get_bar() # make a copy of the internal Bar object +`` +[endsect] +[endsect] diff --git a/doc/reference/scope.qbk b/doc/reference/scope.qbk new file mode 100644 index 0000000000..d17ae69b72 --- /dev/null +++ b/doc/reference/scope.qbk @@ -0,0 +1,83 @@ +[section boost/python/scope.hpp] +[section Introduction] +Defines facilities for querying and controlling the Python scope (namespace) which will contain new wrapped classes and functions. +[endsect] +[section Class `scope`] +The scope class has an associated global Python object which controls the Python namespace in which new extension classes and wrapped functions will be defined as attributes. Default-constructing a new scope object binds it to the associated global Python object. Constructing a scope object with an argument changes the associated global Python object to the one held by the argument, until the lifetime of the scope object ends, at which time the associated global Python object reverts to what it was before the scope object was constructed. +`` +namespace boost { namespace python +{ + class scope : public object + { + public: + scope(scope const&); + scope(object const&); + scope(); + ~scope() + private: + void operator=(scope const&); + }; +}} +`` +[endsect] +[section Class scope constructors and destructor] +`` +explicit scope(scope const& x); +explicit scope(object const& x); +`` +Stores a reference to the current associated scope object, and sets the associated scope object to the one referred to by x.ptr(). The object base class is initialized with x. + +``scope();`` + +Stores a reference to the current associated scope object. The object base class is initialized with the current associated scope object. Outside any module initialization function, the current associated Python object is None. + +``~scope()`` + +Sets the current associated Python object to the stored object. +[endsect] +[section Example] +The following example shows how scope setting can be used to define nested classes. + +C++ Module definition: +`` +#include +#include +#include +using namespace boost::python; + +struct X +{ + void f() {} + + struct Y { int g() { return 42; } }; +}; + +BOOST_PYTHON_MODULE(nested) +{ + // add some constants to the current (module) scope + scope().attr("yes") = 1; + scope().attr("no") = 0; + + // Change the current scope + scope outer + = class_("X") + .def("f", &X::f) + ; + + // Define a class Y in the current scope, X + class_("Y") + .def("g", &X::Y::g) + ; +} +`` +Interactive Python: +`` +>>> import nested +>>> nested.yes +1 +>>> y = nested.X.Y() +>>> y.g() +42 +`` +[endsect] +[endsect] diff --git a/doc/reference/slice.qbk b/doc/reference/slice.qbk new file mode 100644 index 0000000000..19dbe4d97e --- /dev/null +++ b/doc/reference/slice.qbk @@ -0,0 +1,128 @@ +[section boost/python/slice.hpp] +[section Introduction] +Exposes a [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] for the Python [@http://www.python.org/doc/2.3.3/api/slice-objects.html `slice`] type. +[endsect] +[section Class `slice`] +Exposes the extended slicing protocol by wrapping the built-in slice type. The semantics of the constructors and member functions defined below can be fully understood by reading the [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] concept definition. Since `slice` is publicly derived from [link object_wrappers.boost_python_object_hpp.class_object `object`], the public `object` interface applies to `slice` instances as well. +`` +namespace boost { namespace python +{ + class slice : public object + { + public: + slice(); // create an empty slice, equivalent to [::] + + template + slice(Int1 start, Int2 stop); + + template + slice(Int1 start, Int2 stop, Int3 step); + + // Access the parameters this slice was created with. + object start(); + object stop(); + object step(); + + // The return type of slice::get_indices() + template + struct range + { + RandomAccessIterator start; + RandomAccessIterator stop; + int step; + }; + + template + range + get_indices( + RandomAccessIterator const& begin, + RandomAccessIterator const& end); + }; +}} +`` +[endsect] +[section Class `slice` constructors] +``slice();`` +[variablelist +[[Effects][constructs a slice with default stop, start, and step values. Equivalent to the slice object created as part of the Python expression `base[::]`.]] +[[Throws][nothing]] +] +`` +template +slice(Int1 start, Int2 stop); +`` +[variablelist +[[Requires][`start`, `stop`, and `step` are of type `slice_nil` or convertible to type `object`.]] +[[Effects][constructs a new slice with default step value and the provided start and stop values. Equivalent to the slice object created by the built-in Python function `slice(start,stop)`, or as part of the Python expression `base[start:stop]`.]] +[[Throws][`error_already_set` and sets a Python TypeError exception if no conversion is possible from the arguments to type object.]] +] +`` +template +slice(Int1 start, Int2 stop, Int3 step); +`` +[variablelist +[[Requires][`start`, `stop`, and `step` are `slice_nil` or convertible to type `object`.]] +[[Effects][constructs a new slice with start stop and step values. Equivalent to the slice object created by the built-in Python function `slice(start,stop,step)`, or as part of the Python expression `base[start:stop:step]`.]] +[[Throws][`error_already_set` and sets a Python TypeError exception if no conversion is possible from the arguments to type object.]] +] +[endsect] +[section Class `slice` observer functions] +`` +object slice::start() const; +object slice::stop() const; +object slice::step() const; +`` +[variablelist +[[Effects][None]] +[[Throws][nothing]] +[[Returns][the parameter that the slice was created with. If the parameter was omitted or `slice_nil` was used when the slice was created, than that parameter will be a reference to `PyNone` and compare equal to a default-constructed object. In principal, any object may be used when creating a slice object, but in practice they are usually integers.]] +] +`` +template +slice::range +slice::get_indices( + RandomAccessIterator const& begin, + RandomAccessIterator const& end) const; +`` +[variablelist +[[Arguments][A pair of STL-conforming Random Access Iterators that form a half-open range.]] +[[Effects][Create a RandomAccessIterator pair that defines a fully-closed range within the `[begin,end)` range of its arguments. This function translates this slice's indices while accounting for the effects of any PyNone or negative indices, and non-singular step sizes.]] +[[Returns][a `slice::range` that has been initialized with a non-zero value of step and a pair of RandomAccessIterators that point within the range of this functions arguments and define a closed interval.]] +[[Throws][Raises a Python TypeError exception if any of this slice's arguments are neither references to PyNone nor convertible to int. Throws `std::invalid_argument` if the resulting range would be empty. You should always wrap calls to `slice::get_indices()` within `try { ...; } catch (std::invalid_argument) {}` to handle this case and take appropriate action.]] +[[Rationale][closed-interval: If an open interval were used, then for step size other than 1, the required state for the end iterator would point beyond the one-past-the-end position or before the beginning of the specified range. +exceptions on empty slice: It is impossible to define a closed interval over an empty range, so some other form of error checking would have to be used to prevent undefined behavior. In the case where the exception is not caught, it will simply be translated to Python by the default exception handling mechanisms. ]] +] +[endsect] +[section Example] +`` +using namespace boost::python; + +// Perform an extended slice of a Python list. +// Warning: extended slicing was not supported for built-in types prior +// to Python 2.3 +list odd_elements(list l) +{ + return l[slice(_,_,2)]; +} + +// Perform a summation over a slice of a std::vector. +double partial_sum(std::vector const& Foo, const slice index) +{ + slice::range::const_iterator> bounds; + try { + bounds = index.get_indices<>(Foo.begin(), Foo.end()); + } + catch (std::invalid_argument) { + return 0.0; + } + double sum = 0.0; + while (bounds.start != bounds.stop) { + sum += *bounds.start; + std::advance( bounds.start, bounds.step); + } + sum += *bounds.start; + return sum; +} +`` +[endsect] +[endsect] diff --git a/doc/reference/ssize_t.qbk b/doc/reference/ssize_t.qbk new file mode 100644 index 0000000000..1cddfd1bd6 --- /dev/null +++ b/doc/reference/ssize_t.qbk @@ -0,0 +1,27 @@ +[section boost/python/ssize_t.hpp] +[section Introduction] +Python 2.5 introduces a new `Py_ssize_t` typedef and two related macros ([@http://www.python.org/dev/peps/pep-0353/ PEP 353]). The header imports these definitions into the `boost::python` namespace as `ssize_t`, `ssize_t_max`, and `ssize_t_min`. Appropriate definitions are provided for backward compatibility with previous Python versions. +[endsect] +[section Typedefs] +Imports `Py_ssize_t` into the `boost::python` namespace if available, or provides an appropriate typedef for backward compatibility: +`` +#if PY_VERSION_HEX >= 0x02050000 +typedef Py_ssize_t ssize_t; +#else +typedef int ssize_t; +#endif +`` +[endsect] +[section Constants] +Imports `PY_SSIZE_T_MAX` and `PY_SSIZE_T_MIN` as constants into the `boost::python` namespace if available, or provides appropriate constants for backward compatibility: +`` +#if PY_VERSION_HEX >= 0x02050000 +ssize_t const ssize_t_max = PY_SSIZE_T_MAX; +ssize_t const ssize_t_min = PY_SSIZE_T_MIN; +#else +ssize_t const ssize_t_max = INT_MAX; +ssize_t const ssize_t_min = INT_MIN; +#endif +`` +[endsect] +[endsect] diff --git a/doc/reference/stl_iterator.qbk b/doc/reference/stl_iterator.qbk new file mode 100644 index 0000000000..d0b26563e9 --- /dev/null +++ b/doc/reference/stl_iterator.qbk @@ -0,0 +1,108 @@ +[section boost/python/stl_iterator.hpp] +[section Introduction] + provides types for creating C++ Iterators from [@http://www.python.org/doc/current/lib/typeiter.html Python iterables]. +[endsect] +[section Class template `stl_input_iterator`] +Instances of `stl_input_iterator` hold a Python iterator and adapt it for use with STL algorithms. `stl_input_iterator` satisfies the requirements for an Input Iterator. +[table +[[Template Parameter][Requirements][Semantics][Default]] +[[ValueType][ValueType must be CopyConstructible.][Dereferencing an instance of `stl_input_iterator` will return an rvalue of type ValueType.][None]] +] +`` +namespace boost { namespace python +{ + template + struct stl_input_iterator + { + typedef std::ptrdiff_t difference_type; + typedef ValueType value_type; + typedef ValueType* pointer; + typedef ValueType reference; + typedef std::input_iterator_tag iterator_category; + + stl_input_iterator(); + stl_input_iterator(object const& ob); + + stl_input_iterator& operator++(); + stl_input_iterator operator++(int); + + ValueType operator*() const; + + friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs); + friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs); + private: + object it; // For exposition only + object ob; // For exposition only + }; +}} +`` +[endsect] +[section Class template `stl_input_iterator` constructors] +`` +stl_input_iterator() +`` +[variablelist +[[Effects][Creates a past-the-end input iterator, useful for signifying the end of a sequence. ]] +[[Postconditions][`this` is past-the-end]] +[[Throws][Nothing.]] +] +``stl_input_iterator(object const& ob)`` +[variablelist +[[Effects][Calls ob.attr("__iter__")() and stores the resulting Python iterator object in this->it. Then, calls this->it.attr("next")() and stores the result in this->ob. If the sequence is exhausted, sets this->ob to object(). ]] +[[Postconditions][this is a dereferenceable or past-the-end.]] +] +[endsect] +[section Class template `stl_input_iterator` modifiers] +`` +stl_input_iterator &operator++() +`` +[variablelist +[[Effects][Calls this->it.attr("next")() and stores the result in this->ob. If the sequence is exhausted, sets this->ob to object(). ]] +[[Postconditions][this is a dereferenceable or past-the-end.]] +[[Returns][`*this`]] +] +``stl_input_iterator &operator++(int)`` +[variablelist +[[Effects][`stl_input_iterator tmp = *this; ++*this; return tmp;`]] +[[Postconditions][this is a dereferenceable or past-the-end.]] +] +[endsect] +[section Class template `stl_input_iterator` observers] +`` +ValueType operator*() const +`` +[variablelist +[[Effects][Returns the current element in the sequence. ]] +[[Returns][`extract(this->ob);`]] +] +`` +friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs) +`` +[variablelist +[[Effects][Returns true if both iterators are dereferenceable or if both iterators are past-the-end, false otherwise. ]] +[[Returns][`(lhs.ob == object()) == (rhs.ob == object())`]] +] +`` +friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs) +`` +[variablelist +[[Effects][Returns false if both iterators are dereferenceable or if both iterators are past-the-end, true otherwise. ]] +[[Returns][`!(lhs == rhs)`]] +] +[endsect] +[section Example] +`` +#include +#include + +#include + +using namespace boost::python; +std::list sequence_to_int_list(object const& ob) +{ + stl_input_iterator begin(ob), end; + return std::list(begin, end); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/str.qbk b/doc/reference/str.qbk new file mode 100644 index 0000000000..12fe589629 --- /dev/null +++ b/doc/reference/str.qbk @@ -0,0 +1,153 @@ +[section boost/python/str.hpp] +[section Introduction] +Exposes a [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] for the Python [@http://www.python.org/dev/doc/devel/lib/string-methods.html `str`] type. +[endsect] +[section Class `str`] +Exposes the [@http://www.python.org/dev/doc/devel/lib/string-methods.html string methods] of Python's built-in `str` type. The semantics of the constructors and member functions defined below, except for the two-argument constructors which construct str objects from a range of characters, can be fully understood by reading the [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] concept definition. Since str is publicly derived from [link object_wrappers.boost_python_object_hpp.class_object `object`], the public `object` interface applies to `str` instances as well. +`` +namespace boost { namespace python +{ + class str : public object + { + public: + str(); // new str + + str(char const* s); // new str + + str(char const* start, char const* finish); // new str + str(char const* start, std::size_t length); // new str + + template + explicit str(T const& other); + + str capitalize() const; + + template + str center(T const& width) const; + + template + long count(T const& sub) const; + template + long count(T1 const& sub,T2 const& start) const; + template + long count(T1 const& sub,T2 const& start, T3 const& end) const; + + object decode() const; + template + object decode(T const& encoding) const; + template + object decode(T1 const& encoding, T2 const& errors) const; + + object encode() const; + template + object encode(T const& encoding) const; + template + object encode(T1 const& encoding, T2 const& errors) const; + + template + bool endswith(T const& suffix) const; + template + bool endswith(T1 const& suffix, T2 const& start) const; + template + bool endswith(T1 const& suffix, T2 const& start, T3 const& end) const; + + str expandtabs() const; + template + str expandtabs(T const& tabsize) const; + + template + long find(T const& sub) const; + template + long find(T1 const& sub, T2 const& start) const; + template + long find(T1 const& sub, T2 const& start, T3 const& end) const; + + template + long index(T const& sub) const; + template + long index(T1 const& sub, T2 const& start) const; + template + long index(T1 const& sub, T2 const& start, T3 const& end) const; + + bool isalnum() const; + bool isalpha() const; + bool isdigit() const; + bool islower() const; + bool isspace() const; + bool istitle() const; + bool isupper() const; + + template + str join(T const& sequence) const; + + template + str ljust(T const& width) const; + + str lower() const; + str lstrip() const; + + template + str replace(T1 const& old, T2 const& new_) const; + template + str replace(T1 const& old, T2 const& new_, T3 const& maxsplit) const; + + template + long rfind(T const& sub) const; + template + long rfind(T1 const& sub, T2 const& start) const; + template + long rfind(T1 const& sub, T2 const& start, T3 const& end) const; + + template + long rindex(T const& sub) const; + template + long rindex(T1 const& sub, T2 const& start) const; + template + long rindex(T1 const& sub, T2 const& start, T3 const& end) const; + + template + str rjust(T const& width) const; + + str rstrip() const; + + list split() const; + template + list split(T const& sep) const; + template + list split(T1 const& sep, T2 const& maxsplit) const; + + list splitlines() const; + template + list splitlines(T const& keepends) const; + + template + bool startswith(T const& prefix) const; + template + bool startswidth(T1 const& prefix, T2 const& start) const; + template + bool startswidth(T1 const& prefix, T2 const& start, T3 const& end) const; + + str strip() const; + str swapcase() const; + str title() const; + + template + str translate(T const& table) const; + template + str translate(T1 const& table, T2 const& deletechars) const; + + str upper() const; + }; +}} +`` +[endsect] +[section Example] +`` +using namespace boost::python; +str remove_angle_brackets(str x) +{ + return x.strip('<').strip('>'); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/to_python_converter.qbk b/doc/reference/to_python_converter.qbk new file mode 100644 index 0000000000..45d4121c2c --- /dev/null +++ b/doc/reference/to_python_converter.qbk @@ -0,0 +1,91 @@ +[section boost/python/to_python_converter.hpp] +[section Introduction] +`to_python_converter` registers a conversion from objects of a given C++ type into a Python object. +[endsect] +[section Class template `to_python_converter`] +`to_python_converter` adds a wrapper around a static member function of its second template parameter, handling low-level details such as insertion into the converter registry. + +In the table below, x denotes an object of type T +[table +[[Parameter][Requirements][Description]] +[[T][][The C++ type of the source object in the conversion]] +[[Conversion][`PyObject* p = Conversion::convert(x)`, +`if p == 0`, `PyErr_Occurred() != 0`.][A class type whose static member function convert does the real work of the conversion.]] +[[bool has_get_pytype=false][`PyTypeObject const * p = Conversion::get_pytype()`] +[Optional member - if Conversion has `get_pytype` member supply `true` for this parameters. If present `get_pytype` is used to document the return type of functions using this conversion. The `get_pytype` may be implemented using the classes and functions from pytype_function.hpp NOTE : For backward compatibility this parameter may be passed after checking if BOOST_PYTHON_SUPPORTS_PY_SIGNATURES is defined (see [link function_invocation_and_creation.function_documentation.boost_python_pytype_function_hpp.example here]).] +]] + +`` +namespace boost { namespace python +{ + template + struct to_python_converter + { + to_python_converter(); + }; +}} +`` +[section Class template `to_python_converter` constructor] +``to_python_converter();`` +[variablelist +[[Effects][Registers a `to_python` converter which uses `Conversion::convert()` to do its work.]] +] +[endsect] +[endsect] +[section Example] +This example presumes that someone has implemented the standard noddy example module from the Python documentation, and placed the corresponding declarations in "noddy.h". Because noddy_NoddyObject is the ultimate trivial extension type, the example is a bit contrived: it wraps a function for which all information is contained in the type of its return value. + +In C++: +`` +#include +#include +#include "noddy.h" + +struct tag {}; +tag make_tag() { return tag(); } + +using namespace boost::python; + +struct tag_to_noddy +{ + static PyObject* convert(tag const& x) + { + return PyObject_New(noddy_NoddyObject, &noddy_NoddyType); + } + static PyTypeObject const* get_pytype() + { + return &noddy_NoddyType; + } +}; + +BOOST_PYTHON_MODULE(to_python_converter) +{ + def("make_tag", make_tag); + to_python_converter(); //"true" because tag_to_noddy has member get_pytype +} +`` +In Python: +`` +>>> import to_python_converter +>>> def always_none(): +... return None +... +>>> def choose_function(x): +... if (x % 2 != 0): +... return to_python_converter.make_tag +... else: +... return always_none +... +>>> a = [ choose_function(x) for x in range(5) ] +>>> b = [ f() for f in a ] +>>> type(b[0]) + +>>> type(b[1]) + +>>> type(b[2]) + +>>> type(b[3]) + +`` +[endsect] +[endsect] diff --git a/doc/reference/to_python_indirect.qbk b/doc/reference/to_python_indirect.qbk new file mode 100644 index 0000000000..9b03ba5365 --- /dev/null +++ b/doc/reference/to_python_indirect.qbk @@ -0,0 +1,65 @@ +[section boost/python/to_python_indirect.hpp] +[section Introduction] + supplies a way to construct new Python objects that hold wrapped C++ class instances via a pointer or smart pointer. + [endsect] +[section Class `to_python_indirect`] +Class template `to_python_indirect` converts objects of its first argument type to python as extension class instances, using the ownership policy provided by its 2nd argument. +[table +[[Parameter][Requirements][Description]] + [[T][Either `U cv&` (where cv is any optional cv-qualification) or a [link concepts.dereferenceable Dereferenceable] type such that `*x` is convertible to `U const&`, where `U` is a class type. ][`A` type deferencing a C++ class exposed to Python using class template [link high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel `class_`]. ]] +[[MakeHolder][`h = MakeHolder::execute(p);` ][A class whose static `execute()` creates an `instance_holder`. ]] + ] +Instantiations of to_python_indirect are models of [link concepts.resultconverter `ResultConverter`]. +`` +namespace boost { namespace python +{ + template + struct to_python_indirect + { + static bool convertible(); + PyObject* operator()(T ptr_or_reference) const; + private: + static PyTypeObject* type(); + }; +}} +`` +[endsect] +[section Class `to_python_indirect` observers] +``PyObject* operator()(T x) const;`` +[variablelist +[[Requires][`x` refers to an object (if it is a pointer type, it is non-null). `convertible() == true`.]] +[[Effects][Creates an appropriately-typed Boost.Python extension class instance, uses MakeHolder to create an instance_holder from x, installs the instance_holder in the new extension class instance, and returns a pointer to it.]] +] +[endsect] +[section Class `to_python_indirect` statics] +``bool convertible()`` +[variablelist +[[Effects][Returns true iff any module has registered a Python type corresponding to U. ]] +] +[endsect] +[endsect] +[section Example] +This example replicates the functionality of [link function_invocation_and_creation.models_of_resultconvertergenerat.boost_python_reference_existing_.class_reference_existing_object `reference_existing_object`], but without some of the compile-time error checking. +`` +struct make_reference_holder +{ + typedef boost::python::objects::instance_holder* result_type; + template + static result_type execute(T* p) + { + return new boost::python::objects::pointer_holder(p); + } +}; + +struct reference_existing_object +{ + // metafunction returning the ResultConverter + template + struct apply + { + typedef boost::python::to_python_indirect type; + }; +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/to_python_value.qbk b/doc/reference/to_python_value.qbk new file mode 100644 index 0000000000..4b31d73f27 --- /dev/null +++ b/doc/reference/to_python_value.qbk @@ -0,0 +1,34 @@ +[section boost/python/to_python_value.hpp] +[section Introduction] +`to_python_value` is a model of [link concepts.resultconverter ResultConverter] which copies its argument into a new Python object. +[endsect] +[section Class template `to_python_value`] +`` +namespace boost { namespace python +{ + template + struct to_python_value + { + typedef typename add_reference< + typename add_const::type + >::type argument_type; + + static bool convertible(); + PyObject* operator()(argument_type) const; + }; +}} +`` +[endsect] +[section Class `to_python_value` observers] +``static bool convertible();`` +[variablelist +[[Returns][`true` iff a converter has been registered which can convert `T` to python by-value. ]] +] +``PyObject* operator()(argument_type x) const;`` +[variablelist +[[Requires][`convertible() == true`]] +[[Effects][converts `x` to python]] +[[Returns][the resulting Python object iff a converter for `T` has been registered, `0` otherwise. ]] +] +[endsect] +[endsect] diff --git a/doc/reference/topics.qbk b/doc/reference/topics.qbk new file mode 100644 index 0000000000..644f20d437 --- /dev/null +++ b/doc/reference/topics.qbk @@ -0,0 +1,7 @@ +[chapter Topics + [quickbook 1.7] +] + +[include calling.qbk] +[include pickle.qbk] +[include indexing.qbk] diff --git a/doc/reference/tuple.qbk b/doc/reference/tuple.qbk new file mode 100644 index 0000000000..0c54161c68 --- /dev/null +++ b/doc/reference/tuple.qbk @@ -0,0 +1,52 @@ +[section boost/python/tuple.hpp] +[section Introduction] +Exposes a [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] for the Python [@http://www.python.org/doc/current/tut/node7.html#SECTION007300000000000000000`tuple`] type. +[endsect] +[section Class `tuple`] +Exposes the interface of Python's built-in tuple type. The semantics of the constructors and member functions defined below can be fully understood by reading the [link concepts.objectwrapper.typewrapper_concept_requirements TypeWrapper] concept definition. Since tuple is publicly derived from [link object_wrappers.boost_python_object_hpp.class_object `object`], the public `object` interface applies to `tuple` instances as well. +`` +namespace boost { namespace python +{ + class tuple : public object + { + // tuple() -> an empty tuple + tuple(); + + // tuple(sequence) -> tuple initialized from sequence's items + template + explicit tuple(T const& sequence) + }; +}} +`` +[endsect] +[section Function `make_tuple`] +`` +namespace boost { namespace python +{ + tuple make_tuple(); + + template + tuple make_tuple(A0 const& a0); + + template + tuple make_tuple(A0 const& a0, A1 const& a1); + ... + template + tuple make_tuple(A0 const& a0, A1 const& a1,...An const& an); +}} +`` +[variablelist +[[Effect][Constructs a new tuple object composed of `object(a0), + object(a0),...object(an)`. ]] +] +[endsect] +[section Example] +`` +using namespace boost::python; +tuple head_and_tail(object sequence) +{ + return make_tuple(sequence[0],sequence[-1]); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/type_id.qbk b/doc/reference/type_id.qbk new file mode 100644 index 0000000000..bb013119bb --- /dev/null +++ b/doc/reference/type_id.qbk @@ -0,0 +1,83 @@ +[section boost/python/type_id.hpp] +[section Introduction] + provides types and functions for runtime type identification like those of of ``. It exists mostly to work around certain compiler bugs and platform-dependent interactions with shared libraries. +[endsect] +[section Class template `type_info`] +`type_info` instances identify a type. As `std::type_info` is specified to (but unlike its implementation in some compilers), `boost::python::type_info` never represents top-level references or cv-qualification (see section 5.2.8 in the C++ standard). Unlike `std::type_info`, `boost::python::type_info` instances are copyable, and comparisons always work reliably across shared library boundaries. +`` +namespace boost { namespace python +{ + class type_info : totally_ordered + { + public: + // constructor + type_info(std::type_info const& = typeid(void)); + + // comparisons + bool operator<(type_info const& rhs) const; + bool operator==(type_info const& rhs) const; + + // observers + char const* name() const; + }; +}} +`` +[section Class template `type_info` constructor] +``type_info(std::type_info const& = typeid(void));`` +[variablelist +[[Effects][constructs a `type_info` object which identifies the same type as its argument.]] +[[Rationale][Since it is occasionally necessary to make an array of `type_info` objects a benign default argument is supplied. Note: this constructor does not correct for non-conformance of compiler `typeid()` implementations. See `type_id`, below.]] +] +[endsect] +[section Class template `type_info` comparison] +``bool operator<(type_info const &rhs) const;`` +[variablelist +[[Effects][yields a total order over `type_info` objects.]] +] +``bool operator==(type_info const &rhs) const;`` +[variablelist +[[Returns][`true` iff the two values describe the same type.]] +[[Note][The use of `totally_ordered` as a private base class supplies operators `<=`, `>=`, `>`, and `!=`]] +] +[endsect] +[section Class template `type_info` observers] +`` +char const* name() const; +`` +[variablelist +[[Returns][The result of calling `name()` on the argument used to construct the object.]] +] +[endsect] +[endsect] +[section Functions] +`` +std::ostream& operator<<(std::ostream&s, type_info const&x); +`` +[variablelist +[[Effects][Writes a description of the type described by to `x` into s.]] +[[Rationale][Not every C++ implementation provides a truly human-readable `type_info::name()` string, but for some we may be able to decode the string and produce a reasonable representation.]] +[[Note][On some non-conforming C++ implementations, the code is not actually as simple as described above; the semantics are adjusted to work as-if the C++ implementation were conforming.]] +] +`` +template type_info type_id() +`` +[variablelist +[[Returns][`type_info(typeid(T))`]] +[[Note][On some non-conforming C++ implementations, the code is not actually as simple as described above; the semantics are adjusted to work as-if the C++ implementation were conforming.]] +] +[endsect] +[section Example] +The following example, though silly, illustrates how the type_id facility might be used +`` +#include + +// Returns true iff the user passes an int argument +template +bool is_int(T x) +{ + using boost::python::type_id; + return type_id() == type_id(); +} +`` +[endsect] +[endsect] diff --git a/doc/reference/utility.qbk b/doc/reference/utility.qbk new file mode 100644 index 0000000000..3123cd8dc5 --- /dev/null +++ b/doc/reference/utility.qbk @@ -0,0 +1,10 @@ +[chapter Utility and Infrastructure + [quickbook 1.7] +] + +[include has_back_reference.qbk] +[include instance_holder.qbk] +[include pointee.qbk] +[include handle.qbk] +[include type_id.qbk] +[include ssize_t.qbk] diff --git a/doc/reference/with_custodian_and_ward.qbk b/doc/reference/with_custodian_and_ward.qbk new file mode 100644 index 0000000000..76a03632dd --- /dev/null +++ b/doc/reference/with_custodian_and_ward.qbk @@ -0,0 +1,72 @@ +[section boost/python/with_custodian_and_ward.hpp] +[section Introduction] +This header provides facilities for establishing a lifetime dependency between two of a function's Python argument or result objects. The ward object will not be destroyed until after the custodian as long as the custodian object supports [@http://www.python.org/doc/current/lib/module-weakref.html weak references] (Boost.Python extension classes all support weak references). If the custodian object does not support weak references and is not `None`, an appropriate exception will be thrown. The two class templates `with_custodian_and_ward` and `with_custodian_and_ward_postcall` differ in the point at which they take effect. + +In order to reduce the chance of inadvertently creating dangling pointers, the default is to do lifetime binding before the underlying C++ object is invoked. However, before invocation the result object is not available, so `with_custodian_and_ward_postcall` is provided to bind lifetimes after invocation. Also, if a C++ exception is thrown after `with_custodian_and_ward<>::precall` but before the underlying C++ object actually stores a pointer, the lifetime of the custodian and ward objects will be artificially bound together, so one might choose `with_custodian_and_ward_postcall` instead, depending on the semantics of the function being wrapped. + +Please note that this is not the appropriate tool to use when wrapping functions which transfer ownership of a raw pointer across the function-call boundary. Please see the FAQ if you want to do that. +[endsect] +[section Class `with_custodian_and_ward`] +[table +[[Parameter][Requirements][Description][Default]] + [[custodian][ A positive compile-time constant of `type std::size_t`. ][ The 1-based index of the parameter which is the dependency in the lifetime relationship to be established. If used to wrap a member function, parameter 1 is the target object (`*this`). Note that if the target Python object type doesn't support weak references, a Python TypeError exception will be raised when the C++ object being wrapped is called. ][]] +[[ward][ A positive compile-time constant of type `std::size_t`. ][ The 1-based index of the parameter which is the dependent in the lifetime relationship to be established. If used to wrap a member function, parameter 1 is the target object (`*this`). ][]] +[[Base][ A model of [link concepts.callpolicies `CallPolicies`]][ Used for policy [link concepts.callpolicies.callpolicies_composition composition]. ][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct with_custodian_and_ward : Base + { + static bool precall(PyObject* args); + }; +}}`` +[endsect] +[section Class `with_custodian_and_ward` static functions] +``bool precall(PyObject* args);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0`]] +[[Effects][Makes the lifetime of the argument indicated by ward dependent on the lifetime of the argument indicated by custodian. ]] +[[Returns][false and PyErr_Occurred() != 0 upon failure, true otherwise.]] +] +[endsect] + +[section Class `with_custodian_and_ward_postcall`] +[table +[[Parameter][Requirements][Description][Default]] + [[custodian][ A positive compile-time constant of type `std::size_t`. ][ The index of the parameter which is the dependency in the lifetime relationship to be established. Zero indicates the result object; 1 indicates the first argument. If used to wrap a member function, parameter 1 is the target object (`*this`). Note that if the target Python object type doesn't support weak references, a Python TypeError exception will be raised when the C++ object being wrapped is called. ][]] +[[ward][ A positive compile-time constant of type `std::size_t`. ][ The index of the parameter which is the dependent in the lifetime relationship to be established. Zero indicates the result object; 1 indicates the first argument. If used to wrap a member function, parameter 1 is the target object (`*this`). ][]] +[[Base][ A model of [link concepts.callpolicies `CallPolicies`]][ Used for policy [link concepts.callpolicies.callpolicies_composition composition]. ][default_call_policies]] + ] +`` +namespace boost { namespace python +{ + template + struct with_custodian_and_ward_postcall : Base + { + static PyObject* postcall(PyObject* args, PyObject* result); + }; +}} +`` +[endsect] +[section Class `with_custodian_and_ward_postcall` static functions] +``PyObject *postcall(PyObject* args, PyObject* result);`` +[variablelist +[[Requires][`PyTuple_Check(args) != 0`, `result != 0`]] +[[Effects][Makes the lifetime of the object indicated by ward dependent on the lifetime of the object indicated by custodian. ]] +[[Returns][`0` and `PyErr_Occurred() != 0` upon failure, `true` otherwise. ]] +] +[endsect] +[section Example] +The following example shows how `with_custodian_and_ward_postcall` is used by the library to implement `return_internal_reference` +`` +template +struct return_internal_reference + : with_custodian_and_ward_postcall<0, owner_arg, Base> +{ + typedef reference_existing_object result_converter; +}; +`` +[endsect] +[endsect] diff --git a/doc/reference/wrapper.qbk b/doc/reference/wrapper.qbk new file mode 100644 index 0000000000..5c5bfc4847 --- /dev/null +++ b/doc/reference/wrapper.qbk @@ -0,0 +1,117 @@ +[section boost/python/wrapper.hpp] +[section Introduction] +To wrap a class T such that its virtual functions can be "overridden in Python"—so that the corresponding method of a Python derived class will be called when the virtual function is invoked from C++—you must create a C++ wrapper class derived from `T` that overrides those virtual functions so that they call into Python. This header contains classes that can be used to make that job easier. +[endsect] +[section Class `override`] +Encapsulates a Python override of a C++ virtual function. An override object either holds a callable Python object or `None`. +`` +namespace boost +{ + class override : object + { + public: + unspecified operator() const; + template + unspecified operator(A0) const; + template + unspecified operator(A0, A1) const; + ... + template + unspecified operator(A0, A1, ...An) const; + }; +}; +`` +[endsect] +[section Class `override` observer functions] +`` +unspecified operator() const; +template +unspecified operator(A0) const; +template +unspecified operator(A0, A1) const; +... +template +unspecified operator(A0, A1, ...An) const; +`` +[variablelist +[[Effects][If *this holds a callable Python object, it is invoked with the specified arguments in the manner specified here. Otherwise, throws [link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set].]] +[[Returns][An object of unspecified type that holds the Python result of the invocation and, when converted to a C++ type R, attempts to convert that result object to R. If that conversion fails, throws [link high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set].]] +] +[endsect] +[section Class template `wrapper`] +Deriving your wrapper class from both `T` and `wrapper` makes writing that derived class easier. +`` +namespace boost +{ + class wrapper + { + protected: + override get_override(char const* name) const; + }; +}; +`` +[endsect] +[section Class template `wrapper` observer functions] +``override get_override(char const* name) const;`` +[variablelist +[[Requires][name is a [link ntbs].]] +[[Returns][If `*this` is the C++ base class subobject of a Python derived class instance that overrides the named function, returns an override object that delegates to the Python override. Otherwise, returns an override object that holds `None`.]] +] +[endsect] +[section Example] +`` +#include +#include +#include +#include + +using namespace boost::python; + +// Class with one pure virtual function +struct P +{ + virtual ~P(){} + virtual char const* f() = 0; + char const* g() { return "P::g()"; } +}; + +struct PCallback : P, wrapper

+{ + char const* f() + { + return this->get_override("f")(); + } +}; + +// Class with one non-pure virtual function +struct A +{ + virtual ~A(){} + virtual char const* f() { return "A::f()"; } +}; + +struct ACallback : A, wrapper +{ + char const* f() + { + if (override f = this->get_override("f")) + return f(); + return A::f(); + } + + char const* default_f() { return this->A::f(); } +}; + +BOOST_PYTHON_MODULE_INIT(polymorphism) +{ + class_("P") + .def("f", pure_virtual(&P::f)) + ; + + class_("A") + .def("f", &A::f, &ACallback::default_f) + ; +} +`` +[endsect] +[endsect] diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk new file mode 100644 index 0000000000..7e0c82fdfd --- /dev/null +++ b/doc/release_notes.qbk @@ -0,0 +1,11 @@ +[chapter Release Notes + [quickbook 1.7] + [id rn] +] + +[section Version 1.67] + +* The Boost.Python library names now contain the Python version suffix. + A variant compiled with Python 2.7 will thus produce library names + `boost_python27` and `boost_numpy27`, etc., making it possible to host + variants for multiple Python versions next to each other. \ No newline at end of file diff --git a/doc/rst.css b/doc/rst.css new file mode 100644 index 0000000000..afd9a98c31 --- /dev/null +++ b/doc/rst.css @@ -0,0 +1,149 @@ +@import url("doc/src/boostbook.css"); +@import url("doc/src/docutils.css"); +/* Copyright David Abrahams 2006. Distributed under the Boost + Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +dl.docutils dt { + font-weight: bold } + +img.boost-logo { + border: none; + vertical-align: middle +} + +pre.literal-block span.concept { + font-style: italic; +} + +.nav { +display: inline; +list-style-type: none; +} + +.prevpage { +padding-top: -5px; +text-align: left; +float: left; +} + +.nextpage { +padding-top: -20px; +text-align: right; +float: right; +} + +div.small { + font-size: smaller } + +h2 a { + font-size: 90%; +} +h3 a { + font-size: 80%; +} +h4 a { + font-size: 70%; +} +h5 a { + font-size: 60%; +} + +dl,table +{ + text-align: left; + font-size: 10pt; + line-height: 1.15; +} + + +/*============================================================================= + Tables +=============================================================================*/ + +/* The only clue docutils gives us that tables are logically tables, + and not, e.g., footnotes, is that they have border="1". Therefore + we're keying off of that. We used to manually patch docutils to + add a "table" class to all logical tables, but that proved much too + fragile. +*/ + + table[border="1"] + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + table[border="1"] + { + padding: 4px; + } + + /* Table Cells */ + table[border="1"] tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + table[border="1"] tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + @media screen + { + + /* Tables */ + table[border="1"] tr td + { + border: 1px solid #DCDCDC; + } + + table[border="1"] tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + pre, + .screen + { + border: 1px solid #DCDCDC; + } + + td pre + td .screen + { + border: 0px + } + + .sidebar pre + { + border: 0px + } + + } + + pre, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td pre, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + diff --git a/doc/support.html b/doc/support.html deleted file mode 100644 index 3198563417..0000000000 --- a/doc/support.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - Boost.Python - Support Resources - - - - - - - - - -
-

-

-
-

Boost.Python

- -

Support Resources

-
-


- -

Synopsis

- -

This is a list of available resources for support with Boost.Python - problems and feature requests. Please try to resist emailing the - Boost.Python developers directly for support. Use the following - resources instead; the developers are listening!

-
- -
-
Boost - Consulting - Commercial support, development, training, and - distribution for all the Boost libraries, from the people who brought - you Boost.Python.
-  
- -
The Python - C++-sig mailing list is a forum for discussing Python/C++ - interoperability, and Boost.Python in particular. Post your - Boost.Python questions here.
-  
- -
The Boost.Python Wiki - Pages established by Mike Rovner as part of the PythonInfo Wiki serves as - a forum to gather peoples' experience and as a cookbook.
-  
-
-
- -

Revised - - 12 Sept, 2003 -

- -

© Copyright Dave - Abrahams 2003.

- - - diff --git a/doc/support.qbk b/doc/support.qbk new file mode 100644 index 0000000000..f075e3e98e --- /dev/null +++ b/doc/support.qbk @@ -0,0 +1,17 @@ +[chapter Support Resources + [quickbook 1.7] + [id support] +] + + +[h2 Synopsis] +This is a list of available resources for support with Boost.Python problems and feature requests. Please try to resist emailing the Boost.Python developers directly for support. Use the following resources instead; the developers are listening! + +[h2 Support] +* The _bp_list_ is a forum for discussing Python/C++ interoperability, and Boost.Python in particular. Post your Boost.Python questions here. +* The _bb_list_ is a forum for discussing Boost's Build System. +* The Boost.Python [@https://github.com/boostorg/python/issues Issue tracker] + [note In the past we used Trac, which still hosts a considerable number of [@https://svn.boost.org/trac/boost/query?status=!closed&component=python+USE+GITHUB open issues]. We hope to be able to either close them or migrate them to the new issue tracker.] +* The Boost.Python [@https://github.com/boostorg/python/wiki Wiki] +* Boost.Python [@https://github.com/boostorg/python Source repository] + diff --git a/doc/tutorial/doc/tutorial.qbk b/doc/tutorial.qbk similarity index 95% rename from doc/tutorial/doc/tutorial.qbk rename to doc/tutorial.qbk index 10a452200c..197470013e 100644 --- a/doc/tutorial/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -1,27 +1,26 @@ -[library python - [version 2.0] +[article Boost.Python Tutorial + [quickbook 1.6] [authors [de Guzman, Joel], [Abrahams, David]] [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams] [category inter-language support] + [id tutorial] [purpose Reflects C++ classes and functions into Python ] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt - ) + [@http://www.boost.org/LICENSE_1_0.txt] ] ] [/ QuickBook Document version 0.9 ] -[def __note__ [$images/note.png]] -[def __alert__ [$images/alert.png]] -[def __tip__ [$images/tip.png]] -[def :-) [$images/smiley.png]] -[def __jam__ [$images/jam.png]] +[def __note__ [$../images/note.png]] +[def __alert__ [$../images/alert.png]] +[def __tip__ [$../images/tip.png]] +[def :-) [$../images/smiley.png]] +[def __jam__ [$../images/jam.png]] [section QuickStart] @@ -93,7 +92,7 @@ who had to use a different tool. We will skip over the details. Our objective will be to simply create the hello world module and run it in Python. For a complete reference to -building Boost.Python, check out: [@../../../building.html +building Boost.Python, check out: [@../building.html building.html]. After this brief ['bjam] tutorial, we should have built the DLLs and run a python program using the extension. @@ -118,11 +117,11 @@ platforms. The complete list of Bjam executables can be found [h2 Let's Jam!] __jam__ -[@../../../../example/tutorial/Jamroot Here] is our minimalist Jamroot +[@../example/Jamroot Here] is our minimalist Jamroot file. Simply copy the file and tweak [^use-project boost] to where your -boost root directory is and your OK. +boost root directory is and you're OK. -The comments contained in the Jamrules file above should be sufficient +The comments contained in the Jamroot file above should be sufficient to get you going. [h2 Running bjam] @@ -425,7 +424,7 @@ instances of class [^Derived]. In such cases, we use [^return_value_policy] to instruct Python to adopt the pointer to [^Base] and hold the instance in a new Python [^Base] object until the the Python object is destroyed. We will see more of -Boost.Python [link python.call_policies call policies] later. +Boost.Python [link tutorial.functions.call_policies call policies] later. // Tell Python to take ownership of factory's result def("factory", factory, @@ -463,7 +462,7 @@ functions so that a Python override may be called: }; Notice too that in addition to inheriting from `Base`, we also multiply- -inherited `wrapper` (See [@../../../v2/wrapper.html Wrapper]). The +inherited `wrapper` (See [@../reference/high_level_components/boost_python_wrapper_hpp.html#high_level_components.boost_python_wrapper_hpp.class_template_wrapper Wrapper]). The `wrapper` template makes the job of wrapping classes that are meant to overridden in Python, easier. @@ -495,11 +494,11 @@ Methods correspond roughly to C++'s [*member functions]] [section Virtual Functions with Default Implementations] We've seen in the previous section how classes with pure virtual functions are -wrapped using Boost.Python's [@../../../v2/wrapper.html class wrapper] +wrapped using Boost.Python's [@../reference/high_level_components/boost_python_wrapper_hpp.html#high_level_components.boost_python_wrapper_hpp.class_template_wrapper class wrapper] facilities. If we wish to wrap [*non]-pure-virtual functions instead, the mechanism is a bit different. -Recall that in the [link python.class_virtual_functions previous section], we +Recall that in the [link tutorial.exposing.class_virtual_functions previous section], we wrapped a class with a pure virtual function that we then implemented in C++, or Python classes derived from it. Our base class: @@ -812,7 +811,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 [@../reference/function_invocation_and_creation/models_of_callpolicies.html here]. * [*with_custodian_and_ward]: Ties lifetimes of the arguments * [*with_custodian_and_ward_postcall]: Ties lifetimes of the arguments and results @@ -897,7 +896,7 @@ to retrieve the default arguments: def("f", f); // defaults lost! Because of this, when wrapping C++ code, we had to resort to manual -wrapping as outlined in the [link python.overloading previous section], or +wrapping as outlined in the [link tutorial.functions.overloading previous section], or writing thin wrappers: // write "thin wrappers" @@ -970,7 +969,7 @@ fourth macro argument). The thin wrappers are all enclosed in a class named .def("wack_em", &george::wack_em, george_overloads()); -See the [@../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference] +See the [@../reference/function_invocation_and_creation/boost_python_overloads_hpp.html#function_invocation_and_creation.boost_python_overloads_hpp.macros overloads reference] for details. [h2 init and optional] @@ -1037,12 +1036,12 @@ Notice though that we have a situation now where we have a minimum of zero It is important to emphasize however that [*the overloaded functions must have a common sequence of initial arguments]. Otherwise, our scheme above will not work. If this is not the case, we have to wrap our functions -[link python.overloading manually]. +[link tutorial.functions.overloading manually]. Actually, we can mix and match manual wrapping of overloaded functions and automatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] and its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our example -presented in the section [link python.overloading on overloading], since the +presented in the section [link tutorial.functions.overloading on overloading], since the first 4 overload functins have a common sequence of initial arguments, we can use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap the first three of the [^def]s and manually wrap just the last. Here's @@ -1076,7 +1075,7 @@ bidirectional mapping between C++ and Python while maintaining the Python feel. Boost.Python C++ [^object]s are as close as possible to Python. This should minimize the learning curve significantly. -[$images/python.png] +[$../images/python.png] [section Basic Interface] @@ -1267,7 +1266,7 @@ associated with the C++ type passed as its first parameter. The scope is a class that has an associated global Python object which controls the Python namespace in which new extension classes and wrapped functions will be defined as attributes. Details can be found -[@../../../v2/scope.html here].] +[@../reference/high_level_components/boost_python_scope_hpp.html#high_level_components.boost_python_scope_hpp.class_scope here].] You can access those values in Python as @@ -1403,8 +1402,8 @@ There is a difference however. While the reference-counting is fully automatic in Python, the Python C API requires you to do it [@http://www.python.org/doc/current/c-api/refcounting.html by hand]. This is messy and especially hard to get right in the presence of C++ exceptions. -Fortunately Boost.Python provides the [@../../../v2/handle.html handle] and -[@../../../v2/object.html object] class templates to automate the process. +Fortunately Boost.Python provides the [@../reference/utility_and_infrastructure/boost_python_handle_hpp.html#utility_and_infrastructure.boost_python_handle_hpp.class_template_handle handle] and +[@../reference/object_wrappers/boost_python_object_hpp.html#object_wrappers.boost_python_object_hpp.class_object object] class templates to automate the process. [h2 Running Python code] @@ -1418,6 +1417,8 @@ eval evaluates the given expression and returns the resulting value. exec executes the given code (typically a set of statements) returning the result, and exec_file executes the code contained in the given file. +There are also overloads taking `char const*` instead of str as the first argument. + The [^globals] and [^locals] parameters are Python dictionaries containing the globals and locals of the context in which to run the code. For most intents and purposes you can use the namespace dictionary of the @@ -1447,7 +1448,7 @@ containing a phrase that is well-known in programming circles. Often we'd like to have a class to manipulate Python objects. But we have already seen such a class above, and in the -[@python/object.html previous section]: the aptly named [^object] class +[link tutorial.object previous section]: the aptly named [^object] class and its derivatives. We've already seen that they can be constructed from a [^handle]. The following examples should further illustrate this fact: @@ -1467,7 +1468,7 @@ which returns the result directly: [h2 Exception handling] If an exception occurs in the evaluation of the python expression, -[@../../../v2/errors.html#error_already_set-spec error_already_set] is thrown: +[@../reference/high_level_components/boost_python_errors_hpp.html#high_level_components.boost_python_errors_hpp.class_error_already_set error_already_set] is thrown: try { @@ -1759,13 +1760,13 @@ sounds/ \_\_init\_\_.py core/ \_\_init\_\_.py - _core.pyd + \_core.pyd filters/ \_\_init\_\_.py - _filters.pyd + \_filters.pyd io/ \_\_init\_\_.py - _io.pyd + \_io.pyd ] Note that we created a directory for each extension module, and added a @@ -1848,7 +1849,7 @@ we have a class [^point] in C++: } If we are using the technique from the previous session, -[link python.creating_packages Creating Packages], we can code directly +[link tutorial.techniques.creating_packages Creating Packages], we can code directly into [^geom/\_\_init\_\_.py]: [python] @@ -1870,36 +1871,6 @@ This technique has several advantages: * Minimize the need to recompile * Rapid prototyping (you can move the code to C++ if required without changing the interface) -You can even add a little syntactic sugar with the use of metaclasses. Let's -create a special metaclass that "injects" methods in other classes. - - # The one Boost.Python uses for all wrapped classes. - # You can use here any class exported by Boost instead of "point" - BoostPythonMetaclass = point.__class__ - - class injector(object): - class __metaclass__(BoostPythonMetaclass): - def __init__(self, name, bases, dict): - for b in bases: - if type(b) not in (self, type): - for k,v in dict.items(): - setattr(b,k,v) - return type.__init__(self, name, bases, dict) - - # inject some methods in the point foo - class more_point(injector, point): - def __repr__(self): - return 'Point(x=%s, y=%s)' % (self.x, self.y) - def foo(self): - print 'foo!' - -Now let's see how it got: - - >>> print point() - Point(x=10, y=10) - >>> point().foo() - foo! - Another useful idea is to replace constructors with factory functions: _point = point @@ -1971,15 +1942,10 @@ This method is recommended too if you are developing the C++ library and exporting it to Python at the same time: changes in a class will only demand the compilation of a single cpp, instead of the entire wrapper code. -[note If you're exporting your classes with [@../../../../pyste/index.html Pyste], -take a look at the [^--multiple] option, that generates the wrappers in -various files as demonstrated here.] - [note This method is useful too if you are getting the error message ['"fatal error C1204:Compiler limit:internal structure overflow"] when compiling -a large source file, as explained in the [@../../../v2/faq.html#c1204 FAQ].] +a large source file, as explained in the [@../faq/fatal_error_c1204_compiler_limit.html FAQ].] [endsect] [endsect] [/ General Techniques] - diff --git a/doc/tutorial/doc/Jamfile.v2 b/doc/tutorial/doc/Jamfile.v2 deleted file mode 100644 index ba8882636d..0000000000 --- a/doc/tutorial/doc/Jamfile.v2 +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright Joel de Guzman 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -project boost/libs/python/doc/tutorial/doc ; - -import boostbook : boostbook ; -using quickbook ; - -path-constant images : html ; - -boostbook tutorial - : - tutorial.qbk - : - boost.root=../../../../../.. - pdf:img.src.path=$(images)/ - pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/libs/python/doc/tutorial/doc/html - ; diff --git a/doc/tutorial/doc/html/images/note.png b/doc/tutorial/doc/html/images/note.png deleted file mode 100755 index 3ed047cacb..0000000000 Binary files a/doc/tutorial/doc/html/images/note.png and /dev/null differ diff --git a/doc/tutorial/doc/html/images/tip.png b/doc/tutorial/doc/html/images/tip.png deleted file mode 100755 index 9f596b0b88..0000000000 Binary files a/doc/tutorial/doc/html/images/tip.png and /dev/null differ diff --git a/doc/tutorial/doc/html/index.html b/doc/tutorial/doc/html/index.html deleted file mode 100644 index c324f065ce..0000000000 --- a/doc/tutorial/doc/html/index.html +++ /dev/null @@ -1,142 +0,0 @@ - - - -Chapter 1. python 2.0 - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
Next
-
-
-

-Chapter 1. python 2.0

-

-Joel de Guzman -

-

-David Abrahams -

-
-
-

- Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt ) -

-
-
- -
-

-QuickStart

-

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

-

- - Hello World -

-

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

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

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

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

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

-
>>> import hello_ext
->>> print hello_ext.greet()
-hello, world
-
-

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

-
-
- - - -

Last revised: December 26, 2011 at 21:58:39 GMT

-
-
Next
- - diff --git a/doc/tutorial/doc/html/python/embedding.html b/doc/tutorial/doc/html/python/embedding.html deleted file mode 100644 index 4e1c21857b..0000000000 --- a/doc/tutorial/doc/html/python/embedding.html +++ /dev/null @@ -1,269 +0,0 @@ - - - -Embedding - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Embedding

- -

- By now you should know how to use Boost.Python to call your C++ code from Python. - However, sometimes you may need to do the reverse: call Python code from the - C++-side. This requires you to embed the Python interpreter - into your C++ program. -

-

- Currently, Boost.Python does not directly support everything you'll need when - embedding. Therefore you'll need to use the Python/C - API to fill in the gaps. However, Boost.Python already makes embedding - a lot easier and, in a future version, it may become unnecessary to touch the - Python/C API at all. So stay tuned... smiley -

-

- - Building embedded programs -

-

- To be able to embed python into your programs, you have to link to both Boost.Python's - as well as Python's own runtime library. -

-

- Boost.Python's library comes in two variants. Both are located in Boost's - /libs/python/build/bin-stage subdirectory. On Windows, the - variants are called boost_python.lib (for release builds) - and boost_python_debug.lib (for debugging). If you can't - find the libraries, you probably haven't built Boost.Python yet. See Building and Testing on how to do this. -

-

- Python's library can be found in the /libs subdirectory - of your Python directory. On Windows it is called pythonXY.lib where X.Y is - your major Python version number. -

-

- Additionally, Python's /include subdirectory has to be added - to your include path. -

-

- In a Jamfile, all the above boils down to: -

-
projectroot c:\projects\embedded_program ; # location of the program
-
-# bring in the rules for python
-SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
-include python.jam ;
-
-exe embedded_program # name of the executable
-  : #sources
-     embedded_program.cpp
-  : # requirements
-     <find-library>boost_python <library-path>c:\boost\libs\python
-  $(PYTHON_PROPERTIES)
-    <library-path>$(PYTHON_LIB_PATH)
-    <find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
-
-

- - Getting started -

-

- Being able to build is nice, but there is nothing to build yet. Embedding the - Python interpreter into one of your C++ programs requires these 4 steps: -

-
    -
  1. - #include <boost/python.hpp> -
  2. -
  3. - Call Py_Initialize() - to start the interpreter and create the __main__ module. -
  4. -
  5. - Call other Python C API routines to use the interpreter. -
  6. -
-
- - - - - -
[Note]Note

- Note that at this time you must not call Py_Finalize() - to stop the interpreter. This may be fixed in a future version of boost.python. -

-

- (Of course, there can be other C++ code between all of these steps.) -

-

- Now that we can embed the interpreter in - our programs, lets see how to put it to use... -

-
-

-Using the interpreter

-

- As you probably already know, objects in Python are reference-counted. Naturally, - the PyObjects of the Python C API are also reference-counted. - There is a difference however. While the reference-counting is fully automatic - in Python, the Python C API requires you to do it by - hand. This is messy and especially hard to get right in the presence - of C++ exceptions. Fortunately Boost.Python provides the handle - and object class templates to - automate the process. -

-

- - Running Python code -

-

- Boost.python provides three related functions to run Python code from C++. -

-
object eval(str expression, object globals = object(), object locals = object())
-object exec(str code, object globals = object(), object locals = object())
-object exec_file(str filename, object globals = object(), object locals = object())
-
-

- eval evaluates the given expression and returns the resulting value. exec - executes the given code (typically a set of statements) returning the result, - and exec_file executes the code contained in the given file. -

-

- The globals and locals parameters are - Python dictionaries containing the globals and locals of the context in which - to run the code. For most intents and purposes you can use the namespace - dictionary of the __main__ module for both parameters. -

-

- Boost.python provides a function to import a module: -

-
object import(str name)
-
-

- import imports a python module (potentially loading it into the running process - first), and returns it. -

-

- Let's import the __main__ module and run some Python code - in its namespace: -

-
object main_module = import("__main__");
-object main_namespace = main_module.attr("__dict__");
-
-object ignored = exec("hello = file('hello.txt', 'w')\n"
-                      "hello.write('Hello world!')\n"
-                      "hello.close()",
-                      main_namespace);
-
-

- This should create a file called 'hello.txt' in the current directory containing - a phrase that is well-known in programming circles. -

-

- - Manipulating Python objects -

-

- Often we'd like to have a class to manipulate Python objects. But we have - already seen such a class above, and in the previous - section: the aptly named object class and its - derivatives. We've already seen that they can be constructed from a handle. - The following examples should further illustrate this fact: -

-
object main_module = import("__main__");
-object main_namespace = main_module.attr("__dict__");
-object ignored = exec("result = 5 ** 2", main_namespace);
-int five_squared = extract<int>(main_namespace["result"]);
-
-

- Here we create a dictionary object for the __main__ module's - namespace. Then we assign 5 squared to the result variable and read this - variable from the dictionary. Another way to achieve the same result is to - use eval instead, which returns the result directly: -

-
object result = eval("5 ** 2");
-int five_squared = extract<int>(result);
-
-

- - Exception handling -

-

- If an exception occurs in the evaluation of the python expression, error_already_set - is thrown: -

-
try
-{
-    object result = eval("5/0");
-    // execution will never get here:
-    int five_divided_by_zero = extract<int>(result);
-}
-catch(error_already_set const &)
-{
-    // handle the exception in some way
-}
-
-

- The error_already_set exception class doesn't carry any - information in itself. To find out more about the Python exception that occurred, - you need to use the exception - handling functions of the Python C API in your catch-statement. This - can be as simple as calling PyErr_Print() - to print the exception's traceback to the console, or comparing the type - of the exception with those of the standard - exceptions: -

-
catch(error_already_set const &)
-{
-    if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))
-    {
-        // handle ZeroDivisionError specially
-    }
-    else
-    {
-        // print all other errors to stderr
-        PyErr_Print();
-    }
-}
-
-

- (To retrieve even more information from the exception you can use some of - the other exception handling functions listed here.) -

-
-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/exception.html b/doc/tutorial/doc/html/python/exception.html deleted file mode 100644 index 7c053a7e86..0000000000 --- a/doc/tutorial/doc/html/python/exception.html +++ /dev/null @@ -1,63 +0,0 @@ - - - -Exception Translation - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Exception Translation

-

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

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

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

-
struct PodBayDoorException;
-void translator(PodBayDoorException const& x) {
-    PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave...");
-}
-BOOST_PYTHON_MODULE(kubrick) {
-     register_exception_translator<
-          PodBayDoorException>(translator);
-     ...
-
-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/exposing.html b/doc/tutorial/doc/html/python/exposing.html deleted file mode 100644 index 5547b2f205..0000000000 --- a/doc/tutorial/doc/html/python/exposing.html +++ /dev/null @@ -1,591 +0,0 @@ - - - -Exposing Classes - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Exposing Classes

- -

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

-

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

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

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

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

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

-
>>> import hello
->>> planet = hello.World()
->>> planet.set('howdy')
->>> planet.greet()
-'howdy'
-
-
-

-Constructors

-

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

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

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

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

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

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

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

-

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

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

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

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

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

-
-
-

-Class Data Members

-

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

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

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

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

- Then, in Python, assuming we have placed our Var class inside the namespace - hello as we did before: -

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

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

-
>>> x.name = 'e' # can't change name
-Traceback (most recent call last):
-  File "<stdin>", line 1, in ?
-AttributeError: can't set attribute
-
-
-
-

-Class Properties

-

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

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

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

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

- And at last, in Python: -

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

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

-
.add_property("rovalue", &Num::get)
-
-
-
-

-Inheritance

-

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

-

- Consider this trivial inheritance structure: -

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

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

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

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

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

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

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

- Doing so, we get some things for free: -

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

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

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

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

-
// Tell Python to take ownership of factory's result
-def("factory", factory,
-    return_value_policy<manage_new_object>());
-
-
-
-

-Class Virtual Functions

-

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

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

- One of the goals of Boost.Python is to be minimally intrusive on an existing - C++ design. In principle, it should be possible to expose the interface for - a 3rd party library without changing it. It is not ideal to add anything - to our class Base. Yet, when - you have a virtual function that's going to be overridden in Python and called - polymorphically from C++, we'll need to - add some scaffoldings to make things work properly. What we'll do is write - a class wrapper that derives from Base - that will unintrusively hook into the virtual functions so that a Python - override may be called: -

-
struct BaseWrap : Base, wrapper<Base>
-{
-    int f()
-    {
-        return this->get_override("f")();
-    }
-};
-
-

- Notice too that in addition to inheriting from Base, - we also multiply- inherited wrapper<Base> (See Wrapper). - The wrapper template makes - the job of wrapping classes that are meant to overridden in Python, easier. -

- -

- BaseWrap's overridden virtual member function f - in effect calls the corresponding method of the Python object through get_override. -

-

- Finally, exposing Base: -

-
class_<BaseWrap, boost::noncopyable>("Base")
-    .def("f", pure_virtual(&Base::f))
-    ;
-
-

- pure_virtual signals Boost.Python - that the function f is a - pure virtual function. -

-
- - - - - -
[Note]Note
-

- member function and methods -

-

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

-
-
-
-

-Virtual Functions with Default Implementations

-

- We've seen in the previous section how classes with pure virtual functions - are wrapped using Boost.Python's class - wrapper facilities. If we wish to wrap non-pure-virtual - functions instead, the mechanism is a bit different. -

-

- Recall that in the previous - section, we wrapped a class with a pure virtual function that we then - implemented in C++, or Python classes derived from it. Our base class: -

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

- had a pure virtual function f. If, however, its member - function f was not declared as pure virtual: -

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

- We wrap it this way: -

-
struct BaseWrap : Base, wrapper<Base>
-{
-    int f()
-    {
-        if (override f = this->get_override("f"))
-            return f(); // *note*
-        return Base::f();
-    }
-
-    int default_f() { return this->Base::f(); }
-};
-
-

- Notice how we implemented BaseWrap::f. Now, - we have to check if there is an override for f. - If none, then we call Base::f(). -

- -

- Finally, exposing: -

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

- Take note that we expose both &Base::f and &BaseWrap::default_f. Boost.Python needs to keep track - of 1) the dispatch function f and 2) the forwarding function - to its default implementation default_f. There's a special - def function for this purpose. -

-

- In Python, the results would be as expected: -

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

- Calling base.f(): -

-
>>> base.f()
-0
-
-

- Calling derived.f(): -

-
>>> derived.f()
-42
-
-
-
-

-Class Operators/Special Functions

-

- - Python Operators -

-

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

-

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

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

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

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

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

-

- - Special Methods -

-

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

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

- Need we say more? -

-
- - - - - -
[Note]Note

- What is the business of operator<<? Well, the method str requires the operator<< to do its work (i.e. operator<< - is used by the method defined by def(str(self)). -

-
-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/functions.html b/doc/tutorial/doc/html/python/functions.html deleted file mode 100644 index ddd5bc7b70..0000000000 --- a/doc/tutorial/doc/html/python/functions.html +++ /dev/null @@ -1,586 +0,0 @@ - - - -Functions - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Functions

- -

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

-

- Read on... -

-

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

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

-Call Policies

-

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

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

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

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

- What's the problem? -

-

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

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

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

-

- Here's what's happening: -

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

- We could copy result into a new object: -

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

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

-

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

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

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

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

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

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

- Here's what's happening: -

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

- - Call Policies -

-

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

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

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

-
return_internal_reference<1
-
-

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

-
with_custodian_and_ward<1, 2>
-
-

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

-

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

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

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

-
    -
  • - with_custodian_and_ward: Ties lifetimes - of the arguments -
  • -
  • - with_custodian_and_ward_postcall: Ties - lifetimes of the arguments and results -
  • -
  • - return_internal_reference: Ties lifetime - of one argument to that of result -
  • -
  • - return_value_policy<T> with T one of: -
      -
    • - reference_existing_object: naive - (dangerous) approach -
    • -
    • - copy_const_reference: Boost.Python - v1 approach -
    • -
    • - copy_non_const_reference: -
    • -
    • - manage_new_object: Adopt a pointer - and hold the instance -
    • -
    -
  • -
- -
-
-

-Overloading

-

- The following illustrates a scheme for manually wrapping an overloaded member - functions. Of course, the same technique can be applied to wrapping overloaded - non-member functions. -

-

- We have here our C++ class: -

-
struct X
-{
-    bool f(int a)
-    {
-        return true;
-    }
-
-    bool f(int a, double b)
-    {
-        return true;
-    }
-
-    bool f(int a, double b, char c)
-    {
-        return true;
-    }
-
-    int f(int a, int b, int c)
-    {
-        return a + b + c;
-    };
-};
-
-

- Class X has 4 overloaded functions. We will start by introducing some member - function pointer variables: -

-
bool    (X::*fx1)(int)              = &X::f;
-bool    (X::*fx2)(int, double)      = &X::f;
-bool    (X::*fx3)(int, double, char)= &X::f;
-int     (X::*fx4)(int, int, int)    = &X::f;
-
-

- With these in hand, we can proceed to define and wrap this for Python: -

-
.def("f", fx1)
-.def("f", fx2)
-.def("f", fx3)
-.def("f", fx4)
-
-
-
-

-Default Arguments

-

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

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

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

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

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

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

- Because of this, when wrapping C++ code, we had to resort to manual wrapping - as outlined in the previous section, - or writing thin wrappers: -

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

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

-
    -
  • - have default arguments, or -
  • -
  • - are overloaded with a common sequence of initial arguments -
  • -
-

- - BOOST_PYTHON_FUNCTION_OVERLOADS -

-

- Boost.Python now has a way to make it easier. For instance, given a function: -

-
int foo(int a, char b = 1, unsigned c = 2, double d = 3)
-{
-    /*...*/
-}
-
-

- The macro invocation: -

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

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

-
def("foo", foo, foo_overloads());
-
-

- - BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS -

-

- Objects here, objects there, objects here there everywhere. More frequently - than anything else, we need to expose member functions of our classes to - Python. Then again, we have the same inconveniences as before when default - arguments or overloads with a common sequence of initial arguments come into - play. Another macro is provided to make this a breeze. -

-

- Like BOOST_PYTHON_FUNCTION_OVERLOADS, BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS - may be used to automatically create the thin wrappers for wrapping member - functions. Let's have an example: -

-
struct george
-{
-    void
-    wack_em(int a, int b = 0, char c = 'x')
-    {
-        /*...*/
-    }
-};
-
-

- The macro invocation: -

-
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3)
-
-

- will generate a set of thin wrappers for george's wack_em - member function accepting a minimum of 1 and a maximum of 3 arguments (i.e. - the third and fourth macro argument). The thin wrappers are all enclosed - in a class named george_overloads that can then be used - as an argument to def(...): -

-
.def("wack_em", &george::wack_em, george_overloads());
-
-

- See the overloads - reference for details. -

-

- - init and optional -

-

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

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

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

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

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

-
-
-

-Auto-Overloading

-

- It was mentioned in passing in the previous section that BOOST_PYTHON_FUNCTION_OVERLOADS - and BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS can also be - used for overloaded functions and member functions with a common sequence - of initial arguments. Here is an example: -

-
void foo()
-{
-   /*...*/
-}
-
-void foo(bool a)
-{
-   /*...*/
-}
-
-void foo(bool a, int b)
-{
-   /*...*/
-}
-
-void foo(bool a, int b, char c)
-{
-   /*...*/
-}
-
-

- Like in the previous section, we can generate thin wrappers for these overloaded - functions in one-shot: -

-
BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3)
-
-

- Then... -

-
.def("foo", (void(*)(bool, int, char))0, foo_overloads());
-
-

- Notice though that we have a situation now where we have a minimum of zero - (0) arguments and a maximum of 3 arguments. -

-

- - Manual Wrapping -

-

- It is important to emphasize however that the overloaded - functions must have a common sequence of initial arguments. Otherwise, - our scheme above will not work. If this is not the case, we have to wrap - our functions manually. -

-

- Actually, we can mix and match manual wrapping of overloaded functions and - automatic wrapping through BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS - and its sister, BOOST_PYTHON_FUNCTION_OVERLOADS. Following - up on our example presented in the section on - overloading, since the first 4 overload functins have a common sequence - of initial arguments, we can use BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS - to automatically wrap the first three of the defs and - manually wrap just the last. Here's how we'll do this: -

-
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4)
-
-

- Create a member function pointers as above for both X::f overloads: -

-
bool    (X::*fx1)(int, double, char)    = &X::f;
-int     (X::*fx2)(int, int, int)        = &X::f;
-
-

- Then... -

-
.def("f", fx1, xf_overloads());
-.def("f", fx2)
-
-
-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/hello.html b/doc/tutorial/doc/html/python/hello.html deleted file mode 100644 index b78573826d..0000000000 --- a/doc/tutorial/doc/html/python/hello.html +++ /dev/null @@ -1,195 +0,0 @@ - - - -Building Hello World - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Building Hello World

-

- - From Start To Finish -

-

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

-
- - - - - -
[Note]Note
-

- Building without bjam -

-

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

-

- Take note however that the preferred build tool for Boost.Python is bjam. - There are so many ways to set up the build incorrectly. Experience shows - that 90% of the "I can't build Boost.Python" problems come from - people who had to use a different tool. -

-
-

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

-

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

-
    -
  • - hello.cpp -
  • -
  • - hello.py -
  • -
  • - Jamroot -
  • -
-

- The hello.cpp file is our C++ hello world example. The - Jamroot is a minimalist bjam script - that builds the DLLs for us. Finally, hello.py is our Python - program that uses the extension in hello.cpp. -

-

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

-

- - Let's Jam! -

-

- jam -

-

- Here is our minimalist - Jamroot file. Simply copy the file and tweak use-project boost - to where your boost root directory is and your OK. -

-

- The comments contained in the Jamrules file above should be sufficient to get - you going. -

-

- - Running bjam -

-

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

-

- Start it up. -

-

- A file called user-config.jam in your home directory is used to configure your - tools. In Windows, your home directory can be found by typing: -

-
ECHO %HOMEDRIVE%%HOMEPATH%
-
-

- into a command prompt window. Your file should at least have the rules for - your compiler and your python installation. A specific example of this on Windows - would be: -

-
#  MSVC configuration
-using msvc : 8.0 ;
-
-#  Python configuration
-using python : 2.4 : C:dev/tools/Python ;
-
-

- The first rule tells Bjam to use the MSVC 8.0 compiler and associated tools. - The second rule provides information on Python, its version and where it is - located. The above assumes that the Python installation is in C:dev/tools\/Python. - If you have one fairly "standard" python installation for your platform, - you might not need to do this. -

-

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

-

- Finally: -

-
bjam
-
-

- It should be building now: -

-
cd C:\dev\boost\libs\python\example\tutorial
-bjam
-...patience...
-...found 1101 targets...
-...updating 35 targets...
-
-

- And so on... Finally: -

-
Creating library path-to-boost_python.dll
-   Creating library /path-to-hello_ext.exp/
-**passed** ... hello.test
-...updated 35 targets...
-
-

- Or something similar. If all is well, you should now have built the DLLs and - run the Python program. -

-

- There you go... Have fun! -

-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/iterators.html b/doc/tutorial/doc/html/python/iterators.html deleted file mode 100644 index 9fb402b6b5..0000000000 --- a/doc/tutorial/doc/html/python/iterators.html +++ /dev/null @@ -1,187 +0,0 @@ - - - -Iterators - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Iterators

-

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

-

- C++ iterators: -

-
    -
  • - C++ has 5 type categories (random-access, bidirectional, forward, input, - output) -
  • -
  • - There are 2 Operation categories: reposition, access -
  • -
  • - A pair of iterators is needed to represent a (first/last) range. -
  • -
-

- Python Iterators: -

-
    -
  • - 1 category (forward) -
  • -
  • - 1 operation category (next()) -
  • -
  • - Raises StopIteration exception at end -
  • -
-

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

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

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

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

- Or for use in class_<>: -

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

- range -

-

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

-
    -
  • - range(start, finish) -
  • -
  • - range<Policies,Target>(start, finish) -
  • -
-

- Here, start/finish may be one of: -

-
    -
  • - member data pointers -
  • -
  • - member function pointers -
  • -
  • - adaptable function object (use Target parameter) -
  • -
-

- iterator -

-
  • - iterator<T, Policies>() -
-

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

-

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

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

- Now, our C++ Wrapper: -

-
class_<F>("Field")
-    .property("pions", range(&F::p_begin, &F::p_end))
-    .property("bogons", range(&F::b_begin, &F::b_end));
-
-

- stl_input_iterator -

-

- So far, we have seen how to expose C++ iterators and ranges to Python. Sometimes - we wish to go the other way, though: we'd like to pass a Python sequence to - an STL algorithm or use it to initialize an STL container. We need to make - a Python iterator look like an STL iterator. For that, we use stl_input_iterator<>. - Consider how we might implement a function that exposes std::list<int>::assign() to Python: -

-
template<typename T>
-void list_assign(std::list<T>& l, object o) {
-    // Turn a Python sequence into an STL input range
-    stl_input_iterator<T> begin(o), end;
-    l.assign(begin, end);
-}
-
-// Part of the wrapper for list<int>
-class_<std::list<int> >("list_int")
-    .def("assign", &list_assign<int>)
-    // ...
-    ;
-
-

- Now in Python, we can assign any integer sequence to list_int - objects: -

-
x = list_int();
-x.assign([1,2,3,4,5])
-
-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/object.html b/doc/tutorial/doc/html/python/object.html deleted file mode 100644 index 7bc2aa255d..0000000000 --- a/doc/tutorial/doc/html/python/object.html +++ /dev/null @@ -1,360 +0,0 @@ - - - -Object Interface - - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHomeNext -
-
-

-Object Interface

- -

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

-

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

-

- python -

-
-

-Basic Interface

-

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

-

- To illustrate, this Python code snippet: -

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

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

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

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

-
-
-

-Derived Object types

-

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

-
    -
  • - list -
  • -
  • - dict -
  • -
  • - tuple -
  • -
  • - str -
  • -
  • - long_ -
  • -
  • - enum -
  • -
-

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

-
str(1) ==> "1"
-
-

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

-
d.keys()
-
-

- make_tuple is provided for declaring tuple literals. - Example: -

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

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

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

- In finer detail: -

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

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

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

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

- -

- Python: -

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

- C++: -

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

- - class_<T> as objects -

-

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

-

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

-
object vec345 = (
-    class_<Vec2>("Vec2", init<double, double>())
-        .def_readonly("length", &Point::length)
-        .def_readonly("angle", &Point::angle)
-    )(3.0, 4.0);
-
-assert(vec345.attr("length") == 5.0);
-
-
-
-

-Extracting C++ objects

-

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

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

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

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

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

-

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

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

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

-
dict d = extract<dict>(x.attr("__dict__"));
-d["whatever"] = 3;          // modifies x.__dict__ !
-
-
-
-

-Enums

-

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

-
enum choice { red, blue };
-
-

- the construct: -

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

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

-
- - - - - -
[Note]Note
-

- what is a scope? -

-

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

-
-

- You can access those values in Python as -

-
>>> my_module.choice.red
-my_module.choice.red
-
-

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

-
scope in_X = class_<X>("X")
-                .def( ... )
-                .def( ... )
-            ;
-
-// Expose X::nested as X.nested
-enum_<X::nested>("nested")
-    .value("red", red)
-    .value("blue", blue)
-    ;
-
-
-
-

-Creating boost::python::object from PyObject* -

-

- When you want a boost::python::object to manage a pointer to PyObject* - pyobj one does: -

-
boost::python::object o(boost::python::handle<>(pyobj));
-
-

- In this case, the o object, - manages the pyobj, it won’t - increase the reference count on construction. -

-

- Otherwise, to use a borrowed reference: -

-
boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj)));
-
-

- In this case, Py_INCREF is - called, so pyobj is not destructed - when object o goes out of scope. -

-
-
- - - -
-
-
-PrevUpHomeNext -
- - diff --git a/doc/tutorial/doc/html/python/techniques.html b/doc/tutorial/doc/html/python/techniques.html deleted file mode 100644 index 34cfc44426..0000000000 --- a/doc/tutorial/doc/html/python/techniques.html +++ /dev/null @@ -1,440 +0,0 @@ - - - -General Techniques - - - - - - - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-PrevUpHome -
-
-

-General Techniques

- -

- Here are presented some useful techniques that you can use while wrapping code - with Boost.Python. -

-
-

-Creating Packages

-

- A Python package is a collection of modules that provide to the user a certain - functionality. If you're not familiar on how to create packages, a good introduction - to them is provided in the Python - Tutorial. -

-

- But we are wrapping C++ code, using Boost.Python. How can we provide a nice - package interface to our users? To better explain some concepts, let's work - with an example. -

-

- We have a C++ library that works with sounds: reading and writing various - formats, applying filters to the sound data, etc. It is named (conveniently) - sounds. Our library already has a neat C++ namespace hierarchy, - like so: -

-
sounds::core
-sounds::io
-sounds::filters
-
-

- We would like to present this same hierarchy to the Python user, allowing - him to write code like this: -

-
import sounds.filters
-sounds.filters.echo(...) # echo is a C++ function
-
-

- The first step is to write the wrapping code. We have to export each module - separately with Boost.Python, like this: -

-
/* file core.cpp */
-BOOST_PYTHON_MODULE(core)
-{
-    /* export everything in the sounds::core namespace */
-    ...
-}
-
-/* file io.cpp */
-BOOST_PYTHON_MODULE(io)
-{
-    /* export everything in the sounds::io namespace */
-    ...
-}
-
-/* file filters.cpp */
-BOOST_PYTHON_MODULE(filters)
-{
-    /* export everything in the sounds::filters namespace */
-    ...
-}
-
-

- Compiling these files will generate the following Python extensions: core.pyd, - io.pyd and filters.pyd. -

-
- - - - - -
[Note]Note

- The extension .pyd is used for python extension modules, - which are just shared libraries. Using the default for your system, like - .so for Unix and .dll for Windows, - works just as well. -

-

- Now, we create this directory structure for our Python package: -

-
sounds/
-    __init__.py
-    core.pyd
-    filters.pyd
-    io.pyd
-
-

- The file __init__.py is what tells Python that the directory - sounds/ is actually a Python package. It can be a empty - file, but can also perform some magic, that will be shown later. -

-

- Now our package is ready. All the user has to do is put sounds - into his PYTHONPATH - and fire up the interpreter: -

-
>>> import sounds.io
->>> import sounds.filters
->>> sound = sounds.io.open('file.mp3')
->>> new_sound = sounds.filters.echo(sound, 1.0)
-
-

- Nice heh? -

-

- This is the simplest way to create hierarchies of packages, but it is not - very flexible. What if we want to add a pure Python - function to the filters package, for instance, one that applies 3 filters - in a sound object at once? Sure, you can do this in C++ and export it, but - why not do so in Python? You don't have to recompile the extension modules, - plus it will be easier to write it. -

-

- If we want this flexibility, we will have to complicate our package hierarchy - a little. First, we will have to change the name of the extension modules: -

-
/* file core.cpp */
-BOOST_PYTHON_MODULE(_core)
-{
-    ...
-    /* export everything in the sounds::core namespace */
-}
-
-

- Note that we added an underscore to the module name. The filename will have - to be changed to _core.pyd as well, and we do the same - to the other extension modules. Now, we change our package hierarchy like - so: -

-
sounds/
-    __init__.py
-    core/
-        __init__.py
-        core.pyd
-    filters/
-        \_init__.py
-        filters.pyd
-    io/
-        \_init__.py
-        _io.pyd
-
-

- Note that we created a directory for each extension module, and added a __init__.py - to each one. But if we leave it that way, the user will have to access the - functions in the core module with this syntax: -

-
>>> import sounds.core._core
->>> sounds.core._core.foo(...)
-
-

- which is not what we want. But here enters the __init__.py - magic: everything that is brought to the __init__.py namespace - can be accessed directly by the user. So, all we have to do is bring the - entire namespace from _core.pyd to core/__init__.py. - So add this line of code to sounds/core/__init__.py: -

-
from _core import *
-
-

- We do the same for the other packages. Now the user accesses the functions - and classes in the extension modules like before: -

-
>>> import sounds.filters
->>> sounds.filters.echo(...)
-
-

- with the additional benefit that we can easily add pure Python functions - to any module, in a way that the user can't tell the difference between a - C++ function and a Python function. Let's add a pure - Python function, echo_noise, to the filters - package. This function applies both the echo and noise - filters in sequence in the given sound object. We create - a file named sounds/filters/echo_noise.py and code our - function: -

-
import _filters
-def echo_noise(sound):
-    s = _filters.echo(sound)
-    s = _filters.noise(sound)
-    return s
-
-

- Next, we add this line to sounds/filters/__init__.py: -

-
from echo_noise import echo_noise
-
-

- And that's it. The user now accesses this function like any other function - from the filters package: -

-
>>> import sounds.filters
->>> sounds.filters.echo_noise(...)
-
-
-
-

-Extending Wrapped Objects in Python

-

- Thanks to Python's flexibility, you can easily add new methods to a class, - even after it was already created: -

-
>>> class C(object): pass
->>>
->>> # a regular function
->>> def C_str(self): return 'A C instance!'
->>>
->>> # now we turn it in a member function
->>> C.__str__ = C_str
->>>
->>> c = C()
->>> print c
-A C instance!
->>> C_str(c)
-A C instance!
-
-

- Yes, Python rox. smiley -

-

- We can do the same with classes that were wrapped with Boost.Python. Suppose - we have a class point in C++: -

-
class point {...};
-
-BOOST_PYTHON_MODULE(_geom)
-{
-    class_<point>("point")...;
-}
-
-

- If we are using the technique from the previous session, Creating - Packages, we can code directly into geom/__init__.py: -

-
from _geom import *
-
-# a regular function
-def point_str(self):
-    return str((self.x, self.y))
-
-# now we turn it into a member function
-point.__str__ = point_str
-
-

- All point instances created from C++ will - also have this member function! This technique has several advantages: -

-
    -
  • - Cut down compile times to zero for these additional functions -
  • -
  • - Reduce the memory footprint to virtually zero -
  • -
  • - Minimize the need to recompile -
  • -
  • - Rapid prototyping (you can move the code to C++ if required without changing - the interface) -
  • -
-

- You can even add a little syntactic sugar with the use of metaclasses. Let's - create a special metaclass that "injects" methods in other classes. -

-
# The one Boost.Python uses for all wrapped classes.
-# You can use here any class exported by Boost instead of "point"
-BoostPythonMetaclass = point.__class__
-
-class injector(object):
-    class __metaclass__(BoostPythonMetaclass):
-        def __init__(self, name, bases, dict):
-            for b in bases:
-                if type(b) not in (self, type):
-                    for k,v in dict.items():
-                        setattr(b,k,v)
-            return type.__init__(self, name, bases, dict)
-
-# inject some methods in the point foo
-class more_point(injector, point):
-    def __repr__(self):
-        return 'Point(x=%s, y=%s)' % (self.x, self.y)
-    def foo(self):
-        print 'foo!'
-
-

- Now let's see how it got: -

-
>>> print point()
-Point(x=10, y=10)
->>> point().foo()
-foo!
-
-

- Another useful idea is to replace constructors with factory functions: -

-
_point = point
-
-def point(x=0, y=0):
-    return _point(x, y)
-
-

- In this simple case there is not much gained, but for constructurs with many - overloads and/or arguments this is often a great simplification, again with - virtually zero memory footprint and zero compile-time overhead for the keyword - support. -

-
-
-

-Reducing Compiling Time

-

- If you have ever exported a lot of classes, you know that it takes quite - a good time to compile the Boost.Python wrappers. Plus the memory consumption - can easily become too high. If this is causing you problems, you can split - the class_ definitions in multiple files: -

-
/* file point.cpp */
-#include <point.h>
-#include <boost/python.hpp>
-
-void export_point()
-{
-    class_<point>("point")...;
-}
-
-/* file triangle.cpp */
-#include <triangle.h>
-#include <boost/python.hpp>
-
-void export_triangle()
-{
-    class_<triangle>("triangle")...;
-}
-
-

- Now you create a file main.cpp, which contains the BOOST_PYTHON_MODULE - macro, and call the various export functions inside it. -

-
void export_point();
-void export_triangle();
-
-BOOST_PYTHON_MODULE(_geom)
-{
-    export_point();
-    export_triangle();
-}
-
-

- Compiling and linking together all this files produces the same result as - the usual approach: -

-
#include <boost/python.hpp>
-#include <point.h>
-#include <triangle.h>
-
-BOOST_PYTHON_MODULE(_geom)
-{
-    class_<point>("point")...;
-    class_<triangle>("triangle")...;
-}
-
-

- but the memory is kept under control. -

-

- This method is recommended too if you are developing the C++ library and - exporting it to Python at the same time: changes in a class will only demand - the compilation of a single cpp, instead of the entire wrapper code. -

-
- - - - - -
[Note]Note

- If you're exporting your classes with Pyste, - take a look at the --multiple option, that generates - the wrappers in various files as demonstrated here. -

-
- - - - - -
[Note]Note

- This method is useful too if you are getting the error message "fatal - error C1204:Compiler limit:internal structure overflow" - when compiling a large source file, as explained in the FAQ. -

-
-
- - - -
-
-
-PrevUpHome -
- - diff --git a/doc/tutorial/index.html b/doc/tutorial/index.html deleted file mode 100644 index 7924277724..0000000000 --- a/doc/tutorial/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - Automatic redirection failed, click this - link  
-

� Copyright Beman Dawes, 2001

-

Distributed under the Boost Software License, Version 1.0. (See - accompanying file - LICENSE_1_0.txt or copy at - www.boost.org/LICENSE_1_0.txt)

- - diff --git a/doc/v2/Apr2002.html b/doc/v2/Apr2002.html deleted file mode 100644 index 62350defa4..0000000000 --- a/doc/v2/Apr2002.html +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - - -Boost.Python - April 2002 Progress Report - - - - - - - -
-

-

-
-

Boost.Python

-

April 2002 Progress Report

-
-
-

Contents

-
-
Accomplishments
-
-
Arbitrary Arity Support
-
New Callback Interface
-
Call Policies for Construtors
-
Real Users, Real Bugs
-
New Insights
-
Boost.Python V1 Maintenance
-
- -
What's Missing
- -
- -

Accomplishments

- -April was a short month as far as Boost.Python was concerned, since -the spring ISO C++ Committee Meeting (and associated vacation) -occupied me for the 2nd half of the month. However, a suprising amount -of work got done... - -

Arbitrary Arity Support

- -I began using the Boost.Preprocessor -metaprogramming library to generate support for functions and member -functions of arbitrary arity, which was, to say the least, quite an -adventure. The feedback cycle resulting from my foray into -Boost.Preprocessor resulted in several improvements to the library, -most notably in its documentation. - -

- -Boost.Python now supports calls of up to 17 arguments on most -compilers. Because most EDG-based compilers have dismal preprocessor -performance, I had to "manually" expand the metaprograms for -arities from zero to fifteen arguments, and EDG-based compilers with -__EDG_VERSION__ <= 245 only support 15 -arguments by default. If some crazy program finds a need for more than -the default arity support, users can increase the base support by -setting the BOOST_PYTHON_MAX_ARITY preprocessor symbol. - -

New Callback Interface

- -I mentioned in last month's report that I -wasn't pleased with the interface for the interface for calling into -Python, so now it has been redesigned. The new interface is outlined -in this -message (though the GCC 2.95.3 bugs have been fixed). - -

Call Policies for Constructors

- -On April 2nd, I announced -support for the use of call policies with constructors. - -

Real Users, Real Bugs

- -At least two people outside of Kull began actually using Boost.Python -v2 in earnest this month. Peter Bienstman and Pearu Pearson both -provided valuable real-world bug reports that helped me to improve the -library's robustness. - -

New Insights

- -Answering some of Pearu's questions about explicitly converting -objects between Python and C++ actually led me to a new understanding -of the role of the current conversion facilities. In Boost.Python v1, -all conversions between Python and C++ were handled by a single family -of functions, called to_python() and -from_python(). Since the primary role of Boost.Python is -to wrap C++ functions in Python, I used these names for the first kind -of converters I needed: those that extract C++ objects to be used as -function arguments and which C++ function return values to -Python. The better-considered approach in Boost.Python v2 uses a -completely different mechanism for conversions used when calling -Python from C++, as in wrapped virtual function implementations. I -usually think of this as a "callback", as in "calling -back into Python", and I named the converters used in callbacks -accordingly: to_python_callback and -from_python_callback. However, as it turns out, the -behavior of the "callback" converters is the appropriate one -for users who want to explicitly extract a C++ value from a Python -object, or create a Python object from a C++ value. The upshot is that -it probably makes sense to change the name of the existing to_python and -from_python so those names are available for the -user-friendly explicit converters. - -

-Another -of Pearu's questions pushes momentum further in the direction of a -more-sophisticated overloading mechanism than the current -simple-minded "first match" approach, as I suggested last month. - -

Boost.Python V1 Maintenance

- -As much as I'm looking forward to retiring Boost.Python v1, a -significant amount of effort has been being spent dealing with support -problems; the saying that code rots when left alone is true, and -Boost.Python is no exception. Eventually it became obvious to me that -we were going to have to invest some effort in keeping V1 healthy -while working on V2. Ralf and I have expanded support for various -compilers and stabilized the V1 codebase considerably. We discarded -the obsolete Visual Studio projects which were causing so much -confusion. Still to do before the next Boost release: -
    -
  1. Update the build/test documentation with detailed instructions for -configuring various toolsets. -
  2. Provide some links to Boost.Python v2 to let people know what's -coming. -
- - -

What's Missing

- -Last month I announced that I would implement the following which are -not yet complete: -
    -
  1. Document all implemented features -
  2. Implement conversions for char types. This is -implemented but not tested, so we have to assume it doesn't work. -
- -These are my first priority for this month (especially the -documentation). - -

Revised - - 13 November, 2002 - -

-

© Copyright Dave Abrahams - 2002.

- - diff --git a/doc/v2/CallPolicies.html b/doc/v2/CallPolicies.html deleted file mode 100644 index 06384a23d9..0000000000 --- a/doc/v2/CallPolicies.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - - - - Boost.Python - CallPolicies Concept - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

CallPolicies Concept

-
-
- -
-
Introduction
- -
CallPolicies Composition
- -
Concept Requirements
- -
-
-
CallPolicies Concept
-
-
-
- -

Introduction

- -

Models of the CallPolicies concept are used to specialize the behavior - of Python callable objects generated by Boost.Python to wrapped C++ - objects like function and member function pointers, providing three - behaviors:

- -
    -
  1. precall - Python argument tuple management before the - wrapped object is invoked
  2. - -
  3. result_converter - C++ return value handling
  4. - -
  5. postcall - Python argument tuple and result management - after the wrapped object is invoked
  6. -
  7. extract_return_type - metafunction for extracting the return type from a given signature type sequence
  8. -
- -

CallPolicies Composition

- In order to allow the use of multiple models of CallPolicies in the same - callable object, Boost.Python's CallPolicies class templates provide a - chaining interface which allows them to be recursively composed. This - interface takes the form of an optional template parameter, - Base which defaults to default_call_policies. - By convention, the precall function of the Base - is invoked after the precall function supplied by the - outer template, and the postcall function of the - Base is invoked before the postcall - function of the outer template. If a result_converter is - supplied by the outer template, it replaces any - result_converter supplied by the Base. For an - example, see return_internal_reference. - - -

Concept Requirements

- -

CallPolicies Concept

- -

In the table below, x denotes an object whose type - P is a model of CallPolicies, a - denotes a PyObject* pointing to a Python argument tuple - object, and r denotes a PyObject* - referring to a "preliminary" result object.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ExpressionTypeResult/Semantics
x.precall(a)convertible to boolreturns false and PyErr_Occurred() != 0 - upon failure, true otherwise.
P::result_converterA model of ResultConverterGenerator.An MPL unary Metafunction - Class used produce the "preliminary" result object.
x.postcall(a, r)convertible to PyObject*0 0 and PyErr_Occurred() != 0 - upon failure. Must "conserve references" even in the event of an - exception. In other words, if r is not returned, its - reference count must be decremented; if another existing object is - returned, its reference count must be incremented.
P::extract_return_typeA model of Metafunction.An MPL unary Metafunction used extract the return type from a given signature. By default it is derived from mpl::front.
- Models of CallPolicies are required to be CopyConstructible. -
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave 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.

- - - diff --git a/doc/v2/Dereferenceable.html b/doc/v2/Dereferenceable.html deleted file mode 100644 index f7c53fd237..0000000000 --- a/doc/v2/Dereferenceable.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - -Boost.Python - Dereferenceable Concept - - - - - - - -
-

C++ Boost

-
-

Boost.Python

-

Dereferenceable Concept

-
-
-
-
Introduction
-
Concept Requirements
-
-
Dereferenceable Concept
-
-
- -

Introduction

- -

Instances of a Dereferenceable type can be used like a pointer to access an lvalue. - -

Concept Requirements

-

Dereferenceable Concept

- -

In the table below, T is a model of -Dereferenceable, and x denotes an object of -type T. In addition, all pointers are Dereferenceable. - - - - - - - - - - - - - - -
ExpressionResultOperational Semantics
get_pointer(x)convertible to pointee<T>::type* - &*x, or a null pointer -
- -


-

Revised - - 18 December, 2003 - -

-

© Copyright Dave - Abrahams 2002-2003. - -

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. - - diff --git a/doc/v2/Extractor.html b/doc/v2/Extractor.html deleted file mode 100644 index 441ca38b39..0000000000 --- a/doc/v2/Extractor.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - -Boost.Python - Extractor Concept - - - - - - - -
-

C++ Boost

-
-

Boost.Python

-

Extractor Concept

-
-


-
-
Introduction
-
Concept Requirements
-
-
Extractor Concept
-
-
Notes
-
- -

Introduction

- -

An Extractor is a class which Boost.Python can use to extract C++ -objects from Python objects, and is typically used by facilities that -define from_python conversions for -"traditional" Python extension types. - -

Concept Requirements

-

Extractor Concept

- -

In the table below, X denotes a model of -Extractor and a denotes an instance of a Python -object type. - - - - - - - - - - - - - - - - - - -
ExpressionTypeSemantics
X::execute(a)non-void - Returns the C++ object being extracted. The - execute function must not be overloaded. -
&a.ob_type - PyTypeObject** - Points to the ob_type field of an object which is - layout-compatible with PyObject -
- -

Notes

- -Informally, an Extractor's execute member must be a -non-overloaded static function whose single argument is a Python -object type. Acceptable Python object types include those publicly (and -unambiguously) derived from PyObject, and POD types which -are layout-compatible with PyObject. - -
-

Revised - - 13 November, 2002 - -

-

© Copyright Dave - 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. - - diff --git a/doc/v2/HolderGenerator.html b/doc/v2/HolderGenerator.html deleted file mode 100644 index 58b4265af8..0000000000 --- a/doc/v2/HolderGenerator.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - -Boost.Python - Holder Concept - - - - - - - -
-

C++ Boost

-
-

Boost.Python

-

HolderGenerator Concept

-
-


-
-
Introduction
-
Concept Requirements
-
-
HolderGenerator Concept
-
-
- -

Introduction

- -

A HolderGenerator is a unary metafunction class which returns types -suitable for holding instances of its argument in a wrapped C++ class -instance. - -

Concept Requirements

-

HolderGenerator Concept

- -

In the table below, G denotes an type which -models HolderGenerator, and X denotes a class -type. - - - - - - - - - - - -
ExpressionRequirements
G::apply<X>::typeA concrete subclass of instance_holder - which can hold objects of type X. -
- -


-

Revised - - 13 November, 2002 - -

-

© Copyright Dave - 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. - - diff --git a/doc/v2/Jun2002.html b/doc/v2/Jun2002.html deleted file mode 100644 index db1fc25c62..0000000000 --- a/doc/v2/Jun2002.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - -Boost.Python - June 2002 Progress Report - - - - - - - -
-

-

-
-

Boost.Python

-

June 2002 Progress Report

-
-


-

Contents

-
-
Introduction
-
handle<T>
-
object
-
-
object operators
-
object conversions
-
-
list
-
Numerics
-
Community
-
What's Next
-
- -

Introduction

- -July was mostly focused on allowing expressive manipulation of -individual Python objects, or what Ralf Grosse-Kunstleve calls -"Writing Python in C++". The work began with this posting, -which outlines the issues and intention. - -

handle<T>

- -The most basic element needed was a replacement for the -reference<> class template and the -ref typedef from Boost.Python v1, a simple smart -pointer to a Python object. The old v1 typedef -"ref" (for -reference<PyObject>) had to be retired because I -thought it would be too confusing given the importance of boost::ref() to this -library. I began a discussionof -possible names, and it was eventually decided -to rename reference to handle and supply a -default argument so that ref could be spelled -handle<> without an additional typedef. There -were also some interface changes to make it safer and more-efficient -to interface with the raw -PyObject*s forced on us by Python's 'C' API. A -discussion of those protocols can be found here. - -

object

- -It is intended that users will seldom need or want to work with -handle<>; its major distinguishing features are -that it gives direct access to the underlying object representation -through operator* and operator->, and -that can be NULL, both sources of danger. Instead the -library provides a class called object, which -encapsulates a valid Python object and provides a similar interface to -Python's. - -

object operators

- -The first challenge was to provide support for object manipulations -using a Python-like syntax, mostly in the form of operator overloads: - - - - - - - - - - - - - -
Python C++ - -
y = x.foo y = x.attr("foo"); -
x.foo = 1 x.attr("foo") = 1; - -
y = x[z] y = x[z]; -
x[z] = 1 x[z] = 1; - -
y = x[3:-1] y = x.slice(3,-1); - -
y = x[3:] y = x.slice(3,_); - -
y = x[:-2] y = x.slice(_,-2); - -
z = x(1, y) z = x(1, y); -
z = x.f(1, y) z = x.attr("f")(1, y); - -
not x !x - -
x and y x and y -
- -I'm still a unsatisfied with the interface for attribute access. There -original proposal used a syntax like this one: -
-y = x._("foo"); 
-x._("foo") = 1; 
-
- -which was only marginally better than what we've got. Niki Spahiev -then pointed -out a potential conflict with the macro which GNU Gettext suggests -people define. This unfortunate state of affairs forced us into using -attr instead. I'd still like to find a better interface, -but the lack of overloadable C++ operators which aren't already used -in Python is an obstacle. The comma operator is still a possibility, -but it has the wrong precedence: -
-y = x,"foo"    // error
-x,"foo" = 1;   // error
-
-y = (x,"foo"); // ok
-(x,"foo") = 1; // ok
-
- -Well, I guess we could consider adding that to the interface without -removing attr(), to see how it plays out... - -

object conversions

- -The object class also provided an opportunity to replace -Boost.Python v1's to_python() as a user-level -interface. Instead, object has a templated constructor -which can be used to convert any C++ object to Python using the same -underlying mechanisms used for the arguments to call<>. - -

Incidentally, the implementation of operator and conversion support -for object uncovered an inordinate number of compiler bugs in our -targeted platforms. It was a lot more "interesting" than it -should have been. - -

list

- -With object implemented, it was time to begin replacing -the ad-hoc implementations of list, string, -and dictionary supplied by Boost.Python v1 with something -more robust. I started with list as an example. Because -object already provides all of the requisite operators, -publicly deriving list from object seemed like a good -choice. The remaining issues were what do do about the one-argument -list constructor (which in Python attempts to convert its argument to -a list), and how to deal converting with list arguments -to wrapped functions. Some of the issues are laid out in this -thread. Ultimately, it was decided that list(x) -should do the same thing in C++ as in Python (conversion), while -list arguments should only match Python -lists (and list subclasses). The -implementation worked well, and provided a roadmap -for the protocol to be used for implementation of the other built-in -types. - -

Numerics

- -Support for C++ long long and unsigned long -long -(and __int64 on MSVC) to/from python conversions was -added this month. We also improved handling of numeric overflows when -converting, e.g., a Python int to a type with a more limited range of -representation. - -

Community

- - - -Deep thanks to all the Boost.Python contributors! This project -wouldn't be possible without your participation. - -

What's Next

- -As I write this we are already well into the month of July, so I -suggest you consult the Mailing -List Archive if you want to know what's been happening. Otherwise -you'll just have to wait till next month (hopefully the beginning). - -

Revised - - 13 November, 2002 - -

-

© Copyright Dave Abrahams - 2002.

- - diff --git a/doc/v2/Mar2002.html b/doc/v2/Mar2002.html deleted file mode 100644 index 97444d2290..0000000000 --- a/doc/v2/Mar2002.html +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - -Boost.Python - March 2002 Progress Report - - - - - - - -
-

-

-
-

Boost.Python

-

March 2002 Progress Report

-
-
-

Contents

-
-
Accomplishments
-
-
Calling Python from C++
-
Virtual Functions
-
Abstract Classes
-
C++ Implicit Conversions
-
C++ Data Members
-
Miscellaneous
-
- -
The Near future
- -
Notes
- -
- -

Accomplishments

- -March was mostly devoted to the reimplementation of features from -Boost.Python v1, and some new features. Re-examination of the features -from Boost.Python v1 allowed me to make significant improvements. - -

Calling Python from C++

- -The ability to call Python from C++ is crucial for virtual function -support. Implementing this feature well for V2 proved to be more -interesting than I expected. You can review most of the relevant -design decisions -here. - -

-One point which isn't emphasized in that document is that there -are subtle differences in the way from_python conversions -work when used for C++ function arguments and Python function return -values. In particular, while T const& arguments may -invoke rvalue converters, a reference-to-const return value requires -an lvalue converter, since a temporary conversion result would leave -the returned reference dangling. - -

I'm not particularly pleased with the current callback interface, -since it usually results in constructs like: -

-return returning<X&>::call(f, obj);
-
-However, I think the following may be possible and I plan to investigate: -
-return apply<X&>(f, obj);
-
-I'm open to suggestion for better names (and syntaxes)! - -

Virtual Functions

- -Once Python callbacks were implemented, it was just a short step to -implementing virtual functions. Python extension class exposing a C++ -class whose virtual functions are overridable in Python must actually -hold a C++ instance of a class derived from the one exposed to -Python. Needing some way for users to specify that class, I added an -optional template argument to value_holder_generator and -pointer_holder_generator<> to specify the class -actually held. This move began to put pressure on the -class_<> interface, since the need for the user to -produce complicated instantations of -class_<> was increased: - -
-class<Foo, bases<>, value_holder_generator<Foo_callback> >("Foo")
-.def("hello", &Foo::hello)
-...
-
- -

Abstract Classes

- -Normally when a C++ class is exposed to Python, the library registers -a conversion function which allows users to wrap functions returning -values of that type. Naturally, these return values are temporaries, -so the conversion function must make a copy in some -dynamically-allocated storage (a "holder") which is managed -by the corresponding Python object. - -

Unfortunately, in the case of abstract classes (and other types -without a publicly-accessible copy constructor), instantiating this -conversion function causes a compilation error. In order to support -non-copyable classes, there had to be some way to prevent the library -from trying to instantiate the conversion function. The only practical -approach I could think of was to add an additional template parameter -to the class_<> interface. When the number of -template parameters with useful defaults begins to grow, it is often -hard to choose an order which allows users to take advantage of the -defaults. - -

- -This was the straw that broke the -class_<> interface's back and caused the redesign -whose outcome is detailed here. -The approach allows the user to supply the optional parameters in an -arbitrary order. It was inspired by the use of named -template parameters in the Boost Iterator Adaptor -Library, though in this case it is possible to deduce the meaning -of the template parameters entirely from their type properties, -resulting in a simpler interface. Although the move from a -policy-based design to what resembles a configuration DSL usually -implies a loss of flexibility, in this case I think any costs are far -outweighed by the advantages. - -

Note: working around the limitations of the various compilers I'm -supporting was non-trivial, and resulted in a few messy implementation -details. It might be a good idea to switch to a more-straightforward -approach once Metrowerks CodeWarrior Pro8 is released. - -

C++ Implicit Conversions

- -Support for C++ implicit conversion involves creating -from_python converters for a type U which in -turn use from_python converters registered for a type -T where there exists a implicit conversion from -T to U. The current implementation is -subject to two inefficiencies: -
    - -
  1. Because an rvalue from_python converter produces two -pieces of data (a function and a void*) from its -convertible() function, we end up calling the function -for T twice: once when the converter is looked up in the -registry, and again when the conversion is actually performed. - -
  2. A vector is used to mark the "visited" converters, preventing -infinite recursion as T to -U and U to T converters -continually search through one-another. - -
- -I consider the former to be a minor issue. The second may or may not -prove to be computationally significant, but I believe that -architecturally, it points toward a need for more sophisticated -overload resolution. It may be that we want CLOS-style multimethod -dispatching along with C++ style rules that prevent more than one -implicit conversion per argument. - -

C++ Data Members

- -To supply the ability to directly access data members, I was able to -hijack the new Python property -type. I had hoped that I would also be able to re-use the work of make_function to create callable python -objects from C++ functions which access a data member of a given -class. C++ facilities for specifying data member pointer non-type -template arguments require the user to explicitly specify the type of -the data member and this under-utilized feature is also not -well-implemented on all compilers, so passing the member pointer as a -runtime value is the only practical approach. The upshot is that any -such entity would actually have to be a function object, and I -haven't implemented automatic wrapping of C++ callable function -objects yet, so there is less re-use in the implementation than I'd -like. I hope to implement callable object wrapping and refactor this -code one day. I also hope to implement static data member support, -for which Python's property will not be an appropriate descriptor. - -

Miscellaneous

-
    -
  • Moved args<> and bases<> from unnamed namespace to boost::python in their own header files. -
  • Convert NULL pointers returned from wrapped C++ functions to None. -
  • Improved some compile-time error checks. -
  • Eliminated boost/python/detail/eval.hpp in favor of -more-general boost/mpl/apply.hpp. -
  • General code cleanup and refactoring. -
  • Works with Microsoft Visual C++ 7.0 -
  • Warning suppression for many compilers -
  • Elegant interface design for exporting enum types. -
-
- -

The Near Future

- -Before April 15th I plan to -
    -
  1. Document all implemented features -
  2. Implement a CallPolicy interface for constructors of wrapped -classes -
  3. Implement conversions for char types. -
  4. Implement automated code generation for all headers containing -families of overloaded functions to handle arbitrary arity. -
- -I also hope to implement a mechanism for generating conversions -between arbitrary Python sequences and C++ containers, if time permits -(and others haven't already done it)! - -

Notes

- -The older version of KCC used by Kull is generating lots of warnings -about a construct I use to instantiate static members of various class -templates. I'm thinking of moving to an idiom which uses a function -template to suppress it, but worry about bloating the size of debug -builds. Since KCC users may be moving to GCC, I'm not sure that it's -worth doing anything about it. - -

Revised - - 13 November, 2002 - -

-

© Copyright Dave Abrahams - 2002.

- - diff --git a/doc/v2/May2002.html b/doc/v2/May2002.html deleted file mode 100644 index 5e5b6aaa4b..0000000000 --- a/doc/v2/May2002.html +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - - -Boost.Python - May 2002 Progress Report - - - - - - - -
-

-

-
-

Boost.Python

-

May 2002 Progress Report

-
-
-

Contents

-
-
Introduction
-
New Features
-
-
Shared Library Support for AIX
-
Class Enhancements
-
-
Operators
-
Iterators
-
Properties
-
setattr
-
__module__ Attribute
-
-
back_reference
-
- -
Documentation
-
Miscellaneous
-
-
Converters
-
Checkins Mailing List
-
Shared Libraries
-
- -
What's Next
-
- -

Introduction

- -Aside from library development, work on Boost.Python in May was -focused on reducing the support burden. In recent weeks, responding to -requests for support, espcially surrounding building the library, had -begun to impede progress on development. There was a major push to -release a stable 1.28.0 of Boost, including documentation of Boost.Build and specific -instructions for building Boost.Python -v1. The documentation for Boost.Python v2 was also updated as -described here. - -

New Features

- -

Shared Library Support for AIX

- - The Kull group required the ability to build and test Boost.Python - extensions on AIX, a platform with "creatively designed" - shared library semantics. Making this work was a multi-pronged - effort, involving changes to Boost.Build and some great research by - Martin Casado which uncovered the key mechanism required to allow - shared libraries to use functions from the Python executable. The - current solution used in Boost.Build relies on a Python - Script as part of the build process. This is not a problem for - Boost.Python, as Python will be available. However, the commands - issued by the script are so simple that a 100%-pure-Boost.Jam - solution is surely possible. Linking on AIX is sufficiently - interesting to have skewed the Boost.Python development schedule a - bit. - -

Class Enhancements

- -

Operators

- -Support for exposing C++ operators and functions as the corresponding -Python special methods was added. Thinking that the Boost.Python -v1 interface was a little too esoteric (especially the use of -left_operand<...>/right_operand<...> for -asymmetric operands), I introduced a simple form of expression -templates which allow users to simply write the expressions that -should be wrapped, as in this example. - -

Iterators

- -Python iterator support as required by the Kull project resulted in a -highly flexible interface allowing: - -
- -
Direct exposure of a class' begin() and -end() functions: - -
-    ...
-    .def("__iter__", iterator<list_int>())
-
-
- -
Creation of iterators from member functions... -
-    ...
-    .def("__iter__"
-         , range(&my_class::x_begin, &my_class::x_end))
-    )
-
-
- -
...and member data: -
-    ...
-    .def("__iter__"
-         , range(&std::pair<char*,char*>::first, &std::pair<char*,char*>::second))
-    )
-
-
- -
The ability to specify CallPolicies, e.g. to prevent copying of -heavyweight values: - -
-    ...
-    .def("__iter__", 
-         , range<return_value_policy<copy_non_const_reference> >(
-               &my_sequence<heavy>::begin
-             , &my_sequence<heavy>::end))
-
-
- -
- -

Properties

- -The Kull iteration interfaces also required the ability to iterate -over a sequence specified by an instance's attribute: -
->>> f = field()
->>> for e in f.elements:
-...     print e,
-
- -This forced the exposure of the property - interface used internally to implement the data member exposure - facility described in March. Properties are an - incredibly useful idiom, so it's good to be able to provide them - at little new development cost. - -

setattr

- -class_<> acquired a setattr member -function which allows users to easily add new Python objects as class -attributes. - -

__module__ Attribute

- -Ralf Grosse-Kunstleve has been working on pickling support for v2. To -make it work correctly, he had to make sure that a class' -__module__ attribute was set correctly. - -

back_reference

- -The new back_reference<T> template can be used as a -function parameter when the user needs access to both a T -argument and to the Python object which manages it. The function will -only match in the overload resolution process if it would match the -same function signature with T substituted for -back_reference<T>. This feature is not yet -documented. - -

Documentation

- -In a major effort to prepare Boost.Python v2 to replace v1, many pages -of new reference documentation were added: - -
- -
-
CallPolicies.html
-
Dereferenceable.html
-
Extractor.html
-
HolderGenerator.html
-
ResultConverter.html
-
call_method.html
-
callbacks.html
-
data_members.html
-
has_back_reference.html
-
implicit.html
-
instance_holder.html
-
operators.html
-
ptr.html
-
type_id.html
-
with_custodian_and_ward.html
-
- -
-Major updates were made to the following pages: - - -
-
-
call.html
updated
-
class.html
-
reference.html
-
-
- - As usual, careful documentation forces one to consider the - interface again, and there were many interface changes - associated with this effort, including the elevation of the - following components from implementation detail to - first-class library citizen: - -
-
-
type_id.hpp
-
pointee.hpp
-
lvalue_from_pytype.hpp
- -
- -

Miscellaneous

- -

Converters

- -It appears that the world of C++ <==> Python conversion rules is -an endlessly-rich area of exploration. Completing the conversions for -char and char const* types, as described at -the end of April's report, -uncovered some interesting new shades to the problem. It turns out to -be worth distinguishing mutable and immutable lvalue conversions, -because despite the fact that Python doesn't understand -const, it does understand immutability (c.f. Python -strings, which expose an immutable char pointer). It is -also worth recognizing types which represent lvalue sequences, -to prevent Python "foobar" from being silently -truncated to C++ 'f'. More details on this insight can be -found in the mailing list -archive. I don't plan to do anything about this immediately, but I -do think it's the right direction to go in the long run. - -

Checkins Mailing List

- -In order to better coordinate changes made by multiple developers, I -enabled syncmail -for the Boost.Python CVS trees, and established an associated mailing -list. Subscribe to this list to receive notices of each new -checkin. - -

Shared Libraries

- -Beyond the vagaries of dynamic linking on AIX, I have been -participating in a more-general discussion of dynamic linking for -C++. Needless to say, C++ dynamic linking is of critical importance to -Boost.Python: all extension modules are normally built as shared -libraries, and Boost.Python extension modules share a common library -as well. - -In fact, there are at least two separate conversations. One -in the C++ standard extensions mailing list concerns what can be -standardized for C++ and shared libraries; the other, mostly on the gcc mailing list, concerns the -behavior of GCC on Posix/ELF platforms. - -Some of the GCC threads are here: - -
-http://gcc.gnu.org/ml/gcc/2002-05/msg02002.html
-http://gcc.gnu.org/ml/gcc/2002-05/msg02945.html
-http://gcc.gnu.org/ml/gcc/2002-05/msg01758.html -
- -

What's Next

- -Development is focused on what's needed to be able to retire -Boost.Python v1. At the moment, that means deciding the user-friendly -interfaces for to_/from_python conversion, and formally exposing the -Python object smart pointers and object wrapper classes. Quite a few -questions have also been showing up recently about how to embed Python -with Boost.Python, and how to link with it statically; the solutions -to these issues will probably have to be formalized before long. - -

Revised - - 13 November, 2002 - -

-

© Copyright Dave Abrahams - 2002.

- - diff --git a/doc/v2/ObjectWrapper.html b/doc/v2/ObjectWrapper.html deleted file mode 100644 index 7962e69fa5..0000000000 --- a/doc/v2/ObjectWrapper.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - Boost.Python - ObjectWrapper Concept - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

ObjectWrapper and TypeWrapper Concepts

-
-
- -
-
Introduction
- -
Concept Requirements
- -
-
-
ObjectWrapper Concept
- -
TypeWrapper Concept
-
-
- -
Caveat
-
- -

Introduction

- -

This page defines two concepts used to describe classes which manage a - Python objects, and which are intended to support usage with a - Python-like syntax.

- -

Concept Requirements

- -

ObjectWrapper Concept

- Models of the ObjectWrapper concept have object as a publicly-accessible base class, - and are used to supply special construction behavior and/or additional - convenient functionality through (often templated) member functions. - Except when the return type R is itself an TypeWrapper, a member function invocation of - the form -
-x.some_function(a1, a2,...an)
-
- always has semantics equivalent to: -
-extract<R>(x.attr("some_function")(object(a1), object(a2),...object(an)))()
-
- When the R is an TypeWrapper, the result type may be - constructed by taking direct posession of: -
-x.attr("some_function")(object(a1), object(a2),...object(an)).ptr()
-
- [see caveat below] - -

TypeWrapper Concept

- TypeWrapper is a refinement of ObjectWrapper which is associated with a - particular Python type X. For a given TypeWrapper - T, a valid constructor expression -
-T(a1, a2,...an)
-
- builds a new T object managing the result of invoking - X with arguments corresponding to -
-object(a1), object(a2),...object(an)
-
- -When used as arguments to wrapped C++ functions, or as the template -parameter to extract<>, only -instances of the associated Python type will be considered a match. - -

Caveat

- The upshot of the special member function invocation rules when the - return type is a TypeWrapper is that it is possible for the returned - object to manage a Python object of an inappropriate type. This is not - usually a serious problem; the worst-case result is that errors will be - detected at runtime a little later than they might otherwise be. For an - example of how this can occur, note that the dict member function items - returns an object of type list. Now suppose the user defines this - dict subclass in Python: -
->>> class mydict(dict):
-...     def items(self):
-...         return tuple(dict.items(self)) # return a tuple
-
- Since an instance of mydict is also an instance of - dict, when used as an argument to a wrapped C++ function, - boost::python::dict can - accept objects of Python type mydict. Invoking - items() on this object can result in an instance of boost::python::list which actually - holds a Python tuple. Subsequent attempts to use list methods (e.g. - append, or any other mutating operation) on this object will - raise the same exception that would occur if you tried to do it from - Python. -
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/ResultConverter.html b/doc/v2/ResultConverter.html deleted file mode 100644 index be53a9b974..0000000000 --- a/doc/v2/ResultConverter.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - -Boost.Python - ResultConverter Concept - - - - - - - -
-

C++ Boost

-
-

Boost.Python

-

ResultConverter Concept

-
-
-
-
Introduction
-
Concept Requirements
-
-
-
ResultConverter Concept
-
ResultConverterGenerator Concept
-
-
-
- -

Introduction

- -

A ResultConverter for a type T is a type whose -instances can be used to convert C++ return values of type -T to_python. A ResultConverterGenerator is -an MPL unary metafunction class which, given the return type of a C++ -function, returns a ResultConverter for that type. ResultConverters in -Boost.Python generally inspect library's registry of converters to -find a suitable converter, but converters which don't use the registry -are also possible. - -

Concept Requirements

-

ResultConverter Concept

- -

In the table below, C denotes a ResultConverter -type for a type R , c denotes -an object of type C , and r -denotes an object of type R. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ExpressionTypeSemantics
C c; - Constructs a C object. -
c.convertible()convertible to boolfalse iff no conversion from any R value - to a Python object is possible.
c(r)convertible to PyObject*A pointer to a Python object corresponding to r, - or 0 iff r could not be converted - to_python, in which case PyErr_Occurred - should return non-zero.
c.get_pytype()PyTypeObject const*A pointer to a Python Type object corresponding to result of the conversion, - or 0. Used for documentation generation. If 0 is returned - the generated type in the documentation will be object .
- -

ResultConverterGenerator Concept

-

In the table below, G denotes a -ResultConverterGenerator type and R denotes a possible -C++ function return type. - - - - - - - - - -
ExpressionRequirements
G::apply<R>::typeA ResultConverter type for R.
- -


-

Revised - - 09 May, 2002 - -

-

© Copyright Dave - 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. - - diff --git a/doc/v2/acknowledgments.html b/doc/v2/acknowledgments.html deleted file mode 100644 index 28f1b1dbde..0000000000 --- a/doc/v2/acknowledgments.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - Boost.Python - Acknowledgments - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Acknowledgments

-
-


- -

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

- -

Brett Calcott - contributed and maintains the Visual Studio project files and - documentation.

- -

Gottfried - Gan�auge supplied support for opaque pointer conversions, - complete with documentation and a regression test (and I didn't - even have to ask him for those)! - -

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.

- -

Aleksey Gurtovoy - wrote an incredible C++ Template - Metaprogramming Library which allows Boost.Python to perform much of - its compile-time magic. In addition, Aleksey very generously contributed - his time and deep knowledge of the quirks of various buggy compilers to - help us get around problems at crucial moments.

- -

Paul Mensonides, - building on the work Vesa - Karvonen, wrote a similarly amazing Preprocessor Metaprogramming - Library, and generously contributed the time and expertise to get it - working in the Boost.Python library, rewriting much of Boost.Python to - use the new preproccessor metaprogramming constructs and helping us to - work around buggy and slow C++ preprocessors.

- -

Bruno da Silva de - Oliveira contributed the ingenious Pyste ("Pie-Steh") - code generator. - -

Nikolay Mladenov contributed - staticmethod support.

- -

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

- -

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.

- -

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 had independently developed a similar system. When he - discovered Boost.Python v1, he generously contributed countless hours of - coding and much insight into improving it. He is responsible for an early - version of the support for function overloading and wrote the support for - reflecting C++ inheritance relationships. He has helped to improve - error-reporting from both Python and C++ (we hope to do as well in v2 - again soon), and has designed the original support for exposing numeric - operators, including a way to avoid explicit coercion by means of - overloading.

- -

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 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 - - 26 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/args.html b/doc/v2/args.html deleted file mode 100644 index e04720b7e5..0000000000 --- a/doc/v2/args.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/args.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/args.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
keyword-expressions
- -
Classes
- -
-
-
class arg
- -
-
-
class arg - synopsis
- -
class arg - constructor
- -
class arg template - operator =
-
-
-
-
- -
Keyword-expression - operator ,
- -
Functions (deprecated)
- -
-
-
args(...)
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Supplies a family of overloaded functions for specifying argument - keywords for wrapped C++ functions.

- -

keyword-expressions

- -

A keyword-expression results in an object which holds a - sequence of ntbses, and whose type - encodes the number of keywords specified. The keyword-expression - may contain default values for some or all of the keywords it holds

- -

Classes

- -

class arg;

- -

The objects of class arg are keyword-expressions holding one keyword ( - size one )

- -

Class arg synopsis

-
-namespace boost { namespace python
-{
-        struct arg 
-        {
-          template <class T>
-                  arg &operator = (T const &value);
-          explicit arg (char const *name){elements[0].name = name;}
-        };
-
-}}
-
- -

Class arg constructor

-
-arg(char const* name);
-
- -
-
Requires: The argument must be a ntbs.
- -
Effects: Constructs an arg object holding a - keyword with name name.
-
- -

Class arg operator =

-
-template <class T> arg &operator = (T const &value);
-
- -
-
Requires: The argument must convertible to python.
- -
Effects: Assigns default value for the keyword.
- -
Returns: Reference to this.
-
- -

Keyword-expression - operator ,

-
-      keyword-expression operator , (keyword-expression, const arg &kw) const
-      keyword-expression operator , (keyword-expression, const char *name) const;
-
- -
-
Requires: The argument name must be a ntbs.
- -
Effects: Extends the keyword-expression argument with - one more keyword.
- -
Returns: The extended keyword-expression.
-
- -

Functions - (deprecated)

- -

args(...)

-
-  unspecified1 args(char const*);
-    unspecified2 args(char const*, char const*);
-       .
-       .
-       .
-    unspecifiedN args(char const*, char const*, ... char const*);
-
-
- -
-
Requires: Every argument must be a ntbs.
- -
Returns: an object representing a keyword-expression encapsulating - the arguments passed.
-
- -

Example

-
-#include <boost/python/def.hpp>
-using namespace boost::python;
-
-int f(double x, double y, double z=0.0, double w=1.0);
-
-BOOST_PYTHON_MODULE(xxx)
-{
-   def("f", f
-            , ( arg("x"), "y", arg("z")=0.0, arg("w")=1.0 ) 
-            );
-}
-
- -

Revised 01 August, 2003

- -

© Copyright Dave Abrahams 2002-2003.

- - - diff --git a/doc/v2/call.html b/doc/v2/call.html deleted file mode 100644 index adba2b5fe8..0000000000 --- a/doc/v2/call.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - -Boost.Python - <call.hpp> - - - - - - - -
-

-

-
-

Boost.Python

-

Header <call.hpp>

-
-
-

Contents

-
-
Introduction
-
Functions
-
-
call
-
- -
Example(s)
- -
-
-

Introduction

-

- <boost/python/call.hpp> defines the call family of overloaded function - templates, used to invoke Python callable objects from C++. - -

Functions

-
-template <class R, class A1, class A2, ... class An>
-R call(PyObject* callable, A1 const&, A2 const&, ... An const&)
-
-
-
Requires: R is a pointer type, reference - type, or a complete type with an accessible copy constructor
- -
Effects: Invokes callable(a1, a2, ...an) in - Python, where a1...an are the arguments to - call(), converted to Python objects. -
Returns: The result of the Python call, converted to the C++ type R.
- - -
Rationale: For a complete semantic description and - rationale, see this page. -
-
- -

Example(s)

- -The following C++ function applies a Python callable object to its two -arguments and returns the result. If a Python exception is raised or -the result can't be converted to a double, an exception -is thrown. - -
-double apply2(PyObject* func, double x, double y)
-{
-   return boost::python::call<double>(func, x, y);
-}
-
- -

Revised - - 9 May, 2002 - -

-

© Copyright Dave Abrahams - 2002.

- - diff --git a/doc/v2/call_method.html b/doc/v2/call_method.html deleted file mode 100644 index e54ffb26aa..0000000000 --- a/doc/v2/call_method.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - Boost.Python - <call_method.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <call_method.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
call_method
-
-
- -
Example(s)
-
-
- -

Introduction

- -

<boost/python/call_method.hpp> defines the call_method family of overloaded - function templates, used to invoke callable attributes of Python objects - from C++.

- -

Functions

-
-template <class R, class A1, class A2, ... class An>
-R call_method(PyObject* self, char const* method, A1 const&, A2 const&, ... An const&)
-
- -
-
Requires: R is a pointer type, reference type, - or a complete type with an accessible copy constructor
- -
Effects: Invokes - self.method(a1, a2, ...an) in - Python, where a1...an are the - arguments to call_method(), converted to Python objects. - For a complete semantic description, see this - page.
- -
Returns: The result of the Python call, converted to the C++ - type R.
- -
Rationale: call_method is critical to - implementing C++ virtual functions which are overridable in Python, as - shown by the example below.
-
- -

Example(s)

- The following C++ illustrates the use of call_method in - wrapping a class with a virtual function that can be overridden in - Python: - -

C++ Module Definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/utility.hpp>
-#include <cstring>
-
-// class to be wrapped
-class Base
-{
- public:
-   virtual char const* class_name() const { return "Base"; }
-   virtual ~Base();
-};
-
-bool is_base(Base* b)
-{
-   return !std::strcmp(b->class_name(), "Base");
-}
-
-// Wrapper code begins here
-using namespace boost::python;
-
-// Callback class
-class Base_callback : public Base
-{
- public:
-   Base_callback(PyObject* self) : m_self(self) {}
-
-   char const* class_name() const { return call_method<char const*>(m_self, "class_name"); }
-   char const* Base_name() const { return Base::class_name(); }
- private:
-   PyObject* const m_self;
-};
-
-using namespace boost::python;
-BOOST_PYTHON_MODULE(my_module)
-{
-    def("is_base", is_base);
-
-    class_<Base,Base_callback, noncopyable>("Base")
-        .def("class_name", &Base_callback::Base_name)
-        ;
-
-}
-
- -

Python Code

-
->>> from my_module import *
->>> class Derived(Base):
-...    def __init__(self):
-...       Base.__init__(self)
-...    def class_name(self):
-...       return self.__class__.__name__
-...
->>> is_base(Base()) # calls the class_name() method from C++
-1
->>> is_base(Derived())
-0
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/callbacks.html b/doc/v2/callbacks.html deleted file mode 100644 index 4e91befadb..0000000000 --- a/doc/v2/callbacks.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - Boost.Python - Calling Python Functions and Methods - - - - - - - - - -
-

C++ Boost

-
-

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

- -

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
-{
-   ...
-};
-
-void apply(PyObject* callable, X& x)
-{
-   // Invoke callable, passing a Python object which holds a reference to x
-   boost::python::call<void>(callable, boost::ref(x));
-}
-
- In the table below, x denotes the actual argument - object and cv denotes an optional - cv-qualification: "const", "volatile", - or "const volatile". - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Argument TypeBehavior
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.
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.
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!
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

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

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

- -

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.

- -

The compromise I've settled on is this:

- -
    -
  1. The default behavior is pass-by-value. If you pass a non-null - pointer, the pointee is copied into a new Python object; otherwise the - corresponding Python argument will be None.
  2. - -
  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. -
- -

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.

- -

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.

- -

In Boost.Python v2 this is dealt with by:

- -
    -
  1. lifting the compile-time restriction on const char* callback - returns
  2. - -
  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 - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/callbacks.txt b/doc/v2/callbacks.txt deleted file mode 100644 index 2795680fd7..0000000000 --- a/doc/v2/callbacks.txt +++ /dev/null @@ -1,92 +0,0 @@ -.. Copyright David Abrahams 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -Here's the plan: - -I aim to provide an interface similar to that of Boost.Python v1's -callback<>::call(...) for dealing with callbacks. The interface will -look like: - - returning::call("method_name", self_object, a1, a2...); - -or - - returning::call(callable_object, a1, a2...); - -ARGUMENT HANDLING - -There is an issue concerning how to make Python objects from the -arguments a1...aN. A new Python object must be created; should the C++ -object be copied into that Python object, or should the Python object -simply hold a reference/pointer to the C++ object? In general, the -latter approach is unsafe, since the called function may store a -reference to the Python object somewhere. If the Python object is used -after the C++ object is destroyed, we'll crash Python. - -I plan to make the copying behavior the default, and to allow a -non-copying behavior if the user writes boost::ref(a1) instead of a1 -directly. At least this way, the user doesn't get dangerous behavior "by -accident". It's also worth noting that the non-copying ("by-reference") -behavior is in general only available for class types, and will fail at -runtime with a Python exception if used otherwise** - -However, pointer types present a problem: My first thought is to refuse -to compile if any aN has pointer type: after all, a user can always pass -*aN to pass "by-value" or ref(*aN) to indicate a pass-by-reference -behavior. However, this creates a problem for the expected NULL pointer -=> None conversion: it's illegal to dereference a null pointer value. - -We could use another construct, say "ptr(aN)", to deal with null -pointers, but then what does it mean? We know what it does when aN is -NULL, but it might either have by-value or by-reference behavior when aN -is non-null. - -The compromise I've settled on is this: - -1. The default behavior is pass-by-value. If you pass a non-null - pointer, the pointee is copied into a new Python object; otherwise - the corresponding Python argument will be None. - -2. if you want by-reference behavior, use ptr(aN) if aN is a pointer - and ref(aN) otherwise. If a null pointer is passed to ptr(aN), the - corresponding Python argument will be None. - -RESULT HANDLING - -As for results, we have a similar problem: if ResultType is allowed to -be a pointer or reference type, the lifetime of the object it refers to -is probably being managed by a Python object. When that Python object is -destroyed, our pointer dangles. The problem is particularly bad when the -ResultType is char const* - the corresponding Python String object is -typically uniquely-referenced, meaning that the pointer dangles as soon -as returning::call() returns. - -Boost.Python v1 deals with this issue by refusing to compile any uses of -callback::call(), but IMO this goes both too far and not -far enough. It goes too far because there are cases where the owning -String object survives beyond the call (just for instance when it's the -name of a Python class), and it goes not far enough because we might -just as well have the same problem with any returned pointer or -reference. - -I propose to address this in Boost.Python v2 by - - 1. lifting the compile-time restriction on const - char* callback returns - - 2. detecting the case when the reference count on the - result Python object is 1 and throwing an exception - inside of returning::call() when U is a pointer or - reference type. - -I think this is acceptably safe because users have to explicitly specify -a pointer/reference for U in returning, and they will be protected -against dangles at runtime, at least long enough to get out of the -returning::call() invocation. - --Dave - -**It would be possible to make it fail at compile-time for non-class -types such as int and char, but I'm not sure it's a good idea to impose -this restriction yet. diff --git a/doc/v2/class.html b/doc/v2/class.html deleted file mode 100644 index edfc609704..0000000000 --- a/doc/v2/class.html +++ /dev/null @@ -1,790 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/class.hpp>, - <boost/python/class_fwd.hpp> - - - - - - - - - -
-

-

-
-

Boost.Python

- -

Headers <boost/python/class.hpp>, - <boost/python/class_fwd.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class template - class_
- -
-
-
Class class_ - synopsis
- -
Class class_ - constructors
- -
Class class_ - modifier functions
-
-
- -
Class template bases
- -
-
-
Class template - bases synopsis
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

<boost/python/class.hpp> defines the interface - through which users expose their C++ classes to Python. It declares the - class_ class template, which is parameterized on the class - type being exposed. It also exposes the init, - optional and bases utility class templates, which - are used in conjunction with class_.

- -

<boost/python/class_fwd.hpp> contains a forward - declaration of the class_ class template.

- -

Classes

- -

Class template - class_<T, Bases, HeldType, - NonCopyable>

- -

Creates a Python class associated with the C++ type passed as its first - parameter. Although it has four template parameters, only the first one is - required. The three optional arguments can actually be supplied - in any order; Boost.Python determines - the role of the argument from its type.
-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Template ParameterRequirementsSemanticsDefault
TA class type.The class being wrapped
BasesA specialization of bases<...> which - specifies previously-exposed C++ base classes of T[1].Registers from_python conversions from wrapped - T instances to each of its exposed direct and indirect - bases. For each polymorphic base B, registers conversions - from indirectly-held wrapped B instances to - T.bases<>
HeldTypeMust be T, a class derived from T, or a - Dereferenceable type for which - pointee<HeldType>::type is - T or a class derived from T.Specifies the type that is actually embedded in a Python object - wrapping a T instance when T's constructor is - called or when a T or T* is converted to - Python without the use of - ptr, - ref, or Call Policies - such as return_internal_reference. - More details below.T
NonCopyableIf supplied, must be boost::noncopyable.Suppresses automatic registration of to_python - conversions which copy T instances. Required when - T has no publicly-accessible copy constructor.An unspecified type other than - boost::noncopyable.
- -

HeldType Semantics

- -
    -
  1. If HeldType is derived from T, its exposed - constructor(s) must accept an initial PyObject* argument - which refers back to the Python object that contains the - HeldType instance, as shown in this example. This argument is not - included in the init-expression passed to def(init_expr), below, nor is - it passed explicitly by users when Python instances of T are - created. This idiom allows C++ virtual functions which will be overridden - in Python to access the Python object so the Python method can be - invoked. Boost.Python automatically registers additional converters which - allow wrapped instances of T to be passed to wrapped C++ - functions expecting HeldType arguments.
  2. - -
  3. Because Boost.Python will always allow wrapped instances of - T to be passed in place of HeldType arguments, - specifying a smart pointer for HeldType allows users to pass - Python T instances where a smart pointer-to-T - is expected. Smart pointers such as std::auto_ptr<> or - boost::shared_ptr<> - which contain a nested type element_type designating the - referent type are automatically supported; additional smart pointer types - can be supported by specializing pointee<HeldType>.
  4. - -
  5. As in case 1 above, when HeldType is a smart pointer to - a class derived from T, the initial PyObject* - argument must be supplied by all of HeldType's exposed - constructors.
  6. - -
  7. Except in cases 1 and 3, users may optionally specify that T itself - gets initialized with a similar initial PyObject* argument - by specializing has_back_reference<T>.
  8. -
- -

Class - template class_ synopsis

-
-namespace boost { namespace python
-{
-  template <class T
-      , class Bases = bases<>
-            , class HeldType = T
-            , class NonCopyable = unspecified
-           >
-  class class_ : public object
-  {
-    // Constructors with default __init__
-    class_(char const* name);
-    class_(char const* name, char const* docstring);
-
-    // Constructors, specifying non-default __init__
-    template <class Init>
-    class_(char const* name, Init);
-    template <class Init>
-    class_(char const* name, char const* docstring, Init);
-
-    // Exposing additional __init__ functions
-    template <class Init>
-    class_& def(Init);
-
-    // defining methods
-    template <class F>
-    class_& def(char const* name, F f);
-    template <class Fn, class A1>
-    class_& def(char const* name, Fn fn, A1 const&);
-    template <class Fn, class A1, class A2>
-    class_& def(char const* name, Fn fn, A1 const&, A2 const&);
-    template <class Fn, class A1, class A2, class A3>
-    class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&);
-
-    // declaring method as static
-    class_& staticmethod(char const* name);
-    
-    // exposing operators
-    template <unspecified>
-    class_& def(detail::operator_<unspecified>);
-
-    // Raw attribute modification
-    template <class U>
-    class_& setattr(char const* name, U const&);
-
-    // exposing data members
-    template <class D>
-    class_& def_readonly(char const* name, D T::*pm);
-
-    template <class D>
-    class_& def_readwrite(char const* name, D T::*pm);
-
-    // exposing static data members
-    template <class D>
-    class_& def_readonly(char const* name, D const& d);
-    template <class D>
-    class_& def_readwrite(char const* name, D& d);
-
-    // property creation
-    template <class Get>
-    void add_property(char const* name, Get const& fget, char const* doc=0);
-    template <class Get, class Set>
-    void add_property(
-        char const* name, Get const& fget, Set const& fset, char const* doc=0);
-
-    template <class Get>
-    void add_static_property(char const* name, Get const& fget);
-    template <class Get, class Set>
-    void add_static_property(char const* name, Get const& fget, Set const& fset);
-
-    // pickle support
-    template <typename PickleSuite>
-    self& def_pickle(PickleSuite const&);
-    self& enable_pickling();
-  };
-}}
-
- -

Class template - class_ constructors

-
-class_(char const* name);
-class_(char const* name, char const* docstring);
-template <class Init>
-class_(char const* name, Init init_spec);
-template <class Init>
-class_(char const* name, char const* docstring, Init init_spec);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules. If docstring is supplied, it must be an - ntbs. If init_spec is - supplied, it must be either the special enumeration constant - no_init or an init-expression compatible with - T.
- -
Effects: Constructs a class_ object holding a - Boost.Python extension class named name. The - named attribute of the current scope is bound to the new extension - class.
- -
-
    -
  • If supplied, the value of docstring is bound to the - __doc__ attribute of the extension class.
  • - -
  • If init_spec is no_init, a special - __init__ function is generated which always raises a - Python exception. Otherwise, this->def(init_spec) is - called.
  • - -
  • If init_spec is not supplied, - this->def(init<>()) is called.
  • -
-
- -
Rationale:Allowing the user to specify constructor arguments - in the class_<> constructor helps her to avoid the - common run-time errors which result from invoking wrapped member - functions without having exposed an __init__ function which - creates the requisite T instance. Types which are not - default-constructible will cause a compile-time error unless - Init is supplied. The user must always supply - name as there is currently no portable method to derive the - text of the class name from its type.
-
- -

Class - template class_ modifier functions

-
-template <class Init>
-class_& def(Init init_expr);
-
- -
-
Requires: init_expr is the result of an init-expression compatible with - T.
- -
Effects: For each valid - prefix P of Init, adds an - __init__(...) function overload to the - extension class accepting P as arguments. Each overload - generated constructs an object of HeldType according to the - semantics described above, using a copy of - init_expr's call policies. - If the longest valid prefix of - Init contains N types and init_expr - holds M keywords, an initial sequence of the keywords are used - for all but the first N - M arguments of each - overload.
- -
Returns: *this
- -
Rationale: Allows users to easily expose a class' constructor - to Python.
-

-
-template <class F>
-class_& def(char const* name, Fn fn);
-template <class Fn, class A1>
-class_& def(char const* name, Fn fn, A1 const& a1);
-template <class Fn, class A1, class A2>
-class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2);
-template <class Fn, class A1, class A2, class A3>
-class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules.
- -
-
    -
  • If a1 is the result of an overload-dispatch-expression, - only the second form is allowed and fn must be a pointer to function - or pointer to member function whose - arity is the same as A1's maximum - arity. - -
    -
    Effects: For each prefix P of - Fn's sequence of argument types, beginning with the - one whose length is A1's minimum - arity, adds a - name(...) method overload to - the extension class. Each overload generated invokes - a1's call-expression with P, using a copy - of a1's call - policies. If the longest valid prefix of A1 - contains N types and a1 holds M - keywords, an initial sequence of the keywords are used for all - but the first N - M arguments of each - overload.
    -
    -
  • - -
  • Otherwise, a single method overload is built around fn, which - must not be null: - -
      -
    • If fn is a function pointer, its first argument must be of - the form U, U cv&, U - cv*, or U cv* const&, - where T* is convertible to U*, and - a1-a3, if supplied, may be selected in - any order from the table below.
    • - -
    • Otherwise, if fn is a member function pointer, its target - must be T or one of its public base classes, and - a1-a3, if supplied, may be selected in - any order from the table below.
    • - -
    • Otherwise, Fn must be [derived from] - object, and - a1-a2, if supplied, may be selcted in any order from - the first two rows of the table below. To be useful, - fn should be - callable.
    • -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Memnonic NameRequirements/Type propertiesEffects
    docstringAny ntbs.Value will be bound to the __doc__ attribute - of the resulting method overload. If an earlier overload - supplied a docstring, two newline characters and the new - docstring are appended to it.
    policiesA model of CallPoliciesA copy will be used as the call policies of the resulting - method overload.
    keywordsThe result of a keyword-expression - specifying no more arguments than the arity of fn.A copy will be used as the call policies of the resulting - method overload.
    -
  • -
-
- -
Returns: *this
-
-
-class_& staticmethod(char const* name);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules, and corresponds to a method whose overloads have all - been defined.
- -
Effects: Replaces the existing named attribute x with - the result of invoking staticmethod(x) - in Python. Specifies that the corresponding method is static and - therefore no object instance will be passed to it. This is equivalent to - the Python statement:
- -
-
-setattr(self, name, staticmethod(getattr(self, name)))
-
-
- -
Note: Attempting to invoke def(name,...) after - invoking staticmethod(name) will raise a RuntimeError.
- -
Returns: *this
-

-
-template <unspecified>
-class_& def(detail::operator_<unspecified>);
-
- -
-
Effects: Adds a Python special method as - described here.
- -
Returns: *this
-
-
-template <class U>
-class_& setattr(char const* name, U const& u);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules.
- -
Effects: Converts u to Python and adds it to the attribute - dictionary of the extension class:
- -
-
- PyObject_SetAttrString(this->ptr(), - name, object(u).ptr()); -
-
- -
Returns: *this
-

-
-template <class Get>
-void add_property(char const* name, Get const& fget, char const* doc=0);
-template <class Get, class Set>
-void add_property(
-        char const* name, Get const& fget, Set const& fset, char const* doc=0);
-
- -
-
Requires: name is an ntbs which conform to Python's identifier - naming rules.
- -
Effects: Creates a new Python property - class instance, passing object(fget) (and - object(fset) in - the second form) with an (optional) docstring doc to its - constructor, then adds that property to the Python class object under - construction with the given attribute name.
- -
Returns: *this
- -
Rationale: Allows users to easily expose functions that can be - invoked from Python with attribute access syntax.
-

-
-template <class Get>
-void add_static_property(char const* name, Get const& fget);
-template <class Get, class Set>
-void add_static_property(char const* name, Get const& fget, Set const& fset);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules.
- -
Effects: Creates a Boost.Python.StaticProperty object, passing - object(fget) - (and object(fset) in the second - form) to its constructor, then adds that property to the Python class - under construction with the given attribute name. - StaticProperty is a special subclass of Python's property - class which can be called without an initial self - argument.
- -
Returns: *this
- -
Rationale: Allows users to easily expose functions that can be - invoked from Python with static attribute access syntax.
-

-
-template <class D>
-class_& def_readonly(char const* name, D T::*pm, char const* doc=0);
-template <class D>
-class_& def_readonly(char const* name, D const& d);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules. doc is also an ntbs.
- -
Effects:
- -
-
-this->add_property(name, make_getter(pm), doc);
-
and -
-this->add_static_property(name, make_getter(d));
-
respectively.
-
-
- -
Returns: *this
- -
Rationale: Allows users to easily expose a class' data member - or free variable such that it can be inspected from Python with a natural - syntax.
-
-
-template <class D>
-class_& def_readwrite(char const* name, D T::*pm, char const* doc=0);
-template <class D>
-class_& def_readwrite(char const* name, D& d);
-
- -
-
Effects:
- -
-
-this->add_property(name, make_getter(pm), make_setter(pm), doc);
-
and -
-this->add_static_property(name, make_getter(d), make_setter(d));
-
respectively.
-
-
- -
Returns: *this
- -
Rationale: Allows users to easily expose a class' data or free - variable member such that it can be inspected and set from Python with a - natural syntax.
-
-
-template <typename PickleSuite>
-class_& def_pickle(PickleSuite const&);
-
- -
-
Requires: PickleSuite must be publically derived from pickle_suite.
- -
Effects: Defines a legal combination of the special attributes - and methods: __getinitargs__, __getstate__, - __setstate__, __getstate_manages_dict__, - __safe_for_unpickling__, __reduce__
- -
Returns: *this
- -
Rationale: Provides an easy to use - high-level interface for establishing complete pickle support for the - wrapped class. The user is protected by compile-time consistency - checks.
-

-
-class_& enable_pickling();
-
- -
-
Effects: Defines the __reduce__ method and the - __safe_for_unpickling__ attribute.
- -
Returns: *this
- -
Rationale: Light-weight alternative to - def_pickle(). Enables implementation of pickle support from Python.
-

- -

Class template - bases<T1, T2,...TN>

- -

An MPL - sequence which can be used in - class_<...> instantiations indicate a list - of base classes.

- -

Class - template bases synopsis

-
-namespace boost { namespace python
-{
-  template <T1 = unspecified,...Tn = unspecified>
-  struct bases
-  {};
-}}
-
- -

Example(s)

- -

Given a C++ class declaration:

-
-class Foo : public Bar, public Baz
-{
- public:
-   Foo(int x, char const* y);
-   Foo(double);
-
-   std::string const& name() { return m_name; }
-   void name(char const*);
-
-   double value; // public data
- private:
-   ...
-};
-
A corresponding Boost.Python extension class can be created with: -
-using namespace boost::python;
-
-class_<Foo,bases<Bar,Baz> >("Foo",
-          "This is Foo's docstring."
-          "It describes our Foo extension class",
-
-          init<int,char const*>(args("x","y"), "__init__ docstring")
-          )
-   .def(init<double>())
-   .def("get_name", &Foo::get_name, return_internal_reference<>())
-   .def("set_name", &Foo::set_name)
-   .def_readwrite("value", &Foo::value)
-   ;
-
-
- [1] By "previously-exposed" we - mean that the for each B in bases, an instance of - class_<B, ...> must have - already been constructed. -
-class_<Base>("Base");
-class_<Derived, bases<Base> >("Derived");
-
Revised - - 1 November, 2005 - -

© Copyright Dave - Abrahams 2002.

- - diff --git a/doc/v2/configuration.html b/doc/v2/configuration.html deleted file mode 100644 index 1be862ed62..0000000000 --- a/doc/v2/configuration.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - - - - - - - Boost.Python - Configuration - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Configuration

-
-
- -
-
Introduction
- -
Application Defined Macros
- -
Library Defined Implementation - Macros
-
- -

Introduction

- -

Boost.Python uses several configuration macros in <boost/config.hpp>, - as well as configuration macros meant to be supplied by the application. - These macros are documented here.

- -

Application Defined Macros

- -

These are the macros that may be defined by an application using - Boost.Python. Note that if you extend a strict interpretation of - the C++ standard to cover dynamic libraries, using different values of - these macros when compiling different libraries (including extension - modules and the Boost.Python library itself) is a violation of the - ODR. However, we know of no C++ - implementations on which this particular violation is detectable or - causes any problems.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MacroDefaultMeaning
BOOST_PYTHON_MAX_ARITY15The maximum arity of any function, member function, - or constructor to be wrapped, invocation of a Boost.Python - function wich is specified as taking arguments - x1, x2,...Xn. This includes, in - particular, callback mechanisms such as object::operator()(...) - or call_method<R>(... - ).
BOOST_PYTHON_MAX_BASES10The maximum number of template arguments to the - bases<...> - class template, which is used to specify the bases of a wrapped C++ - class..
BOOST_PYTHON_STATIC_MODULEnot definedIf defined, prevents your module initialization - function from being treated as an exported symbol on platforms which - support that distinction in-code
BOOST_PYTHON_ENABLE_CDECLnot definedIf defined, allows functions using the __cdecl - calling convention to be wrapped.
BOOST_PYTHON_ENABLE_STDCALLnot definedIf defined, allows functions using the __stdcall - calling convention to be wrapped.
BOOST_PYTHON_ENABLE_FASTCALLnot definedIf defined, allows functions using the __fastcall - calling convention to be wrapped.
- -

Library Defined Implementation - Macros

- -

These macros are defined by Boost.Python and are implementation - details of interest only to implementors and those porting to new - platforms.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MacroDefaultMeaning
BOOST_PYTHON_TYPE_ID_NAMEnot definedIf defined, this indicates that the type_info - comparison across shared library boundaries does not work on this - platform. In other words, if shared-lib-1 passes - typeid(T) to a function in shared-lib-2 which compares - it to typeid(T), that comparison may return - false. If this macro is #defined, Boost.Python uses and - compares typeid(T).name() instead of using and comparing - the std::type_info objects directly.
BOOST_PYTHON_NO_PY_SIGNATURESnot definedIf defined for a module no pythonic signatures are generated - for the docstrings of the module functions, and no python type is associated with any - of the converters registered by the module. This also reduces the binary size of the - module by about 14% (gcc compiled).
- If defined for the boost_python runtime library, the default for the - docstring_options.enable_py_signatures() is set to false. -
BOOST_PYTHON_SUPPORTS_PY_SIGNATURESdefined if BOOST_PYTHON_NO_PY_SIGNATURES is undefinedThis macro is defined to enable a smooth transition from older Boost.Python versions - which do not support pythonic signatures. For example usage see - here. -
BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPEnot definedIf defined the python type of __init__ method "self" parameters - is properly generated, otherwise object is used. It is undefined - by default because it increases the binary size of the module by about 14% (gcc compiled).
-
- -

Revised - - 7 January, 2003 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/copy_const_reference.html b/doc/v2/copy_const_reference.html deleted file mode 100644 index 97c2a282ce..0000000000 --- a/doc/v2/copy_const_reference.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/copy_const_reference.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/copy_const_reference.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class - copy_const_reference
- -
-
-
Class - copy_const_reference synopsis
- -
Class - copy_const_reference metafunctions
-
-
-
-
- -
Example
-
-
- -

Classes

- -

Class - copy_const_reference

- -

copy_const_reference is a model of ResultConverterGenerator - which can be used to wrap C++ functions returning a reference-to-const - type such that the referenced value is copied into a new Python - object.

- -

Class - copy_const_reference synopsis

-
-namespace boost { namespace python
-{
-    struct copy_const_reference
-    {
-        template <class T> struct apply;
-    };
-}}
-
- -

Class - copy_const_reference metafunctions

-
-template <class T> struct apply
-
- -
-
Requires: T is U const& for - some U.
- -
Returns: typedef to_python_value<T> - type;
-
- -

Example

- -

C++ Module Definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/copy_const_reference.hpp>
-#include <boost/python/return_value_policy.hpp>
-
-// classes to wrap
-struct Bar { int x; }
-
-struct Foo {
-   Foo(int x) : { b.x = x; }
-   Bar const& get_bar() const { return b; }
- private:
-   Bar b;
-};
-
-// Wrapper code
-using namespace boost::python;
-BOOST_PYTHON_MODULE(my_module)
-{
-    class_<Bar>("Bar");
-
-     class_<Foo>("Foo", init<int>())
-        .def("get_bar", &Foo::get_bar
-            , return_value_policy<copy_const_reference>())
-       ;
-}
-
- -

Python Code

-
->>> from my_module import *
->>> f = Foo(3)         # create a Foo object
->>> b = f.get_bar()    # make a copy of the internal Bar object
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/copy_non_const_reference.html b/doc/v2/copy_non_const_reference.html deleted file mode 100644 index 987efad83d..0000000000 --- a/doc/v2/copy_non_const_reference.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/copy_non_const_reference.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/copy_non_const_reference.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class - copy_non_const_reference
- -
-
-
Class - copy_non_const_reference synopsis
- -
Class - copy_non_const_reference metafunctions
-
-
-
-
- -
Example
-
-
- -

Classes

- -

Class - copy_non_const_reference

- -

copy_non_const_reference is a model of ResultConverterGenerator - which can be used to wrap C++ functions returning a - reference-to-non-const type such that the referenced value is copied into - a new Python object.

- -

Class - copy_non_const_reference synopsis

-
-namespace boost { namespace python
-{
-    struct copy_non_const_reference
-    {
-        template <class T> struct apply;
-    };
-}}
-
- -

Class - copy_non_const_reference metafunctions

-
-template <class T> struct apply
-
- -
-
Requires: T is U& for some - non-const U.
- -
Returns: typedef to_python_value<T> - type;
-
- -

Example

- -

C++ code:

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/copy_non_const_reference.hpp>
-#include <boost/python/return_value_policy.hpp>
-
-// classes to wrap
-struct Bar { int x; }
-
-struct Foo {
-   Foo(int x) : { b.x = x; }
-   Bar& get_bar() { return b; }
- private:
-   Bar b;
-};
-
-// Wrapper code
-using namespace boost::python;
-BOOST_PYTHON_MODULE(my_module)
-{
-    class_<Bar>("Bar");
-
-     class_<Foo>("Foo", init<int>())
-        .def("get_bar", &Foo::get_bar
-            , return_value_policy<copy_non_const_reference>())
-       ;
-}
-
- Python Code: -
->>> from my_module import *
->>> f = Foo(3)         # create a Foo object
->>> b = f.get_bar()    # make a copy of the internal Bar object
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/data_members.html b/doc/v2/data_members.html deleted file mode 100644 index 36f818d3d9..0000000000 --- a/doc/v2/data_members.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/data_members.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/data_members.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
make_getter
- -
make_setter
-
-
- -
Example
-
-
- -

Introduction

- -

make_getter() and - make_setter() are the - functions used internally by class_<>::def_readonly and - class_<>::def_readwrite to produce - Python callable objects which wrap C++ data members.

- -

Functions

-
-template <class C, class D>
-object make_getter(D C::*pm);
-
-template <class C, class D, class Policies>
-object make_getter(D C::*pm, Policies const& policies);
-
- -
-
Requires: Policies is a model of CallPolicies.
- -
Effects: Creates a Python callable object which accepts a - single argument that can be converted from_python to - C*, and returns the corresponding member D - member of the C object, converted to_python. - If policies is supplied, it will be applied to the - function as described here. Otherwise, - the library attempts to determine whether D is a - user-defined class type, and if so uses return_internal_reference<>
- -
for Policies. Note that this test may inappropriately - choose return_internal_reference<> in some cases - when D is a smart pointer type. This is a known - defect.
- -
Returns: An instance of object which holds the new Python - callable object.
-
-
-template <class D>
-object make_getter(D const& d);
-template <class D, class Policies>
-object make_getter(D const& d, Policies const& policies);
-
-template <class D>
-object make_getter(D const* p);
-template <class D, class Policies>
-object make_getter(D const* p, Policies const& policies);
-
- -
-
Requires: Policies is a model of CallPolicies.
- -
Effects: Creates a Python callable object which accepts no - arguments and returns d or *p, converted - to_python on demand. If policies is supplied, - it will be applied to the function as described here. Otherwise, the library attempts to - determine whether D is a user-defined class type, and if - so uses reference_existing_object
- -
for Policies.
- -
Returns: An instance of object which holds the new Python - callable object.
-
-
-template <class C, class D>
-object make_setter(D C::*pm);
-
-template <class C, class D, class Policies>
-object make_setter(D C::*pm, Policies const& policies);
-
- -
-
Requires: Policies is a model of CallPolicies.
- -
Effects: Creates a Python callable object which, when called - from Python, expects two arguments which can be converted - from_python to C* and - D const&, respectively, and sets the - corresponding D member of the C object. If - policies is supplied, it will be applied to the function - as described here.
- -
Returns: An instance of object which holds the new Python - callable object.
-
-
-template <class D>
-object make_setter(D& d);
-template <class D, class Policies>
-object make_setter(D& d, Policies const& policies);
-
-template <class D>
-object make_setter(D* p);
-template <class D, class Policies>
-object make_setter(D* p, Policies const& policies);
-
- -
-
Requires: Policies is a model of CallPolicies.
- -
Effects: Creates a Python callable object which accepts one - argument, which is converted from Python to D const& - and written into d or *p, respectively. If - policies is supplied, it will be applied to the function - as described here.
- -
Returns: An instance of object which holds the new Python - callable object.
-
- -

Example

- -

The code below uses make_getter and make_setter to expose a data - member as functions:

-
-#include <boost/python/data_members.hpp>
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-
-struct X
-{
-    X(int x) : y(x) {}
-    int y;
-};
-
-using namespace boost::python;
-
-BOOST_PYTHON_MODULE_INIT(data_members_example)
-{
-    class_<X>("X", init<int>())
-       .def("get", make_getter(&X::y))
-       .def("set", make_setter(&X::y))
-       ;
-}
-
- It can be used this way in Python: -
->>> from data_members_example import *
->>> x = X(1)
->>> x.get()
-1
->>> x.set(2)
->>> x.get()
-2
-
- -

- - 5 August, 2003 -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/def.html b/doc/v2/def.html deleted file mode 100644 index 3c71fd363b..0000000000 --- a/doc/v2/def.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/def.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/def.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
def
-
-
- -
Example
-
-
- -

Introduction

- -

def() is the function which can - be used to expose C++ functions and callable objects as Python functions - in the current scope.

- -

Functions

- def -
-template <class F>
-void def(char const* name, F f);
-
-template <class Fn, class A1>
-void def(char const* name, Fn fn, A1 const&);
-
-template <class Fn, class A1, class A2>
-void def(char const* name, Fn fn, A1 const&, A2 const&);
-
-template <class Fn, class A1, class A2, class A3>
-void def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules.
- -
-
    -
  • If Fn is [derived from] object, it will be added to - the current scope as a single overload. To be useful, - fn should be callable.
  • - -
  • - If a1 is the result of an overload-dispatch-expression, - only the second form is allowed and fn must be a pointer to - function or pointer to member function whose arity is the same as A1's maximum - arity. - -
    -
    Effects: For each prefix P of - Fn's sequence of argument types, beginning with - the one whose length is A1's minimum - arity, adds a - name(...) function overload - to the current scope. Each overload - generated invokes a1's call-expression with - P, using a copy of a1's call policies. If the longest valid - prefix of A1 contains N types and - a1 holds M keywords, an initial sequence - of the keywords are used for all but the first - N - M arguments of each - overload.
    -
    -
    -
  • - -
  • Otherwise, fn must be a non-null function or member function - pointer, and a single function overload built around fn is added to - the current scope. If any of - a1-a3 are supplied, they may be selected - in any order from the table below.
  • -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Memnonic NameRequirements/Type propertiesEffects
docstringAny ntbs.Value will be bound to the __doc__ attribute of - the resulting method overload.
policiesA model of CallPoliciesA copy will be used as the call policies of the resulting - method overload.
keywordsThe result of a keyword-expression - specifying no more arguments than the arity of fn.A copy will be used as the call policies of the resulting - method overload.
-
-
- -

Example

-
-#include <boost/python/def.hpp>
-#include <boost/python/module.hpp>
-#include <boost/python/args.hpp>
-
-using namespace boost::python;
-
-char const* foo(int x, int y) { return "foo"; }
-
-BOOST_PYTHON_MODULE(def_test)
-{
-    def("foo", foo, args("x", "y"), "foo's docstring");
-}
-
- -

- - 7 March, 2003 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/def_visitor.html b/doc/v2/def_visitor.html deleted file mode 100644 index 08fa0c5145..0000000000 --- a/doc/v2/def_visitor.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - Boost.Python - <boost/python/def_visitor.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header <boost/python/def_visitor.hpp>

-
-
- -

Contents

- - -
-
Introduction -
Classes -
-
-
Class def_visitor -
Class def_visitor - synopsis
-
Class def_visitor - requirements
-
-
Example -
-
- -

Introduction

- - -

<boost/python/def_visitor.hpp> provides a generic visitation - interface through which the class_ def member - functionality can be extended non-intrusively to avoid cluttering the class_ - interface. It declares the def_visitor<T> class template, - which is parameterized on the derived type DerivedVisitor, which provides - the actual def functionality through its visit member functions. -

Classes

- -

Class template def_visitor<DerivedVisitor>

- - -

The class def_visitor is a base class paramaterized by its derived class. The - def_visitor class is a protocol class. Its derived class, DerivedVisitor, is - expected to have a member function visit. The def_visitor class is never instantiated - directly. Instead, an instance of its subclass, DerivedVisitor,  is passed - on as an argument to the class_ def member function. -

-Class def_visitor synopsis

-
namespace boost { namespace python {
-
-    template <class DerivedVisitor>
-    class def_visitor {};
-}
-

def_visitor requirements

- - -

The client supplied class DerivedVisitor - template parameter is expected to: -

    -
  • be privately derived from def_visitor
  • -
  • grant friend access to class def_visitor_access
  • -
  • define either or both visit member functions listed in the table below:
  • -
- - - - - - - - - - - - - - - - - - - - - -
ExpressionReturn TypeRequirementsEffects
visitor.visit(cls)voidcls is an instance of a class_  being wrapped - to Python. visitor is a def_visitor derived class.A call to cls.def(visitor) forwards to this member function.
visitor.visit(cls, name, options)voidcls is a class_ instance, name is a C string. visitor is a def_visitor - derived class. options is a context specific optional argument.A call to cls.def(name, visitor) or cls.def(name, visitor, options) forwards - to this member function.
- -

Example

- - -
class X {/*...*/};
-class my_def_visitor : boost::python::def_visitor<my_def_visitor> -{ - friend class def_visitor_access; - - template <class classT> - void visit(classT& c) const - { - c - .def("foo", &my_def_visitor::foo) - .def("bar", &my_def_visitor::bar) - ; - } - - static void foo(X& self); - static void bar(X& self); -}; - -BOOST_PYTHON_MODULE(my_ext) -{ - class_<X>("X") - .def(my_def_visitor()) - ; -} -
-

Revised - 27 August, 2003 -

- - -

© Copyright Joel de Guzman 2003. Distributed under the Boost - Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/v2/default_call_policies.html b/doc/v2/default_call_policies.html deleted file mode 100644 index 30d0a50de7..0000000000 --- a/doc/v2/default_call_policies.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - Boost.Python - - <boost/python/default_call_policies.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header - <boost/python/default_call_policies.hpp>

-
-


- -

Contents

- -
-
Classes - -
-
-
Class - default_call_policies - -
-
-
Class - default_call_policies synopsis - -
Class - default_call_policies static functions -
- -
Class - default_result_converter - -
-
-
Class - default_result_converter synopsis - -
Class - default_result_converter metafunctions -
-
- -
Example -
-
- -

Classes

- -

Class - default_call_policies

- -

default_call_policies is a model of CallPolicies with no precall or - postcall behavior and a result_converter which - handles by-value returns. Wrapped C++ functions and member functions use - default_call_policies unless otherwise specified. You may find - it convenient to derive new models of CallPolicies from - default_call_policies. - -

Class - default_call_policies synopsis

-
-namespace boost { namespace python
-{
-    struct default_call_policies
-    {
-        static bool precall(PyObject*);
-        static PyObject* postcall(PyObject*, PyObject* result);
-        typedef default_result_converter result_converter;
-        template <class Sig> struct extract_return_type : mpl::front<Sig>{};
-    };
-}}
-
- -

Class - default_call_policies static functions

-
-bool precall(PyObject*);
-
- -
-
Returns: true - -
Throws: nothing -
-
-PyObject* postcall(PyObject*, PyObject* result);
-
- -
-
Returns: result - -
Throws: nothing -
- -

Class - default_result_converter

- -

default_result_converter is a model of ResultConverterGenerator which can be - used to wrap C++ functions returning non-pointer types, char - const*, and PyObject*, by-value. - -

Class - default_result_converter synopsis

-
-namespace boost { namespace python
-{
-    struct default_result_converter
-    {
-        template <class T> struct apply;
-    };
-}}
-
- -

Class - default_result_converter metafunctions

-
-template <class T> struct apply
-
- -
-
Requires: T is not a reference type. If - T is a pointer type, T is const - char* or PyObject*. - -
Returns: typedef to_python_value<T - const&> type; -
- -

Example

- -

This example comes from the Boost.Python implementation itself. Because - the return_value_policy - class template does not implement precall or - postcall behavior, its default base class is - default_call_policies: -

-template <class Handler, class Base = default_call_policies>
-struct return_value_policy : Base
-{
-   typedef Handler result_converter;
-};
-
- -

Revised - - 11 June, 2007 - - - -

© Copyright Dave - Abrahams 2002. Distributed under the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/v2/definitions.html b/doc/v2/definitions.html deleted file mode 100644 index cfec181c7f..0000000000 --- a/doc/v2/definitions.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - Boost.Python - Definitions - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Definitions

-
-
- -
-
arity: The number of arguments accepted - by a function or member function. Unless otherwise specified, the - hidden "this" argument to member functions is not counted - when specifying arity
- -

-
- -
ntbs: Null-Terminated Byte String, or - `C'-string. C++ string literals are ntbses. An - ntbs must never be null.
- -

-
- -
raise: Exceptions in Python are - "raised", not "thrown", as they are in C++. When this documentation - says that some Python exception is "raised" in the context of C++ code, - it means that the corresponding Python exception is set via the Python/'C' - API, and throw_error_already_set() - is called.
- -

-
- -
POD: A technical term from the C++ - standard. Short for "Plain Ol'Data": A POD-struct is an aggregate class - that has no non-static data members of type pointer to member, - non-POD-struct, non-POD-union (or array of such types) or reference, - and has no user-defined copy assign- ment operator and no user-defined - destructor. Similarly, a POD-union is an aggregate union that has no - non-static data members of type pointer to member, non-POD-struct, - non-POD-union (or array of such types) or reference, and has no - user-defined copy assignment operator and no user-defined destructor. A - POD class is a class that is either a POD-struct or a POD-union. An - aggregate is an array or a class (clause 9) with no user-declared - constructors (12.1), no private or protected non-static data members - (clause 11), no base classes (clause 10), and no virtual functions - (10.3).
- -

-
- -
ODR: The "One Definition - Rule", which says that any entity in a C++ program must have the same definition in all translation units (object files) which make up a program. -
- -

-
- - -
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/dict.html b/doc/v2/dict.html deleted file mode 100644 index 82ea136536..0000000000 --- a/doc/v2/dict.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/dict.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/dict.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class dict
- -
-
-
Class dict - synopsis
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Exposes a TypeWrapper for the Python - dict - type.

- -

Classes

- -

Class dict

- -

Exposes the mapping - protocol of Python's built-in dict type. The semantics - of the constructors and member functions defined below can be fully - understood by reading the TypeWrapper concept - definition. Since dict is publicly derived from object, the public object - interface applies to dict instances as well.

- -

Class dict - synopsis

-
-namespace boost { namespace python
-{
-   class dict : public object
-   {
-      dict();
-
-      template< class T >
-      dict(T const & data);
-
-      // modifiers
-      void clear();
-      dict copy();
-
-      template <class T1, class T2>
-      tuple popitem();
-
-      template <class T>
-      object setdefault(T const &k);
-
-      template <class T1, class T2>
-      object setdefault(T1 const & k, T2 const & d);
-
-      void update(object_cref E);
- 
-      template< class T >
-      void update(T const & E);
-
-      // observers
-      list values() const;
-    
-      object get(object_cref k) const;
-
-      template<class T>
-      object get(T const & k) const;
-
-      object get(object_cref k, object_cref d) const;
-      object get(T1 const & k, T2 const & d) const;
-
-      bool has_key(object_cref k) const;
-
-      template< class T >
-      bool has_key(T const & k) const;
-
-      list items() const;
-      object iteritems() const;
-      object iterkeys() const;
-      object itervalues() const;
-      list keys() const;
-  };
-}}
-
- -

Example

-
-using namespace boost::python;
-dict swap_object_dict(object target, dict d)
-{
-    dict result = extract<dict>(target.attr("__dict__"));
-    target.attr("__dict__") = d;
-    return result;
-}
-
- -

Revised 30 September, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/docstring_options.html b/doc/v2/docstring_options.html deleted file mode 100644 index a2a0cc6459..0000000000 --- a/doc/v2/docstring_options.html +++ /dev/null @@ -1,386 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/docstring_options.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/docstring_options.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class - docstring_options
- -
-
-
Class - docstring_options synopsis
- -
Class - docstring_options constructors
- -
Class - docstring_options destructors
- -
Class - docstring_options modifiers
-
-
-
-
- -
Examples
-
-
- -

Introduction

- -

Boost.Python supports user-defined docstrings with automatic - appending of C++ signatures. These features are enabled by - default. The class docstring_options is available to - selectively suppress the user-defined docstrings, signatures, or - both.

- -

Classes

- -

Class - docstring_options

- -

Controls the appearance of docstrings of wrapped functions and - member functions for the life-time of the instance. The instances - are noncopyable to eliminate the possibility of surprising side - effects.

- -

Class - docstring_options synopsis

-
-namespace boost { namespace python {
-
-    class docstring_options : boost::noncopyable
-    {
-      public:
-          docstring_options(bool show_all=true);
-
-          docstring_options(bool show_user_defined, bool show_signatures);
-
-          docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures);
-
-          ~docstring_options();
-
-          void
-          disable_user_defined();
-
-          void
-          enable_user_defined();
-
-          void
-          disable_signatures();
-
-          void
-          enable_signatures();
-
-          void
-          disable_py_signatures();
-
-          void
-          enable_py_signatures();
-
-          void
-          disable_cpp_signatures();
-
-          void
-          enable_cpp_signatures();
-
-          void
-          disable_all();
-
-          void
-          enable_all();
-    };
-
-}}
-
- -

Class - docstring_options constructors

-
-docstring_options(bool show_all=true);
-
- -
-
Effects: Constructs a docstring_options - object which controls the appearance of function and - member-function docstrings defined in the code that follows. If - show_all is true, both the - user-defined docstrings and the automatically generated Python and C++ - signatures are shown. If show_all is - false the __doc__ attributes are - None.
-
-
-docstring_options(bool show_user_defined, bool show_signatures);
-
- -
-
Effects: Constructs a docstring_options - object which controls the appearance of function and - member-function docstrings defined in the code that follows. - Iff show_user_defined is true, the - user-defined docstrings are shown. Iff - show_signatures is true, Python and C++ - signatures are automatically added. If both - show_user_defined and show_signatures - are false, the __doc__ attributes are - None.
-
-
-docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures);
-
- -
-
Effects: Constructs a docstring_options - object which controls the appearance of function and - member-function docstrings defined in the code that follows. - Iff show_user_defined is true, the - user-defined docstrings are shown. Iff - show_py_signatures is true, Python - signatures are automatically added. Iff - show_cpp_signatures is true, C++ - signatures are automatically added. If all parameters are - false, the __doc__ attributes are - None.
-
- -

Class - docstring_options destructors

-
-~docstring_options();
-
- -
-
Effects: Restores the previous state of the - docstring options. In particular, if - docstring_options instances are in nested C++ - scopes the settings effective in the enclosing scope are - restored. If the last docstring_options instance - goes out of scope the default "all on" settings are - restored.
-
- -

Class - docstring_options modifier functions

-
-void disable_user_defined();
-void enable_user_defined();
-void disable_signatures();
-void enable_signatures();
-void disable_py_signatures();
-void enable_py_signatures();
-void disable_cpp_signatures();
-void enable_cpp_signatures();
-void disable_all();
-void enable_all();
-
- -
-
These member functions dynamically change the appearance of - docstrings in the code that follows. The - *_user_defined() and *_signatures() - member functions are provided for fine-grained control. The - *_all() member functions are convenient shortcuts - to manipulate all settings simultaneously.
-
- -

Examples

- -

Docstring options defined at compile time

-
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/docstring_options.hpp>
-
-void foo() {}
-
-BOOST_PYTHON_MODULE(demo)
-{
-    using namespace boost::python;
-    docstring_options doc_options(DEMO_DOCSTRING_SHOW_ALL);
-    def("foo", foo, "foo doc");
-}
-
If compiled with -DDEMO_DOCSTRING_SHOW_ALL=true: -
->>> import demo
->>> print demo.foo.__doc__
-foo() -> None : foo doc
-C++ signature:
-    foo(void) -> void
-
If compiled with --DDEMO_DOCSTRING_SHOW_ALL=false: -
->>> import demo
->>> print demo.foo.__doc__
-None
-
- -

Selective suppressions

-
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/args.hpp>
-#include <boost/python/docstring_options.hpp>
-
-int foo1(int i) { return i; }
-int foo2(long l) { return static_cast<int>(l); }
-int foo3(float f) { return static_cast<int>(f); }
-int foo4(double d) { return static_cast<int>(d); }
-
-BOOST_PYTHON_MODULE(demo)
-{
-    using namespace boost::python;
-    docstring_options doc_options;
-    def("foo1", foo1, arg("i"), "foo1 doc");
-    doc_options.disable_user_defined();
-    def("foo2", foo2, arg("l"), "foo2 doc");
-    doc_options.disable_signatures();
-    def("foo3", foo3, arg("f"), "foo3 doc");
-    doc_options.enable_user_defined();
-    def("foo4", foo4, arg("d"), "foo4 doc");
-    doc_options.enable_py_signatures();
-    def("foo5", foo4, arg("d"), "foo5 doc");
-    doc_options.disable_py_signatures();
-    doc_options.enable_cpp_signatures();
-    def("foo6", foo4, arg("d"), "foo6 doc");
-}
-
Python code: -
->>> import demo
->>> print demo.foo1.__doc__
-foo1( (int)i) -> int : foo1 doc
-C++ signature:
-    foo1(int i) -> int
->>> print demo.foo2.__doc__
-foo2( (int)l) -> int : 
-C++ signature:
-    foo2(long l) -> int
->>> print demo.foo3.__doc__
-None
->>> print demo.foo4.__doc__
-foo4 doc
->>> print demo.foo5.__doc__
-foo5( (float)d) -> int : foo5 doc
->>> print demo.foo6.__doc__
-foo6 doc
-C++ signature:
-    foo6(double d) -> int
-
- -

Wrapping from multiple C++ scopes

-
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/args.hpp>
-#include <boost/python/docstring_options.hpp>
-
-int foo1(int i) { return i; }
-int foo2(long l) { return static_cast<int>(l); }
-
-int bar1(int i) { return i; }
-int bar2(long l) { return static_cast<int>(l); }
-
-namespace {
-
-    void wrap_foos()
-    {
-        using namespace boost::python;
-        // no docstring_options here
-        //   -> settings from outer C++ scope are in effect
-        def("foo1", foo1, arg("i"), "foo1 doc");
-        def("foo2", foo2, arg("l"), "foo2 doc");
-    }
-
-    void wrap_bars()
-    {
-        using namespace boost::python;
-        bool show_user_defined = true;
-        bool show_signatures = false;
-        docstring_options doc_options(show_user_defined, show_signatures);
-        def("bar1", bar1, arg("i"), "bar1 doc");
-        def("bar2", bar2, arg("l"), "bar2 doc");
-    }
-}
-
-BOOST_PYTHON_MODULE(demo)
-{
-    boost::python::docstring_options doc_options(false);
-    wrap_foos();
-    wrap_bars();
-}
-
Python code: -
->>> import demo
->>> print demo.foo1.__doc__
-None
->>> print demo.foo2.__doc__
-None
->>> print demo.bar1.__doc__
-bar1 doc
->>> print demo.bar2.__doc__
-bar2 doc
-
- -

See also: boost/libs/python/test/docstring.cpp - and docstring.py

- -

Revised - - 16 January, 2006 -

- -

© Copyright Ralf W. - Grosse-Kunstleve 2006.

- - diff --git a/doc/v2/enum.html b/doc/v2/enum.html deleted file mode 100644 index c5ec2b9217..0000000000 --- a/doc/v2/enum.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/enum.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/enum.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class template - enum_
- -
-
-
Class template enum_ - synopsis
- -
Class template enum_ - constructors
- -
Class template enum_ - modifier functions
-
-
- -
-
- -
Example(s)
-
-
- -

Introduction

- -

<boost/python/enum.hpp> defines the - interface through which users expose their C++ enumeration types - to Python. It declares the - enum_ class template, which is parameterized on the - enumeration type being exposed.

- - -

Classes

- -

Class template - enum_<T>

- -

Creates a Python class derived from Python's int - type which is associated with the C++ type passed as its first - parameter. - -

Class template enum_ - synopsis

-
-namespace boost { namespace python
-{
-  template <class T>
-  class enum_ : public object
-  {
-    enum_(char const* name, char const* doc = 0);
-    enum_<T>& value(char const* name, T);
-    enum_<T>& export_values();
-  };
-}}
-
- -

Class template enum_ - constructors

-
-enum_(char const* name, char const* doc=0);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules. - -
Effects: Constructs an enum_ object - holding a Python extension type derived from int - which is named name. The - named attribute of the current scope is bound to the new - extension type.
-
- -

Class template - enum_ modifier functions

-
-inline enum_<T>& value(char const* name, T x);
-
- -
-
Requires: name is an ntbs which conforms to Python's identifier - naming rules. - -
Effects: adds an instance of the wrapped enumeration - type with value x to the type's dictionary as the - named attribute.
- -
Returns: *this
- -
- -
-inline enum_<T>& export_values();
-
- -
- -
Effects: sets attributes in the current scope with the - same names and values as all enumeration values exposed so far - by calling value().
- -
Returns: *this
- -
- -

Example(s)

- -

C++ module definition -

-#include <boost/python/enum.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/module.hpp>
-
-using namespace boost::python;
-
-enum color { red = 1, green = 2, blue = 4 };
-
-color identity_(color x) { return x; }
-
-BOOST_PYTHON_MODULE(enums)
-{
-    enum_<color>("color")
-        .value("red", red)
-        .value("green", green)
-        .export_values()
-        .value("blue", blue)
-        ;
-    
-    def("identity", identity_);
-}
-
-

Interactive Python: -

->>> from enums import *
-
->>> identity(red)
-enums.color.red
-
->>> identity(color.red)
-enums.color.red
-
->>> identity(green)
-enums.color.green
-
->>> identity(color.green)
-enums.color.green
-
->>> identity(blue)
-Traceback (most recent call last):
-  File "<stdin>", line 1, in ?
-NameError: name blue' is not defined
-
->>> identity(color.blue)
-enums.color.blue
-
->>> identity(color(1))
-enums.color.red
-
->>> identity(color(2))
-enums.color.green
-
->>> identity(color(3))
-enums.color(3)
-
->>> identity(color(4))
-enums.color.blue
-
->>> identity(1)
-Traceback (most recent call last):
-  File "<stdin>", line 1, in ?
-TypeError: bad argument type for built-in operation
-
-
- - Revised - - 13 December, 2002 - - - -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/errors.html b/doc/v2/errors.html deleted file mode 100644 index 69a3cf5700..0000000000 --- a/doc/v2/errors.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/errors.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/errors.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class - error_already_set
- -
-
-
Class - error_already_set synopsis
-
-
-
-
- -
Functions
- -
-
-
handle_exception
- -
expect_non_null
- -
throw_error_already_set
-
-
- -
Examples
-
-
- -

Introduction

- -

<boost/python/errors.hpp> provides types and - functions for managing and translating between Python and C++ exceptions. - This is relatively low-level functionality that is mostly used internally - by Boost.Python. Users should seldom need it.

- -

Classes

- -

Class - error_already_set

- -

error_already_set is an exception type which can be - thrown to indicate that a Python error has occurred. If thrown, the - precondition is that PyErr_Occurred() - returns a value convertible to true. Portable code shouldn't - throw this exception type directly, but should instead use throw_error_already_set(), - below.

- -

Class error_already_set - synopsis

-
-namespace boost { namespace python
-{
-    class error_already_set {};
-}}
-
- -

Functions

-
-template <class T> bool handle_exception(T f) throw();
-
-void handle_exception() throw();
-
- -
-
Requires: The first form requires that the expression - function0<void>(f) - is valid. The second form requires that a C++ exception is currently - being handled (see section 15.1 in the C++ standard).
- -
Effects: The first form calls f() inside a - try block which first attempts to use all registered exception translators. If none of - those translates the exception, the catch clauses then set - an appropriate Python exception for the C++ exception caught, returning - true if an exception was thrown, false - otherwise. The second form passes a function which rethrows the - exception currently being handled to the first form.
- -
Postconditions: No exception is being handled
- -
Throws: nothing
- -
Rationale: At inter-language boundaries it is important to - ensure that no C++ exceptions escape, since the calling language - usually doesn't have the equipment necessary to properly unwind the - stack. Use handle_exception to manage exception - translation whenever your C++ code is called directly from the Python - API. This is done for you automatically by the usual function wrapping - facilities: make_function(), - make_constructor(), - def() and class_::def(). The second form can be - more convenient to use (see the example below), - but various compilers have problems when exceptions are rethrown from - within an enclosing try block.
-
-
-template <class T> T* expect_non_null(T* x);
-
- -
-
Returns: x
- -
Throws: error_already_set() iff x == - 0.
- -
Rationale: Simplifies error-handling when calling functions - in the Python/C - API which return 0 on error.
-
-
-void throw_error_already_set();
-
- -
-
Effects: throw error_already_set();
-
- -
-
Rationale: Many platforms and compilers are not able to - consistently catch exceptions thrown across shared library boundaries. - Using this function from the Boost.Python library ensures that the - appropriate catch block in handle_exception() can catch the - exception.
-
- -

Examples

-
-#include <string>
-#include <boost/python/errors.hpp>
-#include <boost/python/object.hpp>
-#include <boost/python/handle.hpp>
-
-// Returns a std::string which has the same value as obj's "__name__"
-// attribute.
-std::string get_name(boost::python::object obj)
-{
-   // throws if there's no __name__ attribute
-   PyObject* p = boost::python::expect_non_null(
-      PyObject_GetAttrString(obj.ptr(), "__name__"));
-
-   char const* s = PyString_AsString(p);
-   if (s != 0) 
-        Py_DECREF(p);
-
-   // throws if it's not a Python string
-   std::string result(
-      boost::python::expect_non_null(
-         PyString_AsString(p)));
-
-   Py_DECREF(p); // Done with p
-   
-   return result;
-}
-
-//
-// Demonstrate form 1 of handle_exception
-//
-
-// Place into result a Python Int object whose value is 1 if a and b have
-// identical "__name__" attributes, 0 otherwise.
-void same_name_impl(PyObject*& result, boost::python::object a, boost::python::object b)
-{
-   result = PyInt_FromLong(
-      get_name(a) == get_name(a2));
-}
-
-object borrowed_object(PyObject* p)
-{
-   return boost::python::object(
-        boost::python::handle<>(
-             boost::python::borrowed(a1)));
-}
-
-// This is an example Python 'C' API interface function
-extern "C" PyObject*
-same_name(PyObject* args, PyObject* keywords)
-{
-   PyObject* a1;
-   PyObject* a2;
-   PyObject* result = 0;
-
-   if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
-      return 0;
-   
-   // Use boost::bind to make an object compatible with
-   // boost::Function0<void>
-   if (boost::python::handle_exception(
-         boost::bind<void>(same_name_impl, boost::ref(result), borrowed_object(a1), borrowed_object(a2))))
-   {
-      // an exception was thrown; the Python error was set by
-      // handle_exception()
-      return 0;
-   }
-
-   return result;
-}
-
-//
-// Demonstrate form 2 of handle_exception. Not well-supported by all
-// compilers.
-//
-extern "C" PyObject*
-same_name2(PyObject* args, PyObject* keywords)
-{
-   PyObject* a1;
-   PyObject* a2;
-   PyObject* result = 0;
-
-   if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
-      return 0;
-
-   try {
-      return PyInt_FromLong(
-         get_name(borrowed_object(a1)) == get_name(borrowed_object(a2)));
-   }
-   catch(...)
-   {
-      // If an exception was thrown, translate it to Python
-      boost::python::handle_exception();
-      return 0;
-   }
-}
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/exception_translator.html b/doc/v2/exception_translator.html deleted file mode 100644 index 4cc7bb91b4..0000000000 --- a/doc/v2/exception_translator.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/exception_translator.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/exception_translator.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
register_exception_translator
-
-
- -
Example(s)
-
-
- -

Introduction

- -

As described here, it - is important to make sure that exceptions thrown by C++ code do not pass - into the Python interpreter core. By default, Boost.Python translates all - C++ exceptions thrown by wrapped functions and module init functions into - Python, but the default translators are extremely limited: most C++ - exceptions will appear in Python as a RuntimeError - exception whose representation is - 'Unidentifiable C++ Exception'. To produce better - error messages, users can register additional exception translators as - described below.

- -

Functions

- -

register_exception_translator

- -
-template<class ExceptionType, class Translate>
-void register_exception_translator(Translate translate);
-
- -
-
Requires:
- -
- Translate is Copyconstructible, and - the following code must be well-formed: -
-void f(ExceptionType x) { translate(x); }
-
- The expression translate(x) must either throw a C++ - exception, or a subsequent call to PyErr_Occurred() - must return 1. -
- -

- -

Effects: Adds a copy of translate to the sequence of - exception translators tried when Boost.Python catches an exception that - is about to pass into Python's core interpreter. The new translator - will get "first shot" at translating all exceptions matching the catch - clause shown above. Any subsequently-registered translators will be - allowed to translate the exception earlier. A translator which cannot - translate a given C++ exception can re-throw it, and it will be handled - by a translator which was registered earlier (or by the default - translator).
-
- -

Example

-
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/exception_translator.hpp>
-#include <exception>
-
-struct my_exception : std::exception
-{
-  char const* what() throw() { return "One of my exceptions"; }
-};
-
-void translate(my_exception const& e)
-{
-    // Use the Python 'C' API to set up an exception object
-    PyErr_SetString(PyExc_RuntimeError, e.what());
-}
-
-void something_which_throws()
-{
-    ...
-    throw my_exception();
-    ...
-}
-
-BOOST_PYTHON_MODULE(exception_translator_ext)
-{
-  using namespace boost::python;
-  register_exception_translator<my_exception>(&translate);
-  
-  def("something_which_throws", something_which_throws);
-}
-
-
-
- -
- -

Revised 03 October, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/exec.html b/doc/v2/exec.html deleted file mode 100644 index 83d2c9b896..0000000000 --- a/doc/v2/exec.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - - - Boost.Python - <boost/python/exec.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/exec.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
eval
-
exec
-
exec_file
-
-
-
Examples
-
-
- -

Introduction

- -

Exposes a mechanism for embedding the python interpreter into C++ code.

- -

Functions

- -

eval

-
-object eval(str expression,
-            object globals = object(),
-            object locals = object());
-    
-
-
Effects: - Evaluate Python expression from expression in the context - specified by the dictionaries globals and locals. -
-
Returns: - An instance of object - which holds the value of the expression. -
-
- -

exec

-
-object exec(str code,
-            object globals = object(),
-            object locals = object());
-    
-
-
Effects: - Execute Python source code from code in the context - specified by the dictionaries globals and locals. -
-
Returns: - An instance of object - which holds the result of executing the code. -
-
- -

exec_file

-
-object exec_file(str filename,
-                 object globals = object(),
-                 object locals = object());
-    
-
-
Effects: - Execute Python source code from the file named by filename - in the context specified by the dictionaries globals and - locals. -
-
Returns: - An instance of object - which holds the result of executing the code. -
-
- -

Examples

- - The following example demonstrates the use of import - and exec to define a function in python, and later call - it from within C++. - -
-#include <iostream>
-#include <string>
-
-using namespace boost::python;
-
-void greet()
-{ 
-  // Retrieve the main module.
-  object main = import("__main__");
-  
-  // Retrieve the main module's namespace
-  object global(main.attr("__dict__"));
-
-  // Define greet function in Python.
-  object result = exec(
-    "def greet():                   \n"
-    "   return 'Hello from Python!' \n",
-    global, global);
-
-  // Create a reference to it.
-  object greet = global["greet"];
-
-  // Call it.
-  std::string message = extract<std::string>(greet());
-  std::cout << message << std::endl;
-}
-
- - Instead of embedding the python script into a string, - we could also store it in an a file... - -
-def greet():
-   return 'Hello from Python!'
-
- ... and execute that instead. -
-  // ...
-  // Load the greet function from a file.
-  object result = exec_file(script, global, global);
-  // ...
-}
-
-

Revised 01 November, 2005

- -

© Copyright Stefan Seefeld 2005.

- - - diff --git a/doc/v2/extract.html b/doc/v2/extract.html deleted file mode 100644 index 3c6b77f2f0..0000000000 --- a/doc/v2/extract.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/extract.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/extract.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class extract
- -
-
-
Class extract - synopsis
- -
Class extract - constructors and destructor
- -
Class - extract observer functions
-
-
-
-
- - -
Example
-
-
- -

Introduction

- -

Exposes a mechanism for extracting C++ object values from - generalized Python objects. Note that - extract<...> can also be used to - "downcast" an object to some specific ObjectWrapper. Because - invoking a mutable python type with an argument of the same type - (e.g. list([1,2]) typically makes a copy of - the argument object, this may be the only way to access the ObjectWrapper's - interface on the original object. - -

Classes

- -

Class template extract

- -

extract<T> can be used to extract a value of - an arbitrary C++ type from an instance of object. Two usages are supported: -

    -
  1. extract<T>(o) is a temporary object -which is implicitly convertible to T (explicit conversion -is also available through the object's function-call -operator). However, if no conversion is available which can convert -o to an object of type T, a Python -TypeError exception will be raised. - -
  2. extract<T> x(o); constructs an extractor -whose check() member function can be used to ask whether -a conversion is available without causing an exception to be thrown. -
- -

Class template extract - synopsis

-
-namespace boost { namespace python
-{
-  template <class T>
-  struct extract
-  {
-      typedef unspecified result_type;
-
-      extract(PyObject*);
-      extract(object const&);
-
-      result_type operator()() const;
-      operator result_type() const;
-
-      bool check() const;
-  };
-}}
-
- -

Class extract - constructors and destructor

-
-extract(PyObject* p);
-extract(object const&);
-
- -
-
Requires: The first form requires that p is non-null.
- -
Effects:Stores a pointer to the Python object managed - by its constructor argument. In particular, the reference - count of the object is not incremented. The onus is on the user - to be sure it is not destroyed before the extractor's conversion - function is called.
-
- -

Class extract - observer functions

-
-result_type operator()() const;
-operator result_type() const;
-
- -
-
Effects: Converts the stored pointer to - result_type, which is either T or - T const&. -
- -
Returns: An object of result_type - corresponding to the one referenced by the stored pointer.
- -
Throws: error_already_set - and sets a TypeError if no such conversion is - available. May also emit other unspecified exceptions thrown by - the converter which is actually used.
-
- -
-bool check() const;
-
- -
- -
Postconditions: None. In particular, note that a - return value of true does not preclude an exception - being thrown from operator result_type() or - operator()().
- -
Returns: false only if no conversion from the - stored pointer to T is available.
- -
- - -

Examples

- -
-#include <cstdio>
-using namespace boost::python;
-int Print(str s)
-{ 
-   // extract a C string from the Python string object
-   char const* c_str = extract<char const*>(s);
-
-   // Print it using printf
-   std::printf("%s\n", c_str);
-
-   // Get the Python string's length and convert it to an int
-   return extract<int>(s.attr("__len__")())
-}
-
- -The following example shows how extract can be used along with -class_<...> -to create and access an instance of a wrapped C++ class. - -
-struct X
-{
-   X(int x) : v(x) {}
-   int value() { return v; }
- private:
-   int v;
-};
-
-BOOST_PYTHON_MODULE(extract_ext)
-{
-    object x_class(
-       class_<X>("X", init<int>())
-          .def("value", &X::value))
-          ;
-        
-    // Instantiate an X object through the Python interface. 
-    // Its lifetime is now managed by x_obj.
-    object x_obj = x_class(3);
-
-    // Get a reference to the C++ object out of the Python object
-    X& x = extract<X&>(x_obj);
-    assert(x.value() == 3);
-}
-
-

Revised 15 November, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/faq.html b/doc/v2/faq.html deleted file mode 100644 index 75283d77ce..0000000000 --- a/doc/v2/faq.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - - - - - - Boost.Python - FAQ - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Frequently Asked Questions (FAQs)

-
-
- -
- -
How can I wrap a function which takes a - function pointer as an argument?
- -
I'm getting the "attempt to return dangling - reference" error. What am I doing wrong?
- -
Is return_internal_reference - efficient?
- -
How can I wrap functions which take C++ - containers as arguments?
- -
fatal error C1204:Compiler limit:internal - structure overflow
- -
How do I debug my Python extensions?
- -
Why doesn't my *= operator - work?
- -
Does Boost.Python work with Mac OS X?
- -
How can I find the existing PyObject that holds a - C++ object?
- -
How can I wrap a function which needs to take - ownership of a raw pointer?
- -
Compilation takes too much time and eats too much memory! - What can I do to make it faster?
- -
How do I create sub-packages using Boost.Python?
- -
error C2064: term does not evaluate to a function taking 2 arguments -
- -
How can I automatically convert my custom string type to - and from a Python string?
- -
Why is my automatic to-python conversion not being - found?
- -
Is Boost.Python thread-aware/compatible with multiple interpreters?
-
-
- -

How can I wrap a function which takes a - function pointer as an argument?

- - If what you're trying to do is something like this: -
-typedef boost::function<void (string s) > funcptr;
-
-void foo(funcptr fp)
-{
-    fp("hello,world!");
-}
-
-BOOST_PYTHON_MODULE(test)
-{
-    def("foo",foo) ;
-}
-
- -And then: - -
->>> def hello(s):
-...    print s
-...
->>> foo(hello)
-hello, world!
-
- - The short answer is: "you can't". This is not a - Boost.Python limitation so much as a limitation of C++. The - problem is that a Python function is actually data, and the only - way of associating data with a C++ function pointer is to store it - in a static variable of the function. The problem with that is - that you can only associate one piece of data with every C++ - function, and we have no way of compiling a new C++ function - on-the-fly for every Python function you decide to pass - to foo. In other words, this could work if the C++ - function is always going to invoke the same Python - function, but you probably don't want that. - -

If you have the luxury of changing the C++ code you're - wrapping, pass it an object instead and call that; - the overloaded function call operator will invoke the Python - function you pass it behind the object. - -

For more perspective on the issue, see this - posting. - -


- -

I'm getting the "attempt to return dangling - reference" error. What am I doing wrong?

- That exception is protecting you from causing a nasty crash. It usually - happens in response to some code like this: -
-period const& get_floating_frequency() const
-{
-  return boost::python::call_method<period const&>(
-      m_self,"get_floating_frequency");
-}
-
- And you get: -
-ReferenceError: Attempt to return dangling reference to object of type:
-class period
-
- -

In this case, the Python method invoked by call_method - constructs a new Python object. You're trying to return a reference to a - C++ object (an instance of class period) contained within - and owned by that Python object. Because the called method handed back a - brand new object, the only reference to it is held for the duration of - get_floating_frequency() above. When the function returns, - the Python object will be destroyed, destroying the instance of - class period, and leaving the returned reference dangling. - That's already undefined behavior, and if you try to do anything with - that reference you're likely to cause a crash. Boost.Python detects this - situation at runtime and helpfully throws an exception instead of letting - you do that.
-  

-
- -

Is return_internal_reference efficient?

- -
- Q: I have an object composed of 12 doubles. A const& to - this object is returned by a member function of another class. From the - viewpoint of using the returned object in Python I do not care if I get - a copy or a reference to the returned object. In Boost.Python Version 2 - I have the choice of using copy_const_reference or - return_internal_reference. Are there considerations that would lead me - to prefer one over the other, such as size of generated code or memory - overhead? - -

A: copy_const_reference will make an instance with storage - for one of your objects, size = base_size + 12 * sizeof(double). - return_internal_reference will make an instance with storage for a - pointer to one of your objects, size = base_size + sizeof(void*). - However, it will also create a weak reference object which goes in the - source object's weakreflist and a special callback object to manage the - lifetime of the internally-referenced object. My guess? - copy_const_reference is your friend here, resulting in less overall - memory use and less fragmentation, also probably fewer total - cycles.

-
-
- -

How can I wrap functions which take C++ - containers as arguments?

- -

Ralf W. Grosse-Kunstleve provides these notes:

- -
    -
  1. - Using the regular class_<> wrapper: -
    -class_<std::vector<double> >("std_vector_double")
    -  .def(...)
    -  ...
    -  ;
    -
    - This can be moved to a template so that several types (double, int, - long, etc.) can be wrapped with the same code. This technique is used - in the file - -
    - scitbx/include/scitbx/array_family/boost_python/flex_wrapper.h -
    - in the "scitbx" package. The file could easily be modified for - wrapping std::vector<> instantiations. - -

    This type of C++/Python binding is most suitable for containers - that may contain a large number of elements (>10000).

    -
  2. - -
  3. - Using custom rvalue converters. Boost.Python "rvalue converters" - match function signatures such as: -
    -void foo(std::vector<double> const& array); // pass by const-reference
    -void foo(std::vector<double> array); // pass by value
    -
    - Some custom rvalue converters are implemented in the file - -
    - scitbx/include/scitbx/boost_python/container_conversions.h -
    - This code can be used to convert from C++ container types such as - std::vector<> or std::list<> to Python tuples and vice - versa. A few simple examples can be found in the file - -
    - scitbx/array_family/boost_python/regression_test_module.cpp -
    - Automatic C++ container <-> Python tuple conversions are most - suitable for containers of moderate size. These converters generate - significantly less object code compared to alternative 1 above. -
  4. -
- A disadvantage of using alternative 2 is that operators such as - arithmetic +,-,*,/,% are not available. It would be useful to have custom - rvalue converters that convert to a "math_array" type instead of tuples. - This is currently not implemented but is possible within the framework of - Boost.Python V2 as it will be released in the next couple of weeks. [ed.: - this was posted on 2002/03/10] - -

It would also be useful to also have "custom lvalue converters" such - as std::vector<> <-> Python list. These converters would - support the modification of the Python list from C++. For example:

- -

C++:

-
-void foo(std::vector<double>& array)
-{
-  for(std::size_t i=0;i<array.size();i++) {
-    array[i] *= 2;
-  }
-}
-
- Python: -
->>> l = [1, 2, 3]
->>> foo(l)
->>> print l
-[2, 4, 6]
-
- Custom lvalue converters require changes to the Boost.Python core library - and are currently not available. - -

P.S.:

- -

The "scitbx" files referenced above are available via anonymous - CVS:

-
-cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login
-cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx
-
-
- -

fatal error C1204:Compiler limit:internal - structure overflow

- -
- Q: I get this error message when compiling a large source - file. What can I do? - -

A: You have two choices:

- -
    -
  1. Upgrade your compiler (preferred)
  2. - -
  3. - Break your source file up into multiple translation units. - -

    my_module.cpp:

    -
    -...
    -void more_of_my_module();
    -BOOST_PYTHON_MODULE(my_module)
    -{
    -   def("foo", foo);
    -   def("bar", bar);
    -   ...
    -   more_of_my_module();
    -}
    -
    - more_of_my_module.cpp: -
    -void more_of_my_module()
    -{
    -   def("baz", baz);
    -   ...
    -}
    -
    - If you find that a class_<...> declaration - can't fit in a single source file without triggering the error, you - can always pass a reference to the class_ object to a - function in another source file, and call some of its member - functions (e.g. .def(...)) in the auxilliary source - file: - -

    more_of_my_class.cpp:

    -
    -void more_of_my_class(class<my_class>& x)
    -{
    -   x
    -     .def("baz", baz)
    -     .add_property("xx", &my_class::get_xx, &my_class::set_xx)
    -     ;
    -
    -   ...
    -}
    -
    -
  4. -
-
-
- -

How do I debug my Python extensions?

- -

Greg Burley gives the following answer for Unix GCC users:

- -
- Once you have created a boost python extension for your c++ library or - class, you may need to debug the code. Afterall this is one of the - reasons for wrapping the library in python. An expected side-effect or - benefit of using BPL is that debugging should be isolated to the c++ - library that is under test, given that python code is minimal and - boost::python either works or it doesn't. (ie. While errors can occur - when the wrapping method is invalid, most errors are caught by the - compiler ;-). - -

The basic steps required to initiate a gdb session to debug a c++ - library via python are shown here. Note, however that you should start - the gdb session in the directory that contains your BPL my_ext.so - module.

-
-(gdb) target exec python
-(gdb) run
- >>> from my_ext import *
- >>> [C-c]
-(gdb) break MyClass::MyBuggyFunction
-(gdb) cont
- >>> pyobj = MyClass()
- >>> pyobj.MyBuggyFunction()
-Breakpoint 1, MyClass::MyBuggyFunction ...
-Current language:  auto; currently c++
-(gdb) do debugging stuff
-
-
- -

Greg's approach works even better using Emacs' "gdb" - command, since it will show you each line of source as you step through - it.

- -

On Windows, my favorite debugging solution is the debugger that - comes with Microsoft Visual C++ 7. This debugger seems to work with code - generated by all versions of Microsoft and Metrowerks toolsets; it's rock - solid and "just works" without requiring any special tricks from the - user.

- -

Raoul Gough has provided the following for gdb on Windows:

- -
- -

gdb support for Windows DLLs has improved lately, so it is - now possible to debug Python extensions using a few - tricks. Firstly, you will need an up-to-date gdb with support - for minimal symbol extraction from a DLL. Any gdb from version 6 - onwards, or Cygwin gdb-20030214-1 and onwards should do. A - suitable release will have a section in the gdb.info file under - Configuration – Native – Cygwin Native – - Non-debug DLL symbols. Refer to that info section for more - details of the procedures outlined here.

- -

Secondly, it seems necessary to set a breakpoint in the - Python interpreter, rather than using ^C to break execution. A - good place to set this breakpoint is PyOS_Readline, which will - stop execution immediately before reading each interactive - Python command. You have to let Python start once under the - debugger, so that it loads its own DLL, before you can set the - breakpoint:

- -

-

-$ gdb python
-GNU gdb 2003-09-02-cvs (cygwin-special)
-[...]
-
-(gdb) run
-Starting program: /cygdrive/c/Python22/python.exe
-Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32
-Type "help", "copyright", "credits" or "license" for more information.
->>> ^Z
-
-
-Program exited normally.
-(gdb) break *&PyOS_Readline
-Breakpoint 1 at 0x1e04eff0
-(gdb) run
-Starting program: /cygdrive/c/Python22/python.exe
-Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32
-Type "help", "copyright", "credits" or "license" for more information.
-
-Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline ()
-   from /cygdrive/c/WINNT/system32/python22.dll
-(gdb) cont
-Continuing.
->>> from my_ext import *
-
-Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline ()
-   from /cygdrive/c/WINNT/system32/python22.dll
-(gdb) # my_ext now loaded (with any debugging symbols it contains)
-
-
- -

Debugging extensions through Boost.Build

- If you are launching your extension module tests with Boost.Build using the - boost-python-runtest rule, you can ask it to launch your - debugger for you by adding "--debugger=debugger" to your bjam - command-line: -
-bjam -sTOOLS=vc7.1 "--debugger=devenv /debugexe" test
-bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test
-
- It can also be extremely useful to add the -d+2 option when - you run your test, because Boost.Build will then show you the exact - commands it uses to invoke it. This will invariably involve setting up - PYTHONPATH and other important environment variables such as - LD_LIBRARY_PATH which may be needed by your debugger in order to get - things to work right. -
- -

Why doesn't my *= operator work?

- -
- Q: I have exported my class to python, with many overloaded - operators. it works fine for me except the *= - operator. It always tells me "can't multiply sequence with non int - type". If I use p1.__imul__(p2) instead of - p1 *= p2, it successfully executes my code. What's - wrong with me? - -

A: There's nothing wrong with you. This is a bug in Python - 2.2. You can see the same effect in Pure Python (you can learn a lot - about what's happening in Boost.Python by playing with new-style - classes in Pure Python).

-
->>> class X(object):
-...     def __imul__(self, x):
-...         print 'imul'
-...
->>> x = X()
->>> x *= 1
-
- To cure this problem, all you need to do is upgrade your Python to - version 2.2.1 or later. -
-
- -

Does Boost.Python work with Mac OS X?

- - It is known to work under 10.2.8 and 10.3 using - Apple's gcc 3.3 compiler: -
gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1493)
- Under 10.2.8 get the August 2003 gcc update (free at - http://connect.apple.com/). - Under 10.3 get the Xcode Tools v1.0 (also free). -

- Python 2.3 is required. The Python that ships with 10.3 is - fine. Under 10.2.8 use these commands to install Python - as a framework: -

./configure --enable-framework
-make
-make frameworkinstall
- The last command requires root privileges because the target - directory is - /Library/Frameworks/Python.framework/Versions/2.3. - However, the installation does not interfere with the Python - version that ships with 10.2.8. -

- It is also crucial to increase the stacksize before - starting compilations, e.g.: -

limit stacksize 8192k
- If the stacksize is too small the build might crash with - internal compiler errors. -

- Sometimes Apple's compiler exhibits a bug by printing an error - like the following while compiling a - boost::python::class_<your_type> - template instantiation: -

.../inheritance.hpp:44: error: cannot
- dynamic_cast `p' (of type `struct cctbx::boost_python::<unnamed>::add_pair*
-   ') to type `void*' (source type is not polymorphic)
- - We do not know a general workaround, but if the definition of - your_type can be modified the following was found - to work in all cases encountered so far:
struct your_type
-{
-  // before defining any member data
-#if defined(__MACH__) && defined(__APPLE_CC__) && __APPLE_CC__ == 1493
-  bool dummy_;
-#endif
-  // now your member data, e.g.
-  double x;
-  int j;
-  // etc.
-};
- -
-

How can I find the existing PyObject that holds a C++ - object?

- -
- "I am wrapping a function that always returns a pointer to an - already-held C++ object." -
- One way to do that is to hijack the mechanisms used for wrapping a class - with virtual functions. If you make a wrapper class with an initial - PyObject* constructor argument and store that PyObject* as "self", you - can get back to it by casting down to that wrapper type in a thin wrapper - function. For example: -
-class X { X(int); virtual ~X(); ... };
-X* f();  // known to return Xs that are managed by Python objects
-
-
-// wrapping code
-
-struct X_wrap : X
-{
-    X_wrap(PyObject* self, int v) : self(self), X(v) {}
-    PyObject* self;
-};
-
-handle<> f_wrap()
-{
-    X_wrap* xw = dynamic_cast<X_wrap*>(f());
-    assert(xw != 0);
-    return handle<>(borrowed(xw->self));
-}
-
-...
-
-def("f", f_wrap());
-class_<X,X_wrap,boost::noncopyable>("X", init<int>())
-   ...
-   ;
-
- Of course, if X has no virtual functions you'll have to use - static_cast instead of dynamic_cast with no - runtime check that it's valid. This approach also only works if the - X object was constructed from Python, because - Xs constructed from C++ are of course never - X_wrap objects. - -

Another approach to this requires you to change your C++ code a bit; - if that's an option for you it might be a better way to go. work we've - been meaning to get to anyway. When a shared_ptr<X> is - converted from Python, the shared_ptr actually manages a reference to the - containing Python object. When a shared_ptr<X> is converted back to - Python, the library checks to see if it's one of those "Python object - managers" and if so just returns the original Python object. So you could - just write object(p) to get the Python object back. To - exploit this you'd have to be able to change the C++ code you're wrapping - so that it deals with shared_ptr instead of raw pointers.

- -

There are other approaches too. The functions that receive the Python - object that you eventually want to return could be wrapped with a thin - wrapper that records the correspondence between the object address and - its containing Python object, and you could have your f_wrap function - look in that mapping to get the Python object out.

- -
- -

How can I wrap a function which needs to take - ownership of a raw pointer?

- -
- Part of an API that I'm wrapping goes something like this: -
-struct A {}; struct B { void add( A* ); }
-where B::add() takes ownership of the pointer passed to it.
-
- -

However:

-
-a = mod.A()
-b = mod.B()
-b.add( a )
-del a
-del b
-# python interpreter crashes
-# later due to memory corruption.
-
- -

Even binding the lifetime of a to b via - with_custodian_and_ward doesn't prevent the python object a from - ultimately trying to delete the object it's pointing to. Is there a way - to accomplish a 'transfer-of-ownership' of a wrapped C++ object?

- -

--Bruce Lowery

-
- Yes: Make sure the C++ object is held by auto_ptr: -
-class_<A, std::auto_ptr<A> >("A")
-    ...
-    ;
-
- Then make a thin wrapper function which takes an auto_ptr parameter: -
-void b_insert(B& b, std::auto_ptr<A> a)
-{
-    b.insert(a.get());
-    a.release();
-}
-
- Wrap that as B.add. Note that pointers returned via manage_new_object - will also be held by auto_ptr, so this transfer-of-ownership - will also work correctly. - -
-

Compilation takes too much time and eats too - much memory! What can I do to make it faster?

-

- Please refer to the Reducing Compiling Time section in the tutorial. -

- -
-

How do I create sub-packages using Boost.Python?

-

- Please refer to the Creating Packages section in the tutorial. -

- -
-

error C2064: term does - not evaluate to a function taking 2 arguments

- Niall Douglas provides these notes:

- If you see Microsoft Visual C++ 7.1 (MS Visual Studio .NET 2003) issue - an error message like the following it is most likely due to a bug - in the compiler: -

boost\boost\python\detail\invoke.hpp(76):
-error C2064: term does not evaluate to a function taking 2 arguments"
- This message is triggered by code like the following: -
#include <boost/python.hpp>
-
-using namespace boost::python;
-
-class FXThread
-{
-public:
-    bool setAutoDelete(bool doso) throw();
-};
-
-void Export_FXThread()
-{
-    class_< FXThread >("FXThread")
-        .def("setAutoDelete", &FXThread::setAutoDelete)
-    ;
-}
-    
- The bug is related to the throw() modifier. - As a workaround cast off the modifier. E.g.: -
-        .def("setAutoDelete", (bool (FXThread::*)(bool)) &FXThread::setAutoDelete)
-

(The bug has been reported to Microsoft.)

- -
-

How can I automatically - convert my custom string type to and from a Python string?

- Ralf W. Grosse-Kunstleve provides these - notes:

- Below is a small, self-contained demo extension module that shows - how to do this. Here is the corresponding trivial test: -

import custom_string
-assert custom_string.hello() == "Hello world."
-assert custom_string.size("california") == 10
- - If you look at the code you will find: - -
    -
  • A custom to_python converter (easy): - custom_string_to_python_str - -
  • A custom lvalue converter (needs more code): - custom_string_from_python_str -
- - The custom converters are registered in the global Boost.Python - registry near the top of the module initialization function. Once - flow control has passed through the registration code the automatic - conversions from and to Python strings will work in any module - imported in the same process. - -
#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/to_python_converter.hpp>
-
-namespace sandbox { namespace {
-
-  class custom_string
-  {
-    public:
-      custom_string() {}
-      custom_string(std::string const& value) : value_(value) {}
-      std::string const& value() const { return value_; }
-    private:
-      std::string value_;
-  };
-
-  struct custom_string_to_python_str
-  {
-    static PyObject* convert(custom_string const& s)
-    {
-      return boost::python::incref(boost::python::object(s.value()).ptr());
-    }
-  };
-
-  struct custom_string_from_python_str
-  {
-    custom_string_from_python_str()
-    {
-      boost::python::converter::registry::push_back(
-        &convertible,
-        &construct,
-        boost::python::type_id<custom_string>());
-    }
-
-    static void* convertible(PyObject* obj_ptr)
-    {
-      if (!PyString_Check(obj_ptr)) return 0;
-      return obj_ptr;
-    }
-
-    static void construct(
-      PyObject* obj_ptr,
-      boost::python::converter::rvalue_from_python_stage1_data* data)
-    {
-      const char* value = PyString_AsString(obj_ptr);
-      if (value == 0) boost::python::throw_error_already_set();
-      void* storage = (
-        (boost::python::converter::rvalue_from_python_storage<custom_string>*)
-          data)->storage.bytes;
-      new (storage) custom_string(value);
-      data->convertible = storage;
-    }
-  };
-
-  custom_string hello() { return custom_string("Hello world."); }
-
-  std::size_t size(custom_string const& s) { return s.value().size(); }
-
-  void init_module()
-  {
-    using namespace boost::python;
-
-    boost::python::to_python_converter<
-      custom_string,
-      custom_string_to_python_str>();
-
-    custom_string_from_python_str();
-
-    def("hello", hello);
-    def("size", size);
-  }
-
-}} // namespace sandbox::<anonymous>
-
-BOOST_PYTHON_MODULE(custom_string)
-{
-  sandbox::init_module();
-}
- -
-

Why is my automatic to-python conversion not being found?

- Niall Douglas provides these notes:

- If you define custom converters similar to the ones - shown above the def_readonly() and def_readwrite() - member functions provided by boost::python::class_ for - direct access to your member data will not work as expected. - This is because def_readonly("bar", &foo::bar) is - equivalent to: - -

.add_property("bar", make_getter(&foo::bar, return_internal_reference()))
- - Similarly, def_readwrite("bar", &foo::bar) is - equivalent to: - -
.add_property("bar", make_getter(&foo::bar, return_internal_reference()),
-                     make_setter(&foo::bar, return_internal_reference())
- - In order to define return value policies compatible with the - custom conversions replace def_readonly() and - def_readwrite() by add_property(). E.g.: - -
.add_property("bar", make_getter(&foo::bar, return_value_policy<return_by_value>()),
-                     make_setter(&foo::bar, return_value_policy<return_by_value>()))
- -
-

Is Boost.Python thread-aware/compatible with multiple interpreters?

- Niall Douglas provides these notes:

- The quick answer to this is: no.

-

- The longer answer is that it can be patched to be so, but it's - complex. You will need to add custom lock/unlock wrapping of every - time your code enters Boost.Python (particularly every virtual - function override) plus heavily modify - boost/python/detail/invoke.hpp with custom unlock/lock - wrapping of every time Boost.Python enters your code. You must - furthermore take care to not unlock/lock when Boost.Python - is invoking iterator changes via invoke.hpp.

-

- There is a patched invoke.hpp posted on the C++-SIG - mailing list archives and you can find a real implementation of all - the machinery necessary to fully implement this in the TnFOX - project at this - SourceForge project location.

- -
- -

Revised - - 12 March, 2006 - -

- -

© Copyright Dave Abrahams 2002-2006.

- - diff --git a/doc/v2/feb2002.html b/doc/v2/feb2002.html deleted file mode 100644 index 5f15aeace2..0000000000 --- a/doc/v2/feb2002.html +++ /dev/null @@ -1,367 +0,0 @@ - - - - - Boost.Python - February 2002 Progress Report - - - - -
-

-

- -
-

Boost.Python

- -

February 2002 Progress Report

-
-
- -

Contents

- -
-
Python10 Conference Report - -
Boost.Python v2 Progress - -
-
-
Documentation - -
Overhaul of - to_python/from_python - conversion mechanism - -
Miscellaneous -
-
- -

Python10 Conference Report

- I spent the first week of February at the Python10 conference - in Alexandria, VA. I'm including this experience report - for two reasons: firstly, it documents where my time was - used. Secondly, a public presence for Boost.Python and - interaction between the Python and C++ communities is - important to the future of Boost.Python, which in turn is - important to the Kull Project. - -

Andy Koenig, of all people, was the keynote speaker of - this year's opening plenary session. He presented his - "impressions of a polyglot outsider", which - studiously avoided any mention of C++ until the end of his - talk, when he was asked about standardization. I was - surprised to learn that the C++ community at large wanted a - few more years before beginning but when ANSI accepted - HP's request for a standard, the process was forced to - start: it was a matter of participating or having - standardization proceed without one's input. Andy managed - to highlight very effectively the balance of strengths in - Python, one of the most important being its support for - extension via libraries. In many ways that makes Python a - good analogue for C++ in the interpreted world - -

There were several kind mentions of the Boost.Python - library from people who found it indispensable. I was - particularly happy that Karl MacMillan, Michael Droettboom, - and Ichiro Fujinaga from Johns Hopkins is using it to do OCR - on a vast library of music notation, since in a previous life - I was an author of music notation software. These guys are - also drawing on Ullrich Koethe's VIGRA library for image - manipulation (Ullrich has been a major contributor to - Boost.Python). They also have a system for writing the - Boost.Python wrapper code in C++ comments, which allows them - to keep all of the code in one place. I've asked them to - send me some information on that. - -

The development of Swig has been gaining momentum again - (the basic description at - www.boost.org/libs/python/doc/comparisons.html still - applies). The talk given about it by David Beazly was very - well-attended, and they appear to have quite a few users. - Swig's strengths (coverage of many langauages) and - weaknesses (incomplete C++ language support) haven't - changed, although the C++ support seems to have improved - considerably - they now claim to have a complete model of the - C++ type system. It seems to be mostly geared at wrapping - what Walter Landry calls "C-Tran": C++ code which - traffics in built-in types with little use of abstraction. - I'm not knocking that, either: I'm sure a lot of that - code exists, so it's a valuable service. One feature Swig - has which I'd like to steal is the ability to unwrap a - single Python argument into multiple C++ arguments, for - example, by converting a Python string into a pointer and - length. When his talk was over, David approached me about a - possible joint workshop on language binding, which sounds - like a fun idea to me. - -

I spent some considerable time talking with Steven Knight, - the leader of the Scons build tool effort. We had a lot to - share with one another, and I gained a much better - appreciation for many of the Scons design decisions. Scons - seems to be concentrating on being the ultimate build system - substrate, and Steve seemed to think that we were on the - right track with our high-level design. We both hope that the - Boost.Build V2 high-level architecture can eventually be - ported to run on top of Scons. - -

They also have a highly-refined and successful development - procedure which I'd like to emulate for Boost.Build V2. - Among many other things they do, their source-control system - automatically ensures that when you check in a new test, it - is automatically run on the currently checked-in state of the - code, and is expected to fail -- a relatively obvious good - idea which I've never heard before. - -

Guido Van Rossum's "State of the Python - Union" address was full of questions for the community - about what should be done next, but the one idea Guido seemed - to stress was that core language stability and continuing - library development would be a good idea (sound familiar?) I - mentioned the Boost model as a counterpoint to the idea of - something like CPAN (the massive Perl library archives), and - it seemed to generate some significant interest. I've - offered to work with anyone from the Python community who - wants to set up something like Boost. - -

There was some discussion of "string - interpolation" (variable substitution in strings), and - Guido mentioned that he had some thoughts about the - strengths/weaknesses of Python's formatting interface. It - might be useful for those working on formatting for boost to - contact him and find out what he has to say. - -

Ka-Ping Yee demoed a Mailman discussion thread weaver. - This tool weaves the various messages in a discussion thread - into a single document so you can follow the entire - conversation. Since we're looking very seriously at - moving Boost to Mailman, this could be a really useful thing - for us to have. If we do this, we'll move the yahoogroups - discussions into the mailman archive so old discussions can - be easily accessed in the same fashion. - -

And, just because it's cool, though perhaps not - relevant: http://homepages.ulb.ac.be/~arigo/psyco/ is a - promising effort to accelerate the execution of Python code - to speeds approaching those of compiled languages. It - reminded me a lot of Todd Veldhuizen's research into - moving parts of C++ template compilation to runtime, only - coming from the opposite end of things. - -

Boost.Python v2 Progress

- Here's what actually got accomplished. - -

Documentation

- -

My first priority upon returning from Python10 was to get - some documentation in place. After wasting an unfortunate - amount of time looking at automatic documentation tools which - don't quite work, I settled down to use Bill Kempf's - HTML templates designed to be a boost standard. While they - are working well, it is highly labor-intensive. - -

I decided to begin with the high-level reference material, - as opposed to tutorial, narrative, or nitty-gritty details of - the framework. It seemed more important to have a precise - description of the way the commonly-used components work than - to have examples in HTML (since we already have some test - modules), and since the low-level details are much - less-frequently needed by users it made sense for me to - simply respond to support requests for the time being. - -

After completing approximately 60% of the high-level docs - (currently checked in to libs/python/doc/v2), I found myself - ready to start documenting the mechanisms for creating - to-/from-python converters. This caused a dilemma: I had - realized during the previous week that a much simpler, - more-efficient, and easier-to-use implementation was - possible, but I hadn't planned on implementing it right - away, since what was already in place worked adequately. I - had also received my first query on the C++-sig about how to - write such a converter - -

Given the labor-intensive nature of documentation writing, - I decided it would be a bad idea to document the conversion - mechanism if I was just going to rewrite it. Often the best - impetus for simplifying a design is the realization that - understandably documenting its current state would be too - difficult, and this was no exception. - -

Overhaul of - to_python/from_python conversion - mechanism

- -

There were two basic realizations involved here: - -

    -
  1. to_python conversion could be a one-step - process, once an appropriate conversion function is found. - This allows elimination of the separate indirect - convertibility check - -
  2. There are basically two categories of from_python - conversions: those which lvalues stored within or held by - the Python object (essentially extractions), like what - happens when an instance of a C++ class exposed with class_ - is used as the target of a wrapped member function), and - those in which a new rvalue gets created, as when a Python - Float is converted to a C++ - complex<double> or a Python tuple is - converted to a C++ std::vector<>. From - the client side, there are two corresponding categories of - conversion: those which demand an lvalue conversion and - those which can accept an lvalue or an rvalue conversion. -
- The latter realization allowed the following collapse, which - considerably simplified things: - -
- - - - - - - - - - - - - - - - - -
Target Type - - Eligible Converters - -
T - - T rvalue or lvalue - -
T const - -
T volatile - -
T const volatile - -
T const& - -
T const* - - T lvalue - -
T volatile* - -
T const volatile* - -
T& - -
T volatile& - -
T const volatile& - -
T* const& - -
T const* const& - -
T volatile*const& - -
T const volatile*const& -
-
- This job included the following additional enhancements: - -
    -
  • Elimination of virtual functions, which cause object - code bloat - -
  • Registration of a single converter function for all - lvalue conversions, two for all rvalue conversions - -
  • Killed lots of unneeded code - -
  • Increased opacity of registry interface - -
  • Eliminated all need for decorated runtime type - identifiers - -
  • Updated test modules to reflect new interface - -
  • Eliminated the need for users to worry about converter - lifetime issues Additional Builtin Conversion Enhancements - -
  • Support for complex<float>, - complex<double>, and complex<long double> - conversions - -
  • Support for bool conversions - -
  • NULL pointers representable by None in Python - -
  • Support for conversion of Python classic classes to - numeric types -
- -

Miscellaneous

- These don't fit easily under a large heading: - -
    -
  • Support CallPolicies for class member functions - -
  • from_python_data.hpp: revamped type alignment - metaprogram so that it's fast enough for KCC - -
  • classfwd.hpp header forward-declares class_<T> - -
  • indirect_traits.hpp: - -
  • added is_pointer_to_reference - -
  • fixed bugs - -
  • Reduced recompilation dependencies - -
  • msvc_typeinfo works around broken MS/Intel typeid() - implementation - -
  • Many fixes and improvements to the type_traits library - in order to work around compiler bugs and suppress warnings - -
  • Eliminated the need for explicit acquisition of - converter registrations - -
  • Expanded constructor support to 6 arguments - -
  • Implemented generalized pointer lifetime support - -
  • Updated code generation for returning.hpp - -
  • Tracked down and fixed cycle GC bugs - -
  • Added comprehensive unit tests for destroy_reference, - pointer_type_id, select_from_python, complex<T>, - bool, and classic class instance conversions -
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave Abrahams 2002. Distributed - under the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/v2/function_doc_signature.html b/doc/v2/function_doc_signature.html deleted file mode 100644 index e439a77acb..0000000000 --- a/doc/v2/function_doc_signature.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - - - - - Boost.Python - - <boost/python/doobject/function_doc_signature.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/object/function_doc_signature.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class - function_doc_signature_generator
- -
-
-
Class - function_doc_signature_generator synopsis
- -
-
-
-
- -
Examples
-
-
- -

Introduction

- -

Boost.Python supports docstrings with automatic - appending of Pythonic and C++ signatures. This feature is implemented - by class function_doc_signature_generator - The class uses all of the overloads, supplied arg names and default values, as well as - the user-defined docstrings, to generate documentation for a given function.

- -

Classes

- -

Class - function_doc_signature_generator

- -

- The class has only one public function which returns a list of strings documenting the - overloads of a function. -

- -

Class - function_doc_signature_generator synopsis

-
-namespace boost { namespace python { namespace objects {
-
-    class function_doc_signature_generator 
-    {
-      public:
-          static list function_doc_signatures(function const *f);
-    };
-
-}}}
-
- - -

Examples

- -

Docstrings generated with function_doc_signature_generator

-
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/args.hpp>
-#include <boost/python/tuple.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/overloads.hpp>
-#include <boost/python/raw_function.hpp>
-
-using namespace boost::python;
-
-tuple f(int x = 1, double y = 4.25, char const* z = "wow")
-{
-    return make_tuple(x, y, z);
-}
-
-BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3)
-
-
-struct X
-{
-    tuple f(int x = 1, double y = 4.25, char const* z = "wow")
-    {
-        return make_tuple(x, y, z);
-    }
-};
-
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3)
-
-tuple raw_func(tuple args, dict kw)
-{
-    return make_tuple(args, kw);
-}
-
-BOOST_PYTHON_MODULE(args_ext)
-{
-    def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow")
-        , "This is f's docstring"
-        );
-
-    def("raw", raw_function(raw_func));
-
-    def("f1", f, f_overloads("f1's docstring", args("x", "y", "z")));
-
-
-    class_<X>("X", "This is X's docstring", init<>(args("self")))
-        .def("f", &X::f
-             , "This is X.f's docstring"
-             , args("self","x", "y", "z"))
-
-        ;
-
-}
-
-
-Python code: -
->>> import args_ext
->>> help(args_ext)
-Help on module args_ext:
-
-NAME
-    args_ext
-
-FILE
-    args_ext.pyd
-
-CLASSES
-    Boost.Python.instance(__builtin__.object)
-        X
-
-    class X(Boost.Python.instance)
-     |  This is X's docstring
-     |
-     |  Method resolution order:
-     |      X
-     |      Boost.Python.instance
-     |      __builtin__.object
-     |
-     |  Methods defined here:
-     |
-     |  __init__(...)
-     |      __init__( (object)self) -> None :
-     |       C++ signature:
-     |           void __init__(struct _object *)
-     |
-     |  f(...)
-     |      f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring
-     |      C++ signature:
-     |          class boost::python::tuple f(struct X {lvalue},int,double,char const *)
-     |
-     |    .................
-     |
-FUNCTIONS
-    f(...)
-        f([ (int)x=1 [, (float)y=4.25 [, (str)z='wow']]]) -> tuple : This is f's docstring
-        C++ signature:
-            class boost::python::tuple f([ int=1 [,double=4.25 [,char const *='wow']]])
-
-    f1(...)
-        f1([ (int)x [, (float)y [, (str)z]]]) -> tuple : f1's docstring
-        C++ signature:
-            class boost::python::tuple f1([ int [,double [,char const *]]])
-
-    raw(...)
-        object raw(tuple args, dict kwds) :
-        C++ signature:
-            object raw(tuple args, dict kwds)
-
-
-
- -

© Copyright Nikolay Mladenov 2007.

- - diff --git a/doc/v2/handle.html b/doc/v2/handle.html deleted file mode 100644 index b20d94a1ff..0000000000 --- a/doc/v2/handle.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/handle.hpp> - - - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/handle.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class template - handle
- -
-
-
Class handle - synopsis
- -
Class handle - constructors and destructor
- -
Class handle - modifier functions
- -
Class handle - observer functions
-
-
-
-
- -
Functions
- -
-
-
borrowed
- -
allow_null
-
-
-
-
- -

Introduction

- -

<boost/python/handle.hpp> provides - class template handle, a smart pointer for - managing reference-counted Python objects.

- -

Classes

- -

Class template handle

- -

handle is a smart pointer to a Python object type; it - holds a pointer of type T*, where T is its template - parameter. T must be either a type derived from - PyObject or a POD type - whose initial sizeof(PyObject) bytes are layout-compatible - with PyObject. Use handle<> at the - boundary between the Python/'C' API and high-level code; prefer object for a generalized - interface to Python objects.

- -

In this document, the term "upcast" refers to an - operation which converts a pointer Y* to a base class - pointer T* via static_cast<T*> if - Y is derived from T, or via C-style cast - (T*) if it is not. However, in the latter case the "upcast" - is ill-formed if the initial sizeof(PyObject) bytes of - Y are not layout-compatible with PyObject.

- -

Class template handle - synopsis

-
-namespace boost { namespace python
-{
-  template <class T>
-  class handle
-  {
-      typedef unspecified-member-function-pointer bool_type;
-
-   public: // types
-      typedef T element_type;
-
-   public: // member functions
-      ~handle();
-
-      template <class Y>
-      explicit handle(detail::borrowed<null_ok<Y> >* p);
-
-      template <class Y>
-      explicit handle(null_ok<detail::borrowed<Y> >* p);
-
-      template <class Y>
-      explicit handle(detail::borrowed<Y>* p);
-
-      template <class Y>
-      explicit handle(null_ok<Y>* p);
-
-      template <class Y>
-      explicit handle(Y* p);
-
-      handle();
-
-      handle& operator=(handle const& r);
-
-      template<typename Y>
-      handle& operator=(handle<Y> const & r); // never throws
-
-
-      template <typename Y>
-      handle(handle<Y> const& r);
-
-      handle(handle const& r);
-
-      T* operator-> () const;
-      T& operator* () const;
-      T* get() const;
-      void reset();
-      T* release();
-
-      operator bool_type() const; // never throws
-   private:
-      T* m_p;
-  };
-  
-  template <class T> struct null_ok;
-  namespace detail { template <class T> struct borrowed; }
-}}
-
- -

Class handle constructors - and destructor

-
-virtual ~handle();
-
- -
-
Effects: - Py_XDECREF(upcast<PyObject*>(m_p))
-
-
-template <class Y>
-explicit handle(detail::borrowed<null_ok<Y> >* p);
-
- -
-
Effects: - Py_XINCREF(upcast<PyObject*>(p)); - m_p = upcast<T*>(p);
-
-
-template <class Y>
-explicit handle(null_ok<detail::borrowed<Y> >* p);
-
- -
-
Effects: - Py_XINCREF(upcast<PyObject*>(p)); - m_p = upcast<T*>(p);
-
-
-template <class Y>
-explicit handle(detail::borrowed<Y>* p);
-
- -
-
Effects: - Py_XINCREF(upcast<PyObject*>(p)); - m_p = upcast<T*>(expect_non_null(p));
-
-
-template <class Y>
-explicit handle(null_ok<Y>* p);
-
- -
-
Effects: - m_p = upcast<T*>(p);
-
-
-template <class Y>
-explicit handle(Y* p);
-
- -
-
Effects: - m_p = upcast<T*>(expect_non_null(p));
-
-
-handle();
-
- -
-
Effects: m_p = 0;
-
-
-template <typename Y>
-handle(handle<Y> const& r);
-handle(handle const& r);
-
- -
-
Effects: - m_p = r.m_p; Py_XINCREF(upcast<PyObject*>(m_p));
-
- -

Class handle - modifiers

-
-handle& operator=(handle const& r);
-template<typename Y>
-handle& operator=(handle<Y> const & r); // never throws
-
- -
-
Effects: - Py_XINCREF(upcast<PyObject*>(r.m_p)); Py_XDECREF( - upcast<PyObject*>(m_p)); m_p = r.m_p;
-
-
-T* release();
-
- -
-
Effects: T* x = m_p; m_p = 0;return - x;
-
-
-void reset();
-
- -
-
Effects: - *this = handle<T>();
-
- -

Class handle - observers

-
-T* operator-> () const;
-T* get() const;
-
- -
-
Returns: m_p;
-
-
-T& operator* () const;
-
- -
-
Returns: *m_p;
-
-
-operator bool_type() const; // never throws
-
- -
-
Returns: 0 if m_p == 0, a pointer - convertible to true otherwise.
-
- -

Functions

- -

borrowed

-
-template <class T>
-detail::borrowed<T>* borrowed(T* p)
-{
-    return (detail::borrowed<T>*)p;
-}
-
- -

allow_null

-
-template <class T>
-null_ok<T>* allow_null(T* p)
-{
-    return (null_ok<T>*)p;
-}
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002 -.

- - - diff --git a/doc/v2/has_back_reference.html b/doc/v2/has_back_reference.html deleted file mode 100644 index 29b81506cd..0000000000 --- a/doc/v2/has_back_reference.html +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/has_back_reference.hpp> - - - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/has_back_reference.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class template - has_back_reference
- -
-
-
Class template - has_back_reference synopsis
-
-
- -
Example(s)
-
-
-
-
- -

Introduction

- -

<boost/python/has_back_reference.hpp> defines the - predicate metafunction has_back_reference<>, which can - be specialized by the user to indicate that a wrapped class instance - holds a PyObject* corresponding to a Python object.

- -

Classes

- -

Class template - has_back_reference

- -

A unary metafunction whose value is true iff its argument - is a pointer_wrapper<>.

- -

Class template - has_back_reference synopsis

-
-namespace boost { namespace python
-{
-    template<class WrappedClass> class has_back_reference
-    { 
-        typedef mpl::false_ type;
-    };
-}}
-
-

A " - metafunction" that is inspected by Boost.Python to determine how - wrapped classes can be constructed.

- -
-
type::value is an integral constant convertible to bool - of unspecified type.
- -
Specializations may substitute a true-valued integral constant wrapper for - type iff for each invocation of - class_<WrappedClass>::def(init< - type-sequence...>()) and the implicitly wrapped - copy constructor (unless it is - noncopyable), there exists a corresponding constructor - WrappedClass::WrappedClass(PyObject*,  - type-sequence...). If such a specialization exists, - the WrappedClass constructors will be called with a "back - reference" pointer to the corresponding Python object whenever they are - invoked from Python. The easiest way to provide this nested -type - - is to - derive the specialization from mpl::true_. -
-
- -

Example

- -

C++ module definition

-
-#include <boost/python/class.hpp>
-#include <boost/python/module.hpp>
-#include <boost/python/has_back_reference.hpp>
-#include <boost/python/handle.hpp>
-#include <boost/shared_ptr.hpp>
-
-using namespace boost::python;
-using boost::shared_ptr;
-
-struct X
-{
-    X(PyObject* self) : m_self(self), m_x(0) {}
-    X(PyObject* self, int x) : m_self(self), m_x(x) {}
-    X(PyObject* self, X const& other) : m_self(self), m_x(other.m_x) {}
-    
-    handle<> self() { return handle<>(borrowed(m_self)); }
-    int get() { return m_x; }
-    void set(int x) { m_x = x; }
-
-    PyObject* m_self;
-    int m_x;
-};
-
-// specialize has_back_reference for X
-namespace boost { namespace python
-{
-  template <>
-  struct has_back_reference<X>
-    : mpl::true_
-  {};
-}}
-
-struct Y
-{
-    Y() : m_x(0) {}
-    Y(int x) : m_x(x) {}
-    int get() { return m_x; }
-    void set(int x) { m_x = x; }
-
-    int m_x;
-};
-
-shared_ptr<Y> 
-Y_self(shared_ptr<Y> self) { return self; }
-
-BOOST_PYTHON_MODULE(back_references)
-{
-    class_<X>("X")
-       .def(init<int>())
-       .def("self", &X::self)
-       .def("get", &X::get)
-       .def("set", &X::set)
-       ;
-
-    class_<Y, shared_ptr<Y> >("Y")
-       .def(init<int>())
-       .def("get", &Y::get)
-       .def("set", &Y::set)
-       .def("self", Y_self)
-       ;
-}
-
- The following Python session illustrates that x.self() - returns the same Python object on which it is invoked, while - y.self() must create a new Python object which refers to the - same Y instance. - -

Python code

-
->>> from back_references import *
->>> x = X(1)
->>> x2 = x.self()
->>> x2 is x
-1
->>> (x.get(), x2.get())
-(1, 1)
->>> x.set(10)
->>> (x.get(), x2.get())
-(10, 10)
->>>
->>>
->>> y = Y(2)
->>> y2 = y.self()
->>> y2 is y
-0
->>> (y.get(), y2.get())
-(2, 2)
->>> y.set(20)
->>> (y.get(), y2.get())
-(20, 20)
-
- -

Revised - - 18 July, 2004 - -

- -

© Copyright Dave Abrahams 2002 -.

- - - diff --git a/doc/v2/implicit.html b/doc/v2/implicit.html deleted file mode 100644 index e9d5cac583..0000000000 --- a/doc/v2/implicit.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/implicit.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/implicit.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
Function Template - implicitly_convertible
-
-
- -
Example
-
-
- -

Introduction

- implicitly_convertible allows Boost.Python to implicitly - take advantage of a C++ implicit or explicit conversion when matching - Python objects to C++ argument types. - -

Functions

- -

Function template - implicitly_convertible

-
-template <class Source, class Target>
-void implicitly_convertible();
-
- - - - - - - - - - - - - - - - - - - - - -
- implicitly_convertible template parameters
-
ParameterDescription
SourceThe source type of the implicit conversion
TargetThe target type of the implicit conversion
- -
-
Requires: The declaration Target t(s);, where - s is of type Source, is valid.
- -
Effects: registers an rvalue from_python - converter to Target which can succeed for any - PyObject* p iff there exists any registered converter - which can produce Source rvalues
- -
Rationale: C++ users expect to be able to take advantage of - the same sort of interoperability in Python as they do in C++.
-
- -

Example

- -

C++ module definition

-
-#include <boost/python/class.hpp>
-#include <boost/python/implicit.hpp>
-#include <boost/python/module.hpp>
-
-using namespace boost::python;
-
-struct X
-{
-    X(int x) : v(x) {}
-    operator int() const { return v; }
-    int v;
-};
-
-int x_value(X const& x)
-{
-    return x.v;
-}
-
-X make_x(int n) { return X(n); }
-
-BOOST_PYTHON_MODULE(implicit_ext)
-{
-    def("x_value", x_value);
-    def("make_x", make_x);
-
-    class_<X>("X", 
-        init<int>())
-        ;
-
-    implicitly_convertible<X,int>();
-    implicitly_convertible<int,X>();
-}
-
- -

Python code

-
->>> from implicit_ext import *
->>> x_value(X(42))
-42
->>> x_value(42)
-42
->>> x = make_x(X(42))
->>> x_value(x)
-42
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/import.html b/doc/v2/import.html deleted file mode 100644 index 15c1c68c55..0000000000 --- a/doc/v2/import.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - Boost.Python - <boost/python/import.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/import.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
import
-
-
-
Examples
-
-
- -

Introduction

- -

Exposes a mechanism for importing python modules.

- -

Functions

- -

import

-
-object import(str name);
-    
-
-
Effects: Imports the module named by name.
-
Returns: An instance of object - which holds a reference to the imported module.
-
- -

Examples

- - The following example demonstrates the use of import - to access a function in python, and later call it from within C++. - -
-#include <iostream>
-#include <string>
-
-using namespace boost::python;
-
-void print_python_version()
-{ 
-  // Load the sys module.
-  object sys = import("sys");
-
-  // Extract the python version.
-  std::string version = extract<std::string>(sys.attr("version"));
-  std::cout << version << std::endl;
-}
-
-

Revised 01 November, 2005

- -

© Copyright Stefan Seefeld 2005.

- - - diff --git a/doc/v2/index.html b/doc/v2/index.html deleted file mode 100644 index 92593d06e7..0000000000 --- a/doc/v2/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - Loading index page; if nothing happens, please go to ../index.html. - - - diff --git a/doc/v2/indexing.html b/doc/v2/indexing.html deleted file mode 100644 index 72c999c419..0000000000 --- a/doc/v2/indexing.html +++ /dev/null @@ -1,695 +0,0 @@ - - - - - - - - - - - Indexing Support - - - - - - - - -
-

- C++ Boost -

-
-

- Boost.Python -

- -

Headers <boost/python/indexing/indexing_suite.hpp>
- <boost/python/indexing/vector_indexing_suite.hpp>

-
-
-

- Contents -

-
-
- Introduction -
-
- Interface -
-
-
-
- indexing_suite -
-
- indexing_suite - sub-classes -
-
-
-
- vector_indexing_suite -
-
-
-
-
-
-
-
- indexing_suite class -
-
- vector_indexing_suite - class
-
map_indexing_suite class
-
-
-

- Introduction -

-

- Indexing is a Boost Python facility for easy exportation of indexable - C++ containers to Python. Indexable containers are containers that - allow random access through the operator[] (e.g. std::vector). -

-

- While Boost Python has all the facilities needed to expose indexable - C++ containers such as the ubiquitous std::vector to Python, the - procedure is not as straightforward as we'd like it to be. Python - containers do not map easily to C++ containers. Emulating Python - containers in C++ (see Python Reference Manual, Emulating - container types) using Boost Python is non trivial. There are a lot - of issues to consider before we can map a C++ container to Python. - These involve implementing wrapper functions for the methods - __len__, __getitem__, - __setitem__, __delitem__, - __iter__ and __contains. -

-

- The goals: -

-
    -
  • -
    - Make indexable C++ containers behave exactly as one would expect a - Python container to behave. -
    -
  • -
  • - Provide default reference semantics for container element indexing - (__getitem__) such that c[i] can be mutable. - Require: -
    -
    -    val = c[i]
    -    c[i].m()
    -    val == c[i]
    -          
    -
    where m is a non-const (mutating) member function - (method). -
  • -
  • - Return safe references from __getitem__ such that subsequent - adds and deletes to and from the container will not result in - dangling references (will not crash Python). -
  • -
  • - Support slice indexes. -
  • -
  • - Accept Python container arguments (e.g. lists, tuples) wherever - appropriate. -
  • -
  • - Allow for extensibility through re-definable policy classes. -
  • -
  • - Provide predefined support for the most common STL and STL like - indexable containers. -
  • -
-
- -

The Boost.Python Indexing Interface

-

indexing_suite [ Header <boost/python/indexing/indexing_suite.hpp> - ]

-

- The indexing_suite class is the base class for the - management of C++ containers intended to be integrated to Python. The - objective is make a C++ container look and feel and behave exactly as - we'd expect a Python container. The class automatically wraps these - special Python methods (taken from the Python reference: Emulating - container types): -

-
-
-
-
- __len__(self) -
-
- Called to implement the built-in function len()  Should return - the length of the object, an integer >= 0. Also, - an object that doesn't define a __nonzero__() method and whose __len__() method returns zero is considered to be - false in a Boolean context.   -
-
-
-
- __getitem__(self, key) -
-
- Called to implement evaluation of - self[key]. For sequence types, - the accepted keys should be integers and slice - objects.  Note that the special - interpretation of negative indexes (if the class wishes to - emulate a sequence type) is up to the __getitem__() method. If key is of - an inappropriate type, TypeError - may be raised; if of a value outside the set of indexes for - the sequence (after any special interpretation of negative - values), IndexError should be - raised. Note: - for loops expect that an IndexError will be raised for illegal - indexes to allow proper detection of the end of the - sequence. -
-
-
-
- __setitem__(self, key, value) -
-
- Called to implement assignment to - self[key]. Same note as for - __getitem__(). This should only be - implemented for mappings if the objects support changes to the - values for keys, or if new keys can be added, or for sequences if - elements can be replaced. The same exceptions should be raised - for improper key values as for the __getitem__() method. -
-
-
-
- __delitem__(self, key) -
-
- Called to implement deletion of - self[key]. Same note as for - __getitem__(). This should only be - implemented for mappings if the objects support removal of keys, - or for sequences if elements can be removed from the sequence. - The same exceptions should be raised for improper key - values as for the __getitem__() method. -
-
-
-
- __iter__(self) -
-
- This method is called when an iterator is required for a - container. This method should return a new iterator object that - can iterate over all the objects in the container. For mappings, - it should iterate over the keys of the container, and should also - be made available as the method iterkeys(). -

- Iterator objects also need to implement this method; they are - required to return themselves. For more information on iterator - objects, see ``Iterator - Types'' in the Python Library Reference. -

-
-
-
-
- __contains__(self, item) -
-
- Called to implement membership test operators. Should return true - if item is in self, false otherwise. For - mapping objects, this should consider the keys of the mapping - rather than the values or the key-item pairs. -
-
-
-
- -

indexing_suite sub-classes

-

- The indexing_suite is not meant to be used as is. A couple of - policy functions must be supplied by subclasses of - indexing_suite. However, a set of indexing_suite - subclasses for the standard indexable STL containers will be provided, - In most cases, we can simply use the available predefined suites. In - some cases, we can refine the predefined suites to suit our needs. -

- -

vector_indexing_suite [ Header <boost/python/indexing/vector_indexing_suite.hpp> - ]

-

- The vector_indexing_suite class is a predefined - indexing_suite derived class designed to wrap - std::vector (and std::vector like [i.e. a class with - std::vector interface]) classes. It provides all the policies required by the - indexing_suite. -

-

- Example usage: -

-
-    class X {...};
-    ...
-
-    class_<std::vector<X> >("XVec")
-        .def(vector_indexing_suite<std::vector<X> >())
-    ;
-
-

- XVec is now a full-fledged Python container (see the - example in full, - along with its python - test). -

-

map_indexing_suite [ Header <boost/python/indexing/map_indexing_suite.hpp> ]

-

The map_indexing_suite class is a predefined indexing_suite derived class designed to wrap std::map (and std::map like [i.e. a class with std::map interface]) classes. It provides all the policies required by the indexing_suite.

-

Example usage:

-
-    class X {...};
-    ...
-
-    class_<std::map<X> >("XMap")
-        .def(map_indexing_suite<std::map<X> >())
-    ;
-
-

By default indexed elements are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. XMap is now a full-fledged Python container (see the example in full, along with its python test).

-
-

- indexing_suite class

-

indexing_suite<
-
class Container
- , class DerivedPolicies
-
, - bool NoProxy
- , - bool NoSlice
-
, class Data
- , class Index
-
, class Key

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Template Parameter
-
- Requirements - - Semantics - - Default -
- Container - - A class type - - The container type to be wrapped to Python. -   - -
- DerivedPolicies - - A subclass of indexing_suite - - Derived classes provide the policy hooks. See DerivedPolicies below. -   - -
NoProxy A boolean By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. false
- NoSlice - - A boolean - - Do not allow slicing. - false -
- Data -   - - - The container's data type. - - Container::value_type -
Index   The container's index type. Container::size_type
- Key -   - - - The container's key type. - - Container::value_type -
-
-    template <
class Container - , class DerivedPolicies - , bool NoProxy = false
, bool NoSlice = false - , class Data = typename Container::value_type - , class Index = typename Container::size_type - , class Key = typename Container::value_type - >
class indexing_suite - : unspecified - { - public: - - indexing_suite(); // default constructor - } -
-

- DerivedPolicies -

-
-
- Derived classes provide the hooks needed by - the indexing_suite: -
-
-
        data_type&
-        get_item(Container& container, index_type i);
-
-        static object
-        get_slice(Container& container, index_type from, index_type to);
-
-        static void
-        set_item(Container& container, index_type i, data_type const& v);
-
-        static void
-        set_slice(
-            Container& container, index_type from,
-            index_type to, data_type const& v
-        );
-
-        template <class Iter>
-        static void
set_slice(Container& container, index_type from, - index_type to, Iter first, Iter last - ); - - static void - delete_item(Container& container, index_type i); - - static void - delete_slice(Container& container, index_type from, index_type to); - - static size_t - size(Container& container); - - template <class T> - static bool - contains(Container& container, T const& val); - - static index_type - convert_index(Container& container, PyObject* i); - - static index_type - adjust_index(index_type current, index_type from, - index_type to, size_type len - ); -
-
-

- Most of these policies are self explanatory. However, - convert_index and - adjust_index deserve some explanation. -

-

- convert_index converts a Python index into - a C++ index that the container can handle. For instance, negative - indexes in Python, by convention, start counting from the right(e.g. - C[-1] indexes the rightmost element in C). - convert_index should handle the necessary - conversion for the C++ container (e.g. convert -1 to - C.size()-1). convert_index should - also be able to convert the type of the index (A dynamic Python type) - to the actual type that the C++ container expects. -

-

- When a container expands or contracts, held indexes to its elements - must be adjusted to follow the movement of data. For instance, if we - erase 3 elements, starting from index 0 from a 5 element vector, what - used to be at index 4 will now be at index 1: -

-
-    [a][b][c][d][e] ---> [d][e]
-                 ^           ^
-                 4           1
-
-

- adjust_index takes care of the adjustment. - Given a current index, the function should return the adjusted index - when data in the container at index from..to is - replaced by len elements. -

-
-
-
-

- vector_indexing_suite class -

-

- Class template
- vector_indexing_suite<
- class Container
- , bool NoProxy
- , class DerivedPolicies>
-

- - - - - - - - - - - - - - - - - - - - - - - - - -
- Template Parameter
-
- Requirements - - Semantics - - Default -
- Container - - A class type - - The container type to be wrapped to Python. -   - -
- NoProxy - - A boolean - - By default indexed elements have Python reference semantics and - are returned by proxy. This can be disabled by supplying - true in the NoProxy template parameter. - - false -
- DerivedPolicies - - A subclass of indexing_suite - - The vector_indexing_suite may still be derived to - further tweak any of the predefined policies. Static polymorphism - through CRTP (James Coplien. "Curiously Recurring Template - Pattern". C++ Report, Feb. 1995) enables the base - indexing_suite class to call policy function of the most - derived class -   - -
-
-    template <
class Container,
bool NoProxy = false,
class DerivedPolicies = unspecified_default
class vector_indexing_suite : unspecified_base
{
public:

typedef typename Container::value_type data_type;
typedef typename Container::value_type key_type;
typedef typename Container::size_type index_type;
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;

data_type&
get_item(Container& container, index_type i); - - static object - get_slice(Container& container, index_type from, index_type to); - - static void
set_item(Container& container, index_type i, data_type const& v); - - static void - set_slice(Container& container, index_type from, - index_type to, data_type const& v); - - template <class Iter>
static void
set_slice(Container& container, index_type from,
index_type to, Iter first, Iter last); - - static void - delete_item(Container& container, index_type i); - - static void - delete_slice(Container& container, index_type from, index_type to);
- static size_t - size(Container& container); - - static bool - contains(Container& container, key_type const& key); - - static index_type - convert_index(Container& container, PyObject* i); - - static index_type - adjust_index(index_type current, index_type from, - index_type to, size_type len); - }; - -
-

map_indexing_suite class

-

Class template
- map_indexing_suite<
- class Container
- , bool NoProxy
- , class DerivedPolicies>

- - - - - - - - - - - - - - - - - - - - - - - - - -
Template Parameter
-
Requirements Semantics Default
Container A class type The container type to be wrapped to Python.  
NoProxy A boolean By default indexed elements have Python reference semantics and are returned by proxy. This can be disabled by supplying true in the NoProxy template parameter. false
DerivedPolicies A subclass of indexing_suite The vector_indexing_suite may still be derived to further tweak any of the predefined policies. Static polymorphism through CRTP (James Coplien. "Curiously Recurring Template Pattern". C++ Report, Feb. 1995) enables the base indexing_suite class to call policy function of the most derived class  
-
-    template <
class Container,
bool NoProxy = false,
class DerivedPolicies = unspecified_default
class map_indexing_suite : unspecified_base
{
public:

typedef typename Container::value_type value_type;
typedef typename Container::value_type::second_type data_type;
typedef typename Container::key_type key_type;
typedef typename Container::key_type index_type;
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;

static data_type&
get_item(Container& container, index_type i); - - static void
set_item(Container& container, index_type i, data_type const& v); - - static void - delete_item(Container& container, index_type i);
- static size_t - size(Container& container); - - static bool - contains(Container& container, key_type const& key); - - static bool
compare_index(Container& container, index_type a, index_type b); -
static index_type - convert_index(Container& container, PyObject* i); - }; - -
-
- © Copyright Joel de Guzman 2003. Permission to copy, use, modify, - sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided "as is" without - express or implied warranty, and with no claim as to its suitability - for any purpose. -
- - diff --git a/doc/v2/init.html b/doc/v2/init.html deleted file mode 100644 index 2aacaad9f4..0000000000 --- a/doc/v2/init.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/init.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Headers <boost/python/init.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
init-expressions
- -
Classes
- -
-
-
Class template init
- -
-
-
Class template - init synopsis
- -
Class init - constructors
- -
-
- -
Class template - optional
- -
-
-
Class template - optional synopsis
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

<boost/python/init.hpp> defines the interface for - exposing C++ constructors to Python as extension class - __init__ functions.

- -

init-expressions

- An init-expression is used to describe a family of - __init__ methods to be generated for an extension class, and - the result has the following properties: - -
-
-
docstring: An ntbs - whose value will bound to the method's __doc__ - attribute
- -
keywords: A keyword-expression which will be - used to name (a trailing subsequence of) the arguments to the - generated __init__ function(s).
- -
call policies: An instance of a model of CallPolicies.
- -
argument types: An MPL sequence of C++ argument types - which will be used to construct the wrapped C++ object. An init - expression has one or more - valid prefixes which are given by a sequence of - prefixes of its argument types.
-
-
- -

Classes

- -

Class template init<T1 = - unspecified, T2 = - unspecified,...Tn = - unspecified>

- -

A MPL sequence which - can be used to specify a family of one or more __init__ - functions. Only the last Ti supplied - may be an instantiation of optional<...>.

- -

Class template init - synopsis

-
-namespace boost { namespace python
-{
-  template <T1 = unspecified,...Tn = unspecified>
-  struct init
-  {
-      init(char const* doc = 0);
-      template <class Keywords> init(Keywords const& kw, char const* doc = 0);
-      template <class Keywords> init(char const* doc, Keywords const& kw);
-
-      template <class CallPolicies>
-      unspecified operator[](CallPolicies const& policies) const
-  };
-}}
-
- -

Class template init - constructors

-
-init(char const* doc = 0);
-template <class Keywords> init(Keywords const& kw, char const* doc = 0);
-template <class Keywords> init(char const* doc, Keywords const& kw);
-
- -
-
Requires: If supplied, doc is an ntbs. If supplied, kw is the - result of a
- -
Effects: The result is an init-expression whose - docstring is doc and whose keywords are - a reference to kw. If the first form is used, the - resulting expression's keywords are empty. The expression's - call policies are an instance of default_call_policies. - If Tn is optional<U1, U2,... - Um>, the - expression's valid prefixes are given by:
- -
-
- (T1, T2,...Tn-1), - (T1, T2,...Tn-1 - , U1), - (T1, T2,...Tn-1 - , U1, U2), - ...(T1, T2,...Tn-1 - , U1, U2,...Um). -
- Otherwise, the expression has one valid prefix given by the - the template arguments the user specified. -
-
- -

Class template init - observer functions

-
-template <class Policies>
-unspecified operator[](Policies const& policies) const
-
- -
-
Requires: Policies is a model of CallPolicies.
- -
Effects: Returns a new init-expression with all the same - properties as the init object except that its call - policies are replaced by a reference to - policies.
-
- -

Class template optional<T1 - = unspecified, T2 = - unspecified,...Tn = - unspecified>

- -

A MPL sequence which - can be used to specify the optional arguments to an __init__ - function.

- -

Class template - optional synopsis

-
-namespace boost { namespace python
-{
-  template <T1 = unspecified,...Tn = unspecified>
-  struct optional {};
-}}
-
- -

Example(s)

- -

Given the C++ declarations:

-
-class Y;
-class X
-{
- public:
-   X(int x, Y* y) : m_y(y) {}
-   X(double);
- private:
-   Y* m_y;
-};
-
- A corresponding Boost.Python extension class can be created with: -
-using namespace boost::python;
-
-class_<X>("X", "This is X's docstring.",
-          init<int,char const*>(args("x","y"), "X.__init__'s docstring")[
-                with_custodian_and_ward<1,3>()]
-          )
-   .def(init<double>())
-   ;
-
-
- Revised - - 13 November, 2002 - - - -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/instance_holder.html b/doc/v2/instance_holder.html deleted file mode 100755 index 87571d1da8..0000000000 --- a/doc/v2/instance_holder.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - Boost.Python - <boost/python/instance_holder.hpp> - - - - - - - -
-

C++ Boost

- -
-

Boost.Python

- -

Header <boost/python/instance_holder.hpp>

-
-
- -

Contents

- -
-
Introduction - -
Classes - -
-
-
Class - instance_holder - -
-
-
Class - instance_holder synopsis - -
Class - instance_holder destructor - -
Class - instance_holder modifier functions - -
Class - instance_holder observer functions -
-
- -
Example -
-
- -

Introduction

- -

<boost/python/instance_holder.hpp> provides - class instance_holder, the base class for types - which hold C++ instances of wrapped classes. - -

Classes

- -

Class instance_holder

- -

instance_holder is an abstract base class whose - concrete derived classes hold C++ class instances within their - Python object wrappers. To allow multiple inheritance in Python - from C++ class wrappers, each such Python object contains a chain - of instance_holders. When an __init__ - function for a wrapped C++ class is invoked, a new - instance_holder instance is created and installed in - the Python object using its install() - function. Each concrete class derived from - instance_holder must provide a holds() - implementation which allows Boost.Python to query it for the - type(s) it is holding. In order to support the held type's wrapped - constructor(s), the class must also provide constructors that can - accept an initial PyObject* argument referring to the - owning Python object, and which forward the rest of their - arguments to the constructor of the held type. The initial - argument is needed to enable virtual function overriding in - Python, and may be ignored, depending on the specific - instance_holder subclass. - -

Class instance_holder - synopsis

-
-namespace boost { namespace python
-{
-  class instance_holder : noncopyable
-  {
-   public:
-      // destructor
-      virtual ~instance_holder();
-
-      // instance_holder modifiers
-      void install(PyObject* inst) throw();
-
-      // instance_holder observers
-      virtual void* holds(type_info) = 0;
-  };
-}}
-
- -

Class instance_holder - destructor

-
-virtual ~instance_holder();
-
- -
-
Effects: destroys the object -
- -

Class - instance_holder modifiers

-
-void install(PyObject* inst) throw();
-
- -
-
Requires: inst is a Python instance of a - wrapped C++ class type, or is a type derived from a wrapped C++ - class type. -
Effects: installs the new instance at the head of the - Python object's chain of held instances. -
Throws: nothing -
- -

Class instance_holder - observers

-
-virtual void* holds(type_info x) = 0;
-
- -
-
Returns: A pointer to an object of the type described - by x if *this contains such an object, - 0 otherwise. -
- -

Example

- -The following is a simplified version of the instance holder template -used by Boost.Python to wrap classes held by smart pointers: -
-template <class SmartPtr, class Value>
-struct pointer_holder : instance_holder
-{
-   // construct from the SmartPtr type
-   pointer_holder(SmartPtr p)
-       :m_p(p)
-
-   // Forwarding constructors for the held type
-   pointer_holder(PyObject*)
-       :m_p(new Value())
-   {
-   }
-
-   template<class A0>
-   pointer_holder(PyObject*,A0 a0)
-       :m_p(new Value(a0))
-   {
-   }
-
-   template<class A0,class A1>
-   pointer_holder(PyObject*,A0 a0,A1 a1)
-       :m_p(new Value(a0,a1))
-   {
-   }
-   ...
-
- private: // required holder implementation
-   void* holds(type_info dst_t)
-   {
-       // holds an instance of the SmartPtr type...
-       if (dst_t == python::type_id<SmartPtr>())
-           return &this->m_p;
-
-       // ...and an instance of the SmartPtr's element_type, if the
-       // pointer is non-null
-       return python::type_id<Value>() == dst_t ? &*this->m_p : 0;
-   }
-
- private: // data members
-   SmartPtr m_p;
-};
-
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave Abrahams 2002. - - - diff --git a/doc/v2/iterator.html b/doc/v2/iterator.html deleted file mode 100644 index 3557ffb9af..0000000000 --- a/doc/v2/iterator.html +++ /dev/null @@ -1,398 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/iterator.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/iterator.hpp>

-
-


- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class template - iterator
- -
-
-
Class - iterator synopsis
- -
Class template - iterator constructor
-
-
-
- -
-
Class template - iterators
- -
-
-
Class - iterators synopsis
- -
Class template - iterators nested types
- -
Class template - iterators static functions
-
-
-
-
- -
Functions
- -
-
-
range
-
-
- -
Examples
-
-
- -

Introduction

- -

<boost/python/iterator.hpp> provides types and - functions for creating Python - iterators from C++ Containers and Iterators. Note - that if your class_ supports random-access iterators, - implementing __getitem__ - (also known as the Sequence Protocol) may serve you better than using - this facility: Python will automatically create an iterator type for you - (see iter()), - and each access can be range-checked, leaving no possiblity of accessing - through an invalidated C++ iterator.

- -

Classes

- -

Class Template iterator

- -

Instances of iterator<C,P> hold a reference to a - callable Python object which, when invoked from Python, expects a single - argument c convertible to C and creates a - Python iterator that traverses [c.begin(), - c.end()). The optional CallPolicies P can be used to - control how elements are returned during iteration.

- -

In the table below, c is an instance of - Container.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Template ParameterRequirementsSemanticsDefault
Container[c.begin(),c.end()) is a valid Iterator range.The result will convert its argument to c and call - c.begin() and c.end() to acquire iterators. - To invoke Container's const - begin() and end() functions, make it - const.
NextPoliciesA default-constructible model of CallPolicies.Applied to the resulting iterators' next() - method.An unspecified model of CallPolicies which - always makes a copy of the result of deferencing the underlying C++ - iterator
- -

Class Template iterator - synopsis

-
-namespace boost { namespace python
-{
-  template <class Container
-             , class NextPolicies = unspecified>
-  struct iterator : object
-  {
-      iterator();
-  };
-}}
-
- -

Class Template iterator - constructor

-
-iterator()
-
- -
-
Effects:
- -
- Initializes its base class with the result of: -
-range<NextPolicies>(&iterators<Container>::begin, &iterators<Container>::end)
-
-
- -
Postconditions: this->get() points to a - Python callable object which creates a Python iterator as described - above.
- -
Rationale: Provides an easy way to create iterators for the - common case where a C++ class being wrapped provides - begin() and end().
-
- - -

Class Template - iterators

- -

A utility class template which provides a way to reliably call its - argument's begin() and end() member functions. - Note that there is no portable way to take the address of a member - function of a C++ standard library container, so - iterators<> can be particularly helpful when wrapping - them.

- -

In the table below, x is an instance of - C.

- - - - - - - - - - - - - - - - - - - -
Required Valid ExpressionType
x.begin()Convertible to C::const_iterator if C - is a const type; convertible to C::iterator - otherwise.
x.end()Convertible to C::const_iterator if C - is a const type; convertible to C::iterator - otherwise.
- -

Class Template iterators - synopsis

-
-namespace boost { namespace python
-{
-  template <class C>
-  struct iterators
-  {
-      typedef typename C::[const_]iterator iterator;
-      static iterator begin(C& x);
-      static iterator end(C& x);
-  };
-}}
-
-
- -

Class Template iterators nested - types

- If C is a const type, -
-typedef typename C::const_iterator iterator;
-
- Otherwise: -
-typedef typename C::iterator iterator;
-
- -

Class Template iterators static - functions

-
-static iterator begin(C&);
-
- -
-
Returns: x.begin()
-
-
-static iterator end(C&);
-
- -
-
Returns: x.end()
-
- - -

Functions

-
-template <class NextPolicies, class Target, class Accessor1, class Accessor2>
-object range(Accessor1 start, Accessor2 finish);
-
-template <class NextPolicies, class Accessor1, class Accessor2>
-object range(Accessor1 start, Accessor2 finish);
-
-template <class Accessor1, class Accessor2>
-object range(Accessor1 start, Accessor2 finish);
-
- -
-
Requires: NextPolicies is a - default-constructible model of CallPolicies.
- -
Effects:
- -
-
-
The first form creates a Python callable object which, when - invoked, converts its argument to a Target object - x, and creates a Python iterator which traverses - [bind(start,_1)(x)bind(finish,_1)(x)), - applying NextPolicies to the iterator's - next() function.
- -
The second form is identical to the first, except that - Target is deduced from Accessor1 as - follows:
- -
-
    -
  1. If Accessor1 is a function type, - Target is the type of its first argument.
  2. - -
  3. If Accessor1 is a data member pointer of the - form R (T::*), Target is - identical to T.
  4. - -
  5. If Accessor1 is a member function pointer of - the form - R (T::*)(arguments...)  - cv-opt, where cv-opt is an optional - cv-qualifier, Target is identical to - T.
  6. -
-
- -
The third form is identical to the second, except that - NextPolicies is an unspecified model of CallPolicies which - always makes a copy of the result of deferencing the underlying C++ - iterator
-
-
- -
Rationale: The use of boost::bind() allows C++ iterators - to be accessed through functions, member functions or data member - pointers. Customization of NextPolicies (e.g. using - return_internal_reference) - is useful when it is expensive to copy sequence elements of a wrapped - class type. Customization of Target is useful when - Accessor1 is a function object, or when a base class of - the intended target type would otherwise be deduced.
-
- -

Examples

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-
-#include <vector>
-
-using namespace boost::python;
-BOOST_PYTHON_MODULE(demo)
-{
-    class_<std::vector<double> >("dvec")
-        .def("__iter__", iterator<std::vector<double> >())
-        ;
-}
-
- A more comprehensive example can be found in: - -
-
libs/python/test/iterator.cpp
- -
libs/python/test/input_iterator.cpp
- -
libs/python/test/input_iterator.py
- -
-
-

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/list.html b/doc/v2/list.html deleted file mode 100644 index e347ae4617..0000000000 --- a/doc/v2/list.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/list.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/list.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class list
- -
-
-
Class list - synopsis
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Exposes a TypeWrapper for the Python - list - type.

- -

Classes

- -

Class list

- -

Exposes the mapping - protocol of Python's built-in list type. The semantics - of the constructors and member functions defined below can be fully - understood by reading the TypeWrapper concept - definition. Since list is publicly derived from object, the public object - interface applies to list instances as well.

- -

Class list - synopsis

-
-namespace boost { namespace python
-{
-  class list : public object
-  {
-   public:
-      list(); // new list
-
-      template <class T>
-      explicit list(T const& sequence);
-
-      template <class T>
-      void append(T const& x);
-
-      template <class T>
-      long count(T const& value) const;
-
-      template <class T>
-      void extend(T const& x);
-
-      template <class T>
-      long index(T const& x) const;
-
-      template <class T>
-      void insert(object const& index, T const& x); // insert object before index
-
-      object pop(); // remove and return item at index (default last)
-      object pop(long index);
-      object pop(object const& index);
-
-      template <class T>
-      void remove(T const& value);
-
-      void reverse(); // reverse *IN PLACE*
-
-      void sort(); //  sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
-
-      template <class T>
-      void sort(T const& value);
-  };
-}}
-
- -

Example

-
-using namespace boost::python;
-
-// Return the number of zeroes in the list
-long zeroes(list l)
-{
-   return l.count(0);
-}
-
- -

Revised 1 October, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/long.html b/doc/v2/long.html deleted file mode 100644 index 08ceb3bd5c..0000000000 --- a/doc/v2/long.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/long.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/long.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class long_
- -
-
-
Class long_ - synopsis
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Exposes a TypeWrapper for the Python - long - integer type.

- -

Classes

- -

Class long_

- -

Exposes the numeric type - protocol of Python's built-in long type. The semantics - of the constructors and member functions defined below can be fully - understood by reading the TypeWrapper concept - definition. Since long_ is publicly derived from object, the public object - interface applies to long_ instances as well.

- -

Class long_ - synopsis

-
-namespace boost { namespace python
-{
-  class long_ : public object
-  {
-   public:
-      long_(); // new long_
-
-      template <class T>
-      explicit long_(T const& rhs);
-
-      template <class T, class U>
-      long_(T const& rhs, U const& base);
-  };
-}}
-
- -

Example

-
-namespace python = boost::python;
-
-// compute a factorial without overflowing
-python::long_ fact(long n)
-{
-   if (n == 0)
-      return python::long_(1);
-   else
-      return n * fact(n - 1);
-}
-
- -

Revised 1 October, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/lvalue_from_pytype.html b/doc/v2/lvalue_from_pytype.html deleted file mode 100755 index d27c57d0cf..0000000000 --- a/doc/v2/lvalue_from_pytype.html +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/lvalue_from_python.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/lvalue_from_pytype.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class Template - lvalue_from_pytype
- -
-
-
Class Template - lvalue_from_pytype synopsis
- -
Class Template - lvalue_from_pytype constructor
-
-
-
- -
-
Class Template - extract_identity
- -
-
-
Class Template - extract_identity synopsis
- -
Class Template - extract_identity static functions
-
-
- -
Class Template - extract_member
- -
-
-
Class Template - extract_member synopsis
- -
Class Template - extract_member static functions
-
-
-
-
- -
Example
-
-
- -

Introduction

- <boost/python/lvalue_from_pytype.hpp> supplies a - facility for extracting C++ objects from within Python instances of a - given type. This is typically useful for dealing with "traditional" - Python extension types. - -

Classes

- -

Class template - lvalue_from_pytype

- -

Class template lvalue_from_pytype will register - from_python converters which, given an object of the given Python type, - can extract references and pointers to a particular C++ type. Its - template arguments are:

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- lvalue_from_pytype Requirements
- In the table below, x denotes an object of type - PythonObject& -
ParameterRequirementsSemantics
Extractora model of Extractor whose execute - function returns a reference type.Extracts the lvalue from the Python object once its type has been - confirmed
python_typeA compile-time constant PyTypeObject*The Python type of instances convertible by this converter. - Python subtypes are also convertible.
- -

Class template - lvalue_from_pytype synopsis

-
-namespace boost { namespace python
-{
-   template <class Extractor, PyTypeObject const* python_type>
-   struct lvalue_from_pytype
-   {
-       lvalue_from_pytype();
-   };
-}}
-
- -

Class template - lvalue_from_pytype constructor

-
-lvalue_from_pytype();
-
- -
-
Effects: Registers converters which can convert Python - objects of the given type to lvalues of the type returned by - Extractor::execute.
-
- -

Class template - extract_identity

- -

extract_identity is a model of Extractor which can be used in the - common case where the C++ type to be extracted is the same as the Python - object type.

- -

Class template - extract_identity synopsis

-
-namespace boost { namespace python
-{
-   template <class InstanceType>
-   struct extract_identity
-   {
-      static InstanceType& execute(InstanceType& c);
-   };
-}}
-
- -

Class template - extract_identity static functions

-
-InstanceType& execute(InstanceType& c);
-
- -
-
Returns: c
-
- -

Class template - extract_member

- -

extract_member is a model of Extractor which can be used in the - common case in the common case where the C++ type to be extracted is a - member of the Python object.

- -

Class template - extract_member synopsis

-
-namespace boost { namespace python
-{
-   template <class InstanceType, class MemberType, MemberType (InstanceType::*member)>
-   struct extract_member
-   {
-      static MemberType& execute(InstanceType& c);
-   };
-}}
-
- -

Class template - extract_member static functions

-
-static MemberType& execute(InstanceType& c);
-
- -
-
Returns: c.*member
-
- -

Example

- This example presumes that someone has implemented the standard noddy example - module from the Python documentation, and we want to build a module - which manipulates Noddys. Since - noddy_NoddyObject is so simple that it carries no - interesting information, the example is a bit contrived: it assumes you - want to keep track of one particular object for some reason. This module - would have to be dynamically linked to the module which defines - noddy_NoddyType. - -

C++ module definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/handle.hpp>
-#include <boost/python/borrowed.hpp>
-#include <boost/python/lvalue_from_pytype.hpp>
-
-// definition lifted from the Python docs
-typedef struct {
-   PyObject_HEAD
-} noddy_NoddyObject;
-
-using namespace boost::python;
-static handle<noddy_NoddyObject> cache;
-
-bool is_cached(noddy_NoddyObject* x)
-{
-   return x == cache.get();
-}
-
-void set_cache(noddy_NoddyObject* x)
-{
-   cache = handle<noddy_NoddyObject>(borrowed(x));
-}
-
-BOOST_PYTHON_MODULE(noddy_cache)
-{
-   def("is_cached", is_cached);
-   def("set_cache", set_cache);
-
-   // register Noddy lvalue converter
-   lvalue_from_pytype<extract_identity<noddy_NoddyObject>,&noddy_NoddyType>();
-}
-
- -

Python code

-
->>> import noddy
->>> n = noddy.new_noddy()
->>> import noddy_cache
->>> noddy_cache.is_cached(n)
-0
->>> noddy_cache.set_cache(n)
->>> noddy_cache.is_cached(n)
-1
->>> noddy_cache.is_cached(noddy.new_noddy())
-0
-
- -

Revised - - 20 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/make_function.html b/doc/v2/make_function.html deleted file mode 100644 index d5a6cdb06e..0000000000 --- a/doc/v2/make_function.html +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/make_function.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/make_function.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
make_function
- -
make_constructor
-
-
- -
Example
-
-
- -

Introduction

- -

make_function() and - make_constructor() are - the functions used internally by def() and class_<>::def() to produce Python - callable objects which wrap C++ functions and member functions.

- -

Functions

-
-template <class F>
-object make_function(F f)
-
-template <class F, class Policies>
-object make_function(F f, Policies const& policies)
-
-template <class F, class Policies, class KeywordsOrSignature>
-object make_function(F f, Policies const& policies, KeywordsOrSignature const& ks)
-
-template <class F, class Policies, class Keywords, class Signature>
-object make_function(F f, Policies const& policies, Keywords const& kw, Signature const& sig)
-
- -
-
Requires: F is a function pointer or member - function pointer type. If policies are supplied, it must - be a model of CallPolicies. If - kewords are supplied, it must be the result of a keyword-expression - specifying no more arguments than the arity of f.
- -
Effects: Creates a Python callable object which, when called - from Python, converts its arguments to C++ and calls f. If - F is a pointer-to-member-function type, the target - object of the function call (*this) will be taken - from the first Python argument, and subsequent Python arguments - will be used as the arguments - to f.
    -
  • If policies are supplied, it - will be applied to the function as described here. -
  • If keywords are - supplied, the keywords will be applied in order to the final - arguments of the resulting function. -
  • If Signature - is supplied, it should be an instance of an MPL front-extensible - sequence representing the function's return type followed by - its argument types. Pass a Signature when wrapping - function object types whose signatures can't be deduced, or when - you wish to override the types which will be passed to the - wrapped function. -
- -
Returns: An instance of object which holds the new Python - callable object.
- -
Caveats: An argument of pointer type may - be 0 if None is passed from Python. - An argument type which is a constant reference may refer to a - temporary which was created from the Python object for just the - duration of the call to the wrapped function, for example - a std::vector conjured up by the conversion process - from a Python list. Use a non-const reference - argument when a persistent lvalue is required. -
- -
-template <class F>
-object make_constructor(F f)
-
-template <class F, class Policies>
-object make_constructor(F f, Policies const& policies)
-
-template <class F, class Policies, class KeywordsOrSignature>
-object make_constructor(F f, Policies const& policies, KeywordsOrSignature const& ks)
-
-template <class F, class Policies, class Keywords, class Signature>
-object make_constructor(F f, Policies const& policies, Keywords const& kw, Signature const& sig)
-
- -
-
Requires: F is a - function pointer type. If policies are supplied, it must - be a model of CallPolicies. If - kewords are supplied, it must be the result of a keyword-expression - specifying no more arguments than the arity of f.
- -
Effects: Creates a Python callable object which, when called - from Python, converts its arguments to C++ and calls f.
- -
Returns: An instance of object which holds the new Python - callable object.
-
- -

Example

- -

C++ function exposed below returns a callable object wrapping one of - two functions.

-
-#include <boost/python/make_function.hpp>
-#include <boost/python/module.hpp>
-
-char const* foo() { return "foo"; }
-char const* bar() { return "bar"; }
-
-using namespace boost::python;
-object choose_function(bool selector)
-{
-    if (selector)
-        return boost::python::make_function(foo);
-    else
-        return boost::python::make_function(bar);
-}
-
-BOOST_PYTHON_MODULE(make_function_test)
-{
-    def("choose_function", choose_function);
-}
-
- It can be used this way in Python: -
->>> from make_function_test import *
->>> f = choose_function(1)
->>> g = choose_function(0)
->>> f()
-'foo'
->>> g()
-'bar'
-
- -

- - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/manage_new_object.html b/doc/v2/manage_new_object.html deleted file mode 100644 index 57efb41374..0000000000 --- a/doc/v2/manage_new_object.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/manage_new_object.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/manage_new_object.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class - manage_new_object
- -
-
-
Class - manage_new_object synopsis
- -
Class - manage_new_object metafunctions
-
-
-
-
- -
Example
-
-
- -

Classes

- -

Class - manage_new_object

- -

manage_new_object is a model of ResultConverterGenerator - which can be used to wrap C++ functions which return a pointer to an - object allocated with a new-expression, and expect the caller to - take responsibility for deleting that object.

- -

Class - manage_new_object synopsis

-
-namespace boost { namespace python
-{
-    struct manage_new_object
-    {
-        template <class T> struct apply;
-    };
-}}
-
- -

Class - manage_new_object metafunctions

-
-template <class T> struct apply
-
- -
-
Requires: T is U* for some - U.
- -
Returns: typedef to_python_indirect<T> - type;
-
- -

Example

- -

In C++:

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/manage_new_object.hpp>
-#include <boost/python/return_value_policy.hpp>
-
-
-struct Foo {
-   Foo(int x) : x(x){}
-   int get_x() { return x; }
-   int x;
-};
-
-Foo* make_foo(int x) { return new Foo(x); }
-
-// Wrapper code
-using namespace boost::python;
-BOOST_PYTHON_MODULE(my_module)
-{
-    def("make_foo", make_foo, return_value_policy<manage_new_object>())
-    class_<Foo>("Foo")
-        .def("get_x", &Foo::get_x)
-        ;
-}
-
- In Python: -
->>> from my_module import *
->>> f = make_foo(3)     # create a Foo object
->>> f.get_x()
-3
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/module.html b/doc/v2/module.html deleted file mode 100644 index 353523cb6f..0000000000 --- a/doc/v2/module.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - Boost.Python - <boost/python/module.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header <boost/python/module.hpp>

-
-
- -

Contents

- -
-
Introduction - -
Macros - -
-
-
BOOST_PYTHON_MODULE -
- -
Example(s) -
-
- -

Introduction

- -

This header provides the basic facilities needed to create a - Boost.Python extension module. - -

Macros

- -

BOOST_PYTHON_MODULE(name) - is used to declare Python - module initialization functions. The name argument must - exactly match the name of the module to be initialized, and must conform to - Python's identifier naming - rules. Where you would normally write -

-extern "C" void initname()
-{
-   ...
-}
-
- Boost.Python modules should be initialized with -
-BOOST_PYTHON_MODULE(name)
-{
-   ...
-}
-
- -This macro generates two functions in the scope where it is used: -extern "C" void initname(), -and void init_module_name(), whose body must -follow the macro invocation. init_name passes -init_module_name to handle_exception() so -that any C++ exceptions generated are safely processeed. During the -body of init_name, the current scope refers to the module -being initialized. - -

Example(s)

- -

C++ module definition: -

-#include <boost/python/module.hpp>
-
-BOOST_PYTHON_MODULE(xxx)
-{
-    throw "something bad happened"
-}
-
- -Interactive Python: -
->>> import xxx
-Traceback (most recent call last):
-  File "", line 1, in ?
-RuntimeError: Unidentifiable C++ Exception
-
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave - Abrahams 2002. Distributed - under the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/v2/numeric.html b/doc/v2/numeric.html deleted file mode 100644 index eaa390af4d..0000000000 --- a/doc/v2/numeric.html +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/numeric.hpp> - - - - - - - - - -
-

-

-
-

Boost.Python

- -

Header <boost/python/numeric.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class array
- -
-
-
Class array - synopsis
- -
Class array - observer functions
- -
Class array static - functions
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Exposes a TypeWrapper for the Python - array - type.

- -

Classes

- -

Class array

- -

Provides access to the array types of Numerical Python's Numeric and NumArray modules. With - the exception of the functions documented below, the semantics of the constructors and - member functions defined below can be fully understood by reading the - TypeWrapper concept - definition. Since array is publicly derived from - object, the public - object interface applies to array instances as well.

- -

The default behavior is - to use numarray.NDArray as the associated Python type if the - numarray module is installed in the default location. - Otherwise it falls back to use Numeric.ArrayType. If neither - extension module is installed, overloads of wrapped C++ functions with - numeric::array parameters will never be matched, and other - attempted uses of numeric::array will raise an appropriate Python exception. The - associated Python type can be set manually using the set_module_and_type(...) static - function.

- -

Class - array synopsis

-
-namespace boost { namespace python { namespace numeric
-{
-   class array : public object
-   {
-    public:
-      object astype();
-      template <class Type>
-      object astype(Type const& type_);
-
-      template <class Type>
-      array new_(Type const& type_) const;
-
-      template <class Sequence> 
-      void resize(Sequence const& x);
-      void resize(long x1);
-      void resize(long x1, long x2);
-      ...
-      void resize(long x1, long x2,...long xn);
-
-      template <class Sequence> 
-      void setshape(Sequence const& x);
-      void setshape(long x1);
-      void setshape(long x1, long x2);
-      ...
-      void setshape(long x1, long x2,...long xn);
-
-      template <class Indices, class Values>
-      void put(Indices const& indices, Values const& values);
-
-      template <class Sequence>
-      object take(Sequence const& sequence, long axis = 0);
-
-      template <class File>
-      void tofile(File const& f) const;
-
-      object factory();
-      template <class Sequence>
-      object factory(Sequence const&);
-      template <class Sequence, class Typecode>
-      object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false);
-      template <class Sequence, class Typecode, class Type>
-      object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&);
-      template <class Sequence, class Typecode, class Type, class Shape>
-      object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&);
-
-      template <class T1>
-      explicit array(T1 const& x1);
-      template <class T1, class T2>
-      explicit array(T1 const& x1, T2 const& x2);
-      ...
-      template <class T1, class T2,...class Tn>
-      explicit array(T1 const& x1, T2 const& x2,...Tn const& xn);
-
-      static void set_module_and_type();
-      static void set_module_and_type(char const* package_path = 0, char const* type_name = 0);
-      static void get_module_name();
-
-      object argmax(long axis=-1);
-
-      object argmin(long axis=-1);
-
-      object argsort(long axis=-1);
-
-      void byteswap();
-
-      object copy() const;
-
-      object diagonal(long offset = 0, long axis1 = 0, long axis2 = 1) const;
-
-      void info() const;
-
-      bool is_c_array() const;
-      bool isbyteswapped() const;
-      void sort();
-      object trace(long offset = 0, long axis1 = 0, long axis2 = 1) const;
-      object type() const;
-      char typecode() const;
-      
-      object getflat() const;
-      long getrank() const;
-      object getshape() const;
-      bool isaligned() const;
-      bool iscontiguous() const;
-      long itemsize() const;
-      long nelements() const;
-      object nonzero() const;
-   
-      void ravel();
-   
-      object repeat(object const& repeats, long axis=0);
-   
-      void setflat(object const& flat);
-   
-      void swapaxes(long axis1, long axis2);
-   
-      str tostring() const;
-   
-      void transpose(object const& axes = object());
-   
-      object view() const;
-  };
-}}}
-
- -

Class - array observer functions

-
-object factory();
-template <class Sequence>
-object factory(Sequence const&);
-template <class Sequence, class Typecode>
-object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false);
-template <class Sequence, class Typecode, class Type>
-object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&);
-template <class Sequence, class Typecode, class Type, class Shape>
-object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&);
-
These functions map to the underlying array type's array() -function family. They are not called "array" because of the C++ -limitation that you can't define a member function with the same name as its -enclosing class. -
-template <class Type>
-array new_(Type const&) const;
-
This function maps to the underlying array type's new() -function. It is not called "new" because that is a keyword in -C++. - -

Class - array static functions

-
-static void set_module_and_type(char const* package_path, char const* type_name);
-static void set_module_and_type();
-
- -
-
Requires: package_path and - type_name, if supplied, is an ntbs.
- -
Effects: The first form sets the package path of the module - that supplies the type named by type_name to - package_path. The second form restores the default search behavior. The associated Python type - will be searched for only the first time it is needed, and thereafter the - first time it is needed after an invocation of - set_module_and_type.
-
-
-static std::string get_module_name()
-
- -
-
Effects: Returns the name of the module containing the class - that will be held by new numeric::array instances.
-
- -

Example

-
-#include <boost/python/numeric.hpp>
-#include <boost/python/tuple.hpp>
-
-// sets the first element in a 2d numeric array
-void set_first_element(numeric::array& y, double value)
-{
-    y[make_tuple(0,0)] = value;
-}
-
- -

Revised 07 October, 2006

- -

© Copyright Dave - Abrahams 2002-2006.

- - diff --git a/doc/v2/object.html b/doc/v2/object.html deleted file mode 100644 index 8df8ef5f8f..0000000000 --- a/doc/v2/object.html +++ /dev/null @@ -1,1121 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/object.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/object.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Types
- -
-
-
slice_nil
-
-
- -
Classes
- -
-
-
Class - const_attribute_policies
- -
-
-
Class - const_attribute_policies synopsis
- -
Class - const_attribute_policies static functions
-
-
- -
Class - attribute_policies
- -
-
-
Class - attribute_policies synopsis
- -
Class - attribute_policies static functions
-
-
- -
Class - const_objattribute_policies
- -
-
-
Class - const_objattribute_policies synopsis
- -
Class - const_objattribute_policies static functions
-
-
- -
Class - objattribute_policies
- -
-
-
Class - objattribute_policies synopsis
- -
Class - objattribute_policies static functions
-
-
- -
Class - const_item_policies
- -
-
-
Class - const_item_policies synopsis
- -
Class - const_item_policies static functions
-
-
- -
Class - item_policies
- -
-
-
Class - item_policies synopsis
- -
Class - item_policies static functions
-
-
- -
Class - const_slice_policies
- -
-
-
Class - const_slice_policies synopsis
- -
Class - const_slice_policies static functions
-
-
- -
Class - slice_policies
- -
-
-
Class - slice_policies synopsis
- -
Class - slice_policies static functions
-
-
- -
Class - object_operators
- -
-
-
Class - object_operators synopsis
- -
Class - object_operators observer functions
-
-
- -
Class object
- -
-
-
Class object - synopsis
- -
Class object - constructors and destructor
- -
Class template - object modifier functions
- -
Class template - object observer functions
-
-
- -
Class template - proxy
- -
-
-
Class template - proxy synopsis
- -
Class template - proxy modifier functions
- -
Class template - proxy observer functions
-
-
-
-
- -
Functions
- -
-
-
del
- -
comparisons
- -
binary operations
- -
assignment operations
- -
- -
-
operators
-
- -
-
len()
-
-
- -
Example
-
-
- -

Introduction

- -

Exposes the generic Python object wrapper class object, - and related classes. In order to avoid some potenential problems with - argument-dependent lookup and the generalized operators defined on - object, all these facilities are defined in - namespace boost::python::api, and object - is imported into namespace boost::python with a - using-declaration.

- -

Types

- -

-
-class slice_nil;
-static const _ = slice_nil();
-
- A type that can be used to get the effect of leaving out an index in a - Python slice expression: -
->>> x[:-1]
->>> x[::-1]
-
- C++ equivalent: -
-x.slice(_,-1)
-x[slice(_,_,-1)]
-
- -

Classes

- - -

Class - const_attribute_policies

- -

The policies which are used for proxies representing an attribute - access to a const object.

- -

Class - const_attribute_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct const_attribute_policies
-  {
-      typedef char const* key_type;
-      static object get(object const& target, char const* key);
-  };
-}}}
-
- -

Class - const_attribute_policies static functions

-
-static object get(object const& target, char const* key);
-
- -
-
Requires: key is an ntbs.
- -
Effects: accesses the attribute of target named - by key.
- -
Returns: An object managing the result of the - attribute access.
- -
Throws: error_already_set if a - Python exception is raised.
-
- -

Class - attribute_policies

- -

The policies which are used for proxies representing an attribute - access to a mutable object.

- -

Class - attribute_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct attribute_policies : const_attribute_policies
-  {
-      static object const& set(object const& target, char const* key, object const& value);
-      static void del(object const&target, char const* key);
-  };
-}}}
-
- -

Class - attribute_policies static functions

-
-static object const& set(object const& target, char const* key, object const& value);
-
- -
-
Requires: key is an ntbs.
- -
Effects: sets the attribute of target named by - key to value.
- -
Throws: error_already_set if a - Python exception is raised.
-
-
-static void del(object const&target, char const* key);
-
- -
-
Requires: key is an ntbs.
- -
Effects: deletes the attribute of target named - by key.
- -
Throws: error_already_set if a - Python exception is raised.
-
- - - -

Class - const_objattribute_policies

- -

The policies which are used for proxies representing an attribute - access to a const object when the attribute name is - given as a const object.

- -

Class - const_objattribute_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct const_objattribute_policies
-  {
-      typedef object const& key_type;
-      static object get(object const& target, object const& key);
-  };
-}}}
-
- -

Class - const_objattribute_policies static functions

-
-static object get(object const& target, object const& key);
-
- -
-
Requires: key is an object - holding a string.
- -
Effects: accesses the attribute of target named - by key.
- -
Returns: An object managing the result of the - attribute access.
- -
Throws: error_already_set if a - Python exception is raised.
-
- -

Class - objattribute_policies

- -

The policies which are used for proxies representing an attribute - access to a mutable object when the attribute name is - given as a const object.

- -

Class - objattribute_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct objattribute_policies : const_objattribute_policies
-  {
-      static object const& set(object const& target, object const& key, object const& value);
-      static void del(object const&target, object const& key);
-  };
-}}}
-
- -

Class - objattribute_policies static functions

-
-static object const& set(object const& target, object const& key, object const& value);
-
- -
-
Requires: key is an object - holding a string.
- -
Effects: sets the attribute of target named by - key to value.
- -
Throws: error_already_set if a - Python exception is raised.
-
-
-static void del(object const&target, object const& key);
-
- -
-
Requires: key is an object - holding a string.
- -
Effects: deletes the attribute of target named - by key.
- -
Throws: error_already_set if a - Python exception is raised.
-
- - - -

Class - const_item_policies

- -

The policies which are used for proxies representing an item access - (via the Python bracket operators []) to a - const object.

- -

Class - const_item_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct const_item_policies
-  {
-      typedef object key_type;
-      static object get(object const& target, object const& key);
-  };
-}}}
-
- -

Class - const_item_policies static functions

-
-static object get(object const& target, object const& key);
-
- -
-
Effects: accesses the item of target specified - by key.
- -
Returns: An object managing the result of the - item access.
- -
Throws: error_already_set if a - Python exception is raised.
-
- -

Class - item_policies

- -

The policies which are used for proxies representing an item access - (via the Python bracket operators []) to a mutable - object.

- -

Class - item_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct item_policies : const_item_policies
-  {
-      static object const& set(object const& target, object const& key, object const& value);
-      static void del(object const& target, object const& key);
-  };
-}}}
-
- -

Class - item_policies static functions

-
-static object const& set(object const& target, object const& key, object const& value);
-
- -
-
Effects: sets the item of target specified by - key to value.
- -
Throws: error_already_set if a - Python exception is raised.
-
-
-static void del(object const& target, object const& key);
-
- -
-
Effects: deletes the item of target specified - by key.
- -
Throws: error_already_set if a - Python exception is raised.
-
- - - -

Class - const_slice_policies

- -

The policies which are used for proxies representing an slice access - (via the Python slice notation - [x:y]) to a - const object.

- -

Class - const_slice_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct const_slice_policies
-  {
-      typedef std::pair<handle<>, handle<> > key_type;
-      static object get(object const& target, key_type const& key);
-  };
-}}}
-
- -

Class - const_slice_policies static functions

-
-static object get(object const& target, key_type const& key);
-
- -
-
Effects: accesses the slice of target specified - by key.
- -
Returns: An object managing the result of the - slice access.
- -
Throws: error_already_set if a - Python exception is raised.
-
- -

Class - slice_policies

- -

The policies which are used for proxies representing an slice access - to a mutable object.

- -

Class - slice_policies synopsis

-
-namespace boost { namespace python { namespace api
-{
-  struct slice_policies : const_slice_policies
-  {
-      static object const& set(object const& target, key_type const& key, object const& value);
-      static void del(object const& target, key_type const& key);
-  };
-}}}
-
- -

Class - slice_policies static functions

-
-static object const& set(object const& target, key_type const& key, object const& value);
-
- -
-
Effects: sets the slice of target specified by - key to value.
- -
Throws: error_already_set if a - Python exception is raised.
-
-
-static void del(object const& target, key_type const& key);
-
- -
-
Effects: deletes the slice of target specified - by key.
- -
Throws: error_already_set if a - Python exception is raised.
-
- - -

Class template - object_operators<U>

- -

This is the base class of object and its - proxy template used to supply common interface: member - functions, and operators which must be defined within the class body. Its - template parameter U is expected to be a class derived from - object_operators<U>. In practice users should never - use this class directly, but it is documented here because it supplies - important interface to object and its proxies.

- -

Class template - object_operators synopsis

-
-namespace boost { namespace python { namespace api
-{
-  template <class U>
-  class object_operators
-  {
-   public:
-      // function call
-      //
-      object operator()() const;
-
-      template <class A0>
-      object operator()(A0 const&) const;
-      template <class A0, class A1>
-      object operator()(A0 const&, A1 const&) const;
-      ...
-      template <class A0, class A1,...class An>
-      object operator()(A0 const&, A1 const&,...An const&) const;
-
-      detail::args_proxy operator* () const; 
-      object operator()(detail::args_proxy const &args) const; 
-      object operator()(detail::args_proxy const &args, 
-                        detail::kwds_proxy const &kwds) const; 
-
-      // truth value testing
-      //
-      typedef unspecified bool_type;
-      operator bool_type() const;
-
-      // Attribute access
-      //
-      proxy<const_object_attribute> attr(char const*) const;
-      proxy<object_attribute> attr(char const*);
-      proxy<const_object_objattribute> attr(object const&) const;
-      proxy<object_objattribute> attr(object const&);
-
-      // item access
-      //
-      template <class T>
-      proxy<const_object_item> operator[](T const& key) const;
-    
-      template <class T>
-      proxy<object_item> operator[](T const& key);
-
-      // slicing
-      //
-      template <class T, class V>
-      proxy<const_object_slice> slice(T const& start, V const& end) const
-    
-      template <class T, class V>
-      proxy<object_slice> slice(T const& start, V const& end);
-  };
-}}}
-
- -

Class template - object_operators observer functions

-
-object operator()() const;
-template <class A0>
-object operator()(A0 const&) const;
-template <class A0, class A1>
-object operator()(A0 const&, A1 const&) const;
-...
-template <class A0, class A1,...class An>
-object operator()(A0 const& a1, A1 const& a2,...An const& aN) const;
-
- -
-
Effects: - call<object>(object(*static_cast<U*>(this)).ptr(), a1, - a2,...aN)
-
- -
-object operator()(detail::args_proxy const &args) const; 
-
-
-
Effects: - call object with arguments given by the tuple args
-
-
-object operator()(detail::args_proxy const &args, 
-                  detail::kwds_proxy const &kwds) const; 
-
-
-
Effects: - call object with arguments given by the tuple args, and named - arguments given by the dictionary kwds
-
- - -
-operator bool_type() const;
-
- -
-
Effects: Tests truth value of *this.
- -
Returns: - call<object>(object(*static_cast<U*>(this)).ptr(), a1, - a2,...aN)
-
-
-proxy<const_object_attribute> attr(char const* name) const;
-proxy<object_attribute> attr(char const* name);
-
- -
-
Requires: name is an ntbs.
- -
Effects: accesses the named attribute of - *this.
- -
Returns: a proxy object which binds - object(*static_cast<U*>(this)) as its target, and - name as its key.
-
-
-proxy<const_object_objattribute> attr(const object& name) const;
-proxy<object_objattribute> attr(const object& name);
-
- -
-
Requires: name is a object holding a string.
- -
Effects: accesses the named attribute of - *this.
- -
Returns: a proxy object which binds - object(*static_cast<U*>(this)) as its target, and - name as its key.
-
-
-template <class T>
-proxy<const_object_item> operator[](T const& key) const;
-template <class T>
-proxy<object_item> operator[](T const& key);
-
- -
-
Effects: accesses the item of *this indicated - by key.
- -
Returns: a proxy object which binds - object(*static_cast<U*>(this)) as its target, and - object(key) as its key.
-
-
-template <class T, class V>
-proxy<const_object_slice> slice(T const& start; start, V const& finish) const
-template <class T, class V>
-proxy<object_slice> slice(T const& start; start, V const& finish);
-
- -
-
Effects: accesses the slice of *this indicated - by std::make_pair(object(start), object(finish)).
- -
Returns: a proxy object which binds - object(*static_cast<U*>(this)) as its target, and - std::make_pair(object(start), object(finish)) as its - key.
-
- - -

Class object

- -

The intention is that object acts as much like a - Python variable as possible. Thus expressions you'd expect to work - in Python should generally work in the same way from C++. Most of - object's interface is provided by its base class - object_operators<object>, - and the free functions defined in this - header. -

- -

Class object - synopsis

-
-namespace boost { namespace python { namespace api
-{
-  class object : public object_operators<object>
-  {
-   public:
-      object();
-
-      object(object const&);
-      
-      template <class T>
-      explicit object(T const& x);
-
-      ~object();
-
-      object& operator=(object const&); 
-
-      PyObject* ptr() const;
-
-      bool is_none() const;
-  };
-}}}
-
- -

Class object - constructors and destructor

-
-object();
-
- -
-
Effects: Constructs an object managing a reference to the - Python None object.
- -
Throws: nothing.
-
-
-template <class T>
-explicit object(T const& x);
-
- -
-
Effects: converts x to python and manages a - reference to it.
- -
Throws: error_already_set and sets a Python - TypeError exception if no such conversion is - possible.
-
-
-~object();
-
- -
-
Effects: decrements the reference count of the - internally-held object.
-
- -

Class object - modifiers

-
-object& operator=(object const& rhs); 
-
- -
-
Effects: increments the reference count of the object held - by rhs and decrements the reference count of the object - held by *this.
-
- -

Class object - observers

-
-PyObject* ptr() const;
-
- -
-
Returns: a pointer to the internally-held Python - object.
-
- -
-bool is_none() const;
-
- -
-
Returns: result of (ptr() == Py_None)
-
- - -

Class template proxy

- -

This template is instantiated with various Policies described in this - document in order to implement attribute, item, and slice access for - object. It stores an object of type - Policies::key_type.

- -

Class template proxy - synopsis

-
-namespace boost { namespace python { namespace api
-{
-  template <class Policies>
-  class proxy : public object_operators<proxy<Policies> >
-  {
-   public:
-      operator object() const;
-
-      proxy const& operator=(proxy const&) const;
-      template <class T>
-      inline proxy const& operator=(T const& rhs) const;
-      
-      void del() const;
-
-      template <class R>
-      proxy operator+=(R const& rhs);
-      template <class R>
-      proxy operator-=(R const& rhs);
-      template <class R>
-      proxy operator*=(R const& rhs);
-      template <class R>
-      proxy operator/=(R const& rhs);
-      template <class R>
-      proxy operator%=(R const& rhs);
-      template <class R>
-      proxy operator<<=(R const& rhs);
-      template <class R>
-      proxy operator>>=(R const& rhs);
-      template <class R>
-      proxy operator&=(R const& rhs);
-      template <class R>
-      proxy operator|=(R const& rhs);
-  };
-}}}
-
- -

Class template proxy - observer functions

-
-operator object() const;
-
- -
-
Effects: applies - Policies::get(target, key - ) with the proxy's target and key objects.
-
- -

Class template proxy - modifier functions

-
-proxy const& operator=(proxy const& rhs) const;
-template <class T>
-inline proxy const& operator=(T const& rhs) const;
-
- -
-
Effects: - Policies::set(target, key - , object(rhs)) with the proxy's target and key - objects.
-
-
-template <class R>
-proxy operator+=(R const& rhs);
-template <class R>
-proxy operator-=(R const& rhs);
-template <class R>
-proxy operator*=(R const& rhs);
-template <class R>
-proxy operator/=(R const& rhs);
-template <class R>
-proxy operator%=(R const& rhs);
-template <class R>
-proxy operator<<=(R const& rhs);
-template <class R>
-proxy operator>>=(R const& rhs);
-template <class R>
-proxy operator&=(R const& rhs);
-template <class R>
-proxy operator|=(R const& rhs);
-
- -
-
Effects: for a given operator@=, - object(*this) @= rhs;
-
Returns: *this
-
-
-void del() const;
-
- -
-
Effects: - Policies::del(target, key - ) with the proxy's target and key objects.
-
- - -

Functions

-
-template <class T>
-void del(proxy<T> const& x);
-
- -
-
Effects: x.del()
-
-
-
-template<class L,class R> object operator>(L const&l,R const&r);
-template<class L,class R> object operator>=(L const&l,R const&r);
-template<class L,class R> object operator<(L const&l,R const&r);
-template<class L,class R> object operator<=(L const&l,R const&r);
-template<class L,class R> object operator==(L const&l,R const&r);
-template<class L,class R> object operator!=(L const&l,R const&r);
-
- -
-
Effects: returns the result of applying the operator to - object(l) and object(r), respectively, in - Python.
-
-
-
-template<class L,class R> object operator+(L const&l,R const&r);
-template<class L,class R> object operator-(L const&l,R const&r);
-template<class L,class R> object operator*(L const&l,R const&r);
-template<class L,class R> object operator/(L const&l,R const&r);
-template<class L,class R> object operator%(L const&l,R const&r);
-template<class L,class R> object operator<<(L const&l,R const&r);
-template<class L,class R> object operator>>(L const&l,R const&r);
-template<class L,class R> object operator&(L const&l,R const&r);
-template<class L,class R> object operator^(L const&l,R const&r);
-template<class L,class R> object operator|(L const&l,R const&r);
-
- -
-
Effects: returns the result of applying the operator to - object(l) and object(r), respectively, in - Python.
-
-
-
-template<class R> object& operator+=(object&l,R const&r);
-template<class R> object& operator-=(object&l,R const&r);
-template<class R> object& operator*=(object&l,R const&r);
-template<class R> object& operator/=(object&l,R const&r);
-template<class R> object& operator%=(object&l,R const&r);
-template<class R> object& operator<<=(object&l,R const&r)
-template<class R> object& operator>>=(object&l,R const&r);
-template<class R> object& operator&=(object&l,R const&r);
-template<class R> object& operator^=(object&l,R const&r);
-template<class R> object& operator|=(object&l,R const&r);
-
- -
-
Effects: assigns to l the result of applying the - corresponding Python inplace operator to l and - object(r), respectively.
- -
Returns: l.
-
- -
-inline long len(object const& obj);
-
- -
-
Effects: PyObject_Length(obj.ptr())
-
Returns: len() of object.
-
- -

Example

- Python code: -
-def sum_items(seq):
-   result = 0
-   for x in seq:
-      result += x
-   return result
-
- C++ version: -
-object sum_items(object seq)
-{
-   object result = object(0);
-   for (int i = 0; i < len(seq); ++i)
-      result += seq[i];
-   return result;
-}
-
-

Revised - - 15 March, 2010 - -

- -

© Copyright Dave Abrahams 2008.

- - diff --git a/doc/v2/opaque.html b/doc/v2/opaque.html deleted file mode 100644 index fed1d446f4..0000000000 --- a/doc/v2/opaque.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/opaque_pointer_converter.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/opaque_pointer_converter.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class template - opaque<Pointee>
- -
-
-
Class template - opaque synopsis
-
-
-
-
- -
Macros
-
-
-
Macro - BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID
-
-
- -
See Also
-
-
- -

Classes

- -

Class template - opaque<P>

- -

opaque<> registers itself as a converter from - Python objects to pointers to undefined types and vice versa.

- -

Class template - opaque synopsis

-
-namespace boost { namespace python
-{
-    template<class Pointee>
-    struct opaque
-    {
-        opaque();
-    };
-}}
-
- -

Class template - opaque constructor

-
-opaque();
-
- -
-
Effects: -
    -
  • Registers the instance as a - lvalue_from_pytype - converter from Python objects into opaque pointers.

    -

    The Python Objects created are named after the type pointed to - by the opaque pointer being wrapped.

  • -
  • Registers the instance as a - to_python_converter - from opaque pointers to Python objects.

  • -
-

If there is already an instance registered by another module, this - instance doesn't try to register again in order to avoid warnings - about multiple registrations.

- -

Note

-

Normally only a single instance of this class is created for every - Pointee.

-
-
- -

Macros

- -

- Macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)

-

This macro must be used to define specializations of the - type_id function - which can't be instantiated for incomplete types.

-

Note

-

The macro must be invoked in every translation unit which uses the - opaque converter.

- -

See Also

-

- return_opaque_pointer -

- -

Revised - 10 September, 2006 -

- -

© Copyright 2003..2006 Haufe Mediengruppe. All Rights - Reserved.

- - - diff --git a/doc/v2/operators.html b/doc/v2/operators.html deleted file mode 100755 index 69740243fb..0000000000 --- a/doc/v2/operators.html +++ /dev/null @@ -1,921 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/operators.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/operators.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class - self_ns::self_t
- -
-
-
Class self_t - synopsis
- -
Class self_t - inplace operators
- -
Class - self_t comparison functions
- -
Class self_t - non-member operations
- -
Class - self_t unary operations
- -
Class - self_t value operations
-
-
- -
Class template - other
- -
-
-
Class other - synopsis
-
-
- -
Class template - operator_
- -
-
-
Class - operator_ synopsis
-
-
-
-
- -
Objects
- -
-
-
self
-
-
- -
Examples
-
-
- -

Introduction

- -

<boost/python/operators.hpp> provides types and - functions for automatically generating Python special methods - from the corresponding C++ constructs. Most of these constructs are - operator expressions, hence the name. To use the facility, substitute the - self object for an object of the - class type being wrapped in the expression to be exposed, and pass the - result to class_<>::def(). Much of - what is exposed in this header should be considered part of the - implementation, so is not documented in detail here.

- -

Classes

- -

Class self_ns::self_t

- -

self_ns::self_t is the actual type of the self object. The library isolates - self_t in its own namespace, self_ns, in order - to prevent the generalized operator templates which operate on it from - being found by argument-dependent lookup in other contexts. This should - be considered an implementation detail, since users should never have to - mention self_t directly.

- -

Class self_ns::self_t - synopsis

-
-namespace boost { namespace python { namespace self_ns {
-{
-   unspecified-type-declaration self_t;
-
-   // inplace operators
-   template <class T> operator_<unspecified> operator+=(self_t, T);
-   template <class T> operator_<unspecified> operator-=(self_t, T);
-   template <class T> operator_<unspecified> operator*=(self_t, T);
-   template <class T> operator_<unspecified> operator/=(self_t, T);
-   template <class T> operator_<unspecified> operator%=(self_t, T);
-   template <class T> operator_<unspecified> operator>>=(self_t, T);
-   template <class T> operator_<unspecified> operator<<=(self_t, T);
-   template <class T> operator_<unspecified> operator&=(self_t, T);
-   template <class T> operator_<unspecified> operator^=(self_t, T);
-   template <class T> operator_<unspecified> operator|=(self_t, T);
-
-   // comparisons
-   template <class L, class R> operator_<unspecified> operator==(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator!=(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator<(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator>(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator<=(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator>=(L const&, R const&);
-
-   // non-member operations
-   template <class L, class R> operator_<unspecified> operator+(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator-(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator*(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator/(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator%(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator>>(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator<<(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator&(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator^(L const&, R const&);
-   template <class L, class R> operator_<unspecified> operator|(L const&, R const&);
-   template <class L, class R> operator_<unspecified> pow(L const&, R const&);
-
-   // unary operations
-   operator_<unspecified> operator-(self_t);
-   operator_<unspecified> operator+(self_t);
-   operator_<unspecified> operator~(self_t);
-   operator_<unspecified> operator!(self_t);
-
-   // value operations
-   operator_<unspecified> int_(self_t);
-   operator_<unspecified> long_(self_t);
-   operator_<unspecified> float_(self_t);
-   operator_<unspecified> complex_(self_t);
-   operator_<unspecified> str(self_t);
-
-   operator_<unspecified> repr(self_t);
-
-}}};
-
- The tables below describe the methods generated when the results of the - expressions described are passed as arguments to class_<>::def(). - x is an object of the class type being wrapped. - -

Class self_t inplace - operators

- In the table below, If r is an object of type - other<T>, - y is an object of type T; otherwise, - y is an object of the same type as - r. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
C++ ExpressionPython Method NameC++ Implementation
self += r__iadd__x += y
self -= r__isub__x -= y
self *= r__imul__x *= y
self /= r__idiv__x /= y
self %= r__imod__x %= y
self >>= r__irshift__x >>= y
self <<= r__ilshift__x <<= y
self &= r__iand__x &= y
self ^= r__ixor__x ^= y
self |= r__ior__x |= y
- -

Class self_t - comparison functions

- In the tables below, if r is of type self_t, y is an object of - the same type as x;
- if l or r is an object of type - other<T>, - y is an object of type T;
- otherwise, y is an object of the same type as - l or r.
- l is never of type self_t. - -

The column of Python Expressions illustrates the expressions - that will be supported in Python for objects convertible to the types of - x and y. The secondary operation arises due to - Python's reflection - rules for rich comparison operators, and are only used when the - corresponding operation is not defined as a method of the y - object.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
C++ ExpressionPython Method NameC++ ImplementationPython Expressions
- (primary, secondary)
self == r__eq__x == yx == y, y == x
l == self__eq__y == xy == x, x == y
self != r__ne__x != yx != y, y != x
l != self__ne__y != xy != x, x != y
self < r__lt__x < yx < y, y > x
l < self__gt__y < xy > x, x < y
self > r__gt__x > yx > y, y < x
l > self__lt__y > xy < x, x > y
self <= r__le__x <= yx <= y, y >= x
l <= self__ge__y <= xy >= x, x <= y
self >= r__ge__x >= yx >= y, y <= x
l >= self__le__y >= xy <= x, x >= y
- -

Class self_t non-member - operations

- The operations whose names begin with "__r" below will only - be called if the left-hand operand does not already support the given - operation, as described here. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
C++ ExpressionPython Method NameC++ Implementation
self + r__add__x + y
l + self__radd__y + x
self - r__sub__x - y
l - self__rsub__y - x
self * r__mul__x * y
l * self__rmul__y * x
self / r__div__x / y
l / self__rdiv__y / x
self % r__mod__x % y
l % self__rmod__y % x
self >> r__rshift__x >> y
l >> self__rrshift__y >> x
self << r__lshift__x << y
l << self__rlshift__y << x
self & r__and__x & y
l & self__rand__y & x
self ^ r__xor__x ^ y
l ^ self__rxor__y ^ x
self | r__or__x | y
l | self__ror__y | x
pow(self, r)__pow__pow(x, y)
pow(l, self)__rpow__pow(y, x)
- -

Class self_t unary - operations

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
C++ ExpressionPython Method NameC++ Implementation
-self__neg__-x
+self__pos__+x
~self__invert__~x
not self
or
!self
__nonzero__!!x
- -

Class self_t value - operations

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
C++ ExpressionPython Method NameC++ Implementation
int_(self)__int__long(x)
long___long__PyLong_FromLong(x)
float___float__double(x)
complex___complex__std::complex<double>(x)
str__str__lexical_cast<std::string>(x)
repr__repr__lexical_cast<std::string>(x)
- -

Class Template other

- -

Instances of other<T> can be used in operator - expressions with self; the result is equivalent - to the same expression with a T object in place of - other<T>. Use other<T> to prevent - construction of a T object in case it is heavyweight, when - no constructor is available, or simply for clarity.

- -

Class Template other synopsis

-
-namespace boost { namespace python
-{
-  template <class T>
-  struct other
-  {
-  };
-}}
-
- - -

Class Template - detail::operator_

- -

Instantiations of detail::operator_<> are used as - the return type of operator expressions involving self. This should be considered an implementation - detail and is only documented here as a way of showing how the result of - self-expressions match calls to class_<>::def().

- -

Class Template - detail::operator_ synopsis

-
-namespace boost { namespace python { namespace detail
-{
-  template <unspecified>
-  struct operator_
-  {
-  };
-}}}
-
- -

Objects

- -

self

-
-namespace boost { namespace python
-{
-  using self_ns::self;
-}}
-
- -

Example

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/operators.hpp>
-#include <boost/operators.hpp>
-
-struct number
-   : boost::integer_arithmetic<number>
-{
-    explicit number(long x_) : x(x_) {}
-    operator long() const { return x; }
-
-    template <class T>
-    number& operator+=(T const& rhs)
-    { x += rhs; return *this; }
-
-    template <class T>
-    number& operator-=(T const& rhs)
-    { x -= rhs; return *this; }
-    
-    template <class T>
-    number& operator*=(T const& rhs)
-    { x *= rhs; return *this; }
-    
-    template <class T>
-    number& operator/=(T const& rhs)
-    { x /= rhs; return *this; }
-    
-    template <class T>
-    number& operator%=(T const& rhs)
-    { x %= rhs; return *this; }
-
-   long x;
-};
-
-using namespace boost::python;
-BOOST_PYTHON_MODULE(demo)
-{
-   class_<number>("number", init<long>())
-      // interoperate with self
-      .def(self += self)
-      .def(self + self)
-      .def(self -= self)
-      .def(self - self)
-      .def(self *= self)
-      .def(self * self)
-      .def(self /= self)
-      .def(self / self)
-      .def(self %= self)
-      .def(self % self)
-
-      // Convert to Python int
-      .def(int_(self))
-
-      // interoperate with long
-      .def(self += long())
-      .def(self + long())
-      .def(long() + self)
-      .def(self -= long())
-      .def(self - long())
-      .def(long() - self)
-      .def(self *= long())
-      .def(self * long())
-      .def(long() * self)
-      .def(self /= long())
-      .def(self / long())
-      .def(long() / self)
-      .def(self %= long())
-      .def(self % long())
-      .def(long() % self)
-      ;
-}
-
- -

Revised - - 5 October, 2004 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/overloads.html b/doc/v2/overloads.html deleted file mode 100644 index 783e8e5db1..0000000000 --- a/doc/v2/overloads.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/overloads.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/overloads.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
overload-dispatch-expressions
- -
OverloadDispatcher concept
- -
Macros
- -
-
-
BOOST_PYTHON_FUNCTION_OVERLOADS
- -
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Defines facilities for generating families of overloaded Python - functions and extension class methods from C++ functions and - member functions with default arguments, or from similar families - of C++ overloads

- -

overload-dispatch-expressions

- -

- An overload-dispatch-expression is used to describe a - family of overloaded methods to be generated for an extension - class. It has the following properties: - -

-
-
docstring: An ntbs - whose value will bound to the methods' __doc__ - attribute
- -
keywords: A keyword-expression which - will be used to name (a trailing subsequence of) the arguments - to the generated methods.
- -
call policies: An instance of some type which models CallPolicies.
- -
minimum arity - The minimum number of arguments to be accepted by a generated - method overload.
- -
maximum arity - The maximum number of arguments to be accepted by a generated - method overload.
-
-
- -

OverloadDispatcher Concept

- - An OverloadDispatcher X is a class which has a - minimum arity and a maximum arity, and for which - the following following are valid overload-dispatch-expressions, - with the same minimum and maximum arity as the OverloadDispatcher. - -
-X()
-X(docstring)
-X(docstring, keywords)
-X(keywords, docstring)
-X()[policies]
-X(docstring)[policies]
-X(docstring, keywords)[policies]
-X(keywords, docstring)[policies]
-
- -
    -
  • If policies are supplied, it must be an instance of a -type which models CallPolicies, and -will be used as the result's call policies. Otherwise the result's -call policies will be an instance of default_call_policies. - -
  • If docstring is supplied it must be an ntbs, and will be used as the result's docstring. Otherwise the result has an empty docstring. - -
  • If keywords is supplied it must be the result of a keyword-expression - whose length is no greater than X's maximum - arity, and will be used as the result's keywords. Otherwise - the result's keywords will be empty. -
- - - - -

Macros

- -

BOOST_PYTHON_FUNCTION_OVERLOADS(name, func_id, min_args, max_args)

- Expands to the definition of an OverloadDispatcher called - name in the current scope which can be used to - generate the following function invocation: -
-func_id(a1, a2,...ai);
-
- - for all min_args <= i <= max_args. - -

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(name, member_name, min_args, max_args)

- - Expands to the definition of an OverloadDispatcher called - name in the current scope which can be used to - generate the following function invocation: -
-x.member_name(a1, a2,...ai);
-
- - for all min_args <= i <= - max_args, where x is a reference to an - object of class type. - -

Example(s)

- -
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/args.hpp>
-#include <boost/python/tuple.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/overloads.hpp>
-#include <boost/python/return_internal_reference.hpp>
-
-using namespace boost::python;
-
-tuple f(int x = 1, double y = 4.25, char const* z = "wow")
-{
-    return make_tuple(x, y, z);
-}
-
-BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3)
-
-struct Y {};
-struct X
-{
-    Y& f(int x, double y = 4.25, char const* z = "wow")
-    {
-        return inner;
-    }
-    Y inner;
-};
-
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(f_member_overloads, f, 1, 3)
-
-BOOST_PYTHON_MODULE(args_ext)
-{
-    def("f", f, 
-        f_overloads(
-            args("x", "y", "z"), "This is f's docstring"
-        ));
-
-    
-    class_<Y>("Y")
-        ;
-            
-    class_<X>("X", "This is X's docstring")
-        .def("f1", &X::f, 
-                f_member_overloads(
-                    args("x", "y", "z"), "f's docstring"
-                )[return_internal_reference<>()]
-        )
-        ;
-}
-
- -

Revised - - 15 April, 2003 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/pickle.html b/doc/v2/pickle.html deleted file mode 100644 index 22e198d63b..0000000000 --- a/doc/v2/pickle.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - Boost.Python Pickle Support - - - -
- boost.png (6897 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 through the - interface as described in detail in the Python Library - Reference for pickle. This interface involves the special methods - __getinitargs__, __getstate__ and __setstate__ - as described in the following. Note that Boost.Python is also fully - compatible with Python's cPickle module.

-
- -

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, pickle.load - will call the constructor (__init__) without arguments; - i.e., the object must be default-constructible.

-
- -
__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.
- -
__setstate__
- -
When an instance of a Boost.Python extension class is restored by - the unpickler (pickle.load), 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.
-
The three special methods described above may be .def()'ed - individually by the user. However, Boost.Python provides an easy to use - high-level interface via the - boost::python::pickle_suite class that also - enforces consistency: __getstate__ and __setstate__ - must be defined as pairs. Use of this interface is demonstrated by the - following examples. -
- -

Examples

There are three files in boost/libs/python/test - that show how to 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__. This is done in the - following way: - -
    -
  • 1. Definition of the C++ pickle function: -
    -  struct world_pickle_suite : boost::python::pickle_suite
    -  {
    -    static
    -    boost::python::tuple
    -    getinitargs(world const& w)
    -    {
    -        return boost::python::make_tuple(w.get_country());
    -    }
    -  };
    -
    -
  • - -
  • 2. Establishing the Python binding: -
    -  class_<world>("world", args<const std::string&>())
    -      // ...
    -      .def_pickle(world_pickle_suite())
    -      // ...
    -
    -
  • -
-
- -

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: - -
    -
  • 1. Definition of the C++ pickle functions: -
    -  struct world_pickle_suite : boost::python::pickle_suite
    -  {
    -    static
    -    boost::python::tuple
    -    getinitargs(const world& w)
    -    {
    -      // ...
    -    }
    -
    -    static
    -    boost::python::tuple
    -    getstate(const world& w)
    -    {
    -      // ...
    -    }
    -
    -    static
    -    void
    -    setstate(world& w, boost::python::tuple state)
    -    {
    -      // ...
    -    }
    -  };
    -
    -
  • - -
  • 2. Establishing the Python bindings for the entire suite: -
    -  class_<world>("world", args<const std::string&>())
    -      // ...
    -      .def_pickle(world_pickle_suite())
    -      // ...
    -
    -
  • -
- -

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 guard described below 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 a little more code but is unavoidable if the object's - __dict__ is not always empty. -
- -

Pitfall and Safety Guard

The pickle protocol described above has - an important pitfall that the end user of a Boost.Python extension module - might not be aware of: - -

__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 - either at the C++ or the Python level. Finally, the safety guard should - intentionally be overridden. E.g. in C++ (from pickle3.cpp): -
-  struct world_pickle_suite : boost::python::pickle_suite
-  {
-    // ...
-
-    static bool getstate_manages_dict() { return true; }
-  };
-
Alternatively 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

- -
    -
  • 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.
  • - -
  • Avoid using __getstate__ if the instance can also be - reconstructed by way of __getinitargs__. This automatically - avoids the pitfall described above.
  • - -
  • If __getstate__ is required, include the instance's - __dict__ in the Python object that is returned.
  • -
-
- -

Light-weight alternative: pickle support implemented in Python

- -

pickle4.cpp

The - pickle4.cpp example demonstrates an alternative technique for - implementing pickle support. First we direct Boost.Python via the - class_::enable_pickling() member function to define only the - basic attributes required for pickling: -
-  class_<world>("world", args<const std::string&>())
-      // ...
-      .enable_pickling()
-      // ...
-
This enables the standard Python pickle interface as described in the -Python documentation. By "injecting" a __getinitargs__ method into -the definition of the wrapped class we make all instances pickleable: -
-  # import the wrapped world class
-  from pickle4_ext import world
-
-  # definition of __getinitargs__
-  def world_getinitargs(self):
-    return (self.get_country(),)
-
-  # now inject __getinitargs__ (Python is a dynamic language!)
-  world.__getinitargs__ = world_getinitargs
-
See also the - tutorial section on injecting additional methods from Python. -
- © Copyright Ralf W. Grosse-Kunstleve 2001-2004. Distributed under the - Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -

Updated: Feb 2004.

-
- - diff --git a/doc/v2/platforms.html b/doc/v2/platforms.html deleted file mode 100644 index ac984b43fc..0000000000 --- a/doc/v2/platforms.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - Boost.Python - Known Working Platforms and Compilers - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Known Working Platforms and Compilers

-
-
- Please see - our regression - logs for up-to-date information. Note that logs not marked - otherwise reflect the CVS state, not the condition of the release. - -

- Earlier versions of Boost.Python have been successfully - tested on the following platforms and compilers. - -

-
Unix Platforms:
- -
-
-
with Python 2.2 and 2.2.2b1:
- -
-
-
GCC 2.95.3, 2.96, 3.0.4, - 3.1, and 3.2 on RedHat Linux 7.3 - for Intel x86
- -
Tru64 CXX 6.5.1 on OSF v. 5.1 for Dec/Compaq - Alpha
- -
- MIPSPro 7.3.1.2m on IRIX 6.5 for SGI - mips
- -
GCC 3.1 on SunOS 5.8
-
-
- -
with Python 2.2.1
- -
-
-
KCC 3.4d on OSF v. 5.1 for Dec/Compaq Alpha
- -
KCC 3.4d on AIX
-
-
-
-
-
- -
Microsoft Windows XP Professional with Python 2.2, 2.2.1, and 2.2.2b1:
- -
-
-
Microsoft Visual - C++ 6, 7, and 7.1 beta
- -
Microsoft Visual - C++ 6 with STLPort - 4.5.3
- -
- Metrowerks CodeWarrior 7.2, 8.0, 8.2 and 8.3 beta
- -
Intel - C++ 5.0, 6.0, and 7.0 beta
- -
Intel C++ - 5.0 with STLPort - 4.5.3
- -
Cygwin GCC 3.0.4 and 3.2
- -
MinGW-1.1 (GCC 2.95.3-5)
- -
MinGW-2.0 (GCC 3.2)
-
-
-
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/pointee.html b/doc/v2/pointee.html deleted file mode 100644 index 2dcec8c368..0000000000 --- a/doc/v2/pointee.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - Boost.Python - <boost/python/pointee.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header <boost/python/pointee.hpp>

-
-
- -

Contents

- -
-
Introduction - -
Classes - -
-
-
Class Templatepointee - -
-
-
Class Template - pointee synopsis -
-
- -
Example -
-
- -

Introduction

- -

<boost/python/pointee.hpp> introduces a - traits metafunction - template pointee<T> that can be used to extract the "pointed-to" type from the type of a pointer or smart pointer. - -

Classes

- -

Class Template pointee<class T>

- -

pointee<T> is used by the class_<...> - template to deduce the type being held when a pointer or smart - pointer type is used as its HeldType argument. - -

Class Template - pointee synopsis

-
-namespace boost { namespace python
-{
-   template <class T> struct pointee
-   {
-      typedef T::element_type type;
-   };
-
-   // specialization for pointers
-   template <T> struct pointee<T*>
-   {
-      typedef T type;
-   };
-}
-
- - -

Example

- -Given a 3rd-party smart pointer type -smart_pointer<T>, one might partially specialize -pointee<smart_pointer<T> > so that it can be -used as the HeldType for a class wrapper: - -
-#include <boost/python/pointee.hpp>
-#include <boost/python/class.hpp>
-#include <third_party_lib.hpp>
-
-namespace boost { namespace python
-{
-  template <class T> struct pointee<smart_pointer<T> >
-  {
-     typedef T type;
-  };
-}}
-
-BOOST_PYTHON_MODULE(pointee_demo)
-{
-   class_<third_party_class, smart_pointer<third_party_class> >("third_party_class")
-      .def(...)
-      ...
-      ;
-}
-
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave - Abrahams 2002. Distributed - under the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

- - diff --git a/doc/v2/progress_reports.html b/doc/v2/progress_reports.html deleted file mode 100644 index 5a8b015a20..0000000000 --- a/doc/v2/progress_reports.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - -Boost.Python - Progress Reports - - - - - - - -
-

-

-
-

Boost.Python

-

Progress Reports

-
-
- -Monthly progress reports are required as part of Boost Consulting's -contract with LLNL for Boost.Python development. These reports contain -a useful record of the project history, including the rationale for -design decisions and links to relevant discussions. - -
-
February 2002
-
March 2002
-
April 2002
-
May 2002
-
June 2002
-
-
-

Revised - - 13 November, 2002 - -

-

© Copyright Dave Abrahams - 2002.

- - diff --git a/doc/v2/ptr.html b/doc/v2/ptr.html deleted file mode 100644 index 4aca539158..0000000000 --- a/doc/v2/ptr.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - Boost.Python - <boost/python/ptr.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header <boost/python/ptr.hpp>

-
-
- -

Contents

- -
-
Introduction - -
Functions -
-
-
ptr -
- -
Classes -
-
-
Class template pointer_wrapper - -
-
-
Class template pointer_wrapper synopsis - -
Class - pointer_wrapper types - -
Class - pointer_wrapper constructors and destructor - -
Class - pointer_wrapper observer functions - -
-
- -
Metafunctions -
-
-
Class template is_pointer_wrapper - -
-
-
Class template is_pointer_wrapper synopsis -
- - -
Class template unwrap_pointer - -
-
-
Class template unwrap_pointer synopsis -
- -
- - -
Example(s) -
-
- -

Introduction

- -

<boost/python/ptr.hpp> defines the - ptr() function template, which allows users to - specify how to convert C++ pointer values to python in the context - of implementing overridable virtual functions, invoking Python - callable objects, or explicitly converting C++ objects to - Python. Normally, when passing pointers to Python callbacks, the - pointee is copied to ensure that the Python object - never holds a dangling reference. To specify that the new Python - object should merely contain a copy of a pointer p, - the user can pass ptr(p) instead of passing - p directly. This interface is meant to mirror the use - of boost::ref(), - which can be similarly used to prevent copying of referents. - -

ptr(p) returns an instance of pointer_wrapper<>, which - can be detected using the is_pointer_wrapper<> - metafunction; unwrap_pointer<> is a - metafunction which extracts the original pointer type from a - pointer_wrapper<>. These classes can be thought - of as implementation details. - -

Functions

-
-
-template <class T>
-pointer_wrapper<T> ptr(T x);
-
- -
-
Requires: T is a pointer type. - -
Returns: pointer_wrapper<T>(x) - -
Throws: nothing. -
- -

Classes

- -

Class template pointer_wrapper

- -

A "type envelope" which is returned by ptr(), used to indicate reference semantics - for pointers passed to Python callbacks. - -

Class - pointer_wrapper synopsis

-
-namespace boost { namespace python
-{
-    template<class Ptr> class pointer_wrapper
-    { 
-     public:
-        typedef Ptr type;
-
-        explicit pointer_wrapper(Ptr x);
-        operator Ptr() const;
-        Ptr get() const;
-    };
-}}
-
- -

Class template pointer_wrapper types

-
-typedef Ptr type;
-
-The type of the pointer being wrapped. - -

Class template pointer_wrapper constructors and - destructor

-
-explicit pointer_wrapper(Ptr x);
-
- -
-
Requires: Ptr is a pointer type. - -
Effects: Stores x in a the pointer_wrapper<>. -
Throws: nothing. -
- -

Class template pointer_wrapper observer - functions

-
-operator Ptr() const;
-Ptr get() const;
-
- -
-
Returns: a copy of the stored pointer. -
Rationale: pointer_wrapper is intended - to be a stand-in for the actual pointer type, but sometimes it's - better to have an explicit way to retrieve the pointer. -
- -

Metafunctions

- -

Class template is_pointer_wrapper

- -

A unary metafunction whose value is true iff its - argument is a pointer_wrapper<>. - -

Class template is_pointer_wrapper synopsis

-
-namespace boost { namespace python
-{
-    template<class T> class is_pointer_wrapper
-    { 
-        static unspecified value = ...;
-    };
-}}
-
- - -
-
Returns: true iff T is a - specialization of -pointer_wrapper<>. -
value is an integral constant convertible to bool of -unspecified type - -
- -

Class template unwrap_pointer

- -A unary metafunction which extracts the wrapped pointer type from a -specialization of pointer_wrapper<>. - -

Class template unwrap_pointer synopsis

-
-namespace boost { namespace python
-{
-    template<class T> class unwrap_pointer
-    { 
-        typedef unspecified type;
-    };
-}}
-
- -
-
Returns: T::type if T is a - specialization of -pointer_wrapper<>, T otherwise -
- - -

Example(s)

- -This example illustrates the use of ptr() to prevent an -object from being copied: -
-#include <boost/python/call.hpp>
-#include <boost/python/ptr.hpp>
-
-class expensive_to_copy
-{
-   ...
-};
-
-void pass_as_arg(expensive_to_copy* x, PyObject* f)
-{
-   // call the Python function f, passing a Python object built around
-   // which refers to *x by-pointer.
-   //
-   // *** Note: ensuring that *x outlives the argument to f() is    ***
-   // *** up to the user! Failure to do so could result in a crash! ***
-
-   boost::python::call<void>(f, ptr(x));
-}
-...
-
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave - Abrahams 2002. Distributed - under the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/v2/python.html b/doc/v2/python.html deleted file mode 100644 index 9c4e27ec63..0000000000 --- a/doc/v2/python.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - 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 - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/pytype_function.html b/doc/v2/pytype_function.html deleted file mode 100644 index fcc2a7f928..0000000000 --- a/doc/v2/pytype_function.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - - - - - - - - Boost.Python - - <boost/python/doobject/pytype_function.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/converter/pytype_function.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class - wrap_pytype
- -
-
-
Class - wrap_pytype synopsis
- -
-
-
-
- -
-
-
Class - registered_pytype
- -
-
-
Class - registered_pytype synopsis
- -
-
-
-
- -
-
-
Class - expected_from_python_type
- -
-
-
Class - expected_from_python_type synopsis
- -
-
-
-
- -
-
-
Class - to_python_target_type
- -
-
-
Class - to_python_target_type synopsis
- -
-
-
-
- -
Examples
-
-
- -

Introduction

- -

To support Pythonic signatures the converters should supply a get_pytype function - returning a pointer to the associated PyTypeObject. See for example - ResultConverter or - to_python_converter. - The classes in this header file are meant to be used when implmenting get_pytype. - There are also _direct versions of the templates of class T which - should be used with undecorated type parameter, expected to be in the conversion registry when the module loads. -

- -

Classes

- -

Class - wrap_pytype

- -

- This template generates a static get_pytype member returning the template parameter. -

- -

Class - wrap_pytype synopsis

-
-namespace boost { namespace python { namespace converter{
-
-    template < PyTypeObject const *pytype >
-    class wrap_pytype 
-    {
-      public:
-          static PyTypeObject const *get_pytype(){return pytype; }
-    };
-
-}}}
-
- - -

Class - registered_pytype

- -

- This template should be used with template parameters which are (possibly decorated) - types exported to python using class_. - The generated a static get_pytype member - returns the corresponding python type. -

- -

Class - registered_pytype synopsis

-
-namespace boost { namespace python { namespace converter{
-
-    template < class T >
-    class registered_pytype 
-    {
-      public:
-          static PyTypeObject const *get_pytype();
-    };
-
-}}}
-
- - -

Class - expected_from_python_type

- -

- This template generates a static get_pytype member which inspects the registered - from_python converters for the type T and returns a matching python type. -

- -

Class - expected_from_python_type synopsis

-
-namespace boost { namespace python { namespace converter{
-
-    template < class T >
-    class expected_from_python_type 
-    {
-      public:
-          static PyTypeObject const *get_pytype();
-    };
-
-}}}
-
- - -

Class - to_python_target_type

- -

- This template generates a static get_pytype member returning the - python type to which T can be converted. -

- -

Class - to_python_target_type synopsis

-
-namespace boost { namespace python { namespace converter{
-
-    template < class T >
-    class to_python_target_type 
-    {
-      public:
-          static PyTypeObject const *get_pytype();
-    };
-
-}}}
-
- - -

Examples

- - This example presumes that someone has implemented the standard noddy example - module from the Python documentation, and placed the corresponding - declarations in "noddy.h". Because - noddy_NoddyObject is the ultimate trivial extension type, - the example is a bit contrived: it wraps a function for which all - information is contained in the type of its return value. - -

C++ module definition

-
-#include <boost/python/reference.hpp>
-#include <boost/python/module.hpp>
-#include "noddy.h"
-
-struct tag {};
-tag make_tag() { return tag(); }
-
-using namespace boost::python;
-
-struct tag_to_noddy 
-#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported
-: wrap_pytype<&noddy_NoddyType> //inherits get_pytype from wrap_pytype
-#endif
-{
-    static PyObject* convert(tag const& x)
-    {
-        return PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
-    }
-};
-
-BOOST_PYTHON_MODULE(to_python_converter)
-{
-    def("make_tag", make_tag);
-    to_python_converter<tag, tag_to_noddy
-#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
-          , true
-#endif
-          >(); //"true" because tag_to_noddy has member get_pytype
-}
-
- - -

The following example registers to and from python converters using the templates -expected_from_python_type and to_pyhton_target_type. -

-
-#include <boost/python/module.hpp>
-#include <boost/python/def.hpp>
-#include <boost/python/extract.hpp>
-#include <boost/python/to_python_converter.hpp>
-#include <boost/python/class.hpp>
-
-using namespace boost::python;
-
-struct A
-{
-};
-
-struct B
-{
-  A a;
-  B(const A& a_):a(a_){}
-};
-
-// Converter from A to python int
-struct BToPython 
-#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported
-   : converter::to_python_target_type<A>  //inherits get_pytype
-#endif
-{
-  static PyObject* convert(const B& b)
-  {
-    return incref(object(b.a).ptr());
-  }
-};
-
-// Conversion from python int to A
-struct BFromPython
-{
-  BFromPython()
-  {
-    boost::python::converter::registry::push_back
-        ( &convertible
-        , &construct
-        , type_id< B >()
-#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
-        , &converter::expected_from_python_type<A>::get_pytype//convertible to A can be converted to B
-#endif
-        );
-  }
-
-  static void* convertible(PyObject* obj_ptr)
-  {
-      extract<const A&> ex(obj_ptr);
-      if (!ex.check()) return 0;
-      return obj_ptr;
-  }
-
-  static void construct(
-      PyObject* obj_ptr,
-      converter::rvalue_from_python_stage1_data* data)
-  {
-    void* storage = (
-        (converter::rvalue_from_python_storage< B >*)data)-> storage.bytes;
-
-    extract<const A&> ex(obj_ptr);
-    new (storage) B(ex());
-    data->convertible = storage;
-  }
-};
-
-
-B func(const B& b) { return b ; }
-
-BOOST_PYTHON_MODULE(pytype_function_ext)
-{
-  to_python_converter< B , BToPython
-#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
-             ,true 
-#endif
-             >(); //has get_pytype
-  BFromPython();
-
-  class_<A>("A") ;
-
-  def("func", &func);
-
-}
-
-
-
->>> from pytype_function_ext import *
->>> print func.__doc__
-func( (A)arg1) -> A :
-    C++ signature:
-         struct B func(struct B)
-
- - -

© Copyright Nikolay Mladenov 2007.

- - diff --git a/doc/v2/raw_function.html b/doc/v2/raw_function.html deleted file mode 100755 index 0ad4c37c24..0000000000 --- a/doc/v2/raw_function.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/raw_function.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/raw_function.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Functions
- -
-
-
raw_function
-
-
- -
Example
-
-
- -

Introduction

- -

raw_function(...) - is used to convert a function taking a tuple and a dict into a Python callable object - which accepts a variable number of arguments and arbitrary keyword - arguments. - -

Functions

- raw_function -
-template <class F>
-object raw_function(F f, std::size_t min_args = 0);
-
- -
-
Requires: f(tuple(), dict()) is - well-formed.
- -
Returns: a callable object which requires at least min_args arguments. When called, the actual non-keyword arguments will be passed in a tuple as the first argument to f, and the keyword arguments will be passed in a dict as the second argument to f. - - -
- -

Example

-C++: -
-#include <boost/python/def.hpp>
-#include <boost/python/tuple.hpp>
-#include <boost/python/dict.hpp>
-#include <boost/python/module.hpp>
-#include <boost/python/raw_function.hpp>
-
-using namespace boost::python;
-
-tuple raw(tuple args, dict kw)
-{
-    return make_tuple(args, kw);
-}
-
-BOOST_PYTHON_MODULE(raw_test)
-{
-    def("raw", raw_function(raw));
-}
-
- -Python: -
->>> from raw_test import *
-
->>> raw(3, 4, foo = 'bar', baz = 42)
-((3, 4), {'foo': 'bar', 'baz': 42})
-
-

- - 7 March, 2003 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/reference.html b/doc/v2/reference.html deleted file mode 100644 index 5ebdad105e..0000000000 --- a/doc/v2/reference.html +++ /dev/null @@ -1,1192 +0,0 @@ - - - - - - - - - - - - Boost.Python - Reference - - - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Reference

-
-
- -

Contents

- -
-
Concepts
- -
High Level Components
- -
Object Wrappers
- -
Function Invocation and Creation
- -
-
-
Models of - CallPolicies
- -
Models of - ResultConverter
- -
Models of - ResultConverterGenerator
-
-
- -
To/From Python Type Conversion
- -
Embedding
- -
Utility and Infrastructure
- -
Topics
-
-
- - -

Concepts

- -
-
CallPolicies
- -
Dereferenceable
- -
Extractor
- -
HolderGenerator
- -
ResultConverter
- -
ResultConverterGenerator
- -
ObjectWrapper
- -
TypeWrapper
-
- -

High Level Components

- -
-
class.hpp/class_fwd.hpp
- -
-
-
Classes
- -
-
-
class_
- -
bases
-
-
-
-
- -
def.hpp
- -
-
-
Functions
- -
-
-
def
-
-
-
-
- -
def_visitor.hpp
- -
-
-
Classes
-
-
- -
docstring_options.hpp
- -
-
-
Classes
-
-
- -
enum.hpp
- -
-
-
Classes
- -
-
-
enum_
-
-
-
-
- -
errors.hpp
- -
-
-
Classes
- -
-
-
error_already_set
-
-
- -
Functions
- -
-
-
handle_exception
- -
expect_non_null
- -
throw_error_already_set
-
-
-
-
- -
exception_translator.hpp
- -
-
-
Functions
- -
-
-
register_exception_translator
-
-
-
-
- -
init.hpp
- -
-
-
Classes
- -
-
-
init
- -
optional
-
-
-
-
- -
iterator.hpp
- -
-
-
Classes
- -
-
-
iterator
- -
iterators
-
-
- -
Functions
- -
-
-
range
-
-
-
-
- -
module.hpp
- -
-
-
Macros
- -
-
-
BOOST_PYTHON_MODULE
-
-
-
-
- -
operators.hpp
- -
-
-
Classes
- -
-
-
self_t
- -
other
- -
operator_
-
-
- -
Objects
- -
-
-
self
-
-
-
-
- -
scope.hpp
- -
-
-
Classes
- -
-
-
scope
-
-
-
-
- -
stl_iterator.hpp
- -
-
-
Classes
- -
-
-
stl_input_iterator
-
-
-
-
- -
wrapper.hpp
- -
-
-
Classes
- -
-
-
override
- -
wrapper
-
-
-
-
-
- -

Object Wrappers

- -
-
dict.hpp
- -
-
-
Classes
- -
-
-
dict
-
-
-
-
- -
list.hpp
- -
-
-
Classes
- -
-
-
list
-
-
-
-
- -
long.hpp
- -
-
-
Classes
- -
-
-
long_
-
-
-
-
- -
numeric.hpp
- -
-
-
Classes
- -
-
-
numeric::array
-
-
-
-
- -
object.hpp
- -
-
-
Classes
- -
-
-
object
-
-
-
-
- -
str.hpp
- -
-
-
Classes
- -
-
-
str
-
-
-
-
- -
tuple.hpp
- -
-
-
Classes
- -
-
-
tuple
-
-
- -
Functions
- -
-
-
make_tuple
-
-
-
-
- -
slice.hpp
- -
-
-
Classes
- -
-
-
slice
-
-
-
-
-
- -

Function Invocation and Creation

- -
-
args.hpp
- -
-
-
Functions
- -
-
-
args
-
-
-
-
- -
call.hpp
- -
-
-
Functions
- -
-
-
call
-
-
-
-
- -
call_method.hpp
- -
-
-
Functions
- -
-
-
call_method
-
-
-
-
- -
data_members.hpp
- -
-
-
Functions
- -
-
-
make_getter
- -
make_setter
-
-
-
-
- -
make_function.hpp
- -
-
-
Functions
- -
-
-
make_function
- -
make_constructor
-
-
-
-
- -
overloads.hpp
- -
-
-
macros
- -
-
-
BOOST_PYTHON_FUNCTION_OVERLOADS
- -
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
-
-
-
-
- -
ptr.hpp
- -
-
-
Functions
- -
-
-
ptr
-
-
- -
Classes
- -
-
-
pointer_wrapper
-
-
- -
MetaFunctions
- -
-
-
is_pointer_wrapper
- -
unwrap_pointer
-
-
-
-
- -
raw_function.hpp
- -
-
-
Functions
- -
-
-
raw_function
-
-
-
-
- -
- - -

Function documentation

- -
-
function_doc_signature.hpp
- -
-
-
Classes
- -
-
-
function_doc_signature_generator
- -
-
-
-
-
-
-
pytype_function.hpp
- -
-
-
Classes
- -
-
-
wrap_pytype
- -
-
-
expected_from_python_type
- -
-
-
to_python_target_type
- -
-
-
registered_pytype
- -
-
-
-
-
-
- -
- - -

Models of CallPolicies

- -
-
default_call_policies.hpp
- -
-
-
Classes
- -
-
-
default_call_policies
- -
default_result_converter
-
-
-
-
- -
return_arg.hpp
- -
-
-
Classes
- -
-
-
return_arg
- -
return_self
-
-
-
-
- -
return_internal_reference.hpp
- -
-
-
Classes
- -
-
-
- return_internal_reference
-
-
-
-
- -
return_value_policy.hpp
- -
-
-
Classes
- -
-
-
return_value_policy
-
-
-
-
- -
with_custodian_and_ward.hpp
- -
-
-
Classes
- -
-
-
- with_custodian_and_ward
- -
- with_custodian_and_ward_postcall
-
-
-
-
-
- - -

Models of ResultConverter

- -
-
to_python_indirect.hpp
- -
-
-
Classes
- -
-
-
to_python_indirect
-
-
-
-
- -
to_python_value.hpp
- -
-
-
Classes
- -
-
-
to_python_value
-
-
-
-
-
- - -

Models of ResultConverterGenerator

- -
-
copy_const_reference.hpp
- -
-
-
Classes
- -
-
-
copy_const_reference
-
-
-
-
- -
copy_non_const_reference.hpp
- -
-
-
Classes
- -
-
-
- copy_non_const_reference
-
-
-
-
- -
manage_new_object.hpp
- -
-
-
Classes
- -
-
-
manage_new_object
-
-
-
-
- -
reference_existing_object.hpp
- -
-
-
Classes
- -
-
-
- reference_existing_object
-
-
-
-
- -
return_by_value.hpp
- -
-
-
Classes
- -
-
-
return_by_value
-
-
-
-
- -
return_opaque_pointer.hpp
- -
-
-
Classes
- -
-
-
return_opaque_pointer
-
-
-
-
-
-
-
- -

To/From Python Type Conversion

- -
-
extract.hpp
- -
-
-
Classes
- -
-
-
extract
-
-
-
-
- -
implicit.hpp
- -
-
-
Functions
- -
-
-
implicitly_convertible
-
-
-
-
- -
lvalue_from_pytype.hpp
- -
-
-
Classes
- -
-
-
lvalue_from_pytype
- -
extract_identity
- -
extract_member
-
-
-
-
- -
opaque_pointer_converter.hpp
- -
-
-
Classes
- -
-
-
opaque
-
-
- -
Macros
- -
-
-
- BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID
-
-
-
-
- -
to_python_converter.hpp
- -
-
-
Classes
- -
-
-
to_python_converter
-
-
-
-
- -
register_ptr_to_python.hpp
- -
-
-
Functions
- -
-
-
register_ptr_to_python
-
-
-
-
-
- -

Embedding

- -
-
exec.hpp
- -
-
-
Functions
- -
-
-
eval
-
exec
-
exec_file
-
-
-
-
- -
import.hpp
- -
-
-
Functions
- -
-
-
import
-
-
-
-
-
- -

Utility and Infrastructure

- -
-
has_back_reference.hpp
- -
-
-
Classes
- -
-
-
has_back_reference
-
-
-
-
- -
instance_holder.hpp
- -
-
-
Classes
- -
-
-
instance_holder
-
-
-
-
- -
pointee.hpp
- -
-
-
Classes
- -
-
-
class template pointee
-
-
-
-
- -
<boost/python.hpp>
- -
handle.hpp
- -
-
-
Classes
- -
-
-
handle
-
-
- -
Functions
- -
-
-
borrowed
- -
allow_null
-
-
-
-
- -
type_id.hpp
- -
-
-
Functions
- -
-
-
type_id
-
-
- -
Classes
- -
-
-
type_info
-
-
-
-
- -
ssize_t.hpp
- -
-
-
Typedefs
- -
Constants
-
-
-
- -

Topics

- -
-
Calling Python Functions and - Methods
- -
Pickle Support
- Indexing Support
-
-
- -

Revised - - 31 October, 2004 - -

- -

© Copyright Dave Abrahams 2002 -.

- - - diff --git a/doc/v2/reference_existing_object.html b/doc/v2/reference_existing_object.html deleted file mode 100644 index 12e228f50e..0000000000 --- a/doc/v2/reference_existing_object.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/reference_existing_object.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/reference_existing_object.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class - reference_existing_object
- -
-
-
Class - reference_existing_object synopsis
- -
Class - reference_existing_object metafunctions
-
-
-
-
- -
Example
-
-
- -

Classes

- -

Class - reference_existing_object

- -

reference_existing_object is a model of ResultConverterGenerator - which can be used to wrap C++ functions which return a reference or - pointer to a C++ object. When the wrapped function is called, the value - referenced by its return value is not copied. A new Python object is - created which contains a pointer to the referent, and no attempt is made - to ensure that the lifetime of the referent is at least as long as that - of the corresponding Python object. Thus, it can be highly dangerous to use - reference_existing_object without additional lifetime - management from such models of CallPolicies as with_custodian_and_ward. - This class is used in the implementation of return_internal_reference.

- -

Class - reference_existing_object synopsis

-
-namespace boost { namespace python
-{
-    struct reference_existing_object
-    {
-        template <class T> struct apply;
-    };
-}}
-
- -

Class - reference_existing_object metafunctions

-
-template <class T> struct apply
-
- -
-
Requires: T is U& or - U*for some U.
- -
Returns: typedef to_python_indirect<T,V> - type, where V is a class whose - static execute function constructs an instance - holder containing an unowned - U* pointing to the referent of the wrapped function's - return value.
-
- -

Example

- -

In C++:

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/reference_existing_object.hpp>
-#include <boost/python/return_value_policy.hpp>
-#include <utility>
-
-// classes to wrap
-struct Singleton
-{
-   Singleton() : x(0) {}
-
-   int exchange(int n)  // set x and return the old value
-   {
-        std::swap(n, x);
-        return n;
-   }
-
-   int x;
-};
-
-Singleton& get_it()
-{
-   static Singleton just_one;
-   return just_one;
-}
-
-// Wrapper code
-using namespace boost::python;
-BOOST_PYTHON_MODULE(singleton)
-{
-    def("get_it", get_it,
-        return_value_policy<reference_existing_object>());
-
-    class_<Singleton>("Singleton")
-       .def("exchange", &Singleton::exchange)
-       ;
-}
-
- In Python: -
->>> import singleton
->>> s1 = singleton.get_it()  
->>> s2 = singleton.get_it()
->>> id(s1) == id(s2)  # s1 and s2 are not the same object
-0
->>> s1.exchange(42)   # but they reference the same C++ Singleton
-0
->>> s2.exchange(99)
-42
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/register_ptr_to_python.html b/doc/v2/register_ptr_to_python.html deleted file mode 100644 index 5f660e18f0..0000000000 --- a/doc/v2/register_ptr_to_python.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - -Boost.Python - <register_ptr_to_python.hpp> - - - - - - - -
-

-

-
-

Boost.Python

-

Header <register_ptr_to_python.hpp>

-
-
-

Contents

-
-
Introduction
-
Functions
-
-
register_ptr_to_python
-
- -
Example(s)
- -
-
-

Introduction

-

- <boost/python/register_ptr_to_python.hpp> - supplies register_ptr_to_python, a function template - which registers a conversion for smart pointers to Python. The - resulting Python object holds a copy of the converted smart pointer, - but behaves as though it were a wrapped copy of the pointee. If - the pointee type has virtual functions and the class representing - its dynamic (most-derived) type has been wrapped, the Python object - will be an instance of the wrapper for the most-derived type. More than - one smart pointer type for a pointee's class can be registered. -

-

- Note that in order to convert a Python X object to a - smart_ptr<X>& (non-const reference), the embedded C++ - object must be held by smart_ptr<X>, and that when wrapped - objects are created by calling the constructor from Python, how they are held - is determined by the HeldType parameter to - class_<...> instances. -

- -

Functions

-
-template <class P>
-void register_ptr_to_python() 
-
-
-
Requires: P is Dereferenceable. -
-
Effects: Allows conversions to-python of P - instances. -
-
- -

Example(s)

- -

C++ Wrapper Code

- -Here is an example of a module that contains a class A with -virtual functions and some functions that work with -boost::shared_ptr<A>. - -
-struct A
-{
-    virtual int f() { return 0; }
-};
-
-shared_ptr<A> New() { return shared_ptr<A>( new A() ); }
-
-int Ok( const shared_ptr<A>& a ) { return a->f(); }
-
-int Fail( shared_ptr<A>& a ) { return a->f(); }
-
-struct A_Wrapper: A
-{
-    A_Wrapper(PyObject* self_): self(self_) {}
-    int f() { return call_method<int>(self, "f"); }    
-    int default_f() { return A::f(); }    
-    PyObject* self;
-};
-
-BOOST_PYTHON_MODULE(register_ptr)
-{
-    class_<A, A_Wrapper>("A")
-        .def("f", &A::f, &A_Wrapper::default_f)
-    ;
-    
-    def("New", &New);
-    def("Ok", &Call);
-    def("Fail", &Fail);
-    
-    register_ptr_to_python< shared_ptr<A> >();
-} 
-
- -

Python Code

- -
->>> from register_ptr import *
->>> a = A()
->>> Ok(a)     # ok, passed as shared_ptr<A>
-0
->>> Fail(a)   # passed as shared_ptr<A>&, and was created in Python!
-Traceback (most recent call last):
-  File "<stdin>", line 1, in ?
-TypeError: bad argument type for built-in operation
->>>
->>> na = New()   # now "na" is actually a shared_ptr<A> 
->>> Ok(a)
-0
->>> Fail(a)
-0
->>>
-
- -If shared_ptr<A> is registered as follows: - -
-    class_<A, A_Wrapper, shared_ptr<A> >("A")
-        .def("f", &A::f, &A_Wrapper::default_f)
-    ;            
-
- -There will be an error when trying to convert shared_ptr<A> to -shared_ptr<A_Wrapper>: - -
->>> a = New()
-Traceback (most recent call last):
-File "<stdin>", line 1, in ?
-TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<struct A>
->>>    
-
- -

Revised - - 24 Jun, 2003 - -

-

© Copyright Dave Abrahams - 2002.

- - - - diff --git a/doc/v2/return_arg.html b/doc/v2/return_arg.html deleted file mode 100755 index 44cd58c24e..0000000000 --- a/doc/v2/return_arg.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/return_arg.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/return_arg.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class Template - return_arg
- -
-
-
Class Template - return_arg synopsis
- -
Class - return_arg static functions
-
-
- -
Class Template - return_self
-
-
- -
Example
-
-
- -

Introduction

- return_arg and return_self instantiations are - models of CallPolicies which return the - specified argument parameter (usually *this) of a wrapped - (member) function. - -

Classes

- -

Class template - return_arg

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- return_arg template parameters -
ParameterRequirementsDescriptionDefault
arg_posA positive compile-time constant of type - std::size_t.the position of the argument to be returned.1
BaseA model of CallPoliciesUsed for policy composition. Any result_converter it - supplies will be overridden by return_arg, but its - precall and postcall policies are composed - as described here CallPolicies.default_call_policies
- -

Class template - return_arg synopsis

-
-namespace boost { namespace python
-{
-   template <size_t arg_pos=1, class Base = default_call_policies>
-   struct return_arg : Base
-   {
-      static PyObject* postcall(PyObject*, PyObject* result);
-      struct result_converter{ template <class T> struct apply; };
-      template <class Sig> struct extract_return_type : mpl::at_c<Sig, arg_pos>{};
-
-   };
-}}
-
- -

Class return_arg - static functions

-
-PyObject* postcall(PyObject* args, PyObject* result);
-
- -
-
Requires: PyTuple_Check(args) - != 0 and PyTuple_Size(args) != 0
- -
Returns: PyTuple_GetItem(args,arg_pos-1)
-
- -

Class template - return_self

- -

Class template return_self synopsis:

-
-namespace boost { namespace python
-{
-   template <class Base = default_call_policies>
-   struct return_self 
-     : return_arg<1,Base>
-   {};
-}}
-
- -

Example

- -

C++ module definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/return_arg.hpp>
-
-struct Widget
-{
-   Widget() :sensitive_(true){}
-   bool get_sensitive() const { return sensitive_; }
-   void set_sensitive(bool s) { this->sensitive_ = s; }
- private:
-   bool sensitive_;
-};
-
-struct Label : Widget
-{
-   Label() {}
-
-   std::string  get_label() const { return label_; }
-   void set_label(const std::string &l){ label_ = l; }
-
- private:
-   std::string label_;
-};
-
-using namespace boost::python;
-BOOST_PYTHON_MODULE(return_self_ext)
-{
-   class_<widget>("Widget")
-      .def("sensitive", &Widget::get_sensitive)
-      .def("sensitive", &Widget::set_sensitive, return_self<>())
-      ;
-
-   class_<Label, bases<Widget> >("Label")
-      .def("label", &Label::get_label)
-      .def("label", &Label::set_label, return_self<>())
-      ;
-}
-
-
-
- -

Python code

-
->>> from return_self_ext import *
->>> l1 = Label().label("foo").sensitive(false)
->>> l2 = Label().sensitive(false).label("foo") 
-
- -

Revised - - 19 July, 2003 -

- -

© Copyright Dave Abrahams and Nikolay - Mladenov 2003.

- - - diff --git a/doc/v2/return_by_value.html b/doc/v2/return_by_value.html deleted file mode 100644 index 12ca3c43fd..0000000000 --- a/doc/v2/return_by_value.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/return_by_value.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/return_by_value.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class - return_by_value
- -
-
-
Class - return_by_value synopsis
- -
Class - return_by_value metafunctions
-
-
-
-
- -
Example
-
-
- -

Classes

- -

Class - return_by_value

- -

return_by_value is a model of ResultConverterGenerator - which can be used to wrap C++ functions returning any reference or value - type such that the return value is copied into a new Python object.

- -

Class - return_by_value synopsis

-
-namespace boost { namespace python
-{
-    struct return_by_value
-    {
-        template <class T> struct apply;
-    };
-}}
-
- -

Class - return_by_value metafunctions

-
-template <class T> struct apply
-
- -
-
Returns: typedef to_python_value<T> - type;
-
- -

Example

- -

C++ Module Definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/return_by_value.hpp>
-#include <boost/python/return_value_policy.hpp>
-
-// classes to wrap
-struct Bar { };
-
-Bar global_bar;
-
-// functions to wrap:
-Bar b1();
-Bar& b2();
-Bar const& b3();
-
-// Wrapper code
-using namespace boost::python;
-template <class R>
-void def_void_function(char const* name, R (*f)())
-{
-   def(name, f, return_value_policy<return_by_value>());
-}
-
-BOOST_PYTHON_MODULE(my_module)
-{
-    class_<Bar>("Bar");
-    def_void_function("b1", b1);
-    def_void_function("b2", b2);
-    def_void_function("b3", b3);
-}
-
- -

Python Code

-
->>> from my_module import *
->>> b = b1() # each of these calls
->>> b = b2() # creates a brand
->>> b = b3() # new Bar object
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/return_internal_reference.html b/doc/v2/return_internal_reference.html deleted file mode 100644 index 87c33f855b..0000000000 --- a/doc/v2/return_internal_reference.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/return_internal_reference.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/return_internal_reference.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class Template - return_internal_reference
- -
-
-
Class - Template return_internal_reference - synopsis
- -
Class - return_internal_reference static - functions
-
-
-
-
- -
Example
-
-
- -

Introduction

- return_internal_reference instantiations are models of CallPolicies which allow pointers and - references to objects held internally by a free or member function - argument or from the target of a member function to be returned safely - without making a copy of the referent. The default for its first template - argument handles the common case where the containing object is the - target (*this) of a wrapped member function. - -

Classes

- -

Class template - return_internal_reference

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- return_internal_reference template parameters -
ParameterRequirementsDescriptionDefault
owner_argA positive compile-time constant of type - std::size_t.The index of the parameter which contains the object to which the - reference or pointer is being returned. If used to wrap a member - function, parameter 1 is the target object (*this). Note - that if the target Python object type doesn't support weak - references, a Python TypeError exception will be raised - when the function being wrapped is called.1
BaseA model of CallPoliciesUsed for policy composition. Any result_converter it - supplies will be overridden by - return_internal_reference, but its precall - and postcall policies are composed as described here CallPolicies.default_call_policies
- -

Class template - return_internal_reference synopsis

-
-namespace boost { namespace python
-{
-   template <std::size_t owner_arg = 1, class Base = default_call_policies>
-   struct return_internal_reference : Base
-   {
-      static PyObject* postcall(PyObject*, PyObject* result);
-      typedef reference_existing_object result_converter;
-   };
-}}
-
- -

Class - return_internal_reference static functions

-
-PyObject* postcall(PyObject* args, PyObject* result);
-
- -
-
Requires: PyTuple_Check(args) - != 0
- -
Returns: - with_custodian_and_ward_postcall::postcall(args, - result)
-
- -

Example

- -

C++ module definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/return_internal_reference.hpp>
-
-class Bar
-{
- public:
-   Bar(int x) : x(x) {}
-   int get_x() const { return x; }
-   void set_x(int x) { this->x = x; }
- private:
-   int x;
-};
-
-class Foo
-{
- public:
-   Foo(int x) : b(x) {}
-
-   // Returns an internal reference
-   Bar const& get_bar() const { return b; }
-
- private:
-   Bar b;
-};
-
-using namespace boost::python;
-BOOST_PYTHON_MODULE(internal_refs)
-{
-   class_<Bar>("Bar", init<int>())
-      .def("get_x", &Bar::get_x)
-      .def("set_x", &Bar::set_x)
-      ;
-
-   class_<Foo>("Foo", init<int>())
-      .def("get_bar", &Foo::get_bar
-          , return_internal_reference<>())
-      ;
-}
-
- -

Python code

-
->>> from internal_refs import *
->>> f = Foo(3)
->>> b1 = f.get_bar()
->>> b2 = f.get_bar()
->>> b1.get_x()
-3
->>> b2.get_x()
-3
->>> b1.set_x(42)
->>> b2.get_x()
-42
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/return_opaque_pointer.html b/doc/v2/return_opaque_pointer.html deleted file mode 100644 index 52d8396e83..0000000000 --- a/doc/v2/return_opaque_pointer.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - - Boost.Python - <boost/python/return_opaque_pointer.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/return_opaque_pointer.hpp>

-
-
- -

Contents

- -
-
Classes
- -
-
-
Class - return_opaque_pointer
- -
-
-
Class - return_opaque_pointer synopsis
- -
Class - return_opaque_pointer metafunctions
-
-
-
-
- -
Example
- -
See Also
-
-
- -

Classes

- -

Class - return_opaque_pointer

- -

return_opaque_pointer is a model of - - ResultConverterGenerator - which can be used to wrap C++ functions returning pointers to - undefined types such that the return value is copied into a - new Python object.

-

In addition to specifying the return_opaque_pointer - policy the - BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID macro must be - used to define specializations for the - type_id function - on the type pointed to by returned pointer.

- -

Class - return_opaque_pointer synopsis

-
-namespace boost { namespace python
-{
-    struct return_opaque_pointer
-    {
-        template <class R> struct apply;
-    };
-}}
-
- -

Class - return_opaque_pointer metafunctions

-
-template <class R> struct apply
-
- -
-
Returns: typedef - detail::opaque_conversion_holder<R> - type;
-
- -

Example

- -

C++ Module Definition

-
-# include <boost/python/return_opaque_pointer.hpp>
-# include <boost/python/def.hpp>
-# include <boost/python/module.hpp>
-# include <boost/python/return_value_policy.hpp>
-
-typedef struct opaque_ *opaque;
-
-opaque the_op   = ((opaque) 0x47110815);
-
-opaque get () { return the_op; }
-void use (opaque op) {
-    if (op != the_op)
-	throw std::runtime_error (std::string ("failed"));
-}
-
-void failuse (opaque op) {
-    if (op == the_op)
-	throw std::runtime_error (std::string ("success"));
-}
-
-BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_)
-
-namespace bpl = boost::python;
-
-BOOST_PYTHON_MODULE(opaque_ext)
-{
-    bpl::def (
-        "get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>());
-    bpl::def ("use", &::use);
-    bpl::def ("failuse", &::failuse);
-}
-
- -

Python Code

-
-"""
->>> from opaque_ext import *
->>> #
->>> # Check for correct conversion
->>> use(get())
->>> failuse(get())
-Traceback (most recent call last):
-        ...
-RuntimeError: success
->>> #
->>> # Check that there is no conversion from integers ...
->>> use(0)
-Traceback (most recent call last):
-        ...
-TypeError: bad argument type for built-in operation
->>> #
->>> # ... and from strings to opaque objects
->>> use("")
-Traceback (most recent call last):
-        ...
-TypeError: bad argument type for built-in operation
-"""
-def run(args = None):
-    import sys
-    import doctest
-
-    if args is not None:
-        sys.argv = args
-    return doctest.testmod(sys.modules.get(__name__))
-    
-if __name__ == '__main__':
-    print "running..."
-    import sys
-    sys.exit(run()[0])
-
- -

See Also

-

- - opaque -

- -

Revised - 28 January, 2003 -

- -

© Copyright 2003 Haufe Mediengruppe. All Rights - Reserved.

- - - diff --git a/doc/v2/return_value_policy.html b/doc/v2/return_value_policy.html deleted file mode 100644 index b02d4bc39d..0000000000 --- a/doc/v2/return_value_policy.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/return_value_policy.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/return_value_policy.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class Template - return_value_policy
- -
-
-
Class Template - return_value_policy synopsis
-
-
-
-
- -
Example
-
-
- -

Introduction

- return_value_policy instantiations are simply models of CallPolicies which are composed of a ResultConverterGenerator - and optional Base CallPolicies. - -

Classes

- -

Class template - return_value_policy

- - - - - - - - - - - - - - - - - - - - - - - - - -
- return_value_policy template parameters -
ParameterRequirementsDefault
ResultConverterGeneratorA model of ResultConverterGenerator.
BaseA model of CallPoliciesdefault_call_policies
- -

Class template - return_value_policy synopsis

-
-namespace boost { namespace python
-{
-  template <class ResultConverterGenerator, class Base = default_call_policies>
-  struct return_value_policy : Base
-  {
-      typedef ResultConverterGenerator result_converter;
-  };
-}}
-
- -

Example

- -

C++ Module Definition

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/copy_const_reference.hpp>
-#include <boost/python/return_value_policy.hpp>
-
-// classes to wrap
-struct Bar { int x; }
-
-struct Foo {
-   Foo(int x) : { b.x = x; }
-   Bar const& get_bar() const { return b; }
- private:
-   Bar b;
-};
-
-// Wrapper code
-using namespace boost::python;
-BOOST_PYTHON_MODULE(my_module)
-{
-   class_<Bar>("Bar");
-
-   class_<Foo>("Foo", init<int>())
-      .def("get_bar", &Foo::get_bar
-          , return_value_policy<copy_const_reference>())
-      ;
-}
-
- -

Python Code

-
->>> from my_module import *
->>> f = Foo(3)         # create a Foo object
->>> b = f.get_bar()    # make a copy of the internal Bar object
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/scope.html b/doc/v2/scope.html deleted file mode 100644 index 54ef67e3e9..0000000000 --- a/doc/v2/scope.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/scope.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/scope.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class scope
- -
-
-
Class scope - synopsis
- -
Class scope - constructors and destructor
-
-
-
-
- -
Example
-
-
- -

Introduction

- -

Defines facilities for querying and controlling the Python scope - (namespace) which will contain new wrapped classes and functions.

- -

Classes

- -

Class scope

- -

The scope class has an associated global Python - object which controls the Python namespace in which new extension - classes and wrapped functions will be defined as - attributes. Default-constructing a new scope object - binds it to the associated global Python object. Constructing a - scope object with an argument changes the associated - global Python object to the one held by the argument, until the - lifetime of the scope object ends, at which time the - associated global Python object reverts to what it was before the - scope object was constructed.

- -

Class scope - synopsis

-
-namespace boost { namespace python
-{
-  class scope : public object
-  {
-   public:
-      scope(scope const&);
-      scope(object const&);
-      scope();
-      ~scope()
-   private:
-      void operator=(scope const&);
-  };
-}}
-
- -

Class scope constructors - and destructor

-
-explicit scope(scope const& x);
-explicit scope(object const& x);
-
- Stores a reference to the current associated scope object, and sets the - associated scope object to the one referred to by x.ptr(). - The object base class is initialized with x. -
-scope();
-
- Stores a reference to the current associated scope object. The - object base class is initialized with the current associated - scope object. Outside any module initialization function, the current - associated Python object is None. -
-~scope()
-
- Sets the current associated Python object to the stored object. - -

Example

- The following example shows how scope setting can be used to define - nested classes. - -

C++ Module definition:

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/scope.hpp>
-using namespace boost::python;
-
-struct X
-{
-  void f() {}
-
-  struct Y { int g() { return 42; } };
-};
-
-BOOST_PYTHON_MODULE(nested)
-{
-   // add some constants to the current (module) scope
-   scope().attr("yes") = 1;
-   scope().attr("no") = 0;
-
-   // Change the current scope 
-   scope outer
-       = class_<X>("X")
-            .def("f", &X::f)
-            ;
-
-   // Define a class Y in the current scope, X
-   class_<X::Y>("Y")
-      .def("g", &X::Y::g)
-      ;
-}
-
- Interactive Python: -
->>> import nested
->>> nested.yes
-1
->>> y = nested.X.Y()
->>> y.g()
-42
-
- -

Revised 09 October, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/slice.html b/doc/v2/slice.html deleted file mode 100644 index fb6b47c7e3..0000000000 --- a/doc/v2/slice.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - - Boost.Python - <boost/python/slice.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

-

Header <boost/python/slice.hpp>

-
-
-

Contents

-
-
Introduction
-
Classes
-
-
-
Class slice
-
-
-
Class slice -synopsis
-
Class slice -constructors
-
Class slice -observer functions
-
-
-
-
-
Example(s)
-
-
-

Introduction

-

Exposes a TypeWrapper -for the Python slice -type.

-

Classes

-

Class slice

-

Exposes the extended slicing protocol by wrapping the built-in slice -type. The semantics of the constructors and member functions defined -below can be fully understood by reading the TypeWrapper concept -definition. Since slice is publicly derived from object, the public object -interface applies to slice instances as well.
-

-

Class slice synopsis

-
-namespace boost { namespace python
-{
-  class slice : public object
-  {
-   public:
-      slice(); // create an empty slice, equivalent to [::]
-
-      template <typename Int1, typename Int2>
-      slice(Int1 start, Int2 stop);
-
-      template <typename Int1, typename Int2, typename Int3>
-      slice(Int1 start, Int2 stop, Int3 step);
-
-      // Access the parameters this slice was created with.
-      object start();
-      object stop();
-      object step();
-
-      // The return type of slice::get_indices()
-      template <typename RandomAccessIterator>
-      struct range
-      {
-          RandomAccessIterator start;
-          RandomAccessIterator stop;
-          int step;
-      };
-
-      template <typename RandomAccessIterator>
-      range<RandomAccessIterator>
-      get_indices(
-          RandomAccessIterator const& begin, 
-          RandomAccessIterator const& end);
-  };
-}}
-
-

Class slice -constructors
-

-
slice();
-
-
Effects: constructs a slice with default stop, start, and -step values.  Equivalent to the slice object created as part of the Python -expression base[::].
-
Throws: nothing.
-
-
-template <typename Int1, typename Int2>
-slice(Int1 start, Int2 stop);
-
-
-
Requires: start, stop, and step - are of type slice_nil - or convertible to type object.
-
Effects: constructs a new slice with default step value -and the provided start and stop values.  Equivalent to the slice -object -created by the built-in Python function slice(start,stop), -or as part of the Python expression base[start:stop].
-
Throws: error_already_set and sets a Python TypeError -exception if no conversion is possible from the arguments to type object.
-
-
-template <typename Int1, typename Int2, typename Int3>
-slice(Int1 start, Int2 stop, Int3 step);
-
-
Requires: start, stop, and step are slice_nil or convertible to type object.
-
Effects: constructs a new slice with start stop and step -values.  Equivalent to the slice object created -by the built-in Python function slice(start,stop,step), -or as part of the Python expression base[start:stop:step].
-
Throws: error_already_set and sets a Python TypeError -exception if no conversion is possible from the arguments to type -object.
-

Class slice -observer functions
-

-
-object slice::start() const;
-object slice::stop() const;
-object slice::step() const;
-
-
-
Effects: None.
-
Throws: nothing.
-
Returns:the parameter that -the slice was created with. If the parameter was omitted or -slice_nil was used when the slice was created, than that parameter will -be a reference to PyNone and compare equal to a default-constructed -object.  In principal, any object may be used when creating a -slice object, but in practice they are usually integers.
-
-
-
-template <typename RandomAccessIterator>
-slice::range<RandomAccessIterator>
-slice::get_indices( 
-    RandomAccessIterator const& begin, 
-    RandomAccessIterator const& end) const;
-
-
-
Arguments: A pair of STL-conforming Random Access -Iterators that form a half-open range.
-
Effects: Create a RandomAccessIterator pair that defines a -fully-closed range within the [begin,end) range of its arguments.  -This function translates this slice's indices while accounting for the -effects of any PyNone or negative indices, and non-singular step sizes.
-
Returns: a slice::range -that has been initialized with a non-zero value of step and a pair of -RandomAccessIterators that point within the range of this functions -arguments and define a closed interval.
-
Throws: Raises a Python TypeError exception if any of this slice's arguments -are neither references to PyNone nor convertible to int.  Throws -std::invalid_argument if the resulting range would be empty.  You -should always wrap calls to slice::get_indices() -within try { ...; } catch (std::invalid_argument) {} to -handle this case and take appropriate action.
-
Rationale: closed-interval: If -an open interval were used, then for step -size other than 1, the required state for the end iterator would point -beyond the one-past-the-end position or before the beginning of the -specified range.
-exceptions on empty slice: It is impossible to define a closed interval -over an empty range, so some other form of error checking would have to -be used to prevent undefined behavior. In the case where the -exception is not caught, it will simply be translated to Python by the -default exception handling mechanisms.
-
-

Examples

-
-using namespace boost::python;
-
-// Perform an extended slice of a Python list.
-// Warning: extended slicing was not supported for built-in types prior 
-// to Python 2.3
-list odd_elements(list l)
-{
-    return l[slice(_,_,2)];
-}
-
-// Perform a multidimensional extended slice of a Numeric.array
-numeric::array even_columns(numeric::array arr)
-{
-    // select every other column, starting with the second, of a 2-D array.
-    // Equivalent to "return arr[:, 1::2]" in Python.
-    return arr[make_tuple( slice(), slice(1,_,2))];
-}
-
-// Perform a summation over a slice of a std::vector.
-double partial_sum(std::vector<double> const& Foo, const slice index)
-{
-    slice::range<std::vector<double>::const_iterator> bounds;
-    try {
-        bounds = index.get_indices<>(Foo.begin(), Foo.end());
-    }
-    catch (std::invalid_argument) {
-        return 0.0;
-    }
-    double sum = 0.0;
-    while (bounds.start != bounds.stop) {
-        sum += *bounds.start;
-        std::advance( bounds.start, bounds.step);
-    }
-    sum += *bounds.start;
-    return sum;
-}
-
-

Revised 07 Febuary, 2004

-

© Copyright Jonathan Brandmeyer, -2004.  Modification, copying and redistribution of this document -is permitted under the terms and conditions of the Boost Software -License, version 1.0.
-

- - diff --git a/doc/v2/ssize_t.html b/doc/v2/ssize_t.html deleted file mode 100644 index cb4398bb58..0000000000 --- a/doc/v2/ssize_t.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/ssize_t.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/ssize_t.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Typedef
- -
Constants
-
-
- -

Introduction

- -

Python 2.5 introduces a new Py_ssize_t typedef and - two related macros (PEP 353). The - <boost/python/ssize_t.hpp> header imports these - definitions into the boost::python namespace as - ssize_t, ssize_t_max, and ssize_t_min. - Appropriate definitions are provided for backward compatibility - with previous Python versions.

- -

Typedefs

Imports - Py_ssize_t into the boost::python namespace if - available, or provides an appropriate typedef for backward - compatibility: -
-#if PY_VERSION_HEX >= 0x02050000
-typedef Py_ssize_t ssize_t;
-#else
-typedef int ssize_t;
-#endif
-
- -

Constants

Imports - PY_SSIZE_T_MAX and PY_SSIZE_T_MIN as constants - into the boost::python namespace if available, or - provides appropriate constants for backward compatibility: -
-#if PY_VERSION_HEX >= 0x02050000
-ssize_t const ssize_t_max = PY_SSIZE_T_MAX;
-ssize_t const ssize_t_min = PY_SSIZE_T_MIN;
-#else
-ssize_t const ssize_t_max = INT_MAX;
-ssize_t const ssize_t_min = INT_MIN;
-#endif
-
- -

Revised - - 25 September, 2006 -

- -

© Copyright Ralf W. - Grosse-Kunstleve 2006.

- - diff --git a/doc/v2/stl_iterator.html b/doc/v2/stl_iterator.html deleted file mode 100755 index ef197b0f82..0000000000 --- a/doc/v2/stl_iterator.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - - - - Boost.Python - <boost/python/stl_iterator.hpp> - - - - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/stl_iterator.hpp>

-
-
- -

Contents

-
-
Introduction
- -
Classes
- -
-
-
Class template - stl_input_iterator
- -
-
-
Class - stl_input_iterator synopsis
- -
Class template - stl_input_iterator constructors
- -
Class template - stl_input_iterator modifiers
- -
Class template - stl_input_iterator observers
-
-
-
-
- -
Examples
-
-
- -

Introduction

- -

<boost/python/stl_iterator.hpp> provides types - for creating C++ - Iterators from - Python iterables.

- -

Classes

- -

Class Template - stl_input_iterator

- -

Instances of stl_input_iterator<T> hold a Python - iterator and adapt it for use with STL algorithms. - stl_input_iterator<T> satisfies the requirements for - an Input Iterator. -

- - - - - - - - - - - - - - - - - - - - - -
Template ParameterRequirementsSemanticsDefault
ValueTypeValueType must be CopyConstructible.Dereferencing an instance of stl_input_iterator<ValueType> - will return an rvalue of type ValueType.None
- -

Class Template stl_input_iterator - synopsis

- -
-namespace boost { namespace python
-{
-  template <class ValueType>
-  struct stl_input_iterator
-  {
-      typedef std::ptrdiff_t difference_type;
-      typedef ValueType value_type;
-      typedef ValueType* pointer;
-      typedef ValueType reference;
-      typedef std::input_iterator_tag iterator_category;
-
-      stl_input_iterator();
-      stl_input_iterator(object const& ob);
-
-      stl_input_iterator& operator++();
-      stl_input_iterator operator++(int);
-
-      ValueType operator*() const;
-
-      friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs);
-      friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs);
-  private:
-      object it; // For exposition only
-      object ob; // For exposition only
-  };
-}}
-
- -

- Class Template stl_input_iterator - constructors -

- -
-stl_input_iterator()
-
- -
-
Effects: - Creates a past-the-end input iterator, useful for signifying the end of a sequence. -
-
Postconditions: this is past-the-end.
-
Throws: Nothing.
-
- -
-stl_input_iterator(object const& ob)
-
- -
-
Effects: - Calls ob.attr("__iter__")() and stores the resulting Python iterator - object in this->it. Then, calls this->it.attr("next")() and - stores the result in this->ob. If the sequence is exhausted, sets - this->ob to object(). -
- -
Postconditions: this is a dereferenceable or past-the-end.
-
- -

- Class Template stl_input_iterator - modifiers -

- -
-stl_input_iterator& operator++()
-
- -
-
Effects: - Calls this->it.attr("next")() and stores the result in - this->ob. If the sequence is exhausted, sets this->ob - to object(). -
- -
Postconditions: this is a dereferenceable or past-the-end.
- -
Returns: *this.
-
- -
-stl_input_iterator operator++(int)
-
- -
-
Effects: - stl_input_iterator tmp = *this; ++*this; return tmp; -
- -
Postconditions: this is a dereferenceable or past-the-end.
-
- -

Class Templatestl_input_iterator - observers

- -
-ValueType operator*() const
-
- -
-
Effects: - Returns the current element in the sequence. -
-
Returns: - extract<ValueType>(this->ob); -
-
- -
-friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs)
-
- -
-
Effects: - Returns true if both iterators are dereferenceable or if both iterators are past-the-end, - false otherwise. -
-
Returns: - (lhs.ob == object()) == (rhs.ob == object()) -
-
- -
-friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs)
-
- -
-
Effects: - Returns false if both iterators are dereferenceable or if both iterators are past-the-end, - true otherwise. -
-
Returns: - !(lhs == rhs) -
-
- -

Examples

-
-#include <boost/python/object.hpp>
-#include <boost/python/stl_iterator.hpp>
-
-#include <list>
-
-using namespace boost::python;
-std::list<int> sequence_to_int_list(object const& ob)
-{
-    stl_input_iterator<int> begin(ob), end;
-    return std::list<int>(begin, end);
-}
-
- -
-

Revised - 30 -October, 2005 - -

- -

� Copyright Eric Niebler 2005.

- - \ No newline at end of file diff --git a/doc/v2/str.html b/doc/v2/str.html deleted file mode 100644 index 11810d8418..0000000000 --- a/doc/v2/str.html +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/str.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/str.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class str
- -
-
-
Class str - synopsis
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

Exposes a TypeWrapper for the Python - str - type.

- -

Classes

- -

Class str

- -

Exposes the string - methods of Python's built-in str type. The - semantics of the constructors and member functions defined below, - except for the two-argument constructors which construct str - objects from a range of characters, can be fully understood by - reading the TypeWrapper concept - definition. Since str is publicly derived from - object, the - public object interface applies to str instances as - well.

- -

Class str - synopsis

-
-namespace boost { namespace python
-{
-  class str : public object
-  {
-   public:
-      str(); // new str
-
-      str(char const* s); // new str
-
-      str(char const* start, char const* finish); // new str
-      str(char const* start, std::size_t length); // new str
-
-      template <class T>
-      explicit str(T const& other);
-
-      str capitalize() const;
-
-      template <class T>
-      str center(T const& width) const;
-
-      template<class T>
-      long count(T const& sub) const;
-      template<class T1, class T2>
-      long count(T1 const& sub,T2 const& start) const;
-      template<class T1, class T2, class T3>
-      long count(T1 const& sub,T2 const& start, T3 const& end) const;
-
-      object decode() const;
-      template<class T>
-      object decode(T const& encoding) const;
-      template<class T1, class T2>
-      object decode(T1 const& encoding, T2 const& errors) const;
-
-      object encode() const;
-      template <class T>
-      object encode(T const& encoding) const;
-      template <class T1, class T2>
-      object encode(T1 const& encoding, T2 const& errors) const;
-
-      template <class T>
-      bool endswith(T const& suffix) const;
-      template <class T1, class T2>
-      bool endswith(T1 const& suffix, T2 const& start) const;
-      template <class T1, class T2, class T3>
-      bool endswith(T1 const& suffix, T2 const& start, T3 const& end) const;
-
-      str expandtabs() const;
-      template <class T>
-      str expandtabs(T const& tabsize) const;
-
-      template <class T>
-      long find(T const& sub) const;
-      template <class T1, class T2>
-      long find(T1 const& sub, T2 const& start) const;
-      template <class T1, class T2, class T3>
-      long find(T1 const& sub, T2 const& start, T3 const& end) const;
-
-      template <class T>
-      long index(T const& sub) const;
-      template <class T1, class T2>
-      long index(T1 const& sub, T2 const& start) const;
-      template <class T1, class T2, class T3>
-      long index(T1 const& sub, T2 const& start, T3 const& end) const;
-
-      bool isalnum() const;
-      bool isalpha() const;
-      bool isdigit() const;
-      bool islower() const;
-      bool isspace() const;
-      bool istitle() const;
-      bool isupper() const;
-
-      template <class T>
-      str join(T const& sequence) const;
-
-      template <class T>
-      str ljust(T const& width) const;
-
-      str lower() const;
-      str lstrip() const;
-
-      template <class T1, class T2>
-      str replace(T1 const& old, T2 const& new_) const;
-      template <class T1, class T2, class T3>
-      str replace(T1 const& old, T2 const& new_, T3 const& maxsplit) const;
-
-      template <class T>
-      long rfind(T const& sub) const;
-      template <class T1, class T2>
-      long rfind(T1 const& sub, T2 const& start) const;
-      template <class T1, class T2, class T3>
-      long rfind(T1 const& sub, T2 const& start, T3 const& end) const;
-
-      template <class T>
-      long rindex(T const& sub) const;
-      template <class T1, class T2>
-      long rindex(T1 const& sub, T2 const& start) const;
-      template <class T1, class T2, class T3>
-      long rindex(T1 const& sub, T2 const& start, T3 const& end) const;
-
-      template <class T>
-      str rjust(T const& width) const;
-
-      str rstrip() const;
-
-      list split() const; 
-      template <class T>
-      list split(T const& sep) const;
-      template <class T1, class T2>
-      list split(T1 const& sep, T2 const& maxsplit) const;
-
-      list splitlines() const;
-      template <class T>
-      list splitlines(T const& keepends) const;
-
-      template <class T>
-      bool startswith(T const& prefix) const;
-      template <class T1, class T2>
-      bool startswidth(T1 const& prefix, T2 const& start) const;
-      template <class T1, class T2, class T3>
-      bool startswidth(T1 const& prefix, T2 const& start, T3 const& end) const;
-
-      str strip() const;
-      str swapcase() const;
-      str title() const;
-
-      template <class T>
-      str translate(T const& table) const;
-      template <class T1, class T2>
-      str translate(T1 const& table, T2 const& deletechars) const;
-
-      str upper() const;
-  };
-}}
-
- -

Example

-
-using namespace boost::python;
-str remove_angle_brackets(str x)
-{
-  return x.strip('<').strip('>');
-}
-
- -

Revised 3 October, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/to_python_converter.html b/doc/v2/to_python_converter.html deleted file mode 100644 index 81b61d252b..0000000000 --- a/doc/v2/to_python_converter.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - Boost.Python - - <boost/python/to_python_converter.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header - <boost/python/to_python_converter.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class Template - to_python_converter
- -
-
-
Class Template - to_python_converter synopsis
- -
Class Template - to_python_converter constructor
-
-
-
-
- -
Example
-
-
- -

Introduction

- to_python_converter registers a conversion from objects of a - given C++ type into a Python object. - -

Classes

- -

Class template - to_python_converter

- to_python_converter adds a wrapper around a static member - function of its second template parameter, handling low-level details - such as insertion into the converter registry. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- to_python_converter template parameters
- In the table below, x denotes an object of type - T -
ParameterRequirementsDescription
T - The C++ type of the source object in the conversion
Conversion - PyObject* p = Conversion::convert(x),
- if p == 0, PyErr_Occurred() != 0.
A class type whose static member function convert - does the real work of the conversion.
bool has_get_pytype = false - PyTypeObject const * p = Conversion::get_pytype() .Optional member - if Conversion has get_pytype member supply - true for this parameters. - If present get_pytype is used to document the return type - of functions using this conversion. The get_pytype may be implemented - using the classes and functions - from pytype_function.hpp - NOTE : For backward compatibility this parameter may be passed after - checking if BOOST_PYTHON_SUPPORTS_PY_SIGNATURES is defined (see - here). -
- -

Class template - to_python_converter synopsis

-
-namespace boost { namespace python
-{
-  template <class T, class Conversion, bool convertion_has_get_pytype_member=false>
-  struct to_python_converter
-  {
-      to_python_converter();
-  };
-}}
-
- -

Class template - to_python_converter constructor

-
-to_python_converter();
-
- -
-
Effects: Registers a to_python converter which uses - Conversion::convert() to do its work.
-
- -

Example

- This example presumes that someone has implemented the standard noddy example - module from the Python documentation, and placed the corresponding - declarations in "noddy.h". Because - noddy_NoddyObject is the ultimate trivial extension type, - the example is a bit contrived: it wraps a function for which all - information is contained in the type of its return value. - -

C++ module definition

-
-#include <boost/python/reference.hpp>
-#include <boost/python/module.hpp>
-#include "noddy.h"
-
-struct tag {};
-tag make_tag() { return tag(); }
-
-using namespace boost::python;
-
-struct tag_to_noddy
-{
-    static PyObject* convert(tag const& x)
-    {
-        return PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
-    }
-    static PyTypeObject const* get_pytype()
-    {
-        return &noddy_NoddyType;
-    }
-};
-
-BOOST_PYTHON_MODULE(to_python_converter)
-{
-    def("make_tag", make_tag);
-    to_python_converter<tag, tag_to_noddy, true>(); //"true" because tag_to_noddy has member get_pytype
-}
-
- -

Python code

-
->>> import to_python_converter
->>> def always_none():
-...     return None
-...
->>> def choose_function(x):
-...     if (x % 2 != 0):
-...         return to_python_converter.make_tag
-...     else:
-...         return always_none
-...
->>> a = [ choose_function(x) for x in range(5) ]
->>> b = [ f() for f in a ]
->>> type(b[0])
-<type 'NoneType'>
->>> type(b[1])
-<type 'Noddy'>
->>> type(b[2])
-<type 'NoneType'>
->>> type(b[3])
-<type 'Noddy'>
-
- -

Revised - - 11 June, 2007 - -

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/to_python_indirect.html b/doc/v2/to_python_indirect.html deleted file mode 100644 index 17e0a826c4..0000000000 --- a/doc/v2/to_python_indirect.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - Boost.Python - <boost/python/to_python_indirect.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header <boost/python/to_python_indirect.hpp>

-
-
- -

Contents

- -
-
Introduction - - -
Classes - -
-
-
Class Template to_python_indirect - -
-
- -
Class Template - to_python_indirect synopsis - -
Class Template - to_python_indirect observer functions - -
Class Template - to_python_indirect static functions -
-
- -
Example -
-
- -

Introduction

- - <boost/python/to_python_indirect.hpp> supplies - a way to construct new Python objects that hold wrapped C++ class - instances via a pointer or smart pointer. - -

Classes

- -

Class template to_python_indirect

-

Class template to_python_indirect converts objects -of its first argument type to python as extension class instances, using the ownership policy provided by its 2nd argument. - -

- - - - - - - -
- to_python_indirect Requirements
- - In the table below, x denotes an object of - type T, h denotes an - object of type - boost::python::objects::instance_holder*, and - p denotes an object of type - U*. - -
Parameter - - Requirements - - Description - -
T - - Either U cv& - (where cv is any optional cv-qualification) or a Dereferenceable type such that - *x is convertible to U const&, where - U is a class type. - - A type deferencing a C++ class exposed to Python using - class template class_. - -
MakeHolder - - h = MakeHolder::execute(p); - - A class whose static execute() creates an - instance_holder. - -
- - Instantiations of to_python_indirect are models of ResultConverter. - - -

Class template to_python_indirect synopsis

-
-namespace boost { namespace python
-{
-  template <class T, class MakeHolder>
-  struct to_python_indirect
-  {
-     static bool convertible();
-     PyObject* operator()(T ptr_or_reference) const;
-   private:
-     static PyTypeObject* type();
-  };
-}}
-
- -

Class template to_python_indirect observers

-
-PyObject* operator()(T x) const;
-
- -
- -
Requires: x refers to an object (if it - is a pointer type, it is non-null). convertible() == - true. - -
Effects: Creates an appropriately-typed Boost.Python - extension class instance, uses MakeHolder to create - an instance_holder from x, installs - the instance_holder in the new extension class - instance, and returns a pointer to it. - -
- - -

Class template to_python_indirect statics

-
-bool convertible();
-
- -
Effects: Returns true iff any module has - registered a Python type corresponding to U. - -

Example

- -This example replicates the functionality of reference_existing_object, -but without some of the compile-time error checking. - - -
-
-struct make_reference_holder
-{
-   typedef boost::python::objects::instance_holder* result_type;
-   template <class T>
-   static result_type execute(T* p)
-   {
-      return new boost::python::objects::pointer_holder<T*, T>(p);
-   }
-};
-
-struct reference_existing_object
-{
-   // metafunction returning the ResultConverter
-   template <class T>
-   struct apply
-   {
-      typedef boost::python::to_python_indirect<T,make_reference_holder> type;
-   };
-};
-
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave - Abrahams 2002. Distributed - under the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/v2/to_python_value.html b/doc/v2/to_python_value.html deleted file mode 100644 index 3ba0044d1d..0000000000 --- a/doc/v2/to_python_value.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - Boost.Python - <boost/python/to_python_value.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header - <boost/python/to_python_value.hpp>

-
-
- -

Contents

- -
-
Classes - -
-
-
Class - to_python_value - -
-
-
Class template - to_python_value synopsis - -
Class template - to_python_value observer functions -
-
- -
-
- -

Classes

- -

Class template - to_python_value

- -

to_python_value is a model of ResultConverter - which copies its argument into a new Python object. - -

Class - to_python_value synopsis

-
-namespace boost { namespace python
-{
-   template <class T>
-   struct to_python_value
-   {
-      typedef typename add_reference<
-         typename add_const<T>::type
-      >::type argument_type;
-
-      static bool convertible();
-      PyObject* operator()(argument_type) const;
-   };
-}}
-
- -

Class - to_python_value observers

-
-static bool convertible();
-
- -
-
Returns: true iff a converter has been registered which can convert T to python by-value. -
- -
-PyObject* operator()(argument_type x) const;
-
- -
-
Requires: convertible() == true -
Effects: converts x to python -
Returns: the resulting Python object iff a converter for T has been registered, 0 otherwise. -
- -

Revised - - 13 November, 2002 - - - -

© Copyright Dave - Abrahams 2002. Distributed under the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/doc/v2/tuple.html b/doc/v2/tuple.html deleted file mode 100644 index e90244f3e4..0000000000 --- a/doc/v2/tuple.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - Boost.Python - <boost/python/tuple.hpp> - - - - - - - - - -
-

C++ Boost

-
-

Boost.Python

- -

Header <boost/python/tuple.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class tuple
- -
-
-
Class tuple - synopsis
-
-
-
-
- -
Functions
- -
-
-
make_tuple
-
-
- -
Example
-
-
- -

Introduction

- -

Exposes a TypeWrapper for the Python - - tuple type.

- -

Classes

- -

Class tuple

- -

Exposes the interface of Python's built-in tuple type. - The semantics of the constructors and member functions defined below can - be fully understood by reading the TypeWrapper concept - definition. Since tuple is publicly derived from object, the public object - interface applies to tuple instances as well.

- -

Class tuple - synopsis

-
-namespace boost { namespace python
-{
-   class tuple : public object
-   {
-      // tuple() -> an empty tuple
-      tuple();
-
-      // tuple(sequence) -> tuple initialized from sequence's items
-      template <class T>
-      explicit tuple(T const& sequence)
-  };
-}}
-
- -

Functions

- -

make_tuple

-
-namespace boost { namespace python
-{
-  tuple make_tuple();
-
-  template <class A0>
-  tuple make_tuple(A0 const& a0);
-
-  template <class A0, class A1>
-  tuple make_tuple(A0 const& a0, A1 const& a1);
-  ...
-  template <class A0, class A1,...class An> 
-  tuple make_tuple(A0 const& a0, A1 const& a1,...An const& an);
-}}
-
- Constructs a new tuple object composed of object(a0), - object(a0),...object(an). - -

Example

-
-using namespace boost::python;
-tuple head_and_tail(object sequence)
-{
-    return make_tuple(sequence[0],sequence[-1]);
-}
-
- -

Revised 03 October, 2002

- -

© Copyright Dave Abrahams 2002.

- - - diff --git a/doc/v2/type_id.html b/doc/v2/type_id.html deleted file mode 100755 index 570846741c..0000000000 --- a/doc/v2/type_id.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - Boost.Python - <boost/python/type_id.hpp> - - - - - -
-

C++ Boost

- -
-

Boost.Python

- -

Header <boost/python/type_id.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class type_info
- -
-
-
Class - type_info synopsis
- -
Class type_info - constructor
- -
Class - type_info comparison functions
- -
Class - type_info observer functions
-
-
-
-
- -
Functions
- -
-
-
type_id
-
-
- -
Example
-
-
- -

Introduction

- -

<boost/python/type_id.hpp> provides types and - functions for runtime type identification like those of of - <typeinfo>. It exists mostly to work around certain - compiler bugs and platform-dependent interactions with shared - libraries.

- -

Classes

- -

Class type_info

- -

type_info instances identify a type. As - std::type_info is specified to (but unlike its - implementation in some compilers), boost::python::type_info - never represents top-level references or cv-qualification (see section - 5.2.8 in the C++ standard). Unlike std::type_info, - boost::python::type_info instances are copyable, and - comparisons always work reliably across shared library boundaries.

- -

Class type_info synopsis

-
-namespace boost { namespace python
-{
-  class type_info : totally_ordered<type_info>
-  {
-   public:
-      // constructor
-      type_info(std::type_info const& = typeid(void));
-
-      // comparisons
-      bool operator<(type_info const& rhs) const;
-      bool operator==(type_info const& rhs) const;
-
-      // observers
-      char const* name() const;
-  };
-}}
-
- -

Class type_info - constructor

-
-type_info(std::type_info const& = typeid(void));
-
- -
-
Effects: constructs a type_info object which - identifies the same type as its argument.
- -
Rationale: Since it is occasionally necessary to make an - array of type_info objects a benign default argument is - supplied. Note: this constructor does - not correct for non-conformance of compiler - typeid() implementations. See type_id, below.
-
- -

Class type_info - comparisons

-
-bool operator<(type_info const& rhs) const;
-
- -
-
Effects: yields a total order over type_info - objects.
-
-
-bool operator==(type_info const& rhs) const;
-
- -
-
Returns: true iff the two values describe the - same type.
-
- -
-
Note: The use of totally_ordered<type_info> - as a private base class supplies operators <=, - >=, >, and !=
-
- -

Class type_info - observers

-
-char const* name() const;
-
- -
-
Returns: The result of calling name() on the - argument used to construct the object.
-
- -

Functions

-
-std::ostream& operator<<(std::ostream&s, type_info const&x);
-
- -
-
Effects: Writes a description of the type described by to - x into s.
- -
Rationale: Not every C++ implementation provides a truly - human-readable type_info::name() string, but for some we - may be able to decode the string and produce a reasonable - representation.
-
-
-template <class T> type_info type_id()
-
- -
-
Returns: type_info(typeid(T))
- -
Note: On some non-conforming C++ implementations, the code - is not actually as simple as described above; the semantics are - adjusted to work as-if the C++ implementation were - conforming.
-
- -

Example

- The following example, though silly, illustrates how the - type_id facility might be used -
-#include <boost/python/type_id.hpp>
-
-// Returns true iff the user passes an int argument
-template <class T>
-bool is_int(T x)
-{
-   using boost::python::type_id;
-   return type_id<T>() == type_id<int>();
-}
-
- -

Revised - - 13 November, 2002 - -

- -

© Copyright Dave Abrahams 2002. Distributed under the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt)< - - - - diff --git a/doc/v2/with_custodian_and_ward.html b/doc/v2/with_custodian_and_ward.html deleted file mode 100644 index b8e2a498db..0000000000 --- a/doc/v2/with_custodian_and_ward.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - - - - - - - - Boost.Python - <boost/python/with_custodian_and_ward.hpp> - - - - - - - - -
-

- C++ Boost - -

-
-

- Boost.Python -

-

- Header <boost/python/with_custodian_and_ward.hpp> -

-
-


-

- Contents -

-
-
- Introduction -
-
- Classes -
-
-
-
- Class Template - with_custodian_and_ward -
-
-
-
- Class - Template with_custodian_and_ward synopsis -
-
- Class - with_custodian_and_ward static functions -
-
-
-
- Class Template - with_custodian_and_ward_postcall -
-
-
-
- Class - Template with_custodian_and_ward_postcall - synopsis -
-
- Class - with_custodian_and_ward_postcall static - functions -
-
-
-
-
-
- Example -
-
-
-

- Introduction -

This header provides facilities for establishing a lifetime - dependency between two of a function's Python argument or result objects. - The ward object will not be destroyed until after the custodian as - long as the custodian object supports weak - references (Boost.Python extension classes all support weak - references). If the custodian object does not support weak - references and is not None, an appropriate exception will be - thrown. The two class templates with_custodian_and_ward and - with_custodian_and_ward_postcall differ in the point at - which they take effect. -

- In order to reduce the chance of inadvertently creating dangling - pointers, the default is to do lifetime binding before the - underlying C++ object is invoked. However, before invocation the result - object is not available, so - with_custodian_and_ward_postcall is provided to bind - lifetimes after invocation. Also, if a C++ exception is thrown after - with_custodian_and_ward<>::precall but before the - underlying C++ object actually stores a pointer, the lifetime of the - custodian and ward objects will be artificially bound together, so one - might choose with_custodian_and_ward_postcall instead, - depending on the semantics of the function being wrapped. -

-

- Please note that this is not the appropriate tool to use when - wrapping functions which transfer ownership of a raw pointer - across the function-call boundary. Please see the FAQ if you want to do that. -

-

- Classes -

-

- Class template - with_custodian_and_ward -

- - - - - - - - - - - - - - - - - - - - - - - - -
- with_custodian_and_ward template parameters -
- Parameter - - Requirements - - Description - - Default -
- custodian - - A positive compile-time constant of type std::size_t. - - The 1-based index of the parameter which is the dependency in the - lifetime relationship to be established. If used to wrap a member - function, parameter 1 is the target object (*this). - Note that if the target Python object type doesn't support weak - references, a Python TypeError exception will be - raised when the C++ object being wrapped is called. -
- ward - - A positive compile-time constant of type std::size_t. - - The 1-based index of the parameter which is the dependent in the - lifetime relationship to be established. If used to wrap a member - function, parameter 1 is the target object (*this). -
- Base - - A model of CallPolicies - - Used for policy - composition. - - default_call_policies -
-

- Class template - with_custodian_and_ward synopsis -

-
-namespace boost { namespace python
-{
-   template <std::size_t custodian, std::size_t ward, class Base = default_call_policies>
-   struct with_custodian_and_ward : Base
-   {
-      static bool precall(PyObject* args);
-   };
-}}
-
-

- Class - with_custodian_and_ward static functions -

-
-bool precall(PyObject* args);
-
-
-
- Requires: PyTuple_Check(args) - != 0 -
-
- Effects: Makes the lifetime of the argument indicated by - ward dependent on the lifetime of the argument indicated - by custodian. -
-
- Returns: false and PyErr_Occurred() != 0 - upon failure, true otherwise. -
-
-

- Class template - with_custodian_and_ward_postcall -

- - - - - - - - - - - - - - - - - - - - - - - - -
- with_custodian_and_ward_postcall template - parameters -
- Parameter - - Requirements - - Description - - Default -
- custodian - - A compile-time constant of type std::size_t. - - The index of the parameter which is the dependency in the lifetime - relationship to be established. Zero indicates the result object; 1 - indicates the first argument. If used to wrap a member function, - parameter 1 is the target object (*this). Note that if - the target Python object type doesn't support weak references, a - Python TypeError exception will be raised when the C++ - object being wrapped is called. -
- ward - - A compile-time constant of type std::size_t. - - The index of the parameter which is the dependent in the lifetime - relationship to be established. Zero indicates the result object; 1 - indicates the first argument. If used to wrap a member function, - parameter 1 is the target object (*this). -
- Base - - A model of CallPolicies - - Used for policy - composition. - - default_call_policies -
-

- Class - template with_custodian_and_ward_postcall synopsis -

-
-namespace boost { namespace python
-{
-   template <std::size_t custodian, std::size_t ward, class Base = default_call_policies>
-   struct with_custodian_and_ward_postcall : Base
-   {
-      static PyObject* postcall(PyObject* args, PyObject* result);
-   };
-}}
-
-

- Class - with_custodian_and_ward_postcall static functions -

-
-PyObject* postcall(PyObject* args, PyObject* result);
-
-
-
- Requires: PyTuple_Check(args) - != 0, result != 0. -
-
- Effects: Makes the lifetime of the object indicated by - ward dependent on the lifetime of the object indicated - by custodian. -
-
- Returns: 0 and PyErr_Occurred() != 0 - upon failure, true otherwise. -
-
-

- Example -

The following example shows how - with_custodian_and_ward_postcall is used by the library to - implement return_internal_reference - -
-template <std::size_t owner_arg = 1, class Base = default_call_policies>
-struct return_internal_reference
-    : with_custodian_and_ward_postcall<0, owner_arg, Base>
-{
-   typedef reference_existing_object result_converter;
-};
-
-

- Revised - - 13 November, 2002 - -

-

- © Copyright Dave - Abrahams 2002. -

- - diff --git a/doc/v2/wrapper.html b/doc/v2/wrapper.html deleted file mode 100755 index 06239754a9..0000000000 --- a/doc/v2/wrapper.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - Boost.Python - <wrapper.hpp> - - - -
-

-

- -
-

Boost.Python

- -

Header <wrapper.hpp>

-
-
- -

Contents

- -
-
Introduction
- -
Classes
- -
-
-
Class template - override
- -
-
-
Class - override synopsis
- -
Class - override observer functions
-
-
- -
Class template - wrapper
- -
-
-
Class wrapper - synopsis
- -
Class - wrapper observer functions
-
-
-
-
- -
Example(s)
-
-
- -

Introduction

- -

To wrap a class T such that its virtual functions can be - "overridden in Python"—so that the corresponding method of a Python - derived class will be called when the virtual function is invoked from - C++—you must create a C++ wrapper class derived from ``T`` that - overrides those virtual functions so that they call into Python. This - header contains classes that can be used to make that job easier.

- -

Classes

- -

Class override

- -

Encapsulates a Python override of a C++ virtual function. An - override object either holds a callable Python object or - None.

- -

Class override - synopsis

-
-namespace boost
-{
-  class override : object
-  {
-   public:
-      unspecified operator() const;
-      template <class A0>
-      unspecified operator(A0) const;
-      template <class A0, class A1>
-      unspecified operator(A0, A1) const;
-      ...
-      template <class A0, class A1, ...class An>
-      unspecified operator(A0, A1, ...An) const;
-  };
-};
-
- -

Class override - observer functions

-
-unspecified operator() const;
-template <class A0>
-unspecified operator(A0) const;
-template <class A0, class A1>
-unspecified operator(A0, A1) const;
-...
-template <class A0, class A1, ...class An>
-unspecified operator(A0, A1, ...An) const;
-
- -
-
Effects: If *this holds a callable Python - object, it is invoked with the specified arguments in the manner - specified here. Otherwise, throws error_already_set - .
- -
Returns: An object of unspecified type that holds the Python - result of the invocation and, when converted to a C++ type - R, attempts to convert that result object to - R. If that conversion fails, throws error_already_set - .
-
- -

Class template wrapper

- -

Deriving your wrapper class from both ``T`` and - ``wrapper<T> makes writing that derived class easier.

- -

Class template - wrapper synopsis

-
-namespace boost
-{
-  class wrapper
-  {
-   protected:
-      override get_override(char const* name) const;
-  };
-};
-
- -

Class wrapper - observer functions

-
-override get_override(char const* name) const;
-
- -
-
Requires: name is a ntbs.
- -
Returns: If *this is the C++ base class - subobject of a Python derived class instance that overrides the named - function, returns an override object that delegates to the - Python override. Otherwise, returns an override object - that holds None.
-
- -

Example

-
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/wrapper.hpp>
-#include <boost/python/call.hpp>
-
-using namespace boost::python;
-
-// Class with one pure virtual function
-struct P
-{
-    virtual ~P(){}
-    virtual char const* f() = 0;
-    char const* g() { return "P::g()"; }
-};
-
-struct PCallback : P, wrapper<P>
-{
-    char const* f()
-    {
-#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) // Workaround for vc6/vc7
-        return call<char const*>(this->get_override("f").ptr());
-#else 
-        return this->get_override("f")();
-#endif 
-    }
-};
-
-// Class with one non-pure virtual function
-struct A
-{
-    virtual ~A(){}
-    virtual char const* f() { return "A::f()"; }
-};
-
-struct ACallback :  A, wrapper<A>
-{
-    char const* f()
-    {
-        if (override f = this->get_override("f"))
-#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) // Workaround for vc6/vc7
-            return call<char const*>(f.ptr());
-#else 
-            return f();
-#endif 
-
-        return A::f();
-    }
-
-    char const* default_f() { return this->A::f(); }
-};
-
-BOOST_PYTHON_MODULE_INIT(polymorphism)
-{
-    class_<PCallback,boost::noncopyable>("P")
-        .def("f", pure_virtual(&P::f))
-        ;
-
-    class_<ACallback,boost::noncopyable>("A")
-        .def("f", &A::f, &ACallback::default_f)
-        ;
-}
-
- -

Revised - - 31 October, 2004 - - - -

© Copyright Dave - Abrahams 2004 Distributed under the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt)

- diff --git a/example/Jamroot b/example/Jamroot index 27ac49e8c6..fe9d69ecc0 100644 --- a/example/Jamroot +++ b/example/Jamroot @@ -1,43 +1,35 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# Copyright Stefan Seefeld 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) -# Specify the path to the Boost project. If you move this project, -# adjust this path to refer to the Boost root directory. -use-project boost - : ../../.. ; +import python ; -# Set up the project-wide requirements that everything uses the -# boost_python library from the project whose global ID is -# /boost/python. -project - : requirements /boost/python//boost_python - /boost//headers - : usage-requirements /boost//headers - ; - -# Declare the three extension modules. You can specify multiple -# source files after the colon separated by spaces. -python-extension getting_started1 : getting_started1.cpp ; -python-extension getting_started2 : getting_started2.cpp ; -python-extension std_pair_ext : std_pair.cpp ; - -# A little "rule" (function) to clean up the syntax of declaring tests -# of these extension modules. -local rule run-test ( test-name : sources + ) +if ! [ python.configured ] { - import testing ; - testing.make-test run-pyd : $(sources) : : $(test-name) ; + ECHO "warning: no Python configured in user-config.jam" ; + ECHO "warning: will use default configuration" ; + using python ; } -# Declare test targets -run-test test1 : getting_started1 test_getting_started1.py ; -run-test test2 : getting_started2 test_getting_started2.py ; -run-test test3 : std_pair_ext test_std_pair.py ; +# Adjust the following if Boost.Python isn't installed in a default location +lib boost_python ; -# A target that runs all the tests -alias test : test1 test2 test3 ; +project + : requirements +# /path/to/boost/python + boost_python +; -# Only run tests when explicitly requested -explicit test test1 test2 test3 ; +rule run-test ( test-name : sources + ) +{ + import testing ; + testing.make-test run-pyd : $(sources) : : $(test-name) ; +} +build-project quickstart ; +build-project tutorial ; +if [ python.numpy ] +{ + build-project numpy ; +} diff --git a/example/README b/example/README deleted file mode 100644 index 29a94f67dd..0000000000 --- a/example/README +++ /dev/null @@ -1,16 +0,0 @@ -.. Copyright David Abrahams 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -To get started with the Boost Python Library, use the examples -getting_started1.cpp and getting_started2.cpp. Invoking - - bjam --toolset=your-toolset test - -in this directory will build and run the examples. See -http://www.boost.org/more/getting_started.html for details about the ---toolset= option. - -If you move this example from its place in the Boost development tree -you'll need to edit the two lines indicated in Jamroot and -boost-build.jam. diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000000..af03f20ba8 --- /dev/null +++ b/example/README.md @@ -0,0 +1,11 @@ +![logo](https://raw.githubusercontent.com/boostorg/python/develop/doc/images/bpl.png) + +# Examples + +This directory contains various examples using Boost.Python. +You may compile these using the `b2` command either in this directory +or in any of the subdirectories. +You may need to adjust the paths in the Jamroot file if Boost.Python +is not installed in a default location. +See http://boostorg.github.io/python/doc/html/building/no_install_quickstart.html +for details. diff --git a/example/boost-build.jam b/example/boost-build.jam deleted file mode 100755 index b7220e2c2d..0000000000 --- a/example/boost-build.jam +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -# Edit this path to point at the tools/build/v2 subdirectory of your -# Boost installation. Absolute paths work, too. -boost-build ../../../tools/build/v2 ; diff --git a/example/getting_started1.cpp b/example/getting_started1.cpp deleted file mode 100644 index 09d6810395..0000000000 --- a/example/getting_started1.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost -// Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include - -namespace { // Avoid cluttering the global namespace. - - // A couple of simple C++ functions that we want to expose to Python. - std::string greet() { return "hello, world"; } - int square(int number) { return number * number; } -} - -namespace python = boost::python; - -// Python requires an exported function called init in every -// extension module. This is where we build the module contents. -BOOST_PYTHON_MODULE(getting_started1) -{ - // Add regular functions to the module. - python::def("greet", greet); - python::def("square", square); -} diff --git a/example/getting_started2.cpp b/example/getting_started2.cpp deleted file mode 100644 index ee8af32e50..0000000000 --- a/example/getting_started2.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost -// Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include -#include - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class hello - { - public: - hello(const std::string& country) { this->country = country; } - std::string greet() const { return "Hello from " + country; } - private: - std::string country; - }; - - // A function taking a hello object as an argument. - std::string invite(const hello& w) { - return w.greet() + "! Please come soon!"; - } -} - -BOOST_PYTHON_MODULE(getting_started2) -{ - using namespace boost::python; - class_("hello", init()) - // Add a regular member function. - .def("greet", &hello::greet) - // Add invite() as a member of hello! - .def("invite", invite) - ; - - // Also add invite() as a regular function to the module. - def("invite", invite); -} diff --git a/example/numpy/Jamfile b/example/numpy/Jamfile new file mode 100644 index 0000000000..ac70a6ff03 --- /dev/null +++ b/example/numpy/Jamfile @@ -0,0 +1,29 @@ +# Copyright Stefan Seefeld 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import python ; + +# Adjust the following if Boost.Python isn't installed in a default location +lib boost_numpy + : + : /usr/local/Boost/lib + /usr/local/Boost/include + ; + +project numpy + : requirements + /usr/local/Boost/include + boost_numpy + . + ; + +exe simple : simple.cpp boost_numpy /python//python ; +exe dtype : dtype.cpp boost_numpy /python//python ; +exe ndarray : ndarray.cpp /python//python ; +exe fromdata : fromdata.cpp /python//python ; +exe ufunc : ufunc.cpp /python//python ; +exe wrap : wrap.cpp /python//python ; + +python-extension gaussian : gaussian.cpp ; diff --git a/example/numpy/demo_gaussian.py b/example/numpy/demo_gaussian.py new file mode 100644 index 0000000000..08bb58b82a --- /dev/null +++ b/example/numpy/demo_gaussian.py @@ -0,0 +1,38 @@ +# Copyright Jim Bosch 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from __future__ import print_function +import numpy +import gaussian + +mu = numpy.zeros(2, dtype=float) +sigma = numpy.identity(2, dtype=float) +sigma[0, 1] = 0.15 +sigma[1, 0] = 0.15 + +g = gaussian.bivariate_gaussian(mu, sigma) + +r = numpy.linspace(-40, 40, 1001) +x, y = numpy.meshgrid(r, r) + +z = g(x, y) + +s = z.sum() * (r[1] - r[0])**2 +print("sum (should be ~ 1):", s) + +xc = (z * x).sum() / z.sum() +print("x centroid (should be ~ %f): %f" % (mu[0], xc)) + +yc = (z * y).sum() / z.sum() +print("y centroid (should be ~ %f): %f" % (mu[1], yc)) + +xx = (z * (x - xc)**2).sum() / z.sum() +print("xx moment (should be ~ %f): %f" % (sigma[0,0], xx)) + +yy = (z * (y - yc)**2).sum() / z.sum() +print("yy moment (should be ~ %f): %f" % (sigma[1,1], yy)) + +xy = 0.5 * (z * (x - xc) * (y - yc)).sum() / z.sum() +print("xy moment (should be ~ %f): %f" % (sigma[0,1], xy)) diff --git a/example/numpy/dtype.cpp b/example/numpy/dtype.cpp new file mode 100644 index 0000000000..749a36b5e5 --- /dev/null +++ b/example/numpy/dtype.cpp @@ -0,0 +1,49 @@ +// Copyright Ankit Daftery 2011-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** + * @brief An example to show how to create ndarrays with built-in python data types, and extract + * the types and values of member variables + * + * @todo Add an example to show type conversion. + * Add an example to show use of user-defined types + * + */ + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create a 3x3 shape... + p::tuple shape = p::make_tuple(3, 3); + // ...as well as a type for C++ double + np::dtype dtype = np::dtype::get_builtin(); + // Construct an array with the above shape and type + np::ndarray a = np::zeros(shape, dtype); + // Print the array + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + // Print the datatype of the elements + std::cout << "Datatype is:\n" << p::extract(p::str(a.get_dtype())) << std::endl ; + // Using user defined dtypes to create dtype and an array of the custom dtype + // First create a tuple with a variable name and its dtype, double, to create a custom dtype + p::tuple for_custom_dtype = p::make_tuple("ha",dtype) ; + // The list needs to be created, because the constructor to create the custom dtype + // takes a list of (variable,variable_type) as an argument + p::list list_for_dtype ; + list_for_dtype.append(for_custom_dtype) ; + // Create the custom dtype + np::dtype custom_dtype = np::dtype(list_for_dtype) ; + // Create an ndarray with the custom dtype + np::ndarray new_array = np::zeros(shape,custom_dtype); + +} diff --git a/example/numpy/fromdata.cpp b/example/numpy/fromdata.cpp new file mode 100644 index 0000000000..bd073cc697 --- /dev/null +++ b/example/numpy/fromdata.cpp @@ -0,0 +1,48 @@ +// Copyright Ankit Daftery 2011-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** + * @brief An example to show how to access data using raw pointers. This shows that you can use and + * manipulate data in either Python or C++ and have the changes reflected in both. + */ + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create an array in C++ + int arr[] = {1,2,3,4} ; + // Create the ndarray in Python + np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin() , p::make_tuple(4), p::make_tuple(4), p::object()); + // Print the ndarray that we just created, and the source C++ array + std::cout << "C++ array :" << std::endl ; + for (int j=0;j<4;j++) + { + std::cout << arr[j] << ' ' ; + } + std::cout << std::endl << "Python ndarray :" << p::extract(p::str(py_array)) << std::endl; + // Change an element in the python ndarray + py_array[1] = 5 ; + // And see if the C++ container is changed or not + std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl ; + for (int j = 0;j<4 ; j++) + { + std::cout << arr[j] << ' ' ; + } + // Conversely, change it in C++ + arr[2] = 8 ; + // And see if the changes are reflected in the Python ndarray + std::cout << std::endl << "Is the change reflected in the Python ndarray ?" << std::endl << p::extract(p::str(py_array)) << std::endl; + +} diff --git a/example/numpy/gaussian.cpp b/example/numpy/gaussian.cpp new file mode 100644 index 0000000000..5f138b3979 --- /dev/null +++ b/example/numpy/gaussian.cpp @@ -0,0 +1,315 @@ +// Copyright Jim Bosch 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include + +#ifndef M_PI +#include +const double M_PI = boost::math::constants::pi(); +#endif + +namespace bp = boost::python; +namespace bn = boost::python::numpy; + +/** + * A 2x2 matrix class, purely for demonstration purposes. + * + * Instead of wrapping this class with Boost.Python, we'll convert it to/from numpy.ndarray. + */ +class matrix2 { +public: + + double & operator()(int i, int j) { + return _data[i*2 + j]; + } + + double const & operator()(int i, int j) const { + return _data[i*2 + j]; + } + + double const * data() const { return _data; } + +private: + double _data[4]; +}; + +/** + * A 2-element vector class, purely for demonstration purposes. + * + * Instead of wrapping this class with Boost.Python, we'll convert it to/from numpy.ndarray. + */ +class vector2 { +public: + + double & operator[](int i) { + return _data[i]; + } + + double const & operator[](int i) const { + return _data[i]; + } + + double const * data() const { return _data; } + + vector2 operator+(vector2 const & other) const { + vector2 r; + r[0] = _data[0] + other[0]; + r[1] = _data[1] + other[1]; + return r; + } + + vector2 operator-(vector2 const & other) const { + vector2 r; + r[0] = _data[0] - other[0]; + r[1] = _data[1] - other[1]; + return r; + } + +private: + double _data[2]; +}; + +/** + * Matrix-vector multiplication. + */ +vector2 operator*(matrix2 const & m, vector2 const & v) { + vector2 r; + r[0] = m(0, 0) * v[0] + m(0, 1) * v[1]; + r[1] = m(1, 0) * v[0] + m(1, 1) * v[1]; + return r; +} + +/** + * Vector inner product. + */ +double dot(vector2 const & v1, vector2 const & v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} + +/** + * This class represents a simple 2-d Gaussian (Normal) distribution, defined by a + * mean vector 'mu' and a covariance matrix 'sigma'. + */ +class bivariate_gaussian { +public: + + vector2 const & get_mu() const { return _mu; } + + matrix2 const & get_sigma() const { return _sigma; } + + /** + * Evaluate the density of the distribution at a point defined by a two-element vector. + */ + double operator()(vector2 const & p) const { + vector2 u = _cholesky * (p - _mu); + return 0.5 * _cholesky(0, 0) * _cholesky(1, 1) * std::exp(-0.5 * dot(u, u)) / M_PI; + } + + /** + * Evaluate the density of the distribution at an (x, y) point. + */ + double operator()(double x, double y) const { + vector2 p; + p[0] = x; + p[1] = y; + return operator()(p); + } + + /** + * Construct from a mean vector and covariance matrix. + */ + bivariate_gaussian(vector2 const & mu, matrix2 const & sigma) + : _mu(mu), _sigma(sigma), _cholesky(compute_inverse_cholesky(sigma)) + {} + +private: + + /** + * This evaluates the inverse of the Cholesky factorization of a 2x2 matrix; + * it's just a shortcut in evaluating the density. + */ + static matrix2 compute_inverse_cholesky(matrix2 const & m) { + matrix2 l; + // First do cholesky factorization: l l^t = m + l(0, 0) = std::sqrt(m(0, 0)); + l(0, 1) = m(0, 1) / l(0, 0); + l(1, 1) = std::sqrt(m(1, 1) - l(0,1) * l(0,1)); + // Now do forward-substitution (in-place) to invert: + l(0, 0) = 1.0 / l(0, 0); + l(1, 0) = l(0, 1) = -l(0, 1) / l(1, 1); + l(1, 1) = 1.0 / l(1, 1); + return l; + } + + vector2 _mu; + matrix2 _sigma; + matrix2 _cholesky; + +}; + +/* + * We have a two options for wrapping get_mu and get_sigma into NumPy-returning Python methods: + * - we could deep-copy the data, making totally new NumPy arrays; + * - we could make NumPy arrays that point into the existing memory. + * The latter is often preferable, especially if the arrays are large, but it's dangerous unless + * the reference counting is correct: the returned NumPy array needs to hold a reference that + * keeps the memory it points to from being deallocated as long as it is alive. This is what the + * "owner" argument to from_data does - the NumPy array holds a reference to the owner, keeping it + * from being destroyed. + * + * Note that this mechanism isn't completely safe for data members that can have their internal + * storage reallocated. A std::vector, for instance, can be invalidated when it is resized, + * so holding a Python reference to a C++ class that holds a std::vector may not be a guarantee + * that the memory in the std::vector will remain valid. + */ + +/** + * These two functions are custom wrappers for get_mu and get_sigma, providing the shallow-copy + * conversion with reference counting described above. + * + * It's also worth noting that these return NumPy arrays that cannot be modified in Python; + * the const overloads of vector::data() and matrix::data() return const references, + * and passing a const pointer to from_data causes NumPy's 'writeable' flag to be set to false. + */ +static bn::ndarray py_get_mu(bp::object const & self) { + vector2 const & mu = bp::extract(self)().get_mu(); + return bn::from_data( + mu.data(), + bn::dtype::get_builtin(), + bp::make_tuple(2), + bp::make_tuple(sizeof(double)), + self + ); +} +static bn::ndarray py_get_sigma(bp::object const & self) { + matrix2 const & sigma = bp::extract(self)().get_sigma(); + return bn::from_data( + sigma.data(), + bn::dtype::get_builtin(), + bp::make_tuple(2, 2), + bp::make_tuple(2 * sizeof(double), sizeof(double)), + self + ); +} + +/** + * To allow the constructor to work, we need to define some from-Python converters from NumPy arrays + * to the matrix/vector types. The rvalue-from-python functionality is not well-documented in Boost.Python + * itself; you can learn more from boost/python/converter/rvalue_from_python_data.hpp. + */ + +/** + * We start with two functions that just copy a NumPy array into matrix/vector objects. These will be used + * in the templated converted below. The first just uses the operator[] overloads provided by + * bp::object. + */ +static void copy_ndarray_to_mv2(bn::ndarray const & array, vector2 & vec) { + vec[0] = bp::extract(array[0]); + vec[1] = bp::extract(array[1]); +} + +/** + * Here, we'll take the alternate approach of using the strides to access the array's memory directly. + * This can be much faster for large arrays. + */ +static void copy_ndarray_to_mv2(bn::ndarray const & array, matrix2 & mat) { + // Unfortunately, get_strides() can't be inlined, so it's best to call it once up-front. + Py_intptr_t const * strides = array.get_strides(); + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + mat(i, j) = *reinterpret_cast(array.get_data() + i * strides[0] + j * strides[1]); + } + } +} + +/** + * Here's the actual converter. Because we've separated the differences into the above functions, + * we can write a single template class that works for both matrix2 and vector2. + */ +template +struct mv2_from_python { + + /** + * Register the converter. + */ + mv2_from_python() { + bp::converter::registry::push_back( + &convertible, + &construct, + bp::type_id< T >() + ); + } + + /** + * Test to see if we can convert this to the desired type; if not return zero. + * If we can convert, returned pointer can be used by construct(). + */ + static void * convertible(PyObject * p) { + try { + bp::object obj(bp::handle<>(bp::borrowed(p))); + std::auto_ptr array( + new bn::ndarray( + bn::from_object(obj, bn::dtype::get_builtin(), N, N, bn::ndarray::V_CONTIGUOUS) + ) + ); + if (array->shape(0) != 2) return 0; + if (N == 2 && array->shape(1) != 2) return 0; + return array.release(); + } catch (bp::error_already_set & err) { + bp::handle_exception(); + return 0; + } + } + + /** + * Finish the conversion by initializing the C++ object into memory prepared by Boost.Python. + */ + static void construct(PyObject * obj, bp::converter::rvalue_from_python_stage1_data * data) { + // Extract the array we passed out of the convertible() member function. + std::auto_ptr array(reinterpret_cast(data->convertible)); + // Find the memory block Boost.Python has prepared for the result. + typedef bp::converter::rvalue_from_python_storage storage_t; + storage_t * storage = reinterpret_cast(data); + // Use placement new to initialize the result. + T * m_or_v = new (storage->storage.bytes) T(); + // Fill the result with the values from the NumPy array. + copy_ndarray_to_mv2(*array, *m_or_v); + // Finish up. + data->convertible = storage->storage.bytes; + } + +}; + + +BOOST_PYTHON_MODULE(gaussian) { + bn::initialize(); + + // Register the from-python converters + mv2_from_python< vector2, 1 >(); + mv2_from_python< matrix2, 2 >(); + + typedef double (bivariate_gaussian::*call_vector)(vector2 const &) const; + + bp::class_("bivariate_gaussian", bp::init()) + + // Declare the constructor (wouldn't work without the from-python converters). + .def(bp::init< vector2 const &, matrix2 const & >()) + + // Use our custom reference-counting getters + .add_property("mu", &py_get_mu) + .add_property("sigma", &py_get_sigma) + + // First overload accepts a two-element array argument + .def("__call__", (call_vector)&bivariate_gaussian::operator()) + + // This overload works like a binary NumPy universal function: you can pass + // in scalars or arrays, and the C++ function will automatically be called + // on each element of an array argument. + .def("__call__", bn::binary_ufunc::make()) + ; +} diff --git a/example/numpy/ndarray.cpp b/example/numpy/ndarray.cpp new file mode 100644 index 0000000000..d7b57aa730 --- /dev/null +++ b/example/numpy/ndarray.cpp @@ -0,0 +1,71 @@ +// Copyright Ankit Daftery 2011-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** + * @brief An example to show how to create ndarrays using arbitrary Python sequences. + * + * The Python sequence could be any object whose __array__ method returns an array, or any + * (nested) sequence. This example also shows how to create arrays using both unit and + * non-unit strides. + */ + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +#if _MSC_VER +using boost::uint8_t; +#endif + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create an ndarray from a simple tuple + p::object tu = p::make_tuple('a','b','c') ; + np::ndarray example_tuple = np::array (tu) ; + // and from a list + p::list l ; + np::ndarray example_list = np::array (l) ; + // Optionally, you can also specify a dtype + np::dtype dt = np::dtype::get_builtin(); + np::ndarray example_list1 = np::array (l,dt); + // You can also create an array by supplying data.First,create an integer array + int data[] = {1,2,3,4} ; + // Create a shape, and strides, needed by the function + p::tuple shape = p::make_tuple(4) ; + p::tuple stride = p::make_tuple(4) ; + // The function also needs an owner, to keep track of the data array passed. Passing none is dangerous + p::object own ; + // The from_data function takes the data array, datatype,shape,stride and owner as arguments + // and returns an ndarray + np::ndarray data_ex = np::from_data(data,dt,shape,stride,own); + // Print the ndarray we created + std::cout << "Single dimensional array ::" << std::endl << p::extract < char const * > (p::str(data_ex)) << std::endl ; + // Now lets make an 3x2 ndarray from a multi-dimensional array using non-unit strides + // First lets create a 3x4 array of 8-bit integers + uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; + // Now let's create an array of 3x2 elements, picking the first and third elements from each row + // For that, the shape will be 3x2 + shape = p::make_tuple(3,2) ; + // The strides will be 4x2 i.e. 4 bytes to go to the next desired row, and 2 bytes to go to the next desired column + stride = p::make_tuple(4,2) ; + // Get the numpy dtype for the built-in 8-bit integer data type + np::dtype dt1 = np::dtype::get_builtin(); + // First lets create and print out the ndarray as is + np::ndarray mul_data_ex = np::from_data(mul_data,dt1, p::make_tuple(3,4),p::make_tuple(4,1),p::object()); + std::cout << "Original multi dimensional array :: " << std::endl << p::extract < char const * > (p::str(mul_data_ex)) << std::endl ; + // Now create the new ndarray using the shape and strides + mul_data_ex = np::from_data(mul_data,dt1, shape,stride,p::object()); + // Print out the array we created using non-unit strides + std::cout << "Selective multidimensional array :: "< (p::str(mul_data_ex)) << std::endl ; + +} + + diff --git a/example/numpy/simple.cpp b/example/numpy/simple.cpp new file mode 100644 index 0000000000..ad598bde47 --- /dev/null +++ b/example/numpy/simple.cpp @@ -0,0 +1,32 @@ +// Copyright 2011 Stefan Seefeld. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Create a 3x3 shape... + p::tuple shape = p::make_tuple(3, 3); + // ...as well as a type for C++ float + np::dtype dtype = np::dtype::get_builtin(); + // Construct an array with the above shape and type + np::ndarray a = np::zeros(shape, dtype); + // Construct an empty array with the above shape and dtype as well + np::ndarray b = np::empty(shape,dtype); + // Print the array + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + // Reshape the array into a 1D array + a = a.reshape(p::make_tuple(9)); + // Print it again. + std::cout << "Reshaped array:\n" << p::extract(p::str(a)) << std::endl; +} diff --git a/example/numpy/ufunc.cpp b/example/numpy/ufunc.cpp new file mode 100644 index 0000000000..5fb6920457 --- /dev/null +++ b/example/numpy/ufunc.cpp @@ -0,0 +1,86 @@ +// Copyright Ankit Daftery 2011-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** + * @brief An example to demonstrate use of universal functions or ufuncs + * + * + * @todo Calling the overloaded () operator is in a roundabout manner, find a simpler way + * None of the methods like np::add, np::multiply etc are supported as yet + */ + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + + +// Create the structs necessary to implement the ufuncs +// The typedefs *must* be made + +struct UnarySquare +{ + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * r;} +}; + +struct BinarySquare +{ + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a,double b) const { return (a*a + b*b) ; } +}; + +int main(int argc, char **argv) +{ + // Initialize the Python runtime. + Py_Initialize(); + // Initialize NumPy + np::initialize(); + // Expose the struct UnarySquare to Python as a class, and let ud be the class object + p::object ud = p::class_ >("UnarySquare") + .def("__call__", np::unary_ufunc::make()); + // Let inst be an instance of the class ud + p::object inst = ud(); + // Use the "__call__" method to call the overloaded () operator and print the value + std::cout << "Square of unary scalar 1.0 is " << p::extract (p::str(inst.attr("__call__")(1.0))) << std::endl ; + // Create an array in C++ + int arr[] = {1,2,3,4} ; + // ..and use it to create the ndarray in Python + np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin() , p::make_tuple(4), p::make_tuple(4), p::object()); + // Print out the demo array + std::cout << "Demo array is " << p::extract (p::str(demo_array)) << std::endl ; + // Call the "__call__" method to perform the operation and assign the value to result_array + p::object result_array = inst.attr("__call__")(demo_array) ; + // Print the resultant array + std::cout << "Square of demo array is " << p::extract (p::str(result_array)) << std::endl ; + // Lets try the same with a list + p::list li ; + li.append(3); + li.append(7); + // Print out the demo list + std::cout << "Demo list is " << p::extract (p::str(li)) << std::endl ; + // Call the ufunc for the list + result_array = inst.attr("__call__")(li) ; + // And print the list out + std::cout << "Square of demo list is " << p::extract (p::str(result_array)) << std::endl ; + // Now lets try Binary ufuncs + // Expose the struct BinarySquare to Python as a class, and let ud be the class object + ud = p::class_ >("BinarySquare") + .def("__call__", np::binary_ufunc::make()); + // Again initialise inst as an instance of the class ud + inst = ud(); + // Print the two input listsPrint the two input lists + std::cout << "The two input list for binary ufunc are " << std::endl << p::extract (p::str(demo_array)) << std::endl << p::extract (p::str(demo_array)) << std::endl ; + // Call the binary ufunc taking demo_array as both inputs + result_array = inst.attr("__call__")(demo_array,demo_array) ; + std::cout << "Square of list with binary ufunc is " << p::extract (p::str(result_array)) << std::endl ; +} + diff --git a/example/numpy/wrap.cpp b/example/numpy/wrap.cpp new file mode 100644 index 0000000000..33f71c85ad --- /dev/null +++ b/example/numpy/wrap.cpp @@ -0,0 +1,135 @@ +// Copyright Jim Bosch 2011-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** + * A simple example showing how to wrap a couple of C++ functions that + * operate on 2-d arrays into Python functions that take NumPy arrays + * as arguments. + * + * If you find have a lot of such functions to wrap, you may want to + * create a C++ array type (or use one of the many existing C++ array + * libraries) that maps well to NumPy arrays and create Boost.Python + * converters. There's more work up front than the approach here, + * but much less boilerplate per function. See the "Gaussian" example + * included with Boost.NumPy for an example of custom converters, or + * take a look at the "ndarray" project on GitHub for a more complete, + * high-level solution. + * + * Note that we're using embedded Python here only to make a convenient + * self-contained example; you could just as easily put the wrappers + * in a regular C++-compiled module and imported them in regular + * Python. Again, see the Gaussian demo for an example. + */ + +#include +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +// This is roughly the most efficient way to write a C/C++ function that operates +// on a 2-d NumPy array - operate directly on the array by incrementing a pointer +// with the strides. +void fill1(double * array, int rows, int cols, int row_stride, int col_stride) { + double * row_iter = array; + double n = 0.0; // just a counter we'll fill the array with. + for (int i = 0; i < rows; ++i, row_iter += row_stride) { + double * col_iter = row_iter; + for (int j = 0; j < cols; ++j, col_iter += col_stride) { + *col_iter = ++n; + } + } +} + +// Here's a simple wrapper function for fill1. It requires that the passed +// NumPy array be exactly what we're looking for - no conversion from nested +// sequences or arrays with other data types, because we want to modify it +// in-place. +void wrap_fill1(np::ndarray const & array) { + if (array.get_dtype() != np::dtype::get_builtin()) { + PyErr_SetString(PyExc_TypeError, "Incorrect array data type"); + p::throw_error_already_set(); + } + if (array.get_nd() != 2) { + PyErr_SetString(PyExc_TypeError, "Incorrect number of dimensions"); + p::throw_error_already_set(); + } + fill1(reinterpret_cast(array.get_data()), + array.shape(0), array.shape(1), + array.strides(0) / sizeof(double), array.strides(1) / sizeof(double)); +} + +// Another fill function that takes a double**. This is less efficient, because +// it's not the native NumPy data layout, but it's common enough in C/C++ that +// it's worth its own example. This time we don't pass the strides, and instead +// in wrap_fill2 we'll require the C_CONTIGUOUS bitflag, which guarantees that +// the column stride is 1 and the row stride is the number of columns. That +// restricts the arrays that can be passed to fill2 (it won't work on most +// subarray views or transposes, for instance). +void fill2(double ** array, int rows, int cols) { + double n = 0.0; // just a counter we'll fill the array with. + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + array[i][j] = ++n; + } + } +} +// Here's the wrapper for fill2; it's a little more complicated because we need +// to check the flags and create the array of pointers. +void wrap_fill2(np::ndarray const & array) { + if (array.get_dtype() != np::dtype::get_builtin()) { + PyErr_SetString(PyExc_TypeError, "Incorrect array data type"); + p::throw_error_already_set(); + } + if (array.get_nd() != 2) { + PyErr_SetString(PyExc_TypeError, "Incorrect number of dimensions"); + p::throw_error_already_set(); + } + if (!(array.get_flags() & np::ndarray::C_CONTIGUOUS)) { + PyErr_SetString(PyExc_TypeError, "Array must be row-major contiguous"); + p::throw_error_already_set(); + } + double * iter = reinterpret_cast(array.get_data()); + int rows = array.shape(0); + int cols = array.shape(1); + boost::scoped_array ptrs(new double*[rows]); + for (int i = 0; i < rows; ++i, iter += cols) { + ptrs[i] = iter; + } + fill2(ptrs.get(), array.shape(0), array.shape(1)); +} + +BOOST_PYTHON_MODULE(example) { + np::initialize(); // have to put this in any module that uses Boost.NumPy + p::def("fill1", wrap_fill1); + p::def("fill2", wrap_fill2); +} + +int main(int argc, char **argv) +{ + // This line makes our module available to the embedded Python intepreter. +# if PY_VERSION_HEX >= 0x03000000 + PyImport_AppendInittab("example", &PyInit_example); +# else + PyImport_AppendInittab("example", &initexample); +# endif + // Initialize the Python runtime. + Py_Initialize(); + + PyRun_SimpleString( + "import example\n" + "import numpy\n" + "z1 = numpy.zeros((5,6), dtype=float)\n" + "z2 = numpy.zeros((4,3), dtype=float)\n" + "example.fill1(z1)\n" + "example.fill2(z2)\n" + "print z1\n" + "print z2\n" + ); + Py_Finalize(); +} + + diff --git a/example/project.zip b/example/project.zip deleted file mode 100644 index d863defdb7..0000000000 Binary files a/example/project.zip and /dev/null differ diff --git a/example/quickstart/Jamfile b/example/quickstart/Jamfile new file mode 100644 index 0000000000..6dd3513019 --- /dev/null +++ b/example/quickstart/Jamfile @@ -0,0 +1,35 @@ +# Copyright Stefan Seefeld 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import python ; +import testing ; + +project quickstart + : requirements + . + ; + +# Declare a Python extension called hello. +python-extension extending : extending.cpp ; + +# Declare an executable called embedding that embeds Python +exe embedding : embedding.cpp /python//python ; + +# Declare a test of the extension module +testing.make-test run-pyd : extending test_extending.py : : test_ext ; + +# Declare a test of the embedding application +testing.run embedding embedding.cpp + : # any ordinary arguments + : script.py # any arguments that should be treated as relative paths + : # requirements + : test_embed ; # name of test + +# Create a "test" target that runs all the tests +alias test : test_ext test_embed ; + +# make sure the tests don't run by default +explicit test_ext test_embed test ; + diff --git a/example/quickstart/Jamroot b/example/quickstart/Jamroot deleted file mode 100644 index 9b57a00998..0000000000 --- a/example/quickstart/Jamroot +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -# Specify the path to the Boost project. If you move this project, -# adjust the path to refer to the Boost root directory. -use-project boost - : ../../../.. ; - -# Set up the project-wide requirements that everything uses the -# boost_python library defined in the project whose global ID is -# /boost/python. -project boost-python-quickstart - : requirements /boost/python//boost_python - /boost//headers - : usage-requirements /boost//headers - ; - -# Make the definition of the python-extension rule available -import python ; - -# Declare a Python extension called hello. -python-extension extending : extending.cpp ; - -# Declare an executable called embedding that embeds Python -exe embedding : embedding.cpp /python//python ; - -import testing ; - -# Declare a test of the extension module -testing.make-test run-pyd : extending test_extending.py : : test_ext ; - -# Declare a test of the embedding application -testing.run embedding - : # any ordinary arguments - : script.py # any arguments that should be treated as relative paths - : # requirements - : test_embed ; # name of test - -# Create a "test" target that runs all the tests -alias test : test_ext test_embed ; - -# make sure the tests don't run by default -explicit test_ext test_embed test ; - diff --git a/example/quickstart/boost-build.jam b/example/quickstart/boost-build.jam deleted file mode 100644 index a440ea9fee..0000000000 --- a/example/quickstart/boost-build.jam +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -# Edit this path to point at the tools/build/v2 subdirectory of your -# Boost installation. Absolute paths work, too. -boost-build ../../../../tools/build/v2 ; diff --git a/example/quickstart/script.py b/example/quickstart/script.py index 5a8faf79fd..f360cef2d2 100644 --- a/example/quickstart/script.py +++ b/example/quickstart/script.py @@ -1,6 +1,7 @@ +#!/usr/bin/env python3 # Copyright Stefan Seefeld 2006. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -print 'Hello World !' +print('Hello World !') number = 42 diff --git a/example/quickstart/test_extending.py b/example/quickstart/test_extending.py index 14616f7c05..035ca96134 100644 --- a/example/quickstart/test_extending.py +++ b/example/quickstart/test_extending.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 # Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/example/std_pair.cpp b/example/std_pair.cpp deleted file mode 100644 index edf98dd654..0000000000 --- a/example/std_pair.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost -// Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -namespace { // Avoid cluttering the global namespace. - - // Converts a std::pair instance to a Python tuple. - template - struct std_pair_to_tuple - { - static PyObject* convert(std::pair const& p) - { - return boost::python::incref( - boost::python::make_tuple(p.first, p.second).ptr()); - } - static PyTypeObject const *get_pytype () {return &PyTuple_Type; } - }; - - // Helper for convenience. - template - struct std_pair_to_python_converter - { - std_pair_to_python_converter() - { - boost::python::to_python_converter< - std::pair, - std_pair_to_tuple, - true //std_pair_to_tuple has get_pytype - >(); - } - }; - - // Example function returning a std::pair. - std::pair - foo() { return std::pair(3, 5); } - -} // namespace anonymous - -BOOST_PYTHON_MODULE(std_pair_ext) -{ - using namespace boost::python; - std_pair_to_python_converter(); - def("foo", foo); -} diff --git a/example/test_getting_started1.py b/example/test_getting_started1.py deleted file mode 100644 index 32dc1f6eb1..0000000000 --- a/example/test_getting_started1.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -r'''>>> import getting_started1 - >>> print getting_started1.greet() - hello, world - >>> number = 11 - >>> print number, '*', number, '=', getting_started1.square(number) - 11 * 11 = 121 -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_getting_started1 - return doctest.testmod(test_getting_started1) - -if __name__ == '__main__': - import sys - sys.exit(run()[0]) diff --git a/example/test_getting_started2.py b/example/test_getting_started2.py deleted file mode 100644 index ae86017b2c..0000000000 --- a/example/test_getting_started2.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -r'''>>> from getting_started2 import * - >>> hi = hello('California') - >>> hi.greet() - 'Hello from California' - >>> invite(hi) - 'Hello from California! Please come soon!' - >>> hi.invite() - 'Hello from California! Please come soon!' - - >>> class wordy(hello): - ... def greet(self): - ... return hello.greet(self) + ', where the weather is fine' - ... - >>> hi2 = wordy('Florida') - >>> hi2.greet() - 'Hello from Florida, where the weather is fine' - >>> invite(hi2) - 'Hello from Florida! Please come soon!' -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_getting_started2 - return doctest.testmod(test_getting_started2) - -if __name__ == '__main__': - import sys - sys.exit(run()[0]) - diff --git a/example/test_std_pair.py b/example/test_std_pair.py deleted file mode 100644 index 64f239feac..0000000000 --- a/example/test_std_pair.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright Ralf W. Grosse-Kunstleve 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -import std_pair_ext -assert std_pair_ext.foo() == (3, 5) -print "OK" diff --git a/example/tutorial/Jamfile b/example/tutorial/Jamfile new file mode 100644 index 0000000000..a32272e7fc --- /dev/null +++ b/example/tutorial/Jamfile @@ -0,0 +1,19 @@ +# Copyright Stefan Seefeld 2016. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import python ; + +project tutorial + : requirements + . + ; + +python-extension hello_ext : hello.cpp ; + +run-test hello : hello_ext hello.py ; + +alias test : hello ; +explicit test ; + diff --git a/example/tutorial/Jamroot b/example/tutorial/Jamroot deleted file mode 100644 index ac5e1f0345..0000000000 --- a/example/tutorial/Jamroot +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -import python ; - -if ! [ python.configured ] -{ - ECHO "notice: no Python configured in user-config.jam" ; - ECHO "notice: will use default configuration" ; - using python ; -} - -# Specify the path to the Boost project. If you move this project, -# adjust this path to refer to the Boost root directory. -use-project boost - : ../../../.. ; - -# Set up the project-wide requirements that everything uses the -# boost_python library from the project whose global ID is -# /boost/python. -project - : requirements /boost/python//boost_python - /boost//headers - : usage-requirements /boost//headers - ; - -# Declare the three extension modules. You can specify multiple -# source files after the colon separated by spaces. -python-extension hello_ext : hello.cpp ; - -# Put the extension and Boost.Python DLL in the current directory, so -# that running script by hand works. -install convenient_copy - : hello_ext - : on SHARED_LIB PYTHON_EXTENSION - . - ; - -# A little "rule" (function) to clean up the syntax of declaring tests -# of these extension modules. -local rule run-test ( test-name : sources + ) -{ - import testing ; - testing.make-test run-pyd : $(sources) : : $(test-name) ; -} - -# Declare test targets -run-test hello : hello_ext hello.py ; - - diff --git a/example/tutorial/hello.py b/example/tutorial/hello.py index d18b1c535f..7888b2e0fd 100755 --- a/example/tutorial/hello.py +++ b/example/tutorial/hello.py @@ -1,7 +1,8 @@ +#!/usr/bin/env python3 # Copyright Joel de Guzman 2002-2007. Distributed under the Boost # Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # Hello World Example from the tutorial import hello_ext -print hello_ext.greet() +print(hello_ext.greet()) diff --git a/fabscript b/fabscript new file mode 100644 index 0000000000..5a50615fc8 --- /dev/null +++ b/fabscript @@ -0,0 +1,83 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from faber.feature import set +from faber.types import cxx +from faber.tools.compiler import cxxflags, define, include +from faber.tools.python import python +from faber.config import report, cxx_checks +from faber.config.try_run import try_run + +features += include('include') +features += define('BOOST_ALL_NO_LIB') # disable auto-linking +features += define('BOOST_NO_AUTO_PTR') +boost_include = options.get_with('boost-include') +if boost_include: + features += include(boost_include) +python = python.instance() +py_suffix = '{}{}'.format(*python.version.split('.')[:2]) +features |= set(python.include, python.linkpath, python.libs) + +class has_numpy(try_run): + + src = r""" +// If defined, enforces linking against PythonXXd.lib, which +// is usually not included in Python environments. +#undef _DEBUG +#include "Python.h" +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include "numpy/arrayobject.h" + +#if PY_VERSION_HEX >= 0x03000000 +void *initialize() { import_array();} +#else +void initialize() { import_array();} +#endif + +int main() +{ + int result = 0; + Py_Initialize(); + initialize(); + if (PyErr_Occurred()) + { + result = 1; + } + else + { + npy_intp dims = 2; + PyObject * a = PyArray_SimpleNew(1, &dims, NPY_INT); + if (!a) result = 1; + Py_DECREF(a); + } + Py_Finalize(); + return result; +} +""" + def __init__(self, features=()): + + inc = '' + try: + inc = python.check_python('import numpy; print(numpy.get_include())') + features |= include(inc) + except Exception: + # ignore errors, the check will fail during compilation... + pass + try_run.__init__(self, 'has_numpy', has_numpy.src, cxx, features, + if_=(include(inc), define('HAS_NUMPY'))) + +checks = [cxx_checks.has_cxx11(features, define('HAS_CXX11')), + has_numpy(features)] +config = report('config', checks) + +src = module('src', features=features|config.use) +test = module('test', features=features|config.use) +doc = module('doc', features=features|config.use) + +default = src.default diff --git a/include/boost/python.hpp b/include/boost/python.hpp index ae49abaf10..e484034103 100644 --- a/include/boost/python.hpp +++ b/include/boost/python.hpp @@ -42,7 +42,6 @@ # include # include # include -# include # include # include # include @@ -53,6 +52,7 @@ # include # include # include +# include # include # include # include @@ -61,7 +61,9 @@ # include # include # include +# include # include +# include # include # include # include diff --git a/include/boost/python/arg_from_python.hpp b/include/boost/python/arg_from_python.hpp old mode 100755 new mode 100644 index 05611edbbd..983726b065 --- a/include/boost/python/arg_from_python.hpp +++ b/include/boost/python/arg_from_python.hpp @@ -9,7 +9,7 @@ # include # if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) \ || BOOST_WORKAROUND(BOOST_INTEL_WIN, BOOST_TESTED_AT(800)) -# include +# include #endif namespace boost { namespace python { @@ -19,7 +19,7 @@ struct arg_from_python : converter::select_arg_from_python< # if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) \ || BOOST_WORKAROUND(BOOST_INTEL_WIN, BOOST_TESTED_AT(800)) - typename boost::remove_cv::type + typename detail::remove_cv::type # else T # endif @@ -28,7 +28,7 @@ struct arg_from_python typedef typename converter::select_arg_from_python< # if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) \ || BOOST_WORKAROUND(BOOST_INTEL_WIN, BOOST_TESTED_AT(800)) - typename boost::remove_cv::type + typename detail::remove_cv::type # else T # endif diff --git a/include/boost/python/args.hpp b/include/boost/python/args.hpp index 8f8791d76f..27731bd8c9 100644 --- a/include/boost/python/args.hpp +++ b/include/boost/python/args.hpp @@ -11,10 +11,7 @@ # include # include # include - -# include -# include -# include +# include # include # include @@ -102,7 +99,6 @@ namespace detail return this->operator,(python::arg(name)); } -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct is_keywords { @@ -117,40 +113,15 @@ namespace detail template struct is_reference_to_keywords { - BOOST_STATIC_CONSTANT(bool, is_ref = is_reference::value); - typedef typename remove_reference::type deref; - typedef typename remove_cv::type key_t; + BOOST_STATIC_CONSTANT(bool, is_ref = detail::is_reference::value); + typedef typename detail::remove_reference::type deref; + typedef typename detail::remove_cv::type key_t; BOOST_STATIC_CONSTANT(bool, is_key = is_keywords::value); BOOST_STATIC_CONSTANT(bool, value = (is_ref & is_key)); typedef mpl::bool_ type; BOOST_PYTHON_MPL_LAMBDA_SUPPORT(1,is_reference_to_keywords,(T)) }; -# else - typedef char (&yes_keywords_t)[1]; - typedef char (&no_keywords_t)[2]; - - no_keywords_t is_keywords_test(...); - - template - yes_keywords_t is_keywords_test(void (*)(keywords&)); - - template - yes_keywords_t is_keywords_test(void (*)(keywords const&)); - - template - class is_reference_to_keywords - { - public: - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(detail::is_keywords_test( (void (*)(T))0 )) - == sizeof(detail::yes_keywords_t))); - - typedef mpl::bool_ type; - BOOST_PYTHON_MPL_LAMBDA_SUPPORT(1,is_reference_to_keywords,(T)) - }; -# endif } inline detail::keywords<1> args(char const* name) diff --git a/include/boost/python/back_reference.hpp b/include/boost/python/back_reference.hpp index c1daba60c1..e68066f7d5 100644 --- a/include/boost/python/back_reference.hpp +++ b/include/boost/python/back_reference.hpp @@ -29,7 +29,6 @@ struct back_reference T m_value; }; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template class is_back_reference { @@ -44,36 +43,6 @@ class is_back_reference > BOOST_STATIC_CONSTANT(bool, value = true); }; -# else // no partial specialization - -}} // namespace boost::python - -#include - -namespace boost { namespace python { - -namespace detail -{ - typedef char (&yes_back_reference_t)[1]; - typedef char (&no_back_reference_t)[2]; - - no_back_reference_t is_back_reference_test(...); - - template - yes_back_reference_t is_back_reference_test(boost::type< back_reference >); -} - -template -class is_back_reference -{ - public: - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(detail::is_back_reference_test(boost::type())) - == sizeof(detail::yes_back_reference_t))); -}; - -# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // // implementations diff --git a/include/boost/python/base_type_traits.hpp b/include/boost/python/base_type_traits.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/bases.hpp b/include/boost/python/bases.hpp index 0bd7350e55..efcac3f389 100644 --- a/include/boost/python/bases.hpp +++ b/include/boost/python/bases.hpp @@ -6,8 +6,8 @@ # define BASES_DWA2002321_HPP # include -# include # include +# include # include # include # include @@ -24,7 +24,6 @@ namespace boost { namespace python { namespace detail { -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct specifies_bases : mpl::false_ { @@ -35,23 +34,6 @@ namespace boost { namespace python { : mpl::true_ { }; -# else - template < BOOST_PP_ENUM_PARAMS(BOOST_PYTHON_MAX_BASES, class Base) > - static char is_bases_helper(bases< BOOST_PYTHON_BASE_PARAMS > const&); - - static char (& is_bases_helper(...) )[256]; - - template - struct specifies_bases - { - private: - static typename add_reference::type make(); - BOOST_STATIC_CONSTANT(bool, non_ref = !is_reference::value); - public: - BOOST_STATIC_CONSTANT(bool, value = non_ref & (sizeof(is_bases_helper(make())) == 1)); - typedef mpl::bool_ type; - }; -# endif template > struct select_bases : mpl::if_< diff --git a/include/boost/python/borrowed.hpp b/include/boost/python/borrowed.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/call.hpp b/include/boost/python/call.hpp index 5d2d7d2341..c057ee9a12 100644 --- a/include/boost/python/call.hpp +++ b/include/boost/python/call.hpp @@ -60,7 +60,7 @@ call(PyObject* callable ) { PyObject* const result = - PyEval_CallFunction( + PyObject_CallFunction( callable , const_cast("(" BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FIXED, "O") ")") BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FAST_ARG_TO_PYTHON_GET, nil) @@ -69,7 +69,7 @@ call(PyObject* callable // This conversion *must not* be done in the same expression as // the call, because, in the special case where the result is a // reference a Python object which was created by converting a C++ - // argument for passing to PyEval_CallFunction, its reference + // argument for passing to PyObject_CallFunction, its reference // count will be 2 until the end of the full expression containing // the conversion, and that interferes with dangling // pointer/reference detection. diff --git a/include/boost/python/call_method.hpp b/include/boost/python/call_method.hpp index 410f66820e..2f360791d7 100644 --- a/include/boost/python/call_method.hpp +++ b/include/boost/python/call_method.hpp @@ -59,7 +59,7 @@ call_method(PyObject* self, char const* name ) { PyObject* const result = - PyEval_CallMethod( + PyObject_CallMethod( self , const_cast(name) , const_cast("(" BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FIXED, "O") ")") @@ -69,7 +69,7 @@ call_method(PyObject* self, char const* name // This conversion *must not* be done in the same expression as // the call, because, in the special case where the result is a // reference a Python object which was created by converting a C++ - // argument for passing to PyEval_CallFunction, its reference + // argument for passing to PyObject_CallFunction, its reference // count will be 2 until the end of the full expression containing // the conversion, and that interferes with dangling // pointer/reference detection. diff --git a/include/boost/python/cast.hpp b/include/boost/python/cast.hpp old mode 100755 new mode 100644 index 31c61dbf82..c0dd229e84 --- a/include/boost/python/cast.hpp +++ b/include/boost/python/cast.hpp @@ -6,9 +6,8 @@ # define CAST_DWA200269_HPP # include +# include -# include -# include # include # include # include @@ -70,15 +69,15 @@ namespace detail template inline void assert_castable(boost::type* = 0) { - typedef char must_be_a_complete_type[sizeof(T)]; + typedef char must_be_a_complete_type[sizeof(T)] BOOST_ATTRIBUTE_UNUSED; } template inline Target* upcast_impl(Source* x, Target*) { - typedef typename add_cv::type src_t; - typedef typename add_cv::type target_t; - bool const same = is_same::value; + typedef typename detail::add_cv::type src_t; + typedef typename detail::add_cv::type target_t; + bool const same = detail::is_same::value; return detail::upcaster::execute(x, (Target*)0); } diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 253667bbd7..0f1c0fdc1a 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -28,13 +28,10 @@ # include # include # include +# include # include # include -# include -# include -# include - # include # include # include @@ -45,8 +42,7 @@ # if BOOST_WORKAROUND(__MWERKS__, <= 0x3004) \ /* pro9 reintroduced the bug */ \ || (BOOST_WORKAROUND(__MWERKS__, > 0x3100) \ - && BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3201))) \ - || BOOST_WORKAROUND(__GNUC__, < 3) + && BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3201))) # define BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING 1 @@ -54,7 +50,6 @@ # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING # include -# include # endif namespace boost { namespace python { @@ -85,8 +80,8 @@ namespace detail template struct is_data_member_pointer : mpl::and_< - is_member_pointer - , mpl::not_ > + detail::is_member_pointer + , mpl::not_ > > {}; @@ -139,11 +134,11 @@ namespace detail must_be_derived_class_member(Default const&) { // https://svn.boost.org/trac/boost/ticket/5803 - //typedef typename assertion > >::failed test0; + //typedef typename assertion > >::failed test0; # if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407) - typedef typename assertion >::failed test1; + typedef typename assertion >::failed test1 BOOST_ATTRIBUTE_UNUSED; # endif - typedef typename assertion >::failed test2; + typedef typename assertion >::failed test2 BOOST_ATTRIBUTE_UNUSED; not_a_derived_class_member(Fn()); } }; @@ -302,7 +297,6 @@ class class_ : public objects::class_base } // Property creation -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) template self& add_property(char const* name, Get fget, char const* docstr = 0) { @@ -317,47 +311,6 @@ class class_ : public objects::class_base name, this->make_getter(fget), this->make_setter(fset), docstr); return *this; } -# else - private: - template - self& add_property_impl(char const* name, Get fget, char const* docstr, int) - { - base::add_property(name, this->make_getter(fget), docstr); - return *this; - } - - template - self& add_property_impl(char const* name, Get fget, Set fset, ...) - { - base::add_property( - name, this->make_getter(fget), this->make_setter(fset), 0); - return *this; - } - - public: - template - self& add_property(char const* name, Get fget) - { - base::add_property(name, this->make_getter(fget), 0); - return *this; - } - - template - self& add_property(char const* name, Get fget, DocStrOrSet docstr_or_set) - { - this->add_property_impl(name, this->make_getter(fget), docstr_or_set, 0); - return *this; - } - - template - self& - add_property(char const* name, Get fget, Set fset, char const* docstr) - { - base::add_property( - name, this->make_getter(fget), this->make_setter(fset), docstr); - return *this; - } -# endif template self& add_static_property(char const* name, Get fget) @@ -419,10 +372,11 @@ class class_ : public objects::class_base { typedef typename api::is_object_operators::type is_obj_or_proxy; - return this->make_fn_impl( + return objects::add_doc( + this->make_fn_impl( detail::unwrap_wrapper((W*)0) , f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer() - ); + ), NULL); } template @@ -430,10 +384,11 @@ class class_ : public objects::class_base { typedef typename api::is_object_operators::type is_obj_or_proxy; - return this->make_fn_impl( + return objects::add_doc( + this->make_fn_impl( detail::unwrap_wrapper((W*)0) , f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer() - ); + ), NULL); } template diff --git a/include/boost/python/converter/arg_from_python.hpp b/include/boost/python/converter/arg_from_python.hpp old mode 100755 new mode 100644 index e2edce7e1c..0c0daabc1f --- a/include/boost/python/converter/arg_from_python.hpp +++ b/include/boost/python/converter/arg_from_python.hpp @@ -8,8 +8,7 @@ # include # include # include -# include -# include +# include # include # include # include @@ -106,7 +105,7 @@ struct reference_arg_from_python : arg_lvalue_from_python_base template struct arg_rvalue_from_python { - typedef typename boost::add_reference< + typedef typename boost::python::detail::add_lvalue_reference< T // We can't add_const here, or it would be impossible to pass // auto_ptr args from Python to C++ @@ -115,9 +114,9 @@ struct arg_rvalue_from_python arg_rvalue_from_python(PyObject*); bool convertible() const; -# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196 +# if _MSC_FULL_VER > 13102196 typename arg_rvalue_from_python:: -# endif +# endif result_type operator()(); private: diff --git a/include/boost/python/converter/arg_to_python.hpp b/include/boost/python/converter/arg_to_python.hpp old mode 100755 new mode 100644 index 3a19ec4395..bbecae72e5 --- a/include/boost/python/converter/arg_to_python.hpp +++ b/include/boost/python/converter/arg_to_python.hpp @@ -24,11 +24,7 @@ # include # include # include - -# include -# include -# include - +# include # include @@ -116,9 +112,9 @@ namespace detail , typename mpl::if_< mpl::or_< - is_function + boost::python::detail::is_function , indirect_traits::is_pointer_to_function - , is_member_function_pointer + , boost::python::detail::is_member_function_pointer > , function_arg_to_python @@ -127,7 +123,7 @@ namespace detail , object_manager_arg_to_python , typename mpl::if_< - is_pointer + boost::python::detail::is_pointer , pointer_deep_arg_to_python , typename mpl::if_< diff --git a/include/boost/python/converter/arg_to_python_base.hpp b/include/boost/python/converter/arg_to_python_base.hpp old mode 100755 new mode 100644 index d85b302e48..c66ce9c3e0 --- a/include/boost/python/converter/arg_to_python_base.hpp +++ b/include/boost/python/converter/arg_to_python_base.hpp @@ -13,17 +13,9 @@ struct registration; namespace detail { struct BOOST_PYTHON_DECL arg_to_python_base -# if !defined(BOOST_MSVC) || BOOST_MSVC <= 1300 || _MSC_FULL_VER > 13102179 : handle<> -# endif { arg_to_python_base(void const volatile* source, registration const&); -# if defined(BOOST_MSVC) && BOOST_MSVC > 1300 && _MSC_FULL_VER <= 13102179 - PyObject* get() const { return m_ptr.get(); } - PyObject* release() { return m_ptr.release(); } - private: - handle<> m_ptr; -# endif }; } diff --git a/include/boost/python/converter/context_result_converter.hpp b/include/boost/python/converter/context_result_converter.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/converter/obj_mgr_arg_from_python.hpp b/include/boost/python/converter/obj_mgr_arg_from_python.hpp index cd4e1e0ea8..5132804082 100644 --- a/include/boost/python/converter/obj_mgr_arg_from_python.hpp +++ b/include/boost/python/converter/obj_mgr_arg_from_python.hpp @@ -81,9 +81,9 @@ inline object_manager_ref_arg_from_python::object_manager_ref_arg_from_pyth # if defined(__EDG_VERSION__) && __EDG_VERSION__ <= 243 // needed for warning suppression python::detail::borrowed_reference x_ = python::detail::borrowed_reference(x); - python::detail::construct_referent(&m_result.bytes, x_); + python::detail::construct_referent(m_result.bytes, x_); # else - python::detail::construct_referent(&m_result.bytes, (python::detail::borrowed_reference)x); + python::detail::construct_referent(m_result.bytes, (python::detail::borrowed_reference)x); # endif } diff --git a/include/boost/python/converter/object_manager.hpp b/include/boost/python/converter/object_manager.hpp old mode 100755 new mode 100644 index 84e44d475b..b2271a7ea2 --- a/include/boost/python/converter/object_manager.hpp +++ b/include/boost/python/converter/object_manager.hpp @@ -8,7 +8,7 @@ # include # include # include -# include +# include # include # include # include @@ -121,7 +121,6 @@ struct is_object_manager { }; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct is_reference_to_object_manager : mpl::false_ @@ -151,79 +150,6 @@ struct is_reference_to_object_manager : is_object_manager { }; -# else - -namespace detail -{ - typedef char (&yes_reference_to_object_manager)[1]; - typedef char (&no_reference_to_object_manager)[2]; - - // A number of nastinesses go on here in order to work around MSVC6 - // bugs. - template - struct is_object_manager_help - { - typedef typename mpl::if_< - is_object_manager - , yes_reference_to_object_manager - , no_reference_to_object_manager - >::type type; - - // If we just use the type instead of the result of calling this - // function, VC6 will ICE. - static type call(); - }; - - // A set of overloads for each cv-qualification. The same argument - // is passed twice: the first one is used to unwind the cv*, and the - // second one is used to avoid relying on partial ordering for - // overload resolution. - template - typename is_object_manager_help - is_object_manager_helper(U*, void*); - - template - typename is_object_manager_help - is_object_manager_helper(U const*, void const*); - - template - typename is_object_manager_help - is_object_manager_helper(U volatile*, void volatile*); - - template - typename is_object_manager_help - is_object_manager_helper(U const volatile*, void const volatile*); - - template - struct is_reference_to_object_manager_nonref - : mpl::false_ - { - }; - - template - struct is_reference_to_object_manager_ref - { - static T sample_object; - BOOST_STATIC_CONSTANT( - bool, value - = (sizeof(is_object_manager_helper(&sample_object, &sample_object).call()) - == sizeof(detail::yes_reference_to_object_manager) - ) - ); - typedef mpl::bool_ type; - }; -} - -template -struct is_reference_to_object_manager - : mpl::if_< - is_reference - , detail::is_reference_to_object_manager_ref - , detail::is_reference_to_object_manager_nonref - >::type -{ -}; -# endif }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/pointer_type_id.hpp b/include/boost/python/converter/pointer_type_id.hpp index 963f58f717..49eeda42cb 100644 --- a/include/boost/python/converter/pointer_type_id.hpp +++ b/include/boost/python/converter/pointer_type_id.hpp @@ -6,7 +6,7 @@ # define POINTER_TYPE_ID_DWA2002222_HPP # include -# include +# include namespace boost { namespace python { namespace converter { @@ -59,7 +59,7 @@ template type_info pointer_type_id(T(*)() = 0) { return detail::pointer_typeid_select< - is_reference::value + boost::python::detail::is_lvalue_reference::value >::execute((T(*)())0); } diff --git a/include/boost/python/converter/pyobject_type.hpp b/include/boost/python/converter/pyobject_type.hpp index 526f9f9dba..bde39e8057 100644 --- a/include/boost/python/converter/pyobject_type.hpp +++ b/include/boost/python/converter/pyobject_type.hpp @@ -9,8 +9,11 @@ namespace boost { namespace python { namespace converter { -BOOST_PYTHON_DECL PyObject* checked_downcast_impl(PyObject*, PyTypeObject*); - +BOOST_PYTHON_DECL inline +PyObject* checked_downcast_impl(PyObject *obj, PyTypeObject *type) +{ + return (PyType_IsSubtype(Py_TYPE(obj), type) ? obj : NULL); +} // Used as a base class for specializations which need to provide // Python type checking capability. template diff --git a/include/boost/python/converter/pytype_function.hpp b/include/boost/python/converter/pytype_function.hpp old mode 100755 new mode 100644 index 95d0f66d46..d072b55fb3 --- a/include/boost/python/converter/pytype_function.hpp +++ b/include/boost/python/converter/pytype_function.hpp @@ -8,7 +8,8 @@ # include # include # include - +# include +# include namespace boost { namespace python { @@ -45,6 +46,12 @@ inline python::type_info unwind_type_id_(boost::type* = 0, mpl::false_ * =0) return boost::python::detail::unwind_type (); } +template +inline python::type_info unwind_type_id_(boost::type >* = 0, mpl::false_ * =0) +{ + return boost::python::detail::unwind_type (); +} + inline python::type_info unwind_type_id_(boost::type* = 0, mpl::true_* =0) { return type_id(); @@ -53,7 +60,7 @@ inline python::type_info unwind_type_id_(boost::type* = 0, mpl::true_* =0) template inline python::type_info unwind_type_id(boost::type* p= 0) { - return unwind_type_id_(p, (mpl::bool_::value >*)0 ); + return unwind_type_id_(p, (mpl::bool_::value >*)0 ); } } @@ -64,7 +71,7 @@ struct expected_pytype_for_arg static PyTypeObject const *get_pytype() { const converter::registration *r=converter::registry::query( - detail::unwind_type_id_((boost::type*)0, (mpl::bool_::value >*)0 ) + detail::unwind_type_id_((boost::type*)0, (mpl::bool_::value >*)0 ) ); return r ? r->expected_from_python_type(): 0; } @@ -77,7 +84,7 @@ struct registered_pytype static PyTypeObject const *get_pytype() { const converter::registration *r=converter::registry::query( - detail::unwind_type_id_((boost::type*) 0, (mpl::bool_::value >*)0 ) + detail::unwind_type_id_((boost::type*) 0, (mpl::bool_::value >*)0 ) ); return r ? r->m_class_object: 0; } @@ -111,7 +118,7 @@ struct to_python_target_type static PyTypeObject const *get_pytype() { const converter::registration *r=converter::registry::query( - detail::unwind_type_id_((boost::type*)0, (mpl::bool_::value >*)0 ) + detail::unwind_type_id_((boost::type*)0, (mpl::bool_::value >*)0 ) ); return r ? r->to_python_target_type(): 0; } diff --git a/include/boost/python/converter/registered.hpp b/include/boost/python/converter/registered.hpp index 2404cb0ff2..98013052ec 100644 --- a/include/boost/python/converter/registered.hpp +++ b/include/boost/python/converter/registered.hpp @@ -1,18 +1,23 @@ // Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef REGISTERED_DWA2002710_HPP -# define REGISTERED_DWA2002710_HPP -# include -# include -# include -# include -# include -# include -# include -# include -# include + +#ifndef boost_python_converter_registered_hpp_ +#define boost_python_converter_registered_hpp_ + +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_PYTHON_TRACE_REGISTRY) \ + || defined(BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND) +# include +#endif namespace boost { @@ -37,15 +42,14 @@ namespace detail template struct registered : detail::registered_base< - typename add_reference< - typename add_cv::type + typename boost::python::detail::add_lvalue_reference< + typename boost::python::detail::add_cv::type >::type > { }; -# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ - && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1310)) +# if !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1310)) // collapses a few more types to the same static instance. MSVC7.1 // fails to strip cv-qualification from array types in typeid. For // some reason we can't use this collapse there or array converters @@ -71,7 +75,16 @@ namespace detail { registry::lookup_shared_ptr(type_id >()); } - + +#if !defined(BOOST_NO_CXX11_SMART_PTR) + template + inline void + register_shared_ptr0(std::shared_ptr*) + { + registry::lookup_shared_ptr(type_id >()); + } +#endif + template inline void register_shared_ptr1(T const volatile*) @@ -108,4 +121,4 @@ namespace detail }}} // namespace boost::python::converter -#endif // REGISTERED_DWA2002710_HPP +#endif diff --git a/include/boost/python/converter/registered_pointee.hpp b/include/boost/python/converter/registered_pointee.hpp index d9e7ac75a8..28b2988c7f 100644 --- a/include/boost/python/converter/registered_pointee.hpp +++ b/include/boost/python/converter/registered_pointee.hpp @@ -7,56 +7,23 @@ # include # include # include -# include -# include +# include namespace boost { namespace python { namespace converter { struct registration; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct registered_pointee : registered< - typename remove_pointer< - typename remove_cv< - typename remove_reference::type + typename boost::python::detail::remove_pointer< + typename boost::python::detail::remove_cv< + typename boost::python::detail::remove_reference::type >::type >::type > { }; -# else -namespace detail -{ - template - struct registered_pointee_base - { - static registration const& converters; - }; -} - -template -struct registered_pointee - : detail::registered_pointee_base< - typename add_reference< - typename add_cv::type - >::type - > -{ -}; - -// -// implementations -// -namespace detail -{ - template - registration const& registered_pointee_base::converters - = registry::lookup(pointer_type_id()); -} - -# endif }}} // namespace boost::python::converter #endif // REGISTERED_POINTEE_DWA2002710_HPP diff --git a/include/boost/python/converter/return_from_python.hpp b/include/boost/python/converter/return_from_python.hpp old mode 100755 new mode 100644 index 5db9748545..a995a2905a --- a/include/boost/python/converter/return_from_python.hpp +++ b/include/boost/python/converter/return_from_python.hpp @@ -14,7 +14,7 @@ # include # include # include -# include +# include # include # include diff --git a/include/boost/python/converter/rvalue_from_python_data.hpp b/include/boost/python/converter/rvalue_from_python_data.hpp index 471a5255b6..d728681b3e 100644 --- a/include/boost/python/converter/rvalue_from_python_data.hpp +++ b/include/boost/python/converter/rvalue_from_python_data.hpp @@ -8,9 +8,9 @@ # include # include # include +# include +# include # include -# include -# include # include // Data management for potential rvalue conversions from Python to C++ @@ -78,7 +78,7 @@ struct rvalue_from_python_storage // Storage for the result, in case an rvalue must be constructed typename python::detail::referent_storage< - typename add_reference::type + typename boost::python::detail::add_lvalue_reference::type >::type storage; }; @@ -110,7 +110,8 @@ struct rvalue_from_python_data : rvalue_from_python_storage // Destroys any object constructed in the storage. ~rvalue_from_python_data(); private: - typedef typename add_reference::type>::type ref_type; + typedef typename boost::python::detail::add_lvalue_reference< + typename boost::python::detail::add_cv::type>::type ref_type; }; // @@ -132,7 +133,13 @@ template inline rvalue_from_python_data::~rvalue_from_python_data() { if (this->stage1.convertible == this->storage.bytes) - python::detail::destroy_referent(this->storage.bytes); + { + size_t allocated = sizeof(this->storage); + void *ptr = this->storage.bytes; + void *aligned_storage = + ::boost::alignment::align(boost::python::detail::alignment_of::value, 0, ptr, allocated); + python::detail::destroy_referent(aligned_storage); + } } }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/shared_ptr_from_python.hpp b/include/boost/python/converter/shared_ptr_from_python.hpp index c09107765c..b5c62ba940 100644 --- a/include/boost/python/converter/shared_ptr_from_python.hpp +++ b/include/boost/python/converter/shared_ptr_from_python.hpp @@ -1,63 +1,69 @@ // Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef SHARED_PTR_FROM_PYTHON_DWA20021130_HPP -# define SHARED_PTR_FROM_PYTHON_DWA20021130_HPP -# include -# include -# include -# include -# include +#ifndef boost_python_converter_shared_ptr_from_python_hpp_ +#define boost_python_converter_shared_ptr_from_python_hpp_ + +#include +#include +#include +#include +#include #ifndef BOOST_PYTHON_NO_PY_SIGNATURES # include #endif -# include +#include +#include namespace boost { namespace python { namespace converter { -template +template class SP> struct shared_ptr_from_python { - shared_ptr_from_python() - { - converter::registry::insert(&convertible, &construct, type_id >() + shared_ptr_from_python() + { + converter::registry::insert(&convertible, &construct, type_id >() #ifndef BOOST_PYTHON_NO_PY_SIGNATURES - , &converter::expected_from_python_type_direct::get_pytype + , &converter::expected_from_python_type_direct::get_pytype #endif - ); - } + ); + } private: - static void* convertible(PyObject* p) - { - if (p == Py_None) - return p; + static void* convertible(PyObject* p) + { + if (p == Py_None) + return p; - return converter::get_lvalue_from_python(p, registered::converters); - } + return converter::get_lvalue_from_python(p, registered::converters); + } - static void construct(PyObject* source, rvalue_from_python_stage1_data* data) + static void construct(PyObject* source, rvalue_from_python_stage1_data* data) + { + void* const storage = ((converter::rvalue_from_python_storage >*)data)->storage.bytes; + // Deal with the "None" case. + if (data->convertible == source) + new (storage) SP(); + else { - void* const storage = ((converter::rvalue_from_python_storage >*)data)->storage.bytes; - // Deal with the "None" case. - if (data->convertible == source) - new (storage) shared_ptr(); - else - { - boost::shared_ptr hold_convertible_ref_count( - (void*)0, shared_ptr_deleter(handle<>(borrowed(source))) ); - // use aliasing constructor - new (storage) shared_ptr( - hold_convertible_ref_count, - static_cast(data->convertible)); - } - - data->convertible = storage; + void *const storage = ((converter::rvalue_from_python_storage >*)data)->storage.bytes; + // Deal with the "None" case. + if (data->convertible == source) + new (storage) SP(); + else + { + SP hold_convertible_ref_count((void*)0, shared_ptr_deleter(handle<>(borrowed(source))) ); + // use aliasing constructor + new (storage) SP(hold_convertible_ref_count, static_cast(data->convertible)); + } } + data->convertible = storage; + } }; }}} // namespace boost::python::converter -#endif // SHARED_PTR_FROM_PYTHON_DWA20021130_HPP +#endif diff --git a/include/boost/python/converter/shared_ptr_to_python.hpp b/include/boost/python/converter/shared_ptr_to_python.hpp index fe867ace13..02649d406e 100644 --- a/include/boost/python/converter/shared_ptr_to_python.hpp +++ b/include/boost/python/converter/shared_ptr_to_python.hpp @@ -1,14 +1,16 @@ // Copyright David Abrahams 2003. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef SHARED_PTR_TO_PYTHON_DWA2003224_HPP -# define SHARED_PTR_TO_PYTHON_DWA2003224_HPP -# include -# include -# include -# include +#ifndef boost_python_converter_shared_ptr_to_python_hpp_ +#define boost_python_converter_shared_ptr_to_python_hpp_ + +#include +#include +#include +#include namespace boost { namespace python { namespace converter { @@ -23,6 +25,19 @@ PyObject* shared_ptr_to_python(shared_ptr const& x) return converter::registered const&>::converters.to_python(&x); } +#if !defined(BOOST_NO_CXX11_SMART_PTR) +template +PyObject* shared_ptr_to_python(std::shared_ptr const& x) +{ + if (!x) + return python::detail::none(); + else if (shared_ptr_deleter* d = std::get_deleter(x)) + return incref(get_pointer(d->owner)); + else + return converter::registered const&>::converters.to_python(&x); +} +#endif + }}} // namespace boost::python::converter -#endif // SHARED_PTR_TO_PYTHON_DWA2003224_HPP +#endif diff --git a/include/boost/python/copy_const_reference.hpp b/include/boost/python/copy_const_reference.hpp index 19e3b42332..55bede136f 100644 --- a/include/boost/python/copy_const_reference.hpp +++ b/include/boost/python/copy_const_reference.hpp @@ -16,7 +16,7 @@ namespace detail { template struct copy_const_reference_expects_a_const_reference_return_type -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; diff --git a/include/boost/python/copy_non_const_reference.hpp b/include/boost/python/copy_non_const_reference.hpp index 78b70f5d3b..15fef62d67 100644 --- a/include/boost/python/copy_non_const_reference.hpp +++ b/include/boost/python/copy_non_const_reference.hpp @@ -16,7 +16,7 @@ namespace detail { template struct copy_non_const_reference_expects_a_non_const_reference_return_type -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; diff --git a/include/boost/python/data_members.hpp b/include/boost/python/data_members.hpp index b0851fb1b3..989f7d7f93 100644 --- a/include/boost/python/data_members.hpp +++ b/include/boost/python/data_members.hpp @@ -19,14 +19,7 @@ # include # include # include - -# include -# include -# include - -# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) -# include -# endif +# include # include # include @@ -147,20 +140,20 @@ namespace detail // boost::python::make_getter are used to dispatch behavior. The // third argument is a workaround for a CWPro8 partial ordering bug // with pointers to data members. It should be convertible to - // mpl::true_ iff the first argument is a pointer-to-member, and - // mpl::false_ otherwise. The fourth argument is for compilers + // detail::true_ iff the first argument is a pointer-to-member, and + // detail::false_ otherwise. The fourth argument is for compilers // which don't support partial ordering at all and should always be // passed 0L. - // + #if BOOST_WORKAROUND(__EDG_VERSION__, <= 238) template - inline object make_getter(D& d, P& p, mpl::false_, ...); + inline object make_getter(D& d, P& p, detail::false_, ...); #endif // Handle non-member pointers with policies template - inline object make_getter(D* d, Policies const& policies, mpl::false_, int) + inline object make_getter(D* d, Policies const& policies, detail::false_, int) { return python::make_function( detail::datum(d), policies, mpl::vector1() @@ -169,18 +162,18 @@ namespace detail // Handle non-member pointers without policies template - inline object make_getter(D* d, not_specified, mpl::false_, long) + inline object make_getter(D* d, not_specified, detail::false_, long) { typedef typename default_datum_getter_policy::type policies; - return detail::make_getter(d, policies(), mpl::false_(), 0); + return detail::make_getter(d, policies(), detail::false_(), 0); } // Handle pointers-to-members with policies template - inline object make_getter(D C::*pm, Policies const& policies, mpl::true_, int) + inline object make_getter(D C::*pm, Policies const& policies, detail::true_, int) { #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) - typedef typename remove_cv::type Class; + typedef typename detail::remove_cv::type Class; #else typedef C Class; #endif @@ -193,18 +186,18 @@ namespace detail // Handle pointers-to-members without policies template - inline object make_getter(D C::*pm, not_specified, mpl::true_, long) + inline object make_getter(D C::*pm, not_specified, detail::true_, long) { typedef typename default_member_getter_policy::type policies; - return detail::make_getter(pm, policies(), mpl::true_(), 0); + return detail::make_getter(pm, policies(), detail::true_(), 0); } // Handle references template - inline object make_getter(D& d, P& p, mpl::false_, ...) + inline object make_getter(D& d, P& p, detail::false_, ...) { // Just dispatch to the handler for pointer types. - return detail::make_getter(&d, p, mpl::false_(), 0L); + return detail::make_getter(&d, p, detail::false_(), 0L); } // @@ -217,7 +210,7 @@ namespace detail // Handle non-member pointers template - inline object make_setter(D* p, Policies const& policies, mpl::false_, int) + inline object make_setter(D* p, Policies const& policies, detail::false_, int) { return python::make_function( detail::datum(p), policies, mpl::vector2() @@ -226,7 +219,7 @@ namespace detail // Handle pointers-to-members template - inline object make_setter(D C::*pm, Policies const& policies, mpl::true_, int) + inline object make_setter(D C::*pm, Policies const& policies, detail::true_, int) { return python::make_function( detail::member(pm) @@ -237,9 +230,9 @@ namespace detail // Handle references template - inline object make_setter(D& x, Policies const& policies, mpl::false_, ...) + inline object make_setter(D& x, Policies const& policies, detail::false_, ...) { - return detail::make_setter(&x, policies, mpl::false_(), 0L); + return detail::make_setter(&x, policies, detail::false_(), 0L); } } @@ -253,13 +246,13 @@ namespace detail template inline object make_getter(D& d, Policies const& policies) { - return detail::make_getter(d, policies, is_member_pointer(), 0L); + return detail::make_getter(d, policies, detail::is_member_pointer(), 0L); } template inline object make_getter(D const& d, Policies const& policies) { - return detail::make_getter(d, policies, is_member_pointer(), 0L); + return detail::make_getter(d, policies, detail::is_member_pointer(), 0L); } template @@ -267,16 +260,16 @@ inline object make_getter(D& x) { detail::not_specified policy = detail::not_specified(); // suppress a SunPro warning - return detail::make_getter(x, policy, is_member_pointer(), 0L); + return detail::make_getter(x, policy, detail::is_member_pointer(), 0L); } -# if !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +# if !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) template inline object make_getter(D const& d) { detail::not_specified policy = detail::not_specified(); // Suppress a SunPro warning - return detail::make_getter(d, policy, is_member_pointer(), 0L); + return detail::make_getter(d, policy, detail::is_member_pointer(), 0L); } # endif @@ -290,26 +283,26 @@ inline object make_getter(D const& d) template inline object make_setter(D& x, Policies const& policies) { - return detail::make_setter(x, policies, is_member_pointer(), 0); + return detail::make_setter(x, policies, detail::is_member_pointer(), 0); } template inline object make_setter(D const& x, Policies const& policies) { - return detail::make_setter(x, policies, is_member_pointer(), 0); + return detail::make_setter(x, policies, detail::is_member_pointer(), 0); } template inline object make_setter(D& x) { - return detail::make_setter(x, default_call_policies(), is_member_pointer(), 0); + return detail::make_setter(x, default_call_policies(), detail::is_member_pointer(), 0); } -# if !(BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(__EDG_VERSION__, <= 238)) +# if !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) template inline object make_setter(D const& x) { - return detail::make_setter(x, default_call_policies(), is_member_pointer(), 0); + return detail::make_setter(x, default_call_policies(), detail::is_member_pointer(), 0); } # endif diff --git a/include/boost/python/def.hpp b/include/boost/python/def.hpp index 76829b0855..fe2c65f938 100644 --- a/include/boost/python/def.hpp +++ b/include/boost/python/def.hpp @@ -37,7 +37,7 @@ namespace detail // Must not try to use default implementations except with method definitions. typedef typename error::multiple_functions_passed_to_def< Helper::has_default_implementation - >::type assertion; + >::type assertion BOOST_ATTRIBUTE_UNUSED; detail::scope_setattr_doc( name, boost::python::make_function( diff --git a/include/boost/python/def_visitor.hpp b/include/boost/python/def_visitor.hpp old mode 100755 new mode 100644 index 9c8907cd6f..18dd928684 --- a/include/boost/python/def_visitor.hpp +++ b/include/boost/python/def_visitor.hpp @@ -16,7 +16,7 @@ template class class_; class def_visitor_access { # if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) \ - || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + || BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551)) // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. public: @@ -52,7 +52,7 @@ class def_visitor friend class def_visitor_access; # if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) \ - || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + || BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551)) // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. public: diff --git a/include/boost/python/default_call_policies.hpp b/include/boost/python/default_call_policies.hpp index 3d32d2eb49..c882257348 100644 --- a/include/boost/python/default_call_policies.hpp +++ b/include/boost/python/default_call_policies.hpp @@ -8,10 +8,8 @@ # include # include # include +# include # include -# include -# include -# include # include # include @@ -23,7 +21,7 @@ namespace detail { // for "readable" error messages template struct specify_a_return_value_policy_to_wrap_functions_returning -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; @@ -64,7 +62,7 @@ struct default_result_converter struct apply { typedef typename mpl::if_< - mpl::or_, is_reference > + mpl::or_, detail::is_reference > , detail::specify_a_return_value_policy_to_wrap_functions_returning , boost::python::to_python_value< typename detail::value_arg::type diff --git a/include/boost/python/detail/borrowed_ptr.hpp b/include/boost/python/detail/borrowed_ptr.hpp old mode 100755 new mode 100644 index b88457b83a..7d78739ed9 --- a/include/boost/python/detail/borrowed_ptr.hpp +++ b/include/boost/python/detail/borrowed_ptr.hpp @@ -8,8 +8,7 @@ # include # include # include -# include -# include +# include # include namespace boost { namespace python { namespace detail { @@ -19,7 +18,6 @@ template class borrowed typedef T type; }; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct is_borrowed_ptr { @@ -68,35 +66,6 @@ struct is_borrowed_ptr }; # endif -# else // no partial specialization - -typedef char (&yes_borrowed_ptr_t)[1]; -typedef char (&no_borrowed_ptr_t)[2]; - -no_borrowed_ptr_t is_borrowed_ptr_test(...); - -template -typename mpl::if_c< - is_pointer::value - , T - , int - >::type -is_borrowed_ptr_test1(boost::type); - -template -yes_borrowed_ptr_t is_borrowed_ptr_test(borrowed const volatile*); - -template -class is_borrowed_ptr -{ - public: - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(detail::is_borrowed_ptr_test(is_borrowed_ptr_test1(boost::type()))) - == sizeof(detail::yes_borrowed_ptr_t))); -}; - -# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION } diff --git a/include/boost/python/detail/caller.hpp b/include/boost/python/detail/caller.hpp index e479bf427d..2834d6da99 100644 --- a/include/boost/python/detail/caller.hpp +++ b/include/boost/python/detail/caller.hpp @@ -16,6 +16,7 @@ # include # include # include +# include # include # include @@ -31,9 +32,6 @@ # include -# include -# include - # include # include # include @@ -50,7 +48,7 @@ inline PyObject* get(mpl::int_, PyObject* const& args_) return PyTuple_GET_ITEM(args_,N); } -inline unsigned arity(PyObject* const& args_) +inline Py_ssize_t arity(PyObject* const& args_) { return PyTuple_GET_SIZE(args_); } @@ -111,6 +109,23 @@ struct converter_target_type return 0; } }; + +// Generation of ret moved from caller_arity::impl::signature to here due to "feature" in MSVC 15.7.2 with /O2 +// which left the ret uninitialized and caused segfaults in Python interpreter. +template const signature_element* get_ret() +{ + typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type::type rtype; + typedef typename select_result_converter::type result_converter; + + static const signature_element ret = { + (is_void::value ? "void" : type_id().name()) + , &detail::converter_target_type::get_pytype + , boost::detail::indirect_traits::is_reference_to_non_const::value + }; + + return &ret; +} + #endif @@ -231,16 +246,12 @@ struct caller_arity { const signature_element * sig = detail::signature::elements(); #ifndef BOOST_PYTHON_NO_PY_SIGNATURES + // MSVC 15.7.2, when compiling to /O2 left the static const signature_element ret, + // originally defined here, uninitialized. This in turn led to SegFault in Python interpreter. + // Issue is resolved by moving the generation of ret to separate function in detail namespace (see above). + const signature_element * ret = detail::get_ret(); - typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type::type rtype; - typedef typename select_result_converter::type result_converter; - - static const signature_element ret = { - (boost::is_void::value ? "void" : type_id().name()) - , &detail::converter_target_type::get_pytype - , boost::detail::indirect_traits::is_reference_to_non_const::value - }; - py_func_sig_info res = {sig, &ret }; + py_func_sig_info res = {sig, ret }; #else py_func_sig_info res = {sig, sig }; #endif diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 76595ebbfc..e2ac827040 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -29,9 +29,6 @@ # endif # if defined(BOOST_MSVC) -# if _MSC_VER < 1300 -# define BOOST_MSVC6_OR_EARLIER 1 -# endif # pragma warning (disable : 4786) // disable truncated debug symbols # pragma warning (disable : 4251) // disable exported dll function @@ -60,38 +57,31 @@ ****************************************************************************/ // backwards compatibility: -#ifdef BOOST_PYTHON_STATIC_LIB -# define BOOST_PYTHON_STATIC_LINK -# elif !defined(BOOST_PYTHON_DYNAMIC_LIB) -# define BOOST_PYTHON_DYNAMIC_LIB +#if defined(BOOST_PYTHON_STATIC_LINK) && !defined(BOOST_PYTHON_STATIC_LIB) +# define BOOST_PYTHON_STATIC_LIB #endif -#if defined(BOOST_PYTHON_DYNAMIC_LIB) +#if defined(BOOST_PYTHON_DYNAMIC_LINK) && !defined(BOOST_PYTHON_DYNAMIC_LIB) +# define BOOST_PYTHON_DYNAMIC_LIB +#endif -# if !defined(_WIN32) && !defined(__CYGWIN__) \ - && !defined(BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY) \ - && BOOST_WORKAROUND(__GNUC__, >= 3) && (__GNUC_MINOR__ >=5 || __GNUC__ > 3) -# define BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY 1 -# endif +#if !defined(BOOST_PYTHON_STATIC_LIB) && !defined(BOOST_PYTHON_DYNAMIC_LIB) +# define BOOST_PYTHON_DYNAMIC_LIB +#endif -# if BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY -# if defined(BOOST_PYTHON_SOURCE) -# define BOOST_PYTHON_DECL __attribute__ ((__visibility__("default"))) -# define BOOST_PYTHON_BUILD_DLL -# else -# define BOOST_PYTHON_DECL -# endif -# define BOOST_PYTHON_DECL_FORWARD -# define BOOST_PYTHON_DECL_EXCEPTION __attribute__ ((__visibility__("default"))) -# elif (defined(_WIN32) || defined(__CYGWIN__)) +#if defined(BOOST_PYTHON_DYNAMIC_LIB) +# if defined(BOOST_SYMBOL_EXPORT) # if defined(BOOST_PYTHON_SOURCE) -# define BOOST_PYTHON_DECL __declspec(dllexport) +# define BOOST_PYTHON_DECL BOOST_SYMBOL_EXPORT +# define BOOST_PYTHON_DECL_FORWARD BOOST_SYMBOL_FORWARD_EXPORT +# define BOOST_PYTHON_DECL_EXCEPTION BOOST_EXCEPTION_EXPORT # define BOOST_PYTHON_BUILD_DLL # else -# define BOOST_PYTHON_DECL __declspec(dllimport) +# define BOOST_PYTHON_DECL BOOST_SYMBOL_IMPORT +# define BOOST_PYTHON_DECL_FORWARD BOOST_SYMBOL_FORWARD_IMPORT +# define BOOST_PYTHON_DECL_EXCEPTION BOOST_EXCEPTION_IMPORT # endif # endif - #endif #ifndef BOOST_PYTHON_DECL @@ -99,11 +89,11 @@ #endif #ifndef BOOST_PYTHON_DECL_FORWARD -# define BOOST_PYTHON_DECL_FORWARD BOOST_PYTHON_DECL +# define BOOST_PYTHON_DECL_FORWARD #endif #ifndef BOOST_PYTHON_DECL_EXCEPTION -# define BOOST_PYTHON_DECL_EXCEPTION BOOST_PYTHON_DECL +# define BOOST_PYTHON_DECL_EXCEPTION #endif #if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) @@ -121,7 +111,9 @@ // Set the name of our library, this will get undef'ed by auto_link.hpp // once it's done with it: // -#define BOOST_LIB_NAME boost_python +#define _BOOST_PYTHON_CONCAT(N, M, m) N ## M ## m +#define BOOST_PYTHON_CONCAT(N, M, m) _BOOST_PYTHON_CONCAT(N, M, m) +#define BOOST_LIB_NAME BOOST_PYTHON_CONCAT(boost_python, PY_MAJOR_VERSION, PY_MINOR_VERSION) // // If we're importing code from a dll, then tell auto_link.hpp about it: // @@ -134,8 +126,15 @@ #include #endif // auto-linking disabled +#undef BOOST_PYTHON_CONCAT +#undef _BOOST_PYTHON_CONCAT + #ifndef BOOST_PYTHON_NO_PY_SIGNATURES #define BOOST_PYTHON_SUPPORTS_PY_SIGNATURES // enables smooth transition #endif +#if !defined(BOOST_ATTRIBUTE_UNUSED) && defined(__GNUC__) && (__GNUC__ >= 4) +# define BOOST_ATTRIBUTE_UNUSED __attribute__((unused)) +#endif + #endif // CONFIG_DWA052200_H_ diff --git a/include/boost/python/detail/construct.hpp b/include/boost/python/detail/construct.hpp index 5f15d22c6e..e69fbc7538 100644 --- a/include/boost/python/detail/construct.hpp +++ b/include/boost/python/detail/construct.hpp @@ -8,13 +8,7 @@ namespace boost { namespace python { namespace detail { template -void construct_pointee(void* storage, Arg& x -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - , T const volatile* -# else - , T const* -# endif - ) +void construct_pointee(void* storage, Arg& x, T const volatile*) { new (storage) T(x); } diff --git a/include/boost/python/detail/convertible.hpp b/include/boost/python/detail/convertible.hpp old mode 100755 new mode 100644 index 2ce552f5f7..1ff350ec24 --- a/include/boost/python/detail/convertible.hpp +++ b/include/boost/python/detail/convertible.hpp @@ -7,11 +7,11 @@ # if defined(__EDG_VERSION__) && __EDG_VERSION__ <= 241 # include -# include +# include # endif // Supplies a runtime is_convertible check which can be used with tag -// dispatching to work around the Metrowerks Pro7 limitation with boost::is_convertible +// dispatching to work around the Metrowerks Pro7 limitation with boost/std::is_convertible namespace boost { namespace python { namespace detail { typedef char* yes_convertible; diff --git a/include/boost/python/detail/copy_ctor_mutates_rhs.hpp b/include/boost/python/detail/copy_ctor_mutates_rhs.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/cv_category.hpp b/include/boost/python/detail/cv_category.hpp index 1765b36f8c..eb5a8eb9da 100644 --- a/include/boost/python/detail/cv_category.hpp +++ b/include/boost/python/detail/cv_category.hpp @@ -4,7 +4,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #ifndef CV_CATEGORY_DWA200222_HPP # define CV_CATEGORY_DWA200222_HPP -# include +# include namespace boost { namespace python { namespace detail { @@ -12,7 +12,7 @@ template struct cv_tag { BOOST_STATIC_CONSTANT(bool, is_const = is_const_); - BOOST_STATIC_CONSTANT(bool, is_volatile = is_const_); + BOOST_STATIC_CONSTANT(bool, is_volatile = is_volatile_); }; typedef cv_tag cv_unqualified; @@ -26,8 +26,8 @@ struct cv_category // BOOST_STATIC_CONSTANT(bool, c = is_const::value); // BOOST_STATIC_CONSTANT(bool, v = is_volatile::value); typedef cv_tag< - ::boost::is_const::value - , ::boost::is_volatile::value + is_const::value + , is_volatile::value > type; }; diff --git a/include/boost/python/detail/dealloc.hpp b/include/boost/python/detail/dealloc.hpp index f2d914b18c..ce07926ee1 100644 --- a/include/boost/python/detail/dealloc.hpp +++ b/include/boost/python/detail/dealloc.hpp @@ -1,4 +1,4 @@ -// Copyright Gottfried Gan�auge 2003. +// Copyright Gottfried Ganßauge 2003. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/include/boost/python/detail/decorated_type_id.hpp b/include/boost/python/detail/decorated_type_id.hpp index 535508b43d..2596f3104a 100644 --- a/include/boost/python/detail/decorated_type_id.hpp +++ b/include/boost/python/detail/decorated_type_id.hpp @@ -7,7 +7,7 @@ # include # include -# include +# include namespace boost { namespace python { namespace detail { diff --git a/include/boost/python/detail/def_helper.hpp b/include/boost/python/detail/def_helper.hpp index e68ca0cd7b..24f9c5cdb2 100644 --- a/include/boost/python/detail/def_helper.hpp +++ b/include/boost/python/detail/def_helper.hpp @@ -6,13 +6,11 @@ # define DEF_HELPER_DWA200287_HPP # include -# include -# include # include +# include # include # include # include -# include # include # include # include @@ -74,7 +72,8 @@ namespace detail struct tuple_extract_base_select { typedef typename Tuple::head_type head_type; - typedef typename mpl::apply1::type>::type match_t; + typedef typename mpl::apply1::type>::type match_t; BOOST_STATIC_CONSTANT(bool, match = match_t::value); typedef typename tuple_extract_impl::template apply type; }; diff --git a/include/boost/python/detail/def_helper_fwd.hpp b/include/boost/python/detail/def_helper_fwd.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/defaults_def.hpp b/include/boost/python/detail/defaults_def.hpp index 68799f83e6..a721b76794 100644 --- a/include/boost/python/detail/defaults_def.hpp +++ b/include/boost/python/detail/defaults_def.hpp @@ -12,7 +12,7 @@ #define DEFAULTS_DEF_JDG20020811_HPP #include -#include +#include #include #include #include @@ -238,7 +238,7 @@ namespace detail typedef typename OverloadsT::non_void_return_type non_void_return_type; typedef typename mpl::if_c< - boost::is_same::value + is_same::value , void_return_type , non_void_return_type >::type stubs_type; diff --git a/include/boost/python/detail/defaults_gen.hpp b/include/boost/python/detail/defaults_gen.hpp index 0b3e0e2604..88beeedb02 100644 --- a/include/boost/python/detail/defaults_gen.hpp +++ b/include/boost/python/detail/defaults_gen.hpp @@ -213,7 +213,7 @@ namespace detail { \ typedef typename ::boost::python::detail:: \ error::more_keywords_than_function_arguments< \ - N,n_args>::too_many_keywords assertion; \ + N,n_args>::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED; \ } \ template \ fstubs_name(::boost::python::detail::keywords const& keywords, char const* doc = 0) \ @@ -222,7 +222,7 @@ namespace detail { \ typedef typename ::boost::python::detail:: \ error::more_keywords_than_function_arguments< \ - N,n_args>::too_many_keywords assertion; \ + N,n_args>::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED; \ } # if defined(BOOST_NO_VOID_RETURNS) diff --git a/include/boost/python/detail/destroy.hpp b/include/boost/python/detail/destroy.hpp index 0172dca28f..d35b2b536e 100644 --- a/include/boost/python/detail/destroy.hpp +++ b/include/boost/python/detail/destroy.hpp @@ -5,27 +5,14 @@ #ifndef DESTROY_DWA2002221_HPP # define DESTROY_DWA2002221_HPP -# include +# include # include -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) -# include -# endif namespace boost { namespace python { namespace detail { -template < - bool array -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) - , bool enum_ // vc7 has a problem destroying enums -# endif - > struct value_destroyer; +template struct value_destroyer; template <> -struct value_destroyer< - false -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) - , false -# endif - > +struct value_destroyer { template static void execute(T const volatile* p) @@ -35,12 +22,7 @@ struct value_destroyer< }; template <> -struct value_destroyer< - true -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) - , false -# endif - > +struct value_destroyer { template static void execute(A*, T const volatile* const first) @@ -48,10 +30,7 @@ struct value_destroyer< for (T const volatile* p = first; p != first + sizeof(A)/sizeof(T); ++p) { value_destroyer< - boost::is_array::value -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) - , boost::is_enum::value -# endif + is_array::value >::execute(p); } } @@ -63,35 +42,13 @@ struct value_destroyer< } }; -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) -template <> -struct value_destroyer -{ - template - static void execute(T const volatile*) - { - } -}; - -template <> -struct value_destroyer -{ - template - static void execute(T const volatile*) - { - } -}; -# endif template inline void destroy_referent_impl(void* p, T& (*)()) { // note: cv-qualification needed for MSVC6 // must come *before* T for metrowerks value_destroyer< - (boost::is_array::value) -# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) - , (boost::is_enum::value) -# endif + (is_array::value) >::execute((const volatile T*)p); } diff --git a/include/boost/python/detail/enable_if.hpp b/include/boost/python/detail/enable_if.hpp old mode 100755 new mode 100644 index 46a1d532b3..7a37be121a --- a/include/boost/python/detail/enable_if.hpp +++ b/include/boost/python/detail/enable_if.hpp @@ -7,40 +7,7 @@ # include # include -# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) -# include - -namespace boost { namespace python { namespace detail { - -template struct always_void { typedef void type; }; - -template -struct enable_if_arg -{ - typedef typename mpl::if_::type type; -}; - -template -struct disable_if_arg -{ - typedef typename mpl::if_::type type; -}; - -template ::type> -struct enable_if_ret -{ - typedef typename mpl::if_::type type; -}; - -template ::type> -struct disable_if_ret -{ - typedef typename mpl::if_::type type; -}; - -}}} // namespace boost::python::detail - -# elif !defined(BOOST_NO_SFINAE) +#if !defined(BOOST_NO_SFINAE) # include namespace boost { namespace python { namespace detail { diff --git a/include/boost/python/detail/exception_handler.hpp b/include/boost/python/detail/exception_handler.hpp index 7f49868be6..fdc9989836 100644 --- a/include/boost/python/detail/exception_handler.hpp +++ b/include/boost/python/detail/exception_handler.hpp @@ -11,7 +11,7 @@ namespace boost { namespace python { namespace detail { -struct BOOST_PYTHON_DECL_FORWARD exception_handler; +struct exception_handler; typedef function2 const&> handler_function; diff --git a/include/boost/python/detail/force_instantiate.hpp b/include/boost/python/detail/force_instantiate.hpp old mode 100755 new mode 100644 index 63e2874945..a8901b2da7 --- a/include/boost/python/detail/force_instantiate.hpp +++ b/include/boost/python/detail/force_instantiate.hpp @@ -10,23 +10,9 @@ namespace boost { namespace python { namespace detail { // Allows us to force the argument to be instantiated without // incurring unused variable warnings -# if !defined(BOOST_MSVC) || BOOST_MSVC < 1300 || _MSC_FULL_VER > 13102196 - template inline void force_instantiate(T const&) {} -# else - -# pragma optimize("g", off) -inline void force_instantiate_impl(...) {} -# pragma optimize("", on) -template -inline void force_instantiate(T const& x) -{ - detail::force_instantiate_impl(&x); -} -# endif - }}} // namespace boost::python::detail #endif // FORCE_INSTANTIATE_DWA200265_HPP diff --git a/include/boost/python/detail/if_else.hpp b/include/boost/python/detail/if_else.hpp index 244e63a8ae..3f505c5edb 100644 --- a/include/boost/python/detail/if_else.hpp +++ b/include/boost/python/detail/if_else.hpp @@ -25,46 +25,11 @@ struct if_selected }; }; -# if defined(BOOST_MSVC) && (BOOST_MSVC == 1300) -namespace msvc70_aux { - -template< bool > struct inherit_from -{ - template< typename T > struct result - { - typedef T type; - }; -}; - -template<> struct inherit_from -{ - template< typename T > struct result - { - struct type {}; - }; -}; - -template< typename T > -struct never_true -{ - BOOST_STATIC_CONSTANT(bool, value = false); -}; - -} // namespace msvc70_aux - -#endif // # if defined(BOOST_MSVC) && (BOOST_MSVC == 1300) - template struct elif_selected { -# if !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__MWERKS__) && __MWERKS__ <= 0x2407) +# if !(defined(__MWERKS__) && __MWERKS__ <= 0x2407) template class then; -# elif defined(BOOST_MSVC) && (BOOST_MSVC == 1300) - template - struct then : msvc70_aux::inherit_from< msvc70_aux::never_true::value > - ::template result< if_selected >::type - { - }; # else template struct then : if_selected @@ -73,7 +38,7 @@ struct elif_selected # endif }; -# if !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__MWERKS__) && __MWERKS__ <= 0x2407) +# if !(defined(__MWERKS__) && __MWERKS__ <= 0x2407) template template class elif_selected::then : public if_selected diff --git a/include/boost/python/detail/invoke.hpp b/include/boost/python/detail/invoke.hpp index 939fa11818..4c5296ff12 100644 --- a/include/boost/python/detail/invoke.hpp +++ b/include/boost/python/detail/invoke.hpp @@ -11,8 +11,6 @@ # include # include -# include - # include # include # include diff --git a/include/boost/python/detail/is_auto_ptr.hpp b/include/boost/python/detail/is_auto_ptr.hpp index 3b8198b8dd..36affcd215 100644 --- a/include/boost/python/detail/is_auto_ptr.hpp +++ b/include/boost/python/detail/is_auto_ptr.hpp @@ -8,6 +8,8 @@ # ifndef BOOST_NO_AUTO_PTR # include # include +# else +# include # endif namespace boost { namespace python { namespace detail { diff --git a/include/boost/python/detail/is_shared_ptr.hpp b/include/boost/python/detail/is_shared_ptr.hpp old mode 100755 new mode 100644 index 547af3f1cb..383383bc12 --- a/include/boost/python/detail/is_shared_ptr.hpp +++ b/include/boost/python/detail/is_shared_ptr.hpp @@ -1,17 +1,23 @@ // Copyright David Abrahams 2003. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef IS_SHARED_PTR_DWA2003224_HPP -# define IS_SHARED_PTR_DWA2003224_HPP -# include -# include +#ifndef boost_python_detail_is_shared_ptr_hpp_ +#define boost_python_detail_is_shared_ptr_hpp_ + +#include +#include namespace boost { namespace python { namespace detail { BOOST_PYTHON_IS_XXX_DEF(shared_ptr, shared_ptr, 1) - +#if !defined(BOOST_NO_CXX11_SMART_PTR) +template +struct is_shared_ptr > : std::true_type {}; +#endif + }}} // namespace boost::python::detail -#endif // IS_SHARED_PTR_DWA2003224_HPP +#endif diff --git a/include/boost/python/detail/is_wrapper.hpp b/include/boost/python/detail/is_wrapper.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/msvc_typeinfo.hpp b/include/boost/python/detail/msvc_typeinfo.hpp index 10f845058a..bfc84164f0 100644 --- a/include/boost/python/detail/msvc_typeinfo.hpp +++ b/include/boost/python/detail/msvc_typeinfo.hpp @@ -7,15 +7,18 @@ #include #include -#include // -// Fix for MSVC's broken typeid() implementation which doesn't strip +// Fix for icc's broken typeid() implementation which doesn't strip // decoration. This fix doesn't handle cv-qualified array types. It // could probably be done, but I haven't figured it out yet. // -# if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(BOOST_INTEL_CXX_VERSION) && BOOST_INTEL_CXX_VERSION <= 700 +// Note: This file is badly named. It initially was MSVC specific, but was +// extended to cover intel too. Now the old version of MSVC is no longer +// supported, but the intel version is still supported. + +# if defined(BOOST_INTEL_CXX_VERSION) && BOOST_INTEL_CXX_VERSION <= 700 namespace boost { namespace python { namespace detail { @@ -44,8 +47,14 @@ inline typeinfo typeid_ref(type*, ...) return detail::typeid_ref_1((T(*)())0); } +#if defined(BOOST_MSVC) || (defined(__BORLANDC__) && !defined(BOOST_DISABLE_WIN32)) +# define BOOST_PYTT_DECL __cdecl +#else +# define BOOST_PYTT_DECL /**/ +#endif + template< typename T > T&(* is_ref_tester1(type) )(type) { return 0; } -inline char BOOST_TT_DECL is_ref_tester1(...) { return 0; } +inline char BOOST_PYTT_DECL is_ref_tester1(...) { return 0; } template inline typeinfo msvc_typeid(boost::type*) @@ -71,5 +80,5 @@ inline typeinfo assert_array_typeid_compiles() }}} // namespace boost::python::detail -# endif // BOOST_MSVC +# endif // BOOST_INTEL_CXX_VERSION #endif // MSVC_TYPEINFO_DWA200222_HPP diff --git a/include/boost/python/detail/nullary_function_adaptor.hpp b/include/boost/python/detail/nullary_function_adaptor.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/pointee.hpp b/include/boost/python/detail/pointee.hpp index e18c1f49b6..e786b37626 100644 --- a/include/boost/python/detail/pointee.hpp +++ b/include/boost/python/detail/pointee.hpp @@ -5,7 +5,7 @@ #ifndef POINTEE_DWA2002323_HPP # define POINTEE_DWA2002323_HPP -# include +# include namespace boost { namespace python { namespace detail { diff --git a/include/boost/python/detail/prefix.hpp b/include/boost/python/detail/prefix.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/python_type.hpp b/include/boost/python/detail/python_type.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/referent_storage.hpp b/include/boost/python/detail/referent_storage.hpp index 0a1ef5a04e..f646d2ae1d 100644 --- a/include/boost/python/detail/referent_storage.hpp +++ b/include/boost/python/detail/referent_storage.hpp @@ -5,44 +5,25 @@ #ifndef REFERENT_STORAGE_DWA200278_HPP # define REFERENT_STORAGE_DWA200278_HPP # include +# include # include namespace boost { namespace python { namespace detail { -struct alignment_dummy; -typedef void (*function_ptr)(); -typedef int (alignment_dummy::*member_ptr); -typedef int (alignment_dummy::*member_function_ptr)(); - -# define BOOST_PYTHON_ALIGNER(T, n) \ - typename mpl::if_c< \ - sizeof(T) <= size, T, char>::type t##n - -// Storage for size bytes, aligned to all fundamental types no larger than size -template -union aligned_storage +template +struct aligned_storage { - BOOST_PYTHON_ALIGNER(char, 0); - BOOST_PYTHON_ALIGNER(short, 1); - BOOST_PYTHON_ALIGNER(int, 2); - BOOST_PYTHON_ALIGNER(long, 3); - BOOST_PYTHON_ALIGNER(float, 4); - BOOST_PYTHON_ALIGNER(double, 5); - BOOST_PYTHON_ALIGNER(long double, 6); - BOOST_PYTHON_ALIGNER(void*, 7); - BOOST_PYTHON_ALIGNER(function_ptr, 8); - BOOST_PYTHON_ALIGNER(member_ptr, 9); - BOOST_PYTHON_ALIGNER(member_function_ptr, 10); + union type + { + typename ::boost::aligned_storage::type data; char bytes[size]; + }; }; - -# undef BOOST_PYTHON_ALIGNER - + // Compute the size of T's referent. We wouldn't need this at all, // but sizeof() is broken in CodeWarriors <= 8.0 template struct referent_size; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct referent_size @@ -51,24 +32,12 @@ union aligned_storage std::size_t, value = sizeof(T)); }; -# else - - template struct referent_size - { - static T f(); - BOOST_STATIC_CONSTANT(std::size_t, value = sizeof(f())); - }; - -# endif - // A metafunction returning a POD type which can store U, where T == // U&. If T is not a reference type, returns a POD which can store T. template struct referent_storage { - typedef aligned_storage< - ::boost::python::detail::referent_size::value - > type; + typedef typename aligned_storage::value, alignment_of::value>::type type; }; }}} // namespace boost::python::detail diff --git a/include/boost/python/detail/result.hpp b/include/boost/python/detail/result.hpp index 9b8b486423..2390693a88 100644 --- a/include/boost/python/detail/result.hpp +++ b/include/boost/python/detail/result.hpp @@ -11,8 +11,8 @@ # include # include +# include -# include # include # include @@ -43,9 +43,7 @@ namespace boost { namespace python { namespace detail { template boost::type* result(R (T::*), int = 0) { return 0; } -# if (defined(BOOST_MSVC) && _MSC_FULL_VER <= 13102140) \ - || (defined(__GNUC__) && __GNUC__ < 3) \ - || (defined(__MWERKS__) && __MWERKS__ < 0x3000) +# if (defined(__MWERKS__) && __MWERKS__ < 0x3000) // This code actually works on all implementations, but why use it when we don't have to? template struct get_result_type diff --git a/include/boost/python/detail/sfinae.hpp b/include/boost/python/detail/sfinae.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/string_literal.hpp b/include/boost/python/detail/string_literal.hpp index 50193b6436..0961ec7c4e 100644 --- a/include/boost/python/detail/string_literal.hpp +++ b/include/boost/python/detail/string_literal.hpp @@ -7,14 +7,12 @@ # include # include -# include -# include +# include # include # include namespace boost { namespace python { namespace detail { -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct is_string_literal : mpl::false_ { @@ -45,43 +43,6 @@ struct is_string_literal { }; # endif -# else -template -struct string_literal_helper -{ - typedef char (&yes_string_literal)[1]; - typedef char (&no_string_literal)[2]; - - template - struct apply - { - typedef apply self; - static T x; - static yes_string_literal check(char const*); - static no_string_literal check(char*); - static no_string_literal check(void const volatile*); - - BOOST_STATIC_CONSTANT( - bool, value = sizeof(self::check(x)) == sizeof(yes_string_literal)); - typedef mpl::bool_ type; - }; -}; - -template <> -struct string_literal_helper -{ - template - struct apply : mpl::false_ - { - }; -}; - -template -struct is_string_literal - : string_literal_helper::value>::apply -{ -}; -# endif }}} // namespace boost::python::detail diff --git a/include/boost/python/detail/translate_exception.hpp b/include/boost/python/detail/translate_exception.hpp index df7ec2dd6c..877db2b2c6 100644 --- a/include/boost/python/detail/translate_exception.hpp +++ b/include/boost/python/detail/translate_exception.hpp @@ -6,11 +6,9 @@ # define TRANSLATE_EXCEPTION_TDS20091020_HPP # include +# include # include -# include -# include -# include # include @@ -33,7 +31,7 @@ struct translate_exception typename add_const::type >::type exception_non_ref; # else - typedef typename add_reference< + typedef typename add_lvalue_reference< typename add_const::type >::type exception_cref; # endif diff --git a/include/boost/python/detail/type_list.hpp b/include/boost/python/detail/type_list.hpp index 9483c1945c..0ad3f63d84 100644 --- a/include/boost/python/detail/type_list.hpp +++ b/include/boost/python/detail/type_list.hpp @@ -30,10 +30,6 @@ # include # endif -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION # include -# else -# include -# endif #endif // TYPE_LIST_DWA2002913_HPP diff --git a/include/boost/python/detail/type_list_impl_no_pts.hpp b/include/boost/python/detail/type_list_impl_no_pts.hpp deleted file mode 100644 index 15d9252374..0000000000 --- a/include/boost/python/detail/type_list_impl_no_pts.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef BOOST_PP_IS_ITERATING -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -# ifndef TYPE_LIST_IMPL_NO_PTS_DWA2002913_HPP -# define TYPE_LIST_IMPL_NO_PTS_DWA2002913_HPP - -# include - -# include -# include -# include -# include -# include -# include -# include - -namespace boost { namespace python { namespace detail { - -template< typename T > -struct is_list_arg -{ - enum { value = true }; -}; - -template<> -struct is_list_arg -{ - enum { value = false }; -}; - -template struct type_list_impl_chooser; - -# define BOOST_PYTHON_LIST_ACTUAL_PARAMS BOOST_PP_ENUM_PARAMS_Z(1,BOOST_PYTHON_LIST_SIZE,T) -# define BOOST_PYTHON_LIST_FORMAL_PARAMS BOOST_PP_ENUM_PARAMS_Z(1,BOOST_PYTHON_LIST_SIZE,class T) - -# define BOOST_PP_ITERATION_PARAMS_1 \ - (3, (0, BOOST_PYTHON_LIST_SIZE, )) -# include BOOST_PP_ITERATE() - -# define BOOST_PYTHON_PLUS() + -# define BOOST_PYTHON_IS_LIST_ARG(z, n, data) \ - BOOST_PP_IF(n, BOOST_PYTHON_PLUS, BOOST_PP_EMPTY)() \ - is_list_arg< BOOST_PP_CAT(T,n) >::value - -template< - BOOST_PYTHON_LIST_FORMAL_PARAMS - > -struct type_list_count_args -{ - enum { value = - BOOST_PP_REPEAT_1(BOOST_PYTHON_LIST_SIZE, BOOST_PYTHON_IS_LIST_ARG, _) - }; -}; - -template< - BOOST_PYTHON_LIST_FORMAL_PARAMS - > -struct type_list_impl -{ - typedef type_list_count_args< BOOST_PYTHON_LIST_ACTUAL_PARAMS > arg_num_; - typedef typename detail::type_list_impl_chooser< arg_num_::value > - ::template result_< BOOST_PYTHON_LIST_ACTUAL_PARAMS >::type type; -}; - -template< - BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_PYTHON_LIST_SIZE, class T, mpl::void_) - > -struct type_list - : detail::type_list_impl< BOOST_PYTHON_LIST_ACTUAL_PARAMS >::type -{ - typedef typename detail::type_list_impl< - BOOST_PYTHON_LIST_ACTUAL_PARAMS - >::type type; -}; - -# undef BOOST_PYTHON_IS_LIST_ARG -# undef BOOST_PYTHON_PLUS -# undef BOOST_PYTHON_LIST_FORMAL_PARAMS -# undef BOOST_PYTHON_LIST_ACTUAL_PARAMS - -}}} // namespace boost::python::detail - -# endif // TYPE_LIST_IMPL_NO_PTS_DWA2002913_HPP - -#else // BOOST_PP_IS_ITERATING - -# define N BOOST_PP_ITERATION() - -template<> -struct type_list_impl_chooser -{ - template< - BOOST_PYTHON_LIST_FORMAL_PARAMS - > - struct result_ - { - typedef typename BOOST_PP_CAT(mpl::vector,N)< - BOOST_PP_ENUM_PARAMS(N, T) - >::type type; - }; -}; - -# undef N - -#endif // BOOST_PP_IS_ITERATING diff --git a/include/boost/python/detail/type_traits.hpp b/include/boost/python/detail/type_traits.hpp new file mode 100644 index 0000000000..fda54c80f2 --- /dev/null +++ b/include/boost/python/detail/type_traits.hpp @@ -0,0 +1,111 @@ +// Copyright Shreyans Doshi 2017. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PYTHON_DETAIL_TYPE_TRAITS_HPP +# define BOOST_PYTHON_DETAIL_TYPE_TRAITS_HPP + + +#include +#ifdef BOOST_NO_CXX11_HDR_TYPE_TRAITS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +#endif + +# include +# include +# include + + +namespace boost { namespace python { namespace detail { + +#ifdef BOOST_NO_CXX11_HDR_TYPE_TRAITS + using boost::alignment_of; + using boost::add_const; + using boost::add_cv; + using boost::add_lvalue_reference; + using boost::add_pointer; + + using boost::is_array; + using boost::is_class; + using boost::is_const; + using boost::is_convertible; + using boost::is_enum; + using boost::is_function; + using boost::is_integral; + using boost::is_lvalue_reference; + using boost::is_member_function_pointer; + using boost::is_member_pointer; + using boost::is_pointer; + using boost::is_polymorphic; + using boost::is_reference; + using boost::is_same; + using boost::is_scalar; + using boost::is_union; + using boost::is_void; + using boost::is_volatile; + + using boost::remove_reference; + using boost::remove_pointer; + using boost::remove_cv; + using boost::remove_const; + + using boost::mpl::true_; + using boost::mpl::false_; +#else + using std::alignment_of; + using std::add_const; + using std::add_cv; + using std::add_lvalue_reference; + using std::add_pointer; + + using std::is_array; + using std::is_class; + using std::is_const; + using std::is_convertible; + using std::is_enum; + using std::is_function; + using std::is_integral; + using std::is_lvalue_reference; + using std::is_member_function_pointer; + using std::is_member_pointer; + using std::is_pointer; + using std::is_polymorphic; + using std::is_reference; + using std::is_same; + using std::is_scalar; + using std::is_union; + using std::is_void; + using std::is_volatile; + + using std::remove_reference; + using std::remove_pointer; + using std::remove_cv; + using std::remove_const; + + typedef std::integral_constant true_; + typedef std::integral_constant false_; +#endif + using boost::is_base_and_derived; + using boost::type_with_alignment; + using boost::has_trivial_copy; +}}} // namespace boost::python::detail + + +#endif //BOOST_DETAIL_TYPE_TRAITS_HPP diff --git a/include/boost/python/detail/unwind_type.hpp b/include/boost/python/detail/unwind_type.hpp old mode 100755 new mode 100644 index 9a997c9dbd..b81bf7c898 --- a/include/boost/python/detail/unwind_type.hpp +++ b/include/boost/python/detail/unwind_type.hpp @@ -7,17 +7,19 @@ # include # include -# include +# include namespace boost { namespace python { namespace detail { -#ifndef _MSC_VER //if forward declared, msvc6.5 does not recognize them as inline -// forward declaration, required (at least) by Tru64 cxx V6.5-042 +#if (!defined(_MSC_VER) || _MSC_VER >= 1915) +// If forward declared, msvc6.5 does not recognize them as inline. +// However, as of msvc14.15 (_MSC_VER 1915/Visual Studio 15.8.0) name lookup is now consistent with other compilers. +// forward declaration, required (at least) by Tru64 cxx V6.5-042 and msvc14.15 template inline typename Generator::result_type unwind_type(U const& p, Generator* = 0); -// forward declaration, required (at least) by Tru64 cxx V6.5-042 +// forward declaration, required (at least) by Tru64 cxx V6.5-042 and msvc14.15 template inline typename Generator::result_type unwind_type(boost::type*p = 0, Generator* = 0); @@ -83,7 +85,7 @@ struct unwind_helper template inline typename Generator::result_type -#ifndef _MSC_VER +#if (!defined(_MSC_VER) || _MSC_VER >= 1915) unwind_type(U const& p, Generator*) #else unwind_type(U const& p, Generator* = 0) @@ -148,17 +150,17 @@ struct unwind_helper2 // why bother? template inline typename Generator::result_type -#ifndef _MSC_VER +#if (!defined(_MSC_VER) || _MSC_VER >= 1915) unwind_type(boost::type*, Generator*) #else unwind_type(boost::type*p =0, Generator* =0) #endif { BOOST_STATIC_CONSTANT(int, indirection - = (boost::is_pointer::value ? pointer_ : 0) + = (is_pointer::value ? pointer_ : 0) + (indirect_traits::is_reference_to_pointer::value ? reference_to_pointer_ - : boost::is_reference::value + : is_lvalue_reference::value ? reference_ : 0)); diff --git a/include/boost/python/detail/unwrap_type_id.hpp b/include/boost/python/detail/unwrap_type_id.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/unwrap_wrapper.hpp b/include/boost/python/detail/unwrap_wrapper.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/detail/value_arg.hpp b/include/boost/python/detail/value_arg.hpp old mode 100755 new mode 100644 index 747588d6fd..2c938dacca --- a/include/boost/python/detail/value_arg.hpp +++ b/include/boost/python/detail/value_arg.hpp @@ -6,8 +6,7 @@ # include # include -# include -# include +# include namespace boost { namespace python { namespace detail { @@ -16,7 +15,7 @@ struct value_arg : mpl::if_< copy_ctor_mutates_rhs , T - , typename add_reference< + , typename add_lvalue_reference< typename add_const::type >::type > diff --git a/include/boost/python/detail/value_is_shared_ptr.hpp b/include/boost/python/detail/value_is_shared_ptr.hpp index 361c369b5b..53e687f016 100644 --- a/include/boost/python/detail/value_is_shared_ptr.hpp +++ b/include/boost/python/detail/value_is_shared_ptr.hpp @@ -1,17 +1,28 @@ // Copyright David Abrahams 2003. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef VALUE_IS_SHARED_PTR_DWA2003224_HPP -# define VALUE_IS_SHARED_PTR_DWA2003224_HPP -# include -# include +#ifndef boost_python_detail_value_is_shared_ptr_hpp_ +#define boost_python_detail_value_is_shared_ptr_hpp_ + +#include +#include namespace boost { namespace python { namespace detail { -BOOST_PYTHON_VALUE_IS_XXX_DEF(shared_ptr, shared_ptr, 1) - +template +struct value_is_shared_ptr +{ + static bool const value = is_shared_ptr + ::type> + ::type> + ::value; + typedef mpl::bool_ type; +}; + }}} // namespace boost::python::detail #endif // VALUE_IS_SHARED_PTR_DWA2003224_HPP diff --git a/include/boost/python/detail/value_is_xxx.hpp b/include/boost/python/detail/value_is_xxx.hpp index 2b12564907..e270f89ca3 100644 --- a/include/boost/python/detail/value_is_xxx.hpp +++ b/include/boost/python/detail/value_is_xxx.hpp @@ -9,40 +9,11 @@ # include # include -# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -# include -# include - -# define BOOST_PYTHON_VALUE_IS_XXX_DEF(name, qualified_name, nargs) \ -template \ -struct value_is_##name \ -{ \ - typedef char yes; \ - typedef char (&no)[2]; \ - \ - static typename add_reference::type dummy; \ - \ - template < BOOST_PP_ENUM_PARAMS_Z(1, nargs, class U) > \ - static yes test( \ - qualified_name< BOOST_PP_ENUM_PARAMS_Z(1, nargs, U) > const&, int \ - ); \ - \ - template \ - static no test(U&, ...); \ - \ - BOOST_STATIC_CONSTANT( \ - bool, value \ - = (sizeof(test(dummy, 0)) == sizeof(yes))); \ - \ - typedef mpl::bool_ type; \ -}; - -# else - -# include -# include +# include # include +namespace boost { namespace python { namespace detail { + # define BOOST_PYTHON_VALUE_IS_XXX_DEF(name, qualified_name, nargs) \ template \ struct value_is_##name \ @@ -53,10 +24,10 @@ struct value_is_##name \ typename remove_reference::type \ >::type \ >::value); \ - typedef mpl::bool_ type; \ + typedef mpl::bool_ type; \ \ }; -# endif +}}} // namespace boost::python::detail #endif // VALUE_IS_XXX_DWA2003224_HPP diff --git a/include/boost/python/detail/void_ptr.hpp b/include/boost/python/detail/void_ptr.hpp index 06f680104d..5543b23a4a 100644 --- a/include/boost/python/detail/void_ptr.hpp +++ b/include/boost/python/detail/void_ptr.hpp @@ -5,7 +5,7 @@ #ifndef VOID_PTR_DWA200239_HPP # define VOID_PTR_DWA200239_HPP -# include +# include namespace boost { namespace python { namespace detail { diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index eaef7841d5..037e4bf2ec 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -47,6 +47,13 @@ # endif #endif +// pyconfig.h defines a macro with hypot name, what breaks libstdc++ math headers +// that Python.h tries to include afterwards. +#if defined(__MINGW32__) +# include +# include +#endif + # include # if defined(_SGI_COMPILER_VERSION) && _SGI_COMPILER_VERSION >= 740 # undef _POSIX_C_SOURCE @@ -83,15 +90,25 @@ // than MSVC on Win32 // #if defined(_WIN32) || defined(__CYGWIN__) + # if defined(__GNUC__) && defined(__CYGWIN__) -# define SIZEOF_LONG 4 +# if defined(__LP64__) +# define SIZEOF_LONG 8 +# else +# define SIZEOF_LONG 4 +# endif + # if PY_MAJOR_VERSION < 2 || PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION <= 2 typedef int pid_t; -# define WORD_BIT 32 +# if defined(__LP64__) +# define WORD_BIT 64 +# else +# define WORD_BIT 32 +# endif # define hypot _hypot # include @@ -129,19 +146,45 @@ typedef int pid_t; # undef hypot // undo the evil #define left by Python. -# elif defined(__BORLANDC__) +# elif defined(__BORLANDC__) && !defined(__clang__) # undef HAVE_HYPOT # define HAVE_HYPOT 1 # endif #endif // _WIN32 +#if defined(__GNUC__) +# if defined(__has_warning) +# define BOOST_PYTHON_GCC_HAS_WREGISTER __has_warning("-Wregister") +# else +# define BOOST_PYTHON_GCC_HAS_WREGISTER __GNUC__ >= 7 +# endif +#else +# define BOOST_PYTHON_GCC_HAS_WREGISTER 0 +#endif + +// Python.h header uses `register` keyword until Python 3.4 +#if BOOST_PYTHON_GCC_HAS_WREGISTER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wregister" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 5033) // 'register' is no longer a supported storage class +#endif + #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 2 && PY_MICRO_VERSION < 2 # include #else # include #endif +#if BOOST_PYTHON_GCC_HAS_WREGISTER +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif +#undef BOOST_PYTHON_GCC_HAS_WREGISTER + #ifdef BOOST_PYTHON_ULONG_MAX_UNDEFINED # undef ULONG_MAX # undef BOOST_PYTHON_ULONG_MAX_UNDEFINED @@ -184,7 +227,11 @@ typedef int pid_t; # define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, +#endif +#if PY_VERSION_HEX < 0x030900A4 +# define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0) +# define Py_SET_SIZE(obj, size) ((Py_SIZE(obj) = (size)), (void)0) #endif diff --git a/include/boost/python/detail/wrapper_base.hpp b/include/boost/python/detail/wrapper_base.hpp old mode 100755 new mode 100644 index e5b93aa449..60ac99436e --- a/include/boost/python/detail/wrapper_base.hpp +++ b/include/boost/python/detail/wrapper_base.hpp @@ -5,8 +5,7 @@ # define WRAPPER_BASE_DWA2004722_HPP # include -# include -# include +# include namespace boost { namespace python { @@ -14,21 +13,21 @@ class override; namespace detail { - class BOOST_PYTHON_DECL_FORWARD wrapper_base; + class wrapper_base; namespace wrapper_base_ // ADL disabler { inline PyObject* get_owner(wrapper_base const volatile& w); inline PyObject* - owner_impl(void const volatile* /*x*/, mpl::false_) + owner_impl(void const volatile* /*x*/, detail::false_) { return 0; } template inline PyObject* - owner_impl(T const volatile* x, mpl::true_); + owner_impl(T const volatile* x, detail::true_); template inline PyObject* @@ -59,7 +58,7 @@ namespace detail { template inline PyObject* - owner_impl(T const volatile* x, mpl::true_) + owner_impl(T const volatile* x, detail::true_) { if (wrapper_base const volatile* w = dynamic_cast(x)) { diff --git a/include/boost/python/docstring_options.hpp b/include/boost/python/docstring_options.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/errors.hpp b/include/boost/python/errors.hpp index 72960d9ea2..1eec6c2fe6 100644 --- a/include/boost/python/errors.hpp +++ b/include/boost/python/errors.hpp @@ -14,7 +14,7 @@ namespace boost { namespace python { -struct BOOST_PYTHON_DECL_EXCEPTION error_already_set +struct BOOST_PYTHON_DECL error_already_set { virtual ~error_already_set(); }; diff --git a/include/boost/python/exception_translator.hpp b/include/boost/python/exception_translator.hpp index eb72da62a1..1aa1465bdf 100644 --- a/include/boost/python/exception_translator.hpp +++ b/include/boost/python/exception_translator.hpp @@ -7,7 +7,8 @@ # include -# include +# include +# include # include # include # include @@ -17,6 +18,7 @@ namespace boost { namespace python { template void register_exception_translator(Translate translate, boost::type* = 0) { + using namespace boost::placeholders; detail::register_exception_handler( boost::bind(detail::translate_exception(), _1, _2, translate) ); diff --git a/include/boost/python/exec.hpp b/include/boost/python/exec.hpp index 3ed1e15ce9..32a74991a7 100644 --- a/include/boost/python/exec.hpp +++ b/include/boost/python/exec.hpp @@ -20,6 +20,10 @@ object BOOST_PYTHON_DECL eval(str string, object global = object(), object local = object()); +object +BOOST_PYTHON_DECL +eval(char const *string, object global = object(), object local = object()); + // Execute an individual python statement from str. // global and local are the global and local scopes respectively, // used during execution. @@ -27,6 +31,10 @@ object BOOST_PYTHON_DECL exec_statement(str string, object global = object(), object local = object()); +object +BOOST_PYTHON_DECL +exec_statement(char const *string, object global = object(), object local = object()); + // Execute python source code from str. // global and local are the global and local scopes respectively, // used during execution. @@ -34,6 +42,10 @@ object BOOST_PYTHON_DECL exec(str string, object global = object(), object local = object()); +object +BOOST_PYTHON_DECL +exec(char const *string, object global = object(), object local = object()); + // Execute python source code from file filename. // global and local are the global and local scopes respectively, // used during execution. @@ -41,6 +53,10 @@ object BOOST_PYTHON_DECL exec_file(str filename, object global = object(), object local = object()); +object +BOOST_PYTHON_DECL +exec_file(char const *filename, object global = object(), object local = object()); + } } diff --git a/include/boost/python/extract.hpp b/include/boost/python/extract.hpp index 544c61f070..bfdeb83ce7 100644 --- a/include/boost/python/extract.hpp +++ b/include/boost/python/extract.hpp @@ -21,8 +21,7 @@ # include # include -#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(BOOST_INTEL_WIN, <= 900) -// workaround for VC++ 6.x or 7.0 +#if BOOST_WORKAROUND(BOOST_INTEL_WIN, <= 900) # define BOOST_EXTRACT_WORKAROUND () #else # define BOOST_EXTRACT_WORKAROUND diff --git a/include/boost/python/handle.hpp b/include/boost/python/handle.hpp old mode 100755 new mode 100644 index 461a219ad8..ee9a7cd09d --- a/include/boost/python/handle.hpp +++ b/include/boost/python/handle.hpp @@ -87,8 +87,6 @@ class handle return *this; } -#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300) - template handle& operator=(handle const & r) // never throws { @@ -97,8 +95,6 @@ class handle return *this; } -#endif - template handle(handle const& r) : m_p(python::xincref(python::upcast(r.get()))) @@ -159,7 +155,6 @@ typedef handle type_handle; // // Compile-time introspection // -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template class is_handle { @@ -173,28 +168,6 @@ class is_handle > public: BOOST_STATIC_CONSTANT(bool, value = true); }; -# else -namespace detail -{ - typedef char (&yes_handle_t)[1]; - typedef char (&no_handle_t)[2]; - - no_handle_t is_handle_test(...); - - template - yes_handle_t is_handle_test(boost::type< handle >); -} - -template -class is_handle -{ - public: - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(detail::is_handle_test(boost::type())) - == sizeof(detail::yes_handle_t))); -}; -# endif // // implementations diff --git a/include/boost/python/handle_fwd.hpp b/include/boost/python/handle_fwd.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/init.hpp b/include/boost/python/init.hpp index 6598fd3547..0ee763cc26 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -68,7 +68,7 @@ namespace detail template struct more_keywords_than_init_arguments { - typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1]; + typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1] BOOST_ATTRIBUTE_UNUSED; }; } @@ -76,27 +76,6 @@ namespace detail // // This metaprogram checks if T is an optional // -#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - - template - struct is_optional { - - private: - - template - static boost::type_traits::yes_type f(optional); - static boost::type_traits::no_type f(...); - static T t(); - - public: - - BOOST_STATIC_CONSTANT( - bool, value = - sizeof(f(t())) == sizeof(::boost::type_traits::yes_type)); - typedef mpl::bool_ type; - }; - -#else template struct is_optional @@ -108,7 +87,6 @@ namespace detail : mpl::true_ {}; -#endif template struct define_class_init_helper; @@ -246,7 +224,7 @@ class init : public init_base > { typedef typename detail::error::more_keywords_than_init_arguments< N, n_arguments::value + 1 - >::too_many_keywords assertion; + >::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED; } template @@ -255,7 +233,7 @@ class init : public init_base > { typedef typename detail::error::more_keywords_than_init_arguments< N, n_arguments::value + 1 - >::too_many_keywords assertion; + >::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED; } template diff --git a/include/boost/python/instance_holder.hpp b/include/boost/python/instance_holder.hpp index 933f50d1a1..f4ed1e6608 100644 --- a/include/boost/python/instance_holder.hpp +++ b/include/boost/python/instance_holder.hpp @@ -38,7 +38,7 @@ struct BOOST_PYTHON_DECL instance_holder : private noncopyable // Allocate storage for an object of the given size at the given // offset in the Python instance<> object if bytes are available // there. Otherwise allocate size bytes of heap memory. - static void* allocate(PyObject*, std::size_t offset, std::size_t size); + static void* allocate(PyObject*, std::size_t offset, std::size_t size, std::size_t alignment = 1); // Deallocate storage from the heap if it was not carved out of // the given Python object by allocate(), above. diff --git a/include/boost/python/iterator.hpp b/include/boost/python/iterator.hpp index a64a920735..b0ea578959 100644 --- a/include/boost/python/iterator.hpp +++ b/include/boost/python/iterator.hpp @@ -8,12 +8,10 @@ # include # include +# include # include # include -# include -# include - # if defined(BOOST_MSVC) && (BOOST_MSVC == 1400) /* > warning C4180: qualifier applied to function type has no meaning; ignored Peter Dimov wrote: @@ -24,7 +22,7 @@ works correctly. */ # pragma warning(disable: 4180) # endif -# include +# include # include namespace boost { namespace python { @@ -42,6 +40,7 @@ namespace detail , Target&(*)() ) { + using namespace boost::placeholders; return objects::make_iterator_function( boost::protect(boost::bind(get_start, _1)) , boost::protect(boost::bind(get_finish, _1)) @@ -80,7 +79,7 @@ namespace detail template struct iterators : detail::iterators_impl< - boost::is_const::value + detail::is_const::value >::template apply { }; diff --git a/include/boost/python/list.hpp b/include/boost/python/list.hpp index 10fd40fda5..0d5e2c8fd9 100644 --- a/include/boost/python/list.hpp +++ b/include/boost/python/list.hpp @@ -73,7 +73,7 @@ class list : public detail::list_base } template - long count(T const& value) const + ssize_t count(T const& value) const { return base::count(object(value)); } diff --git a/include/boost/python/long.hpp b/include/boost/python/long.hpp index 129c61f9e4..c15604c91c 100644 --- a/include/boost/python/long.hpp +++ b/include/boost/python/long.hpp @@ -24,8 +24,8 @@ namespace detail BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(long_base, object) private: - static detail::new_non_null_reference call(object const&); - static detail::new_non_null_reference call(object const&, object const&); + static detail::new_reference call(object const&); + static detail::new_reference call(object const&, object const&); }; } diff --git a/include/boost/python/lvalue_from_pytype.hpp b/include/boost/python/lvalue_from_pytype.hpp index e15dfbbb85..59d31b89cf 100644 --- a/include/boost/python/lvalue_from_pytype.hpp +++ b/include/boost/python/lvalue_from_pytype.hpp @@ -13,6 +13,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -35,7 +36,7 @@ namespace detail { static inline void* execute(PyObject* op) { - typedef typename boost::add_reference::type param; + typedef typename add_lvalue_reference::type param; return &Extractor::execute( boost::python::detail::void_ptr_to_reference( op, (param(*)())0 ) diff --git a/include/boost/python/make_constructor.hpp b/include/boost/python/make_constructor.hpp index 8ae722bbe3..3769970cad 100644 --- a/include/boost/python/make_constructor.hpp +++ b/include/boost/python/make_constructor.hpp @@ -43,22 +43,32 @@ namespace detail private: template - void dispatch(U* x, mpl::true_) const + void dispatch(U* x, detail::true_) const { - std::auto_ptr owner(x); - dispatch(owner, mpl::false_()); +#if defined(BOOST_NO_CXX11_SMART_PTR) + std::auto_ptr owner(x); + dispatch(owner, detail::false_()); +#else + std::unique_ptr owner(x); + dispatch(std::move(owner), detail::false_()); +#endif } template - void dispatch(Ptr x, mpl::false_) const + void dispatch(Ptr x, detail::false_) const { typedef typename pointee::type value_type; typedef objects::pointer_holder holder; typedef objects::instance instance_t; - void* memory = holder::allocate(this->m_self, offsetof(instance_t, storage), sizeof(holder)); + void* memory = holder::allocate(this->m_self, offsetof(instance_t, storage), sizeof(holder), + boost::python::detail::alignment_of::value); try { +#if defined(BOOST_NO_CXX11_SMART_PTR) (new (memory) holder(x))->install(this->m_self); +#else + (new (memory) holder(std::move(x)))->install(this->m_self); +#endif } catch(...) { holder::deallocate(this->m_self, memory); @@ -104,14 +114,6 @@ namespace detail // If the BasePolicy_ supplied a result converter it would be // ignored; issue an error if it's not the default. -#if defined _MSC_VER && _MSC_VER < 1300 - typedef is_same< - typename BasePolicy_::result_converter - , default_result_converter - > same_result_converter; - //see above for explanation - BOOST_STATIC_ASSERT(same_result_converter::value) ; -#else BOOST_MPL_ASSERT_MSG( (is_same< typename BasePolicy_::result_converter @@ -120,7 +122,6 @@ namespace detail , MAKE_CONSTRUCTOR_SUPPLIES_ITS_OWN_RESULT_CONVERTER_THAT_WOULD_OVERRIDE_YOURS , (typename BasePolicy_::result_converter) ); -#endif typedef constructor_result_converter result_converter; typedef offset_args > argument_package; }; @@ -183,7 +184,7 @@ namespace detail typedef typename detail::error::more_keywords_than_function_arguments< NumKeywords::value, arity - >::too_many_keywords assertion; + >::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED; typedef typename outer_constructor_signature::type outer_signature; diff --git a/include/boost/python/make_function.hpp b/include/boost/python/make_function.hpp index f2f2a9e545..7dd7c316b3 100644 --- a/include/boost/python/make_function.hpp +++ b/include/boost/python/make_function.hpp @@ -55,7 +55,7 @@ namespace detail typedef typename detail::error::more_keywords_than_function_arguments< NumKeywords::value, arity - >::too_many_keywords assertion; + >::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED; return objects::function_object( detail::caller(f, p) diff --git a/include/boost/python/manage_new_object.hpp b/include/boost/python/manage_new_object.hpp index d81421dace..9ff341c1ac 100644 --- a/include/boost/python/manage_new_object.hpp +++ b/include/boost/python/manage_new_object.hpp @@ -7,9 +7,9 @@ # include # include +# include # include # include -# include namespace boost { namespace python { @@ -17,7 +17,7 @@ namespace detail { template struct manage_new_object_requires_a_pointer_return_type -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; @@ -29,7 +29,7 @@ struct manage_new_object struct apply { typedef typename mpl::if_c< - boost::is_pointer::value + detail::is_pointer::value , to_python_indirect , detail::manage_new_object_requires_a_pointer_return_type >::type type; diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index a9536c88ee..7fe5a1c8a2 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -66,25 +66,9 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); # endif -# if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(BOOST_PYTHON_STATIC_MODULE) - -# define BOOST_PYTHON_MODULE_INIT(name) \ - void BOOST_PP_CAT(init_module_,name)(); \ -extern "C" __declspec(dllexport) _BOOST_PYTHON_MODULE_INIT(name) - -# elif BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY - -# define BOOST_PYTHON_MODULE_INIT(name) \ - void BOOST_PP_CAT(init_module_,name)(); \ -extern "C" __attribute__ ((__visibility__("default"))) _BOOST_PYTHON_MODULE_INIT(name) - -# else - -# define BOOST_PYTHON_MODULE_INIT(name) \ - void BOOST_PP_CAT(init_module_,name)(); \ -extern "C" _BOOST_PYTHON_MODULE_INIT(name) - -# endif +# define BOOST_PYTHON_MODULE_INIT(name) \ + void BOOST_PP_CAT(init_module_,name)(); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) # endif diff --git a/include/boost/python/numeric.hpp b/include/boost/python/numeric.hpp deleted file mode 100644 index ab4db8c32e..0000000000 --- a/include/boost/python/numeric.hpp +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef NUMARRAY_DWA2002922_HPP -# define NUMARRAY_DWA2002922_HPP - -# include - -# include -# include -# include -# include -# include -# include -# include - -namespace boost { namespace python { namespace numeric { - -class array; - -namespace aux -{ - struct BOOST_PYTHON_DECL array_base : object - { -# define BOOST_PP_LOCAL_MACRO(n) \ - array_base(BOOST_PP_ENUM_PARAMS_Z(1, n, object const& x)); -# define BOOST_PP_LOCAL_LIMITS (1, 7) -# include BOOST_PP_LOCAL_ITERATE() - - object argmax(long axis=-1); - object argmin(long axis=-1); - object argsort(long axis=-1); - object astype(object const& type = object()); - void byteswap(); - object copy() const; - object diagonal(long offset = 0, long axis1 = 0, long axis2 = 1) const; - void info() const; - bool is_c_array() const; - bool isbyteswapped() const; - array new_(object type) const; - void sort(); - object trace(long offset = 0, long axis1 = 0, long axis2 = 1) const; - object type() const; - char typecode() const; - - object factory( - object const& sequence = object() - , object const& typecode = object() - , bool copy = true - , bool savespace = false - , object type = object() - , object shape = object()); - - object getflat() const; - long getrank() const; - object getshape() const; - bool isaligned() const; - bool iscontiguous() const; - long itemsize() const; - long nelements() const; - object nonzero() const; - - void put(object const& indices, object const& values); - - void ravel(); - - object repeat(object const& repeats, long axis=0); - - void resize(object const& shape); - - void setflat(object const& flat); - void setshape(object const& shape); - - void swapaxes(long axis1, long axis2); - - object take(object const& sequence, long axis = 0) const; - - void tofile(object const& file) const; - - str tostring() const; - - void transpose(object const& axes = object()); - - object view() const; - - public: // implementation detail - do not touch. - BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(array_base, object); - }; - - struct BOOST_PYTHON_DECL array_object_manager_traits - { - static bool check(PyObject* obj); - static detail::new_non_null_reference adopt(PyObject* obj); - static PyTypeObject const* get_pytype() ; - }; -} // namespace aux - -class array : public aux::array_base -{ - typedef aux::array_base base; - public: - - object astype() { return base::astype(); } - - template - object astype(Type const& type_) - { - return base::astype(object(type_)); - } - - template - array new_(Type const& type_) const - { - return base::new_(object(type_)); - } - - template - void resize(Sequence const& x) - { - base::resize(object(x)); - } - -# define BOOST_PP_LOCAL_MACRO(n) \ - void resize(BOOST_PP_ENUM_PARAMS_Z(1, n, long x)) \ - { \ - resize(make_tuple(BOOST_PP_ENUM_PARAMS_Z(1, n, x))); \ - } -# define BOOST_PP_LOCAL_LIMITS (1, BOOST_PYTHON_MAX_ARITY) -# include BOOST_PP_LOCAL_ITERATE() - - template - void setshape(Sequence const& x) - { - base::setshape(object(x)); - } - -# define BOOST_PP_LOCAL_MACRO(n) \ - void setshape(BOOST_PP_ENUM_PARAMS_Z(1, n, long x)) \ - { \ - setshape(make_tuple(BOOST_PP_ENUM_PARAMS_Z(1, n, x))); \ - } -# define BOOST_PP_LOCAL_LIMITS (1, BOOST_PYTHON_MAX_ARITY) -# include BOOST_PP_LOCAL_ITERATE() - - template - void put(Indices const& indices, Values const& values) - { - base::put(object(indices), object(values)); - } - - template - object take(Sequence const& sequence, long axis = 0) - { - return base::take(object(sequence), axis); - } - - template - void tofile(File const& f) const - { - base::tofile(object(f)); - } - - object factory() - { - return base::factory(); - } - - template - object factory(Sequence const& sequence) - { - return base::factory(object(sequence)); - } - - template - object factory( - Sequence const& sequence - , Typecode const& typecode_ - , bool copy = true - , bool savespace = false - ) - { - return base::factory(object(sequence), object(typecode_), copy, savespace); - } - - template - object factory( - Sequence const& sequence - , Typecode const& typecode_ - , bool copy - , bool savespace - , Type const& type - ) - { - return base::factory(object(sequence), object(typecode_), copy, savespace, object(type)); - } - - template - object factory( - Sequence const& sequence - , Typecode const& typecode_ - , bool copy - , bool savespace - , Type const& type - , Shape const& shape - ) - { - return base::factory(object(sequence), object(typecode_), copy, savespace, object(type), object(shape)); - } - -# define BOOST_PYTHON_ENUM_AS_OBJECT(z, n, x) object(BOOST_PP_CAT(x,n)) -# define BOOST_PP_LOCAL_MACRO(n) \ - template \ - explicit array(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, n, T, const& x)) \ - : base(BOOST_PP_ENUM_1(n, BOOST_PYTHON_ENUM_AS_OBJECT, x)) \ - {} -# define BOOST_PP_LOCAL_LIMITS (1, 7) -# include BOOST_PP_LOCAL_ITERATE() -# undef BOOST_PYTHON_AS_OBJECT - - static BOOST_PYTHON_DECL void set_module_and_type(char const* package_name = 0, char const* type_attribute_name = 0); - static BOOST_PYTHON_DECL std::string get_module_name(); - - public: // implementation detail -- for internal use only - BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(array, base); -}; - -} // namespace boost::python::numeric - -namespace converter -{ - template <> - struct object_manager_traits< numeric::array > - : numeric::aux::array_object_manager_traits - { - BOOST_STATIC_CONSTANT(bool, is_specialized = true); - }; -} - -}} // namespace boost::python - -#endif // NUMARRAY_DWA2002922_HPP diff --git a/include/boost/python/numpy.hpp b/include/boost/python/numpy.hpp new file mode 100644 index 0000000000..18a6389d51 --- /dev/null +++ b/include/boost/python/numpy.hpp @@ -0,0 +1,34 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_hpp_ +#define boost_python_numpy_hpp_ + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace numpy { + +/** + * @brief Initialize the Numpy C-API + * + * This must be called before using anything in boost.numpy; + * It should probably be the first line inside BOOST_PYTHON_MODULE. + * + * @internal This just calls the Numpy C-API functions "import_array()" + * and "import_ufunc()", and then calls + * dtype::register_scalar_converters(). + */ +BOOST_NUMPY_DECL void initialize(bool register_scalar_converters=true); + +}}} // namespace boost::python::numpy + +#endif diff --git a/include/boost/python/numpy/config.hpp b/include/boost/python/numpy/config.hpp new file mode 100644 index 0000000000..f70b94cb3e --- /dev/null +++ b/include/boost/python/numpy/config.hpp @@ -0,0 +1,85 @@ +// (C) Copyright Samuli-Petrus Korhonen 2017. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The author gratefully acknowleges the support of NMR Solutions, Inc., in +// producing this work. + +// Revision History: +// 15 Feb 17 Initial version + +#ifndef CONFIG_NUMPY20170215_H_ +# define CONFIG_NUMPY20170215_H_ + +# include + +/***************************************************************************** + * + * Set up dll import/export options: + * + ****************************************************************************/ + +// backwards compatibility: +#ifdef BOOST_NUMPY_STATIC_LIB +# define BOOST_NUMPY_STATIC_LINK +# elif !defined(BOOST_NUMPY_DYNAMIC_LIB) +# define BOOST_NUMPY_DYNAMIC_LIB +#endif + +#if defined(BOOST_NUMPY_DYNAMIC_LIB) +# if defined(BOOST_SYMBOL_EXPORT) +# if defined(BOOST_NUMPY_SOURCE) +# define BOOST_NUMPY_DECL BOOST_SYMBOL_EXPORT +# define BOOST_NUMPY_DECL_FORWARD BOOST_SYMBOL_FORWARD_EXPORT +# define BOOST_NUMPY_DECL_EXCEPTION BOOST_EXCEPTION_EXPORT +# define BOOST_NUMPY_BUILD_DLL +# else +# define BOOST_NUMPY_DECL BOOST_SYMBOL_IMPORT +# define BOOST_NUMPY_DECL_FORWARD BOOST_SYMBOL_FORWARD_IMPORT +# define BOOST_NUMPY_DECL_EXCEPTION BOOST_EXCEPTION_IMPORT +# endif +# endif + +#endif + +#ifndef BOOST_NUMPY_DECL +# define BOOST_NUMPY_DECL +#endif + +#ifndef BOOST_NUMPY_DECL_FORWARD +# define BOOST_NUMPY_DECL_FORWARD +#endif + +#ifndef BOOST_NUMPY_DECL_EXCEPTION +# define BOOST_NUMPY_DECL_EXCEPTION +#endif + +// enable automatic library variant selection ------------------------------// + +#if !defined(BOOST_NUMPY_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_NUMPY_NO_LIB) +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define _BOOST_PYTHON_CONCAT(N, M, m) N ## M ## m +#define BOOST_PYTHON_CONCAT(N, M, m) _BOOST_PYTHON_CONCAT(N, M, m) +#define BOOST_LIB_NAME BOOST_PYTHON_CONCAT(boost_numpy, PY_MAJOR_VERSION, PY_MINOR_VERSION) +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#ifdef BOOST_NUMPY_DYNAMIC_LIB +# define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#undef BOOST_PYTHON_CONCAT +#undef _BOOST_PYTHON_CONCAT + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION + +#endif // CONFIG_NUMPY20170215_H_ diff --git a/include/boost/python/numpy/dtype.hpp b/include/boost/python/numpy/dtype.hpp new file mode 100644 index 0000000000..9438d79fdc --- /dev/null +++ b/include/boost/python/numpy/dtype.hpp @@ -0,0 +1,118 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_dtype_hpp_ +#define boost_python_numpy_dtype_hpp_ + +/** + * @file boost/python/numpy/dtype.hpp + * @brief Object manager for Python's numpy.dtype class. + */ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace numpy { + +/** + * @brief A boost.python "object manager" (subclass of object) for numpy.dtype. + * + * @todo This could have a lot more interesting accessors. + */ +class BOOST_NUMPY_DECL dtype : public object { + static python::detail::new_reference convert(object::object_cref arg, bool align); +public: + + /// @brief Convert an arbitrary Python object to a data-type descriptor object. + template + explicit dtype(T arg, bool align=false) : object(convert(arg, align)) {} + + /** + * @brief Get the built-in numpy dtype associated with the given scalar template type. + * + * This is perhaps the most useful part of the numpy API: it returns the dtype object + * corresponding to a built-in C++ type. This should work for any integer or floating point + * type supported by numpy, and will also work for std::complex if + * sizeof(std::complex) == 2*sizeof(T). + * + * It can also be useful for users to add explicit specializations for POD structs + * that return field-based dtypes. + */ + template static dtype get_builtin(); + + /// @brief Return the size of the data type in bytes. + int get_itemsize() const; + + /** + * @brief Compare two dtypes for equivalence. + * + * This is more permissive than equality tests. For instance, if long and int are the same + * size, the dtypes corresponding to each will be equivalent, but not equal. + */ + friend BOOST_NUMPY_DECL bool equivalent(dtype const & a, dtype const & b); + + /** + * @brief Register from-Python converters for NumPy's built-in array scalar types. + * + * This is usually called automatically by initialize(), and shouldn't be called twice + * (doing so just adds unused converters to the Boost.Python registry). + */ + static void register_scalar_converters(); + + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(dtype, object); + +}; + +BOOST_NUMPY_DECL bool equivalent(dtype const & a, dtype const & b); + +namespace detail +{ + +template dtype get_int_dtype(); + +template dtype get_float_dtype(); + +template dtype get_complex_dtype(); + +template ::value> +struct builtin_dtype; + +template +struct builtin_dtype { + static dtype get() { return get_int_dtype< 8*sizeof(T), boost::is_unsigned::value >(); } +}; + +template <> +struct BOOST_NUMPY_DECL builtin_dtype { + static dtype get(); +}; + +template +struct builtin_dtype { + static dtype get() { return get_float_dtype< 8*sizeof(T) >(); } +}; + +template +struct builtin_dtype< std::complex, false > { + static dtype get() { return get_complex_dtype< 16*sizeof(T) >(); } +}; + +} // namespace detail + +template +inline dtype dtype::get_builtin() { return detail::builtin_dtype::get(); } + +} // namespace boost::python::numpy + +namespace converter { +NUMPY_OBJECT_MANAGER_TRAITS(numpy::dtype); +}}} // namespace boost::python::converter + +#endif diff --git a/include/boost/python/numpy/internal.hpp b/include/boost/python/numpy/internal.hpp new file mode 100644 index 0000000000..c24718f0ae --- /dev/null +++ b/include/boost/python/numpy/internal.hpp @@ -0,0 +1,36 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_internal_hpp_ +#define boost_python_numpy_internal_hpp_ + +/** + * @file boost/python/numpy/internal.hpp + * @brief Internal header file to include the Numpy C-API headers. + * + * This should only be included by source files in the boost.numpy library itself. + */ + +#include +#include +#ifdef BOOST_PYTHON_NUMPY_INTERNAL +#define NO_IMPORT_ARRAY +#define NO_IMPORT_UFUNC +#else +#ifndef BOOST_PYTHON_NUMPY_INTERNAL_MAIN +ERROR_internal_hpp_is_for_internal_use_only +#endif +#endif +#define PY_ARRAY_UNIQUE_SYMBOL BOOST_NUMPY_ARRAY_API +#define PY_UFUNC_UNIQUE_SYMBOL BOOST_UFUNC_ARRAY_API +#include +#include +#include + +#define NUMPY_OBJECT_MANAGER_TRAITS_IMPL(pytype,manager) \ + PyTypeObject const * object_manager_traits::get_pytype() { return &pytype; } + +#endif diff --git a/include/boost/python/numpy/invoke_matching.hpp b/include/boost/python/numpy/invoke_matching.hpp new file mode 100644 index 0000000000..095ca3a8db --- /dev/null +++ b/include/boost/python/numpy/invoke_matching.hpp @@ -0,0 +1,186 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_invoke_matching_hpp_ +#define boost_python_numpy_invoke_matching_hpp_ + +/** + * @brief Template invocation based on dtype matching. + */ + +#include +#include +#include + +namespace boost { namespace python { namespace numpy { +namespace detail +{ + +struct BOOST_NUMPY_DECL add_pointer_meta +{ + template + struct apply + { + typedef typename boost::add_pointer::type type; + }; + +}; + +struct BOOST_NUMPY_DECL dtype_template_match_found {}; +struct BOOST_NUMPY_DECL nd_template_match_found {}; + +template +struct dtype_template_invoker +{ + + template + void operator()(T *) const + { + if (dtype::get_builtin() == m_dtype) + { + m_func.Function::template apply(); + throw dtype_template_match_found(); + } + } + + dtype_template_invoker(dtype const & dtype_, Function func) + : m_dtype(dtype_), m_func(func) {} + +private: + dtype const & m_dtype; + Function m_func; +}; + +template +struct dtype_template_invoker< boost::reference_wrapper > +{ + + template + void operator()(T *) const + { + if (dtype::get_builtin() == m_dtype) + { + m_func.Function::template apply(); + throw dtype_template_match_found(); + } + } + + dtype_template_invoker(dtype const & dtype_, Function & func) + : m_dtype(dtype_), m_func(func) {} + +private: + dtype const & m_dtype; + Function & m_func; +}; + +template +struct nd_template_invoker +{ + template + void operator()(boost::mpl::integral_c *) const + { + if (m_nd == N) + { + m_func.Function::template apply(); + throw nd_template_match_found(); + } + } + + nd_template_invoker(int nd, Function func) : m_nd(nd), m_func(func) {} + +private: + int m_nd; + Function m_func; +}; + +template +struct nd_template_invoker< boost::reference_wrapper > +{ + template + void operator()(boost::mpl::integral_c *) const + { + if (m_nd == N) + { + m_func.Function::template apply(); + throw nd_template_match_found(); + } + } + + nd_template_invoker(int nd, Function & func) : m_nd(nd), m_func(func) {} + +private: + int m_nd; + Function & m_func; +}; + +} // namespace boost::python::numpy::detail + +template +void invoke_matching_nd(int nd, Function f) +{ + detail::nd_template_invoker invoker(nd, f); + try { boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);} + catch (detail::nd_template_match_found &) { return;} + PyErr_SetString(PyExc_TypeError, "number of dimensions not found in template list."); + python::throw_error_already_set(); +} + +template +void invoke_matching_dtype(dtype const & dtype_, Function f) +{ + detail::dtype_template_invoker invoker(dtype_, f); + try { boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);} + catch (detail::dtype_template_match_found &) { return;} + PyErr_SetString(PyExc_TypeError, "dtype not found in template list."); + python::throw_error_already_set(); +} + +namespace detail +{ + +template +struct array_template_invoker_wrapper_2 +{ + template + void apply() const { m_func.Function::template apply();} + array_template_invoker_wrapper_2(Function & func) : m_func(func) {} + +private: + Function & m_func; +}; + +template +struct array_template_invoker_wrapper_1 +{ + template + void apply() const { invoke_matching_nd(m_nd, array_template_invoker_wrapper_2(m_func));} + array_template_invoker_wrapper_1(int nd, Function & func) : m_nd(nd), m_func(func) {} + +private: + int m_nd; + Function & m_func; +}; + +template +struct array_template_invoker_wrapper_1< DimSequence, boost::reference_wrapper > + : public array_template_invoker_wrapper_1< DimSequence, Function > +{ + array_template_invoker_wrapper_1(int nd, Function & func) + : array_template_invoker_wrapper_1< DimSequence, Function >(nd, func) {} +}; + +} // namespace boost::python::numpy::detail + +template +void invoke_matching_array(ndarray const & array_, Function f) +{ + detail::array_template_invoker_wrapper_1 wrapper(array_.get_nd(), f); + invoke_matching_dtype(array_.get_dtype(), wrapper); +} + +}}} // namespace boost::python::numpy + +#endif diff --git a/include/boost/python/numpy/matrix.hpp b/include/boost/python/numpy/matrix.hpp new file mode 100644 index 0000000000..829f544af5 --- /dev/null +++ b/include/boost/python/numpy/matrix.hpp @@ -0,0 +1,84 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_matrix_hpp_ +#define boost_python_numpy_matrix_hpp_ + +/** + * @brief Object manager for numpy.matrix. + */ + +#include +#include +#include +#include + + +namespace boost { namespace python { namespace numpy { + +/** + * @brief A boost.python "object manager" (subclass of object) for numpy.matrix. + * + * @internal numpy.matrix is defined in Python, so object_manager_traits::get_pytype() + * is implemented by importing numpy and getting the "matrix" attribute of the module. + * We then just hope that doesn't get destroyed while we need it, because if we put + * a dynamic python object in a static-allocated boost::python::object or handle<>, + * bad things happen when Python shuts down. I think this solution is safe, but I'd + * love to get that confirmed. + */ +class BOOST_NUMPY_DECL matrix : public ndarray +{ + static object construct(object_cref obj, dtype const & dt, bool copy); + static object construct(object_cref obj, bool copy); +public: + + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(matrix, ndarray); + + /// @brief Equivalent to "numpy.matrix(obj,dt,copy)" in Python. + explicit matrix(object const & obj, dtype const & dt, bool copy=true) + : ndarray(extract(construct(obj, dt, copy))) {} + + /// @brief Equivalent to "numpy.matrix(obj,copy=copy)" in Python. + explicit matrix(object const & obj, bool copy=true) + : ndarray(extract(construct(obj, copy))) {} + + /// \brief Return a view of the matrix with the given dtype. + matrix view(dtype const & dt) const; + + /// \brief Copy the scalar (deep for all non-object fields). + matrix copy() const; + + /// \brief Transpose the matrix. + matrix transpose() const; + +}; + +/** + * @brief CallPolicies that causes a function that returns a numpy.ndarray to + * return a numpy.matrix instead. + */ +template +struct as_matrix : Base +{ + static PyObject * postcall(PyObject *, PyObject * result) + { + object a = object(handle<>(result)); + numpy::matrix m(a, false); + Py_INCREF(m.ptr()); + return m.ptr(); + } +}; + +} // namespace boost::python::numpy + +namespace converter +{ + +NUMPY_OBJECT_MANAGER_TRAITS(numpy::matrix); + +}}} // namespace boost::python::converter + +#endif diff --git a/include/boost/python/numpy/ndarray.hpp b/include/boost/python/numpy/ndarray.hpp new file mode 100644 index 0000000000..2cb3b509f8 --- /dev/null +++ b/include/boost/python/numpy/ndarray.hpp @@ -0,0 +1,313 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_ndarray_hpp_ +#define boost_python_numpy_ndarray_hpp_ + +/** + * @brief Object manager and various utilities for numpy.ndarray. + */ + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { namespace python { namespace numpy { + +/** + * @brief A boost.python "object manager" (subclass of object) for numpy.ndarray. + * + * @todo This could have a lot more functionality (like boost::python::numeric::array). + * Right now all that exists is what was needed to move raw data between C++ and Python. + */ + +class BOOST_NUMPY_DECL ndarray : public object +{ + + /** + * @brief An internal struct that's byte-compatible with PyArrayObject. + * + * This is just a hack to allow inline access to this stuff while hiding numpy/arrayobject.h + * from the user. + */ + struct array_struct + { + PyObject_HEAD + char * data; + int nd; + Py_intptr_t * shape; + Py_intptr_t * strides; + PyObject * base; + PyObject * descr; + int flags; + PyObject * weakreflist; + }; + + /// @brief Return the held Python object as an array_struct. + array_struct * get_struct() const { return reinterpret_cast(this->ptr()); } + +public: + + /** + * @brief Enum to represent (some) of Numpy's internal flags. + * + * These don't match the actual Numpy flag values; we can't get those without including + * numpy/arrayobject.h or copying them directly. That's very unfortunate. + * + * @todo I'm torn about whether this should be an enum. It's very convenient to not + * make these simple integer values for overloading purposes, but the need to + * define every possible combination and custom bitwise operators is ugly. + */ + enum bitflag + { + NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2, + ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8, + CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8, + FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8, + UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8 + }; + + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(ndarray, object); + + /// @brief Return a view of the scalar with the given dtype. + ndarray view(dtype const & dt) const; + + /// @brief Copy the array, cast to a specified type. + ndarray astype(dtype const & dt) const; + + /// @brief Copy the scalar (deep for all non-object fields). + ndarray copy() const; + + /// @brief Return the size of the nth dimension. raises IndexError if k not in [-get_nd() : get_nd()-1 ] + Py_intptr_t shape(int n) const; + + /// @brief Return the stride of the nth dimension. raises IndexError if k not in [-get_nd() : get_nd()-1] + Py_intptr_t strides(int n) const; + + /** + * @brief Return the array's raw data pointer. + * + * This returns char so stride math works properly on it. It's pretty much + * expected that the user will have to reinterpret_cast it. + */ + char * get_data() const { return get_struct()->data; } + + /// @brief Return the array's data-type descriptor object. + dtype get_dtype() const; + + /// @brief Return the object that owns the array's data, or None if the array owns its own data. + object get_base() const; + + /// @brief Set the object that owns the array's data. Use with care. + void set_base(object const & base); + + /// @brief Return the shape of the array as an array of integers (length == get_nd()). + Py_intptr_t const * get_shape() const { return get_struct()->shape; } + + /// @brief Return the stride of the array as an array of integers (length == get_nd()). + Py_intptr_t const * get_strides() const { return get_struct()->strides; } + + /// @brief Return the number of array dimensions. + int get_nd() const { return get_struct()->nd; } + + /// @brief Return the array flags. + bitflag get_flags() const; + + /// @brief Reverse the dimensions of the array. + ndarray transpose() const; + + /// @brief Eliminate any unit-sized dimensions. + ndarray squeeze() const; + + /// @brief Equivalent to self.reshape(*shape) in Python. + ndarray reshape(python::tuple const & shape) const; + + /** + * @brief If the array contains only a single element, return it as an array scalar; otherwise return + * the array. + * + * @internal This is simply a call to PyArray_Return(); + */ + object scalarize() const; +}; + +/** + * @brief Construct a new array with the given shape and data type, with data initialized to zero. + */ +BOOST_NUMPY_DECL ndarray zeros(python::tuple const & shape, dtype const & dt); +BOOST_NUMPY_DECL ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); + +/** + * @brief Construct a new array with the given shape and data type, with data left uninitialized. + */ +BOOST_NUMPY_DECL ndarray empty(python::tuple const & shape, dtype const & dt); +BOOST_NUMPY_DECL ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); + +/** + * @brief Construct a new array from an arbitrary Python sequence. + * + * @todo This does't seem to handle ndarray subtypes the same way that "numpy.array" does in Python. + */ +BOOST_NUMPY_DECL ndarray array(object const & obj); +BOOST_NUMPY_DECL ndarray array(object const & obj, dtype const & dt); + +namespace detail +{ + +BOOST_NUMPY_DECL ndarray from_data_impl(void * data, + dtype const & dt, + std::vector const & shape, + std::vector const & strides, + object const & owner, + bool writeable); + +template +ndarray from_data_impl(void * data, + dtype const & dt, + Container shape, + Container strides, + object const & owner, + bool writeable, + typename boost::enable_if< boost::python::detail::is_integral >::type * enabled = NULL) +{ + std::vector shape_(shape.begin(),shape.end()); + std::vector strides_(strides.begin(), strides.end()); + return from_data_impl(data, dt, shape_, strides_, owner, writeable); +} + +BOOST_NUMPY_DECL ndarray from_data_impl(void * data, + dtype const & dt, + object const & shape, + object const & strides, + object const & owner, + bool writeable); + +} // namespace boost::python::numpy::detail + +/** + * @brief Construct a new ndarray object from a raw pointer. + * + * @param[in] data Raw pointer to the first element of the array. + * @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin(). + * @param[in] shape Shape of the array as STL container of integers; must have begin() and end(). + * @param[in] strides Shape of the array as STL container of integers; must have begin() and end(). + * @param[in] owner An arbitray Python object that owns that data pointer. The array object will + * keep a reference to the object, and decrement it's reference count when the + * array goes out of scope. Pass None at your own peril. + * + * @todo Should probably take ranges of iterators rather than actual container objects. + */ +template +inline ndarray from_data(void * data, + dtype const & dt, + Container shape, + Container strides, + python::object const & owner) +{ + return numpy::detail::from_data_impl(data, dt, shape, strides, owner, true); +} + +/** + * @brief Construct a new ndarray object from a raw pointer. + * + * @param[in] data Raw pointer to the first element of the array. + * @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin(). + * @param[in] shape Shape of the array as STL container of integers; must have begin() and end(). + * @param[in] strides Shape of the array as STL container of integers; must have begin() and end(). + * @param[in] owner An arbitray Python object that owns that data pointer. The array object will + * keep a reference to the object, and decrement it's reference count when the + * array goes out of scope. Pass None at your own peril. + * + * This overload takes a const void pointer and sets the "writeable" flag of the array to false. + * + * @todo Should probably take ranges of iterators rather than actual container objects. + */ +template +inline ndarray from_data(void const * data, + dtype const & dt, + Container shape, + Container strides, + python::object const & owner) +{ + return numpy::detail::from_data_impl(const_cast(data), dt, shape, strides, owner, false); +} + +/** + * @brief Transform an arbitrary object into a numpy array with the given requirements. + * + * @param[in] obj An arbitrary python object to convert. Arrays that meet the requirements + * will be passed through directly. + * @param[in] dt Data type descriptor. Often retrieved with dtype::get_builtin(). + * @param[in] nd_min Minimum number of dimensions. + * @param[in] nd_max Maximum number of dimensions. + * @param[in] flags Bitwise OR of flags specifying additional requirements. + */ +BOOST_NUMPY_DECL ndarray from_object(object const & obj, + dtype const & dt, + int nd_min, + int nd_max, + ndarray::bitflag flags=ndarray::NONE); + +BOOST_NUMPY_DECL inline ndarray from_object(object const & obj, + dtype const & dt, + int nd, + ndarray::bitflag flags=ndarray::NONE) +{ + return from_object(obj, dt, nd, nd, flags); +} + +BOOST_NUMPY_DECL inline ndarray from_object(object const & obj, + dtype const & dt, + ndarray::bitflag flags=ndarray::NONE) +{ + return from_object(obj, dt, 0, 0, flags); +} + +BOOST_NUMPY_DECL ndarray from_object(object const & obj, + int nd_min, + int nd_max, + ndarray::bitflag flags=ndarray::NONE); + +BOOST_NUMPY_DECL inline ndarray from_object(object const & obj, + int nd, + ndarray::bitflag flags=ndarray::NONE) +{ + return from_object(obj, nd, nd, flags); +} + +BOOST_NUMPY_DECL inline ndarray from_object(object const & obj, + ndarray::bitflag flags=ndarray::NONE) +{ + return from_object(obj, 0, 0, flags); +} + +BOOST_NUMPY_DECL inline ndarray::bitflag operator|(ndarray::bitflag a, + ndarray::bitflag b) +{ + return ndarray::bitflag(int(a) | int(b)); +} + +BOOST_NUMPY_DECL inline ndarray::bitflag operator&(ndarray::bitflag a, + ndarray::bitflag b) +{ + return ndarray::bitflag(int(a) & int(b)); +} + +} // namespace boost::python::numpy + +namespace converter +{ + +NUMPY_OBJECT_MANAGER_TRAITS(numpy::ndarray); + +}}} // namespace boost::python::converter + +#endif diff --git a/include/boost/python/numpy/numpy_object_mgr_traits.hpp b/include/boost/python/numpy/numpy_object_mgr_traits.hpp new file mode 100644 index 0000000000..a138f4cd52 --- /dev/null +++ b/include/boost/python/numpy/numpy_object_mgr_traits.hpp @@ -0,0 +1,38 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_numpy_object_mgr_traits_hpp_ +#define boost_python_numpy_numpy_object_mgr_traits_hpp_ + +#include + +/** + * @brief Macro that specializes object_manager_traits by requiring a + * source-file implementation of get_pytype(). + */ + +#define NUMPY_OBJECT_MANAGER_TRAITS(manager) \ +template <> \ +struct BOOST_NUMPY_DECL object_manager_traits \ +{ \ + BOOST_STATIC_CONSTANT(bool, is_specialized = true); \ + static inline python::detail::new_reference adopt(PyObject* x) \ + { \ + return python::detail::new_reference(python::pytype_check((PyTypeObject*)get_pytype(), x)); \ + } \ + static bool check(PyObject* x) \ + { \ + return ::PyObject_IsInstance(x, (PyObject*)get_pytype()); \ + } \ + static manager* checked_downcast(PyObject* x) \ + { \ + return python::downcast((checked_downcast_impl)(x, (PyTypeObject*)get_pytype())); \ + } \ + static PyTypeObject const * get_pytype(); \ +} + +#endif + diff --git a/include/boost/python/numpy/scalars.hpp b/include/boost/python/numpy/scalars.hpp new file mode 100644 index 0000000000..c2a83d8253 --- /dev/null +++ b/include/boost/python/numpy/scalars.hpp @@ -0,0 +1,58 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_scalars_hpp_ +#define boost_python_numpy_scalars_hpp_ + +/** + * @brief Object managers for array scalars (currently only numpy.void is implemented). + */ + +#include +#include +#include + +namespace boost { namespace python { namespace numpy { + +/** + * @brief A boost.python "object manager" (subclass of object) for numpy.void. + * + * @todo This could have a lot more functionality. + */ +class BOOST_NUMPY_DECL void_ : public object +{ + static python::detail::new_reference convert(object_cref arg, bool align); +public: + + /** + * @brief Construct a new array scalar with the given size and void dtype. + * + * Data is initialized to zero. One can create a standalone scalar object + * with a certain dtype "dt" with: + * @code + * void_ scalar = void_(dt.get_itemsize()).view(dt); + * @endcode + */ + explicit void_(Py_ssize_t size); + + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(void_, object); + + /// @brief Return a view of the scalar with the given dtype. + void_ view(dtype const & dt) const; + + /// @brief Copy the scalar (deep for all non-object fields). + void_ copy() const; + +}; + +} // namespace boost::python::numpy + +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS(numpy::void_); +}}} // namespace boost::python::converter + +#endif diff --git a/include/boost/python/numpy/ufunc.hpp b/include/boost/python/numpy/ufunc.hpp new file mode 100644 index 0000000000..79d7d262b8 --- /dev/null +++ b/include/boost/python/numpy/ufunc.hpp @@ -0,0 +1,206 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_numpy_ufunc_hpp_ +#define boost_python_numpy_ufunc_hpp_ + +/** + * @brief Utilities to create ufunc-like broadcasting functions out of C++ functors. + */ + +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace numpy { + +/** + * @brief A boost.python "object manager" (subclass of object) for PyArray_MultiIter. + * + * multi_iter is a Python object, but a very low-level one. It should generally only be used + * in loops of the form: + * @code + * while (iter.not_done()) { + * ... + * iter.next(); + * } + * @endcode + * + * @todo I can't tell if this type is exposed in Python anywhere; if it is, we should use that name. + * It's more dangerous than most object managers, however - maybe it actually belongs in + * a detail namespace? + */ +class BOOST_NUMPY_DECL multi_iter : public object +{ +public: + + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(multi_iter, object); + + /// @brief Increment the iterator. + void next(); + + /// @brief Check if the iterator is at its end. + bool not_done() const; + + /// @brief Return a pointer to the element of the nth broadcasted array. + char * get_data(int n) const; + + /// @brief Return the number of dimensions of the broadcasted array expression. + int get_nd() const; + + /// @brief Return the shape of the broadcasted array expression as an array of integers. + Py_intptr_t const * get_shape() const; + + /// @brief Return the shape of the broadcasted array expression in the nth dimension. + Py_intptr_t shape(int n) const; + +}; + +/// @brief Construct a multi_iter over a single sequence or scalar object. +BOOST_NUMPY_DECL multi_iter make_multi_iter(object const & a1); + +/// @brief Construct a multi_iter by broadcasting two objects. +BOOST_NUMPY_DECL multi_iter make_multi_iter(object const & a1, object const & a2); + +/// @brief Construct a multi_iter by broadcasting three objects. +BOOST_NUMPY_DECL multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3); + +/** + * @brief Helps wrap a C++ functor taking a single scalar argument as a broadcasting ufunc-like + * Python object. + * + * Typical usage looks like this: + * @code + * struct TimesPI + * { + * typedef double argument_type; + * typedef double result_type; + * double operator()(double input) const { return input * M_PI; } + * }; + * + * BOOST_PYTHON_MODULE(example) + * { + * class_< TimesPI >("TimesPI") + * .def("__call__", unary_ufunc::make()); + * } + * @endcode + * + */ +template +struct unary_ufunc +{ + + /** + * @brief A C++ function with object arguments that broadcasts its arguments before + * passing them to the underlying C++ functor. + */ + static object call(TUnaryFunctor & self, object const & input, object const & output) + { + dtype in_dtype = dtype::get_builtin(); + dtype out_dtype = dtype::get_builtin(); + ndarray in_array = from_object(input, in_dtype, ndarray::ALIGNED); + ndarray out_array = ! output.is_none() ? + from_object(output, out_dtype, ndarray::ALIGNED | ndarray::WRITEABLE) + : zeros(in_array.get_nd(), in_array.get_shape(), out_dtype); + multi_iter iter = make_multi_iter(in_array, out_array); + while (iter.not_done()) + { + TArgument * argument = reinterpret_cast(iter.get_data(0)); + TResult * result = reinterpret_cast(iter.get_data(1)); + *result = self(*argument); + iter.next(); + } + return out_array.scalarize(); + } + + /** + * @brief Construct a boost.python function object from call() with reasonable keyword names. + * + * Users will often want to specify their own keyword names with the same signature, but this + * is a convenient shortcut. + */ + static object make() + { + return make_function(call, default_call_policies(), (arg("input"), arg("output")=object())); + } +}; + +/** + * @brief Helps wrap a C++ functor taking a pair of scalar arguments as a broadcasting ufunc-like + * Python object. + * + * Typical usage looks like this: + * @code + * struct CosSum + * { + * typedef double first_argument_type; + * typedef double second_argument_type; + * typedef double result_type; + * double operator()(double input1, double input2) const { return std::cos(input1 + input2); } + * }; + * + * BOOST_PYTHON_MODULE(example) + * { + * class_< CosSum >("CosSum") + * .def("__call__", binary_ufunc::make()); + * } + * @endcode + * + */ +template +struct binary_ufunc +{ + + static object + call(TBinaryFunctor & self, object const & input1, object const & input2, + object const & output) + { + dtype in1_dtype = dtype::get_builtin(); + dtype in2_dtype = dtype::get_builtin(); + dtype out_dtype = dtype::get_builtin(); + ndarray in1_array = from_object(input1, in1_dtype, ndarray::ALIGNED); + ndarray in2_array = from_object(input2, in2_dtype, ndarray::ALIGNED); + multi_iter iter = make_multi_iter(in1_array, in2_array); + ndarray out_array = !output.is_none() + ? from_object(output, out_dtype, ndarray::ALIGNED | ndarray::WRITEABLE) + : zeros(iter.get_nd(), iter.get_shape(), out_dtype); + iter = make_multi_iter(in1_array, in2_array, out_array); + while (iter.not_done()) + { + TArgument1 * argument1 = reinterpret_cast(iter.get_data(0)); + TArgument2 * argument2 = reinterpret_cast(iter.get_data(1)); + TResult * result = reinterpret_cast(iter.get_data(2)); + *result = self(*argument1, *argument2); + iter.next(); + } + return out_array.scalarize(); + } + + static object make() + { + return make_function(call, default_call_policies(), + (arg("input1"), arg("input2"), arg("output")=object())); + } + +}; + +} // namespace boost::python::numpy + +namespace converter +{ + +NUMPY_OBJECT_MANAGER_TRAITS(numpy::multi_iter); + +}}} // namespace boost::python::converter + +#endif diff --git a/include/boost/python/object.hpp b/include/boost/python/object.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/object/add_to_namespace.hpp b/include/boost/python/object/add_to_namespace.hpp index 9f4167d6d2..e81186790a 100644 --- a/include/boost/python/object/add_to_namespace.hpp +++ b/include/boost/python/object/add_to_namespace.hpp @@ -18,6 +18,8 @@ BOOST_PYTHON_DECL void add_to_namespace( BOOST_PYTHON_DECL void add_to_namespace( object const& name_space, char const* name, object const& attribute, char const* doc); +BOOST_PYTHON_DECL object const& add_doc(object const& attribute, char const* doc); + }}} // namespace boost::python::objects #endif // ADD_TO_NAMESPACE_DWA200286_HPP diff --git a/include/boost/python/object/class_metadata.hpp b/include/boost/python/object/class_metadata.hpp index 155ae35d06..06d3f8efa7 100644 --- a/include/boost/python/object/class_metadata.hpp +++ b/include/boost/python/object/class_metadata.hpp @@ -1,43 +1,40 @@ -// Copyright David Abrahams 2004. Distributed under the Boost -// Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef CLASS_METADATA_DWA2004719_HPP -# define CLASS_METADATA_DWA2004719_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 +// Copyright David Abrahams 2004. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef boost_python_object_class_metadata_hpp_ +#define boost_python_object_class_metadata_hpp_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include namespace boost { namespace python { namespace objects { @@ -53,11 +50,7 @@ struct register_base_of template inline void operator()(Base*) const { -# if !BOOST_WORKAROUND(BOOST_MSVC, == 1200) - BOOST_MPL_ASSERT_NOT((is_same)); -# else - BOOST_STATIC_ASSERT(!(is_same::value)); -# endif + BOOST_MPL_ASSERT_NOT((boost::python::detail::is_same)); // Register the Base class register_dynamic_id(); @@ -66,14 +59,14 @@ struct register_base_of register_conversion(false); // Register the down-cast, if appropriate. - this->register_downcast((Base*)0, is_polymorphic()); + this->register_downcast((Base*)0, boost::python::detail::is_polymorphic()); } private: - static inline void register_downcast(void*, mpl::false_) {} + static inline void register_downcast(void*, boost::python::detail::false_) {} template - static inline void register_downcast(Base*, mpl::true_) + static inline void register_downcast(Base*, boost::python::detail::true_) { register_conversion(true); } @@ -84,18 +77,22 @@ struct register_base_of // Preamble of register_class. Also used for callback classes, which // need some registration of their own. // + template inline void register_shared_ptr_from_python_and_casts(T*, Bases) { - // Constructor performs registration - python::detail::force_instantiate(converter::shared_ptr_from_python()); + // Constructor performs registration + python::detail::force_instantiate(converter::shared_ptr_from_python()); +#if !defined(BOOST_NO_CXX11_SMART_PTR) + python::detail::force_instantiate(converter::shared_ptr_from_python()); +#endif - // - // register all up/downcasts here. We're using the alternate - // interface to mpl::for_each to avoid an MSVC 6 bug. - // - register_dynamic_id(); - mpl::for_each(register_base_of(), (Bases*)0, (add_pointer*)0); + // + // register all up/downcasts here. We're using the alternate + // interface to mpl::for_each to avoid an MSVC 6 bug. + // + register_dynamic_id(); + mpl::for_each(register_base_of(), (Bases*)0, (boost::python::detail::add_pointer*)0); } // @@ -106,7 +103,7 @@ struct select_held_type : mpl::if_< mpl::or_< python::detail::specifies_bases - , is_same + , boost::python::detail::is_same > , Prev , T @@ -153,9 +150,9 @@ struct class_metadata >::type bases; typedef mpl::or_< - is_same - , is_same - , is_same + boost::python::detail::is_same + , boost::python::detail::is_same + , boost::python::detail::is_same > is_noncopyable; // @@ -164,11 +161,11 @@ struct class_metadata // Compute the actual type that will be held in the Holder. typedef typename mpl::if_< - is_same, T, held_type_arg + boost::python::detail::is_same, T, held_type_arg >::type held_type; // Determine if the object will be held by value - typedef is_convertible use_value_holder; + typedef mpl::bool_::value> use_value_holder; // Compute the "wrapped type", that is, if held_type is a smart // pointer, we're talking about the pointee. @@ -179,10 +176,12 @@ struct class_metadata >::type wrapped; // Determine whether to use a "back-reference holder" - typedef mpl::or_< - has_back_reference - , is_same - , is_base_and_derived + typedef mpl::bool_< + mpl::or_< + has_back_reference + , boost::python::detail::is_same + , is_base_and_derived + >::value > use_back_reference; // Select the holder. @@ -209,7 +208,7 @@ struct class_metadata template inline static void register_aux(python::wrapper*) { - typedef typename mpl::not_ >::type use_callback; + typedef typename mpl::not_ >::type use_callback; class_metadata::register_aux2((T2*)0, use_callback()); } @@ -222,8 +221,7 @@ struct class_metadata template inline static void register_aux2(T2*, Callback) { - objects::register_shared_ptr_from_python_and_casts((T2*)0, bases()); - + objects::register_shared_ptr_from_python_and_casts((T2*)0, bases()); class_metadata::maybe_register_callback_class((T2*)0, Callback()); class_metadata::maybe_register_class_to_python((T2*)0, is_noncopyable()); @@ -239,7 +237,7 @@ struct class_metadata inline static void maybe_register_pointer_to_python(...) {} #ifndef BOOST_PYTHON_NO_PY_SIGNATURES - inline static void maybe_register_pointer_to_python(void*,void*,mpl::true_*) + inline static void maybe_register_pointer_to_python(void*,void*,mpl::true_*) { objects::copy_class_object(python::type_id(), python::type_id >()); objects::copy_class_object(python::type_id(), python::type_id >()); @@ -284,9 +282,8 @@ struct class_metadata template inline static void maybe_register_callback_class(T2*, mpl::true_) { - objects::register_shared_ptr_from_python_and_casts( + objects::register_shared_ptr_from_python_and_casts( (wrapped*)0, mpl::single_view()); - // explicit qualification of type_id makes msvc6 happy objects::copy_class_object(python::type_id(), python::type_id()); } @@ -294,4 +291,4 @@ struct class_metadata }}} // namespace boost::python::object -#endif // CLASS_METADATA_DWA2004719_HPP +#endif diff --git a/include/boost/python/object/forward.hpp b/include/boost/python/object/forward.hpp index 2faf3321ec..c6515bb55b 100644 --- a/include/boost/python/object/forward.hpp +++ b/include/boost/python/object/forward.hpp @@ -6,19 +6,11 @@ # define FORWARD_DWA20011215_HPP # include -# include -# include -# include # include # include +# include # include -# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) -# include -# include -# include -# else -# include -# endif +# include namespace boost { namespace python { namespace objects { @@ -28,7 +20,8 @@ namespace boost { namespace python { namespace objects { template struct reference_to_value { - typedef typename add_reference::type>::type reference; + typedef typename boost::python::detail::add_lvalue_reference::type>::type reference; reference_to_value(reference x) : m_value(x) {} reference get() const { return m_value; } @@ -42,24 +35,13 @@ struct reference_to_value template struct forward : mpl::if_< -# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - // vc6 chokes on unforwarding enums nested in classes - mpl::and_< - is_scalar - , mpl::not_< - is_enum - > - > -# else - mpl::or_, is_scalar > -# endif + mpl::or_, boost::python::detail::is_scalar > , T , reference_to_value > { }; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct unforward { @@ -82,92 +64,10 @@ struct unforward_cref template struct unforward_cref > - : add_reference::type> + : boost::python::detail::add_lvalue_reference::type> { }; -# else // no partial specialization - -namespace detail -{ - typedef char (&yes_reference_to_value_t)[1]; - typedef char (&no_reference_to_value_t)[2]; - - no_reference_to_value_t is_reference_to_value_test(...); - - template - yes_reference_to_value_t is_reference_to_value_test(boost::type< reference_to_value >); - - template - struct unforwarder - { - template - struct apply - { - typedef typename unwrap_reference::type& type; - }; - }; - - template<> - struct unforwarder - { - template - struct apply - { - typedef typename T::reference type; - }; - }; - - template - struct cref_unforwarder - { - template - struct apply - : python::detail::value_arg< - typename unwrap_reference::type - > - { - }; - }; - - template<> - struct cref_unforwarder - { - template - struct apply - : python::detail::value_arg< - typename T::reference - > - { - }; - }; - - template - struct is_reference_to_value - { - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(is_reference_to_value_test(boost::type())) - == sizeof(yes_reference_to_value_t))); - typedef mpl::bool_ type; - }; -} - -template -struct unforward - : public detail::unforwarder< - detail::is_reference_to_value::value - >::template apply -{}; - -template -struct unforward_cref - : public detail::cref_unforwarder< - detail::is_reference_to_value::value - >::template apply -{}; - -# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template typename reference_to_value::reference diff --git a/include/boost/python/object/function.hpp b/include/boost/python/object/function.hpp index f29d344820..ec1fc3d38b 100644 --- a/include/boost/python/object/function.hpp +++ b/include/boost/python/object/function.hpp @@ -35,6 +35,8 @@ struct BOOST_PYTHON_DECL function : PyObject static void add_to_namespace( object const& name_space, char const* name, object const& attribute, char const* doc); + static object const& add_doc(object const& attribute, char const* doc); + object const& doc() const; void doc(object const& x); @@ -42,6 +44,8 @@ struct BOOST_PYTHON_DECL function : PyObject object const& get_namespace() const { return m_namespace; } + object const& get_module() const { return m_module; } + private: // helper functions object signature(bool show_return_type=false) const; object signatures(bool show_return_type=false) const; @@ -53,6 +57,7 @@ struct BOOST_PYTHON_DECL function : PyObject handle m_overloads; object m_name; object m_namespace; + object m_module; object m_doc; object m_arg_names; unsigned m_nkeyword_values; diff --git a/include/boost/python/object/function_doc_signature.hpp b/include/boost/python/object/function_doc_signature.hpp old mode 100755 new mode 100644 index 4f00cb385a..91c90895ca --- a/include/boost/python/object/function_doc_signature.hpp +++ b/include/boost/python/object/function_doc_signature.hpp @@ -18,13 +18,13 @@ namespace boost { namespace python { namespace objects { class function_doc_signature_generator{ - static const char * py_type_str(const python::detail::signature_element &s); + static str py_type_str(const python::detail::signature_element &s, const object& current_module_name); static bool arity_cmp( function const *f1, function const *f2 ); static bool are_seq_overloads( function const *f1, function const *f2 , bool check_docs); static std::vector flatten(function const *f); static std::vector split_seq_overloads( const std::vector &funcs, bool split_on_doc_change); static str raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false); - static str parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types); + static str parameter_string(py_function const &f, size_t n, object arg_names, const object& module_name, bool cpp_types); static str pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false); public: diff --git a/include/boost/python/object/inheritance.hpp b/include/boost/python/object/inheritance.hpp index b49a0442e2..90e56f0c1d 100644 --- a/include/boost/python/object/inheritance.hpp +++ b/include/boost/python/object/inheritance.hpp @@ -8,9 +8,8 @@ # include # include # include -# include -# include # include +# include namespace boost { namespace python { namespace objects { @@ -58,7 +57,7 @@ struct non_polymorphic_id_generator template struct dynamic_id_generator : mpl::if_< - boost::is_polymorphic + boost::python::detail::is_polymorphic , boost::python::objects::polymorphic_id_generator , boost::python::objects::non_polymorphic_id_generator > @@ -104,7 +103,7 @@ struct implicit_cast_generator template struct cast_generator : mpl::if_< - is_base_and_derived + boost::python::detail::is_base_and_derived , implicit_cast_generator , dynamic_cast_generator > diff --git a/include/boost/python/object/inheritance_query.hpp b/include/boost/python/object/inheritance_query.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/object/instance.hpp b/include/boost/python/object/instance.hpp index 177576ef82..ee4a6c5822 100644 --- a/include/boost/python/object/instance.hpp +++ b/include/boost/python/object/instance.hpp @@ -6,12 +6,12 @@ # define INSTANCE_DWA200295_HPP # include -# include +# include # include namespace boost { namespace python { - struct BOOST_PYTHON_DECL_FORWARD instance_holder; + struct instance_holder; }} // namespace boost::python namespace boost { namespace python { namespace objects { @@ -25,10 +25,10 @@ struct instance PyObject* weakrefs; instance_holder* objects; - typedef typename type_with_alignment< - ::boost::alignment_of::value + typedef typename boost::python::detail::type_with_alignment< + boost::python::detail::alignment_of::value >::type align_t; - + union { align_t align; @@ -41,9 +41,10 @@ struct additional_instance_size { typedef instance instance_data; typedef instance instance_char; - BOOST_STATIC_CONSTANT( - std::size_t, value = sizeof(instance_data) - - BOOST_PYTHON_OFFSETOF(instance_char,storage)); + BOOST_STATIC_CONSTANT(std::size_t, + value = sizeof(instance_data) - + BOOST_PYTHON_OFFSETOF(instance_char,storage) + + boost::python::detail::alignment_of::value); }; }}} // namespace boost::python::object diff --git a/include/boost/python/object/iterator.hpp b/include/boost/python/object/iterator.hpp index ab748fe82d..874950365d 100644 --- a/include/boost/python/object/iterator.hpp +++ b/include/boost/python/object/iterator.hpp @@ -6,6 +6,7 @@ # define ITERATOR_DWA2002510_HPP # include +# include # include # include @@ -24,11 +25,7 @@ # include -# include -# include -# include - -# include +# include namespace boost { namespace python { namespace objects { @@ -45,7 +42,7 @@ struct iterator_range { iterator_range(object sequence, Iterator start, Iterator finish); - typedef boost::detail::iterator_traits traits_t; + typedef std::iterator_traits traits_t; struct next { @@ -71,35 +68,7 @@ struct iterator_range # endif }; -# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - // for compilers which can't deduce the value_type of pointers, we - // have a special implementation of next. This takes advantage of - // the fact that T* results are treated like T& results by - // Boost.Python's function wrappers. - struct next_ptr - { - typedef Iterator result_type; - - result_type - operator()(iterator_range& self) - { - if (self.m_start == self.m_finish) - stop_iteration_error(); - return self.m_start++; - } - }; - - typedef mpl::if_< - is_same< - boost::detail::please_invoke_BOOST_TT_BROKEN_COMPILER_SPEC_on_cv_unqualified_pointee - , typename traits_t::value_type - > - , next_ptr - , next - >::type next_fn; -# else typedef next next_fn; -# endif object m_sequence; // Keeps the sequence alive while iterating. Iterator m_start; @@ -230,8 +199,8 @@ inline object make_iterator_function( ) { typedef typename Accessor1::result_type iterator; - typedef typename add_const::type iterator_const; - typedef typename add_reference::type iterator_cref; + typedef typename boost::python::detail::add_const::type iterator_const; + typedef typename boost::python::detail::add_lvalue_reference::type iterator_cref; return detail::make_iterator_function( get_start diff --git a/include/boost/python/object/make_holder.hpp b/include/boost/python/object/make_holder.hpp index 0d54dd9f66..735e5395ca 100644 --- a/include/boost/python/object/make_holder.hpp +++ b/include/boost/python/object/make_holder.hpp @@ -89,8 +89,9 @@ struct make_holder BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, t, a)) { typedef instance instance_t; - - void* memory = Holder::allocate(p, offsetof(instance_t, storage), sizeof(Holder)); + + void* memory = Holder::allocate(p, offsetof(instance_t, storage), sizeof(Holder), + boost::python::detail::alignment_of::value); try { (new (memory) Holder( p BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_DO_FORWARD_ARG, nil)))->install(p); diff --git a/include/boost/python/object/make_instance.hpp b/include/boost/python/object/make_instance.hpp index 5f2630adc7..713fdc5ecd 100644 --- a/include/boost/python/object/make_instance.hpp +++ b/include/boost/python/object/make_instance.hpp @@ -9,10 +9,10 @@ # include # include # include +# include # include # include # include -# include namespace boost { namespace python { namespace objects { @@ -24,7 +24,8 @@ struct make_instance_impl template static inline PyObject* execute(Arg& x) { - BOOST_MPL_ASSERT((mpl::or_, is_union >)); + BOOST_MPL_ASSERT((mpl::or_, + boost::python::detail::is_union >)); PyTypeObject* type = Derived::get_class_object(x); @@ -42,11 +43,14 @@ struct make_instance_impl // construct the new C++ object and install the pointer // in the Python object. - Derived::construct(&instance->storage, (PyObject*)instance, x)->install(raw_result); + Holder *holder =Derived::construct(instance->storage.bytes, (PyObject*)instance, x); + holder->install(raw_result); // Note the position of the internally-stored Holder, // for the sake of destruction - Py_SIZE(instance) = offsetof(instance_t, storage); + const size_t offset = reinterpret_cast(holder) - + reinterpret_cast(instance->storage.bytes) + offsetof(instance_t, storage); + Py_SET_SIZE(instance, offset); // Release ownership of the python object protect.cancel(); @@ -68,7 +72,10 @@ struct make_instance static inline Holder* construct(void* storage, PyObject* instance, reference_wrapper x) { - return new (storage) Holder(instance, x); + size_t allocated = objects::additional_instance_size::value; + void* aligned_storage = ::boost::alignment::align(boost::python::detail::alignment_of::value, + sizeof(Holder), storage, allocated); + return new (aligned_storage) Holder(instance, x); } }; diff --git a/include/boost/python/object/make_ptr_instance.hpp b/include/boost/python/object/make_ptr_instance.hpp index 9fdb23f6be..92412b31fe 100644 --- a/include/boost/python/object/make_ptr_instance.hpp +++ b/include/boost/python/object/make_ptr_instance.hpp @@ -7,7 +7,7 @@ # include # include -# include +# include # include # include # include @@ -21,7 +21,11 @@ struct make_ptr_instance template static inline Holder* construct(void* storage, PyObject*, Arg& x) { - return new (storage) Holder(x); +#if defined(BOOST_NO_CXX11_SMART_PTR) + return new (storage) Holder(x); +#else + return new (storage) Holder(std::move(x)); +#endif } template @@ -43,7 +47,7 @@ struct make_ptr_instance return 0; // means "return None". PyTypeObject* derived = get_derived_class_object( - BOOST_DEDUCED_TYPENAME is_polymorphic::type(), p); + BOOST_DEDUCED_TYPENAME boost::python::detail::is_polymorphic::type(), p); if (derived) return derived; @@ -51,16 +55,16 @@ struct make_ptr_instance } template - static inline PyTypeObject* get_derived_class_object(mpl::true_, U const volatile* x) + static inline PyTypeObject* get_derived_class_object(boost::python::detail::true_, U const volatile* x) { converter::registration const* r = converter::registry::query( - type_info(typeid(*get_pointer(x))) + type_info(typeid(*x)) ); return r ? r->m_class_object : 0; } template - static inline PyTypeObject* get_derived_class_object(mpl::false_, U*) + static inline PyTypeObject* get_derived_class_object(boost::python::detail::false_, U*) { return 0; } diff --git a/include/boost/python/object/pickle_support.hpp b/include/boost/python/object/pickle_support.hpp index cbdbcbb9d6..aa96d655ee 100644 --- a/include/boost/python/object/pickle_support.hpp +++ b/include/boost/python/object/pickle_support.hpp @@ -107,7 +107,7 @@ namespace detail { { typedef typename error_messages::missing_pickle_suite_function_or_incorrect_signature< - Class_>::error_type error_type; + Class_>::error_type error_type BOOST_ATTRIBUTE_UNUSED; } }; diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index 4627e34ad2..c3b57e833a 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -21,6 +21,7 @@ # include # include # include +# include # include @@ -35,8 +36,6 @@ # include -# include - namespace boost { namespace python { template class wrapper; @@ -46,11 +45,7 @@ template class wrapper; namespace boost { namespace python { namespace objects { -# if BOOST_WORKAROUND(__GNUC__, == 2) -# define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) (typename unforward::type)objects::do_unforward(a##n,0) -# else -# define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) objects::do_unforward(a##n,0) -# endif +#define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) objects::do_unforward(a##n,0) template struct pointer_holder : instance_holder @@ -111,20 +106,28 @@ struct pointer_holder_back_reference : instance_holder template inline pointer_holder::pointer_holder(Pointer p) +#if defined(BOOST_NO_CXX11_SMART_PTR) : m_p(p) +#else + : m_p(std::move(p)) +#endif { } template inline pointer_holder_back_reference::pointer_holder_back_reference(Pointer p) +#if defined(BOOST_NO_CXX11_SMART_PTR) : m_p(p) +#else + : m_p(std::move(p)) +#endif { } template void* pointer_holder::holds(type_info dst_t, bool null_ptr_only) { - typedef typename boost::remove_const< Value >::type non_const_value; + typedef typename boost::python::detail::remove_const< Value >::type non_const_value; if (dst_t == python::type_id() && !(null_ptr_only && get_pointer(this->m_p)) diff --git a/include/boost/python/object/py_function.hpp b/include/boost/python/object/py_function.hpp index ba9aadf49f..df2fb44a4f 100644 --- a/include/boost/python/object/py_function.hpp +++ b/include/boost/python/object/py_function.hpp @@ -135,7 +135,11 @@ struct py_function {} py_function(py_function const& rhs) - : m_impl(rhs.m_impl) +#if defined(BOOST_NO_CXX11_SMART_PTR) + : m_impl(rhs.m_impl) +#else + : m_impl(std::move(rhs.m_impl)) +#endif {} PyObject* operator()(PyObject* args, PyObject* kw) const @@ -164,7 +168,11 @@ struct py_function } private: +#if defined(BOOST_NO_CXX11_SMART_PTR) mutable std::auto_ptr m_impl; +#else + mutable std::unique_ptr m_impl; +#endif }; }}} // namespace boost::python::objects diff --git a/include/boost/python/object/stl_iterator_core.hpp b/include/boost/python/object/stl_iterator_core.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index f4d452cab1..a4e91786d1 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -33,11 +33,7 @@ namespace boost { namespace python { namespace objects { -# if BOOST_WORKAROUND(__GNUC__, == 2) -# define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) (typename unforward::type)objects::do_unforward(a##n,0) -# else -# define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) objects::do_unforward(a##n,0) -# endif +#define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) objects::do_unforward(a##n,0) template struct value_holder : instance_holder diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 9c9dc10bfc..16480d0d89 100644 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -31,16 +31,7 @@ # include # include # include - -# include -# include -# include - -# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) -# include -# endif - -# include +# include namespace boost { namespace python { @@ -98,11 +89,7 @@ namespace api class object_operators : public def_visitor { protected: -# if !defined(BOOST_MSVC) || BOOST_MSVC >= 1300 typedef object const& object_cref; -# else - typedef object object_cref; -# endif public: // function call // @@ -139,25 +126,11 @@ namespace api template const_object_item - operator[](T const& key) const -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - ; -# else - { - return (*this)[object(key)]; - } -# endif + operator[](T const& key) const; template object_item - operator[](T const& key) -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - ; -# else - { - return (*this)[object(key)]; - } -# endif + operator[](T const& key); // slicing // @@ -175,29 +148,11 @@ namespace api template const_object_slice - slice(T const& start, V const& end) const -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - ; -# else - { - return this->slice( - slice_bound::type(start) - , slice_bound::type(end)); - } -# endif + slice(T const& start, V const& end) const; template object_slice - slice(T const& start, V const& end) -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - ; -# else - { - return this->slice( - slice_bound::type(start) - , slice_bound::type(end)); - } -# endif + slice(T const& start, V const& end); private: // def visitation for adding callable objects as class methods @@ -207,7 +162,7 @@ namespace api // It's too late to specify anything other than docstrings if // the callable object is already wrapped. BOOST_STATIC_ASSERT( - (is_same::value + (detail::is_same::value || detail::is_string_literal::value)); objects::add_to_namespace(cl, name, this->derived_visitor(), helper.doc()); @@ -248,55 +203,20 @@ namespace api PyObject* m_ptr; }; -# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct is_derived_impl - { - static T x; - template - static X* to_pointer(X const&); - - static char test(U const*); - typedef char (&no)[2]; - static no test(...); - - BOOST_STATIC_CONSTANT(bool, value = sizeof(test(to_pointer(x))) == 1); - }; - - template - struct is_derived - : mpl::bool_::value> - {}; -# else template struct is_derived - : is_convertible< - typename remove_reference::type* + : boost::python::detail::is_convertible< + typename detail::remove_reference::type* , U const* > {}; -# endif template typename objects::unforward_cref::type do_unforward_cref(T const& x) { -# if BOOST_WORKAROUND(__GNUC__, == 2) - typedef typename objects::unforward_cref::type ret; - return ret(x); -# else return x; -# endif } -# if BOOST_WORKAROUND(__GNUC__, == 2) - // GCC 2.x has non-const string literals; this hacks around that problem. - template - char const (& do_unforward_cref(char const(&x)[N]) )[N] - { - return x; - } -# endif - class object; template @@ -323,14 +243,7 @@ namespace api // explicit conversion from any C++ object to Python template - explicit object( - T const& x -# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - // use some SFINAE to un-confuse MSVC about its - // copy-initialization ambiguity claim. - , typename mpl::if_,int&,int>::type* = 0 -# endif - ) + explicit object(T const& x) : object_base(object_base_initializer(x)) { } @@ -348,7 +261,7 @@ namespace api // Macros for forwarding constructors in classes derived from // object. Derived classes will usually want these as an // implementation detail -# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_(derived, base) \ +# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(derived, base) \ inline explicit derived(::boost::python::detail::borrowed_reference p) \ : base(p) {} \ inline explicit derived(::boost::python::detail::new_reference p) \ @@ -356,23 +269,6 @@ namespace api inline explicit derived(::boost::python::detail::new_non_null_reference p) \ : base(p) {} -# if !defined(BOOST_MSVC) || BOOST_MSVC >= 1300 -# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_ -# else - // MSVC6 has a bug which causes an explicit template constructor to - // be preferred over an appropriate implicit conversion operator - // declared on the argument type. Normally, that would cause a - // runtime failure when using extract to extract a type with a - // templated constructor. This additional constructor will turn that - // runtime failure into an ambiguity error at compile-time due to - // the lack of partial ordering, or at least a link-time error if no - // generalized template constructor is declared. -# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(derived, base) \ - BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_(derived, base) \ - template \ - explicit derived(extract const&); -# endif - // // object_initializer -- get the handle to construct the object with, // based on whether T is a proxy or derived from object @@ -381,14 +277,14 @@ namespace api struct object_initializer_impl { static PyObject* - get(object const& x, mpl::true_) + get(object const& x, detail::true_) { return python::incref(x.ptr()); } template static PyObject* - get(T const& x, mpl::false_) + get(T const& x, detail::false_) { return python::incref(converter::arg_to_python(x).get()); } @@ -399,7 +295,7 @@ namespace api { template static PyObject* - get(proxy const& x, mpl::false_) + get(proxy const& x, detail::false_) { return python::incref(x.operator object().ptr()); } @@ -523,6 +419,7 @@ inline api::object_base& api::object_base::operator=(api::object_base const& rhs inline api::object_base::~object_base() { + assert( Py_REFCNT(m_ptr) > 0 ); Py_DECREF(m_ptr); } diff --git a/include/boost/python/object_items.hpp b/include/boost/python/object_items.hpp old mode 100755 new mode 100644 index f0761dadbb..b048689a7c --- a/include/boost/python/object_items.hpp +++ b/include/boost/python/object_items.hpp @@ -44,7 +44,6 @@ object_operators::operator[](object_cref key) const return const_object_item(x, key); } -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 template template inline const_object_item @@ -60,8 +59,6 @@ object_operators::operator[](T const& key) { return (*this)[object(key)]; } -# endif - inline object const_item_policies::get(object const& target, object const& key) { diff --git a/include/boost/python/object_operators.hpp b/include/boost/python/object_operators.hpp index d436bb0144..45d6d028cc 100644 --- a/include/boost/python/object_operators.hpp +++ b/include/boost/python/object_operators.hpp @@ -9,7 +9,7 @@ # include # include -# include +# include # include # include @@ -40,7 +40,7 @@ struct is_object_operators # if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE) template struct enable_binary - : boost::iterators::enable_if, T> + : boost::enable_if_::value, T> {}; # define BOOST_PYTHON_BINARY_RETURN(T) typename enable_binary::type # else diff --git a/include/boost/python/object_protocol_core.hpp b/include/boost/python/object_protocol_core.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/object_slices.hpp b/include/boost/python/object_slices.hpp index 748c2e954b..6cd3dc2974 100644 --- a/include/boost/python/object_slices.hpp +++ b/include/boost/python/object_slices.hpp @@ -99,7 +99,7 @@ object_operators::slice(object_cref start, slice_nil) const object_cref2 x = *static_cast(this); return const_object_slice(x, api::slice_key(borrowed(start.ptr()), allow_null((PyObject*)0))); } -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 + template template inline const_object_slice @@ -119,8 +119,6 @@ object_operators::slice(T const& start, V const& end) typename slice_bound::type(start) , typename slice_bound::type(end)); } -# endif - inline object const_slice_policies::get(object const& target, key_type const& key) { diff --git a/include/boost/python/opaque_pointer_converter.hpp b/include/boost/python/opaque_pointer_converter.hpp index 10eb4234c8..120985202b 100644 --- a/include/boost/python/opaque_pointer_converter.hpp +++ b/include/boost/python/opaque_pointer_converter.hpp @@ -1,4 +1,4 @@ -// Copyright Gottfried Gan�auge 2003..2006. +// Copyright Gottfried Ganßauge 2003..2006. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -13,14 +13,11 @@ # include # include # include +# include # include # include # include -# include -# include -# include - # include # include @@ -172,28 +169,19 @@ PyTypeObject opaque::type_object = }; }} // namespace boost::python -# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) - -# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) - -# else - // If you change the below, don't forget to alter the end of type_id.hpp # define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \ namespace boost { namespace python { \ template<> \ - inline type_info type_id(BOOST_PYTHON_EXPLICIT_TT_DEF(Pointee)) \ + inline type_info type_id() \ { \ return type_info (typeid (Pointee *)); \ } \ template<> \ - inline type_info type_id( \ - BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile Pointee&)) \ + inline type_info type_id() \ { \ return type_info (typeid (Pointee *)); \ } \ }} -# endif - # endif // OPAQUE_POINTER_CONVERTER_HPP_ diff --git a/include/boost/python/other.hpp b/include/boost/python/other.hpp old mode 100755 new mode 100644 index eeece99b7d..26ebb426ba --- a/include/boost/python/other.hpp +++ b/include/boost/python/other.hpp @@ -1,5 +1,5 @@ -#ifndef OTHER_DWA20020601_HPP -# define OTHER_DWA20020601_HPP +#ifndef BOOST_PYTHON_OTHER_HPP +# define BOOST_PYTHON_OTHER_HPP # include // Copyright David Abrahams 2002. @@ -7,10 +7,6 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -# if _MSC_VER+0 >= 1020 -# pragma once -# endif - # include namespace boost { namespace python { @@ -20,7 +16,6 @@ template struct other typedef T type; }; -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION namespace detail { template @@ -51,64 +46,7 @@ namespace detail typedef T type; }; } -# else // no partial specialization - -}} // namespace boost::python - -#include - -namespace boost { namespace python { - -namespace detail -{ - typedef char (&yes_other_t)[1]; - typedef char (&no_other_t)[2]; - - no_other_t is_other_test(...); - - template - yes_other_t is_other_test(type< other >); - - template - struct other_unwrapper - { - template - struct apply - { - typedef T type; - }; - }; - - template<> - struct other_unwrapper - { - template - struct apply - { - typedef typename T::type type; - }; - }; - - template - class is_other - { - public: - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(detail::is_other_test(type())) - == sizeof(detail::yes_other_t))); - }; - - template - class unwrap_other - : public detail::other_unwrapper< - is_other::value - >::template apply - {}; -} - -# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION }} // namespace boost::python -#endif // #ifndef OTHER_DWA20020601_HPP +#endif diff --git a/include/boost/python/override.hpp b/include/boost/python/override.hpp index 39714257f9..b631226fd6 100644 --- a/include/boost/python/override.hpp +++ b/include/boost/python/override.hpp @@ -97,7 +97,7 @@ class override : public object operator()() const { detail::method_result x( - PyEval_CallFunction( + PyObject_CallFunction( this->ptr() , const_cast("()") )); @@ -132,7 +132,7 @@ detail::method_result operator()( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, const& a) ) const { detail::method_result x( - PyEval_CallFunction( + PyObject_CallFunction( this->ptr() , const_cast("(" BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FIXED, "O") ")") BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_fast_arg_to_python_get, nil) diff --git a/include/boost/python/pointee.hpp b/include/boost/python/pointee.hpp index ab8bb87439..7ec01e0824 100644 --- a/include/boost/python/pointee.hpp +++ b/include/boost/python/pointee.hpp @@ -6,9 +6,7 @@ # define POINTEE_DWA2002323_HPP # include - -# include -# include +# include namespace boost { namespace python { @@ -17,7 +15,7 @@ namespace detail template struct pointee_impl { - template struct apply : remove_pointer {}; + template struct apply : detail::remove_pointer {}; }; template <> @@ -33,11 +31,11 @@ namespace detail template struct pointee : detail::pointee_impl< - ::boost::is_pointer::value + detail::is_pointer::value >::template apply { }; -}} // namespace boost::python::detail +}} // namespace boost::python #endif // POINTEE_DWA2002323_HPP diff --git a/include/boost/python/proxy.hpp b/include/boost/python/proxy.hpp old mode 100755 new mode 100644 index a956eac1cc..d3331d5676 --- a/include/boost/python/proxy.hpp +++ b/include/boost/python/proxy.hpp @@ -15,11 +15,7 @@ class proxy : public object_operators > { typedef typename Policies::key_type key_type; -# if !defined(BOOST_MSVC) || BOOST_MSVC >= 1300 typedef proxy const& assignment_self; -# else - typedef proxy assignment_self; -# endif public: proxy(object const& target, key_type const& key); operator object() const; diff --git a/include/boost/python/ptr.hpp b/include/boost/python/ptr.hpp index af1339c426..8e97aa4064 100644 --- a/include/boost/python/ptr.hpp +++ b/include/boost/python/ptr.hpp @@ -1,5 +1,5 @@ -#ifndef PTR_DWA20020601_HPP -# define PTR_DWA20020601_HPP +#ifndef BOOST_PYTHON_PTR_HPP +# define BOOST_PYTHON_PTR_HPP # include // Copyright David Abrahams 2002. @@ -11,10 +11,6 @@ // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // Copyright (C) 2001 Peter Dimov -# if _MSC_VER+0 >= 1020 -# pragma once -# endif - # include # include @@ -38,7 +34,6 @@ inline pointer_wrapper ptr(T t) return pointer_wrapper(t); } -# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template class is_pointer_wrapper : public mpl::false_ @@ -64,65 +59,7 @@ class unwrap_pointer > public: typedef T type; }; -# else // no partial specialization - -}} // namespace boost::python - -#include - -namespace boost { namespace python { - -namespace detail -{ - typedef char (&yes_pointer_wrapper_t)[1]; - typedef char (&no_pointer_wrapper_t)[2]; - - no_pointer_wrapper_t is_pointer_wrapper_test(...); - - template - yes_pointer_wrapper_t is_pointer_wrapper_test(boost::type< pointer_wrapper >); - - template - struct pointer_unwrapper - { - template - struct apply - { - typedef T type; - }; - }; - - template<> - struct pointer_unwrapper - { - template - struct apply - { - typedef typename T::type type; - }; - }; -} - -template -class is_pointer_wrapper -{ - public: - BOOST_STATIC_CONSTANT( - bool, value = ( - sizeof(detail::is_pointer_wrapper_test(boost::type())) - == sizeof(detail::yes_pointer_wrapper_t))); - typedef mpl::bool_ type; -}; - -template -class unwrap_pointer - : public detail::pointer_unwrapper< - is_pointer_wrapper::value - >::template apply -{}; - -# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION }} // namespace boost::python -#endif // #ifndef PTR_DWA20020601_HPP +#endif diff --git a/include/boost/python/pure_virtual.hpp b/include/boost/python/pure_virtual.hpp old mode 100755 new mode 100644 index b3b34ffcdb..f3b298de2c --- a/include/boost/python/pure_virtual.hpp +++ b/include/boost/python/pure_virtual.hpp @@ -47,7 +47,7 @@ namespace detail // replaced by void, and whose first argument is replaced by C&. template typename replace_front2::type - error_signature(S BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(C)) + error_signature(S) { typedef typename replace_front2::type r; return r(); @@ -96,6 +96,7 @@ namespace detail , make_function( detail::nullary_function_adaptor(pure_virtual_called) , default_call_policies() + , options.keywords() , detail::error_signature(detail::get_signature(m_pmf)) ) ); diff --git a/include/boost/python/raw_function.hpp b/include/boost/python/raw_function.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/refcount.hpp b/include/boost/python/refcount.hpp old mode 100755 new mode 100644 index 5ba5433c22..aa6aa5dbb6 --- a/include/boost/python/refcount.hpp +++ b/include/boost/python/refcount.hpp @@ -27,12 +27,14 @@ inline T* xincref(T* p) template inline void decref(T* p) { + assert( Py_REFCNT(python::upcast(p)) > 0 ); Py_DECREF(python::upcast(p)); } template inline void xdecref(T* p) { + assert( !p || Py_REFCNT(python::upcast(p)) > 0 ); Py_XDECREF(python::upcast(p)); } diff --git a/include/boost/python/reference_existing_object.hpp b/include/boost/python/reference_existing_object.hpp index bb8ddf7380..4c8344070b 100644 --- a/include/boost/python/reference_existing_object.hpp +++ b/include/boost/python/reference_existing_object.hpp @@ -9,7 +9,7 @@ # include # include # include -# include +# include namespace boost { namespace python { @@ -17,7 +17,7 @@ namespace detail { template struct reference_existing_object_requires_a_pointer_or_reference_return_type -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; @@ -31,7 +31,7 @@ struct reference_existing_object struct apply { BOOST_STATIC_CONSTANT( - bool, ok = is_pointer::value || is_reference::value); + bool, ok = detail::is_pointer::value || detail::is_reference::value); typedef typename mpl::if_c< ok diff --git a/include/boost/python/register_ptr_to_python.hpp b/include/boost/python/register_ptr_to_python.hpp index 7a22fe5052..d39bd0cf71 100644 --- a/include/boost/python/register_ptr_to_python.hpp +++ b/include/boost/python/register_ptr_to_python.hpp @@ -12,7 +12,7 @@ namespace boost { namespace python { template -void register_ptr_to_python(BOOST_EXPLICIT_TEMPLATE_TYPE(P)) +void register_ptr_to_python() { typedef typename boost::python::pointee

::type X; objects::class_value_wrapper< diff --git a/include/boost/python/return_arg.hpp b/include/boost/python/return_arg.hpp old mode 100755 new mode 100644 index c36f898d7d..de23993987 --- a/include/boost/python/return_arg.hpp +++ b/include/boost/python/return_arg.hpp @@ -12,8 +12,7 @@ # include #endif -# include -# include +# include # include # include @@ -29,7 +28,7 @@ namespace detail { template struct return_arg_pos_argument_must_be_positive -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; diff --git a/include/boost/python/return_by_value.hpp b/include/boost/python/return_by_value.hpp index 593fc59cfe..42d7076d17 100644 --- a/include/boost/python/return_by_value.hpp +++ b/include/boost/python/return_by_value.hpp @@ -8,8 +8,7 @@ # include # include -# include -# include +# include # include diff --git a/include/boost/python/return_internal_reference.hpp b/include/boost/python/return_internal_reference.hpp index acb89e6dc8..cc60f4422a 100644 --- a/include/boost/python/return_internal_reference.hpp +++ b/include/boost/python/return_internal_reference.hpp @@ -18,7 +18,7 @@ namespace detail { template struct return_internal_reference_owner_arg_must_be_greater_than_zero -# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) +# if defined(__GNUC__) || defined(__EDG__) {} # endif ; diff --git a/include/boost/python/return_opaque_pointer.hpp b/include/boost/python/return_opaque_pointer.hpp index cf544d8030..4654e3bd51 100644 --- a/include/boost/python/return_opaque_pointer.hpp +++ b/include/boost/python/return_opaque_pointer.hpp @@ -1,4 +1,4 @@ -// Copyright Gottfried Gan�auge 2003. +// Copyright Gottfried Ganßauge 2003. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/include/boost/python/self.hpp b/include/boost/python/self.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/signature.hpp b/include/boost/python/signature.hpp index f1143e3abe..ab4bca390a 100644 --- a/include/boost/python/signature.hpp +++ b/include/boost/python/signature.hpp @@ -14,9 +14,9 @@ # include # include -# include # include +# include # include # include # include @@ -42,7 +42,7 @@ template struct most_derived { typedef typename mpl::if_< - is_convertible + detail::is_convertible , C1 , C2 >::type type; diff --git a/include/boost/python/slice.hpp b/include/boost/python/slice.hpp index 19f316a1e7..80660fab77 100644 --- a/include/boost/python/slice.hpp +++ b/include/boost/python/slice.hpp @@ -119,7 +119,7 @@ class slice : public detail::slice_base slice::range ret; typedef typename iterator_difference::type difference_type; - difference_type max_dist = boost::detail::distance(begin, end); + difference_type max_dist = std::distance(begin, end); object slice_start = this->start(); object slice_stop = this->stop(); @@ -212,7 +212,7 @@ class slice : public detail::slice_base // (inclusive), and final_dist is the maximum distance covered by the // slice. typename iterator_difference::type final_dist = - boost::detail::distance( ret.start, ret.stop); + std::distance( ret.start, ret.stop); // First case, if both ret.start and ret.stop are equal, then step // is irrelevant and we can return here. diff --git a/include/boost/python/stl_iterator.hpp b/include/boost/python/stl_iterator.hpp old mode 100755 new mode 100644 diff --git a/include/boost/python/str.hpp b/include/boost/python/str.hpp index 426a3a255c..434c8c986c 100644 --- a/include/boost/python/str.hpp +++ b/include/boost/python/str.hpp @@ -184,7 +184,7 @@ class str : public detail::str_base template long count(T1 const& sub,T2 const& start, T3 const& end) const { - return base::count(object(sub), object(start)); + return base::count(object(sub), object(start), object(end)); } #if PY_VERSION_HEX < 0x03000000 diff --git a/include/boost/python/suite/indexing/detail/indexing_suite_detail.hpp b/include/boost/python/suite/indexing/detail/indexing_suite_detail.hpp index 70df8a7273..d470e32d77 100644 --- a/include/boost/python/suite/indexing/detail/indexing_suite_detail.hpp +++ b/include/boost/python/suite/indexing/detail/indexing_suite_detail.hpp @@ -11,7 +11,7 @@ # include # include # include -# include +# include # include # include #include @@ -216,7 +216,13 @@ namespace boost { namespace python { namespace detail { { for (const_iterator i = proxies.begin(); i != proxies.end(); ++i) { - if ((*i)->ob_refcnt <= 0) + if ( +#if PY_VERSION_HEX < 0x03090000 + (*i)->ob_refcnt +#else + Py_REFCNT(*i) +#endif + <= 0) { PyErr_SetString(PyExc_RuntimeError, "Invariant: Proxy vector in an inconsistent state"); @@ -465,14 +471,14 @@ namespace boost { namespace python { namespace detail { template static object - base_get_item_helper(DataType const& p, mpl::true_) + base_get_item_helper(DataType const& p, detail::true_) { return object(ptr(p)); } template static object - base_get_item_helper(DataType const& x, mpl::false_) + base_get_item_helper(DataType const& x, detail::false_) { return object(x); } diff --git a/include/boost/python/suite/indexing/indexing_suite.hpp b/include/boost/python/suite/indexing/indexing_suite.hpp index b636b2111c..3469a2a40f 100644 --- a/include/boost/python/suite/indexing/indexing_suite.hpp +++ b/include/boost/python/suite/indexing/indexing_suite.hpp @@ -14,7 +14,7 @@ # include # include # include -# include +# include namespace boost { namespace python { @@ -122,20 +122,16 @@ namespace boost { namespace python { mpl::bool_ , mpl::not_ > , typename mpl::or_< - is_same - , is_same > - , is_same > - , is_same > >::type> + detail::is_same + , detail::is_same > + , detail::is_same > + , detail::is_same > >::type> no_proxy; typedef detail::container_element container_element_t; -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - struct return_policy : return_internal_reference<> {}; -#else typedef return_internal_reference<> return_policy; -#endif typedef typename mpl::if_< no_proxy diff --git a/include/boost/python/to_python_converter.hpp b/include/boost/python/to_python_converter.hpp index 378d159e97..4391b6dce9 100644 --- a/include/boost/python/to_python_converter.hpp +++ b/include/boost/python/to_python_converter.hpp @@ -48,12 +48,7 @@ template < class T, class Conversion, bool has_get_pytype=false > struct to_python_converter { #ifndef BOOST_PYTHON_NO_PY_SIGNATURES -#if 0 //defined _MSC_VER && _MSC_VER >=1310 - //probably other compilers could come here as well - typedef typename detail::test_get_pytype HasGetPytype; -#else typedef boost::mpl::bool_ HasGetPytype; -#endif static PyTypeObject const* get_pytype_1(boost::mpl::true_ *) { diff --git a/include/boost/python/to_python_indirect.hpp b/include/boost/python/to_python_indirect.hpp index 23ad026319..0a19aca5ff 100644 --- a/include/boost/python/to_python_indirect.hpp +++ b/include/boost/python/to_python_indirect.hpp @@ -18,10 +18,7 @@ # include -# include -# include - -# include +# include # if defined(__ICL) && __ICL < 600 # include @@ -38,7 +35,7 @@ struct to_python_indirect inline PyObject* operator()(U const& ref) const { - return this->execute(const_cast(ref), is_pointer()); + return this->execute(const_cast(ref), detail::is_pointer()); } #ifndef BOOST_PYTHON_NO_PY_SIGNATURES inline PyTypeObject const* @@ -49,20 +46,20 @@ struct to_python_indirect #endif private: template - inline PyObject* execute(U* ptr, mpl::true_) const + inline PyObject* execute(U* ptr, detail::true_) const { // No special NULL treatment for references if (ptr == 0) return python::detail::none(); else - return this->execute(*ptr, mpl::false_()); + return this->execute(*ptr, detail::false_()); } template - inline PyObject* execute(U const& x, mpl::false_) const + inline PyObject* execute(U const& x, detail::false_) const { U* const p = &const_cast(x); - if (is_polymorphic::value) + if (detail::is_polymorphic::value) { if (PyObject* o = detail::wrapper_base_::owner(p)) return incref(o); @@ -86,8 +83,10 @@ namespace detail // copy constructor. # if defined(__ICL) && __ICL < 600 typedef boost::shared_ptr smart_pointer; -# else +# elif defined(BOOST_NO_CXX11_SMART_PTR) typedef std::auto_ptr smart_pointer; +# else + typedef std::unique_ptr smart_pointer; # endif typedef objects::pointer_holder holder_t; diff --git a/include/boost/python/to_python_value.hpp b/include/boost/python/to_python_value.hpp index a48948d256..b6ec0135ba 100644 --- a/include/boost/python/to_python_value.hpp +++ b/include/boost/python/to_python_value.hpp @@ -1,30 +1,30 @@ // Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef TO_PYTHON_VALUE_DWA200221_HPP -# define TO_PYTHON_VALUE_DWA200221_HPP -# include +#ifndef boost_python_to_python_value_hpp_ +#define boost_python_to_python_value_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 namespace boost { namespace python { @@ -114,10 +114,16 @@ struct object_manager_get_pytype BOOST_STATIC_CONSTANT(bool, uses_registry = false); private: #ifndef BOOST_PYTHON_NO_PY_SIGNATURES - template - PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} - template - PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} + template + PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} + template + PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} +# if !defined(BOOST_NO_CXX11_SMART_PTR) + template + PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} + template + PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} +# endif #endif }; } @@ -147,11 +153,6 @@ namespace detail template inline PyObject* registry_to_python_value::operator()(argument_type x) const { - typedef converter::registered r; -# if BOOST_WORKAROUND(__GNUC__, < 3) - // suppresses an ICE, somehow - (void)r::converters; -# endif return converter::registered::converters.to_python(&x); } @@ -173,4 +174,4 @@ namespace detail }} // namespace boost::python -#endif // TO_PYTHON_VALUE_DWA200221_HPP +#endif diff --git a/include/boost/python/type_id.hpp b/include/boost/python/type_id.hpp index 4a5727d514..601601c311 100644 --- a/include/boost/python/type_id.hpp +++ b/include/boost/python/type_id.hpp @@ -14,12 +14,10 @@ # include # include # include -# include -# include +# include # ifndef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE # if defined(__GNUC__) \ - && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) \ && !defined(__EDG_VERSION__) # define BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE # endif @@ -30,7 +28,7 @@ namespace boost { namespace python { // for this compiler at least, cross-shared-library type_info // comparisons don't work, so use typeid(x).name() instead. It's not // yet clear what the best default strategy is. -# if (defined(__GNUC__) && __GNUC__ >= 3) \ +# if defined(__GNUC__) \ || defined(_AIX) \ || ( defined(__sgi) && defined(__host_mips)) \ || (defined(__hpux) && defined(__HP_aCC)) \ @@ -69,21 +67,18 @@ struct type_info : private totally_ordered base_id_t m_base_type; }; -# ifdef BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS -# define BOOST_PYTHON_EXPLICIT_TT_DEF(T) ::boost::type* -# else -# define BOOST_PYTHON_EXPLICIT_TT_DEF(T) -# endif + +// This macro is obsolete. Port away and remove. +# define BOOST_PYTHON_EXPLICIT_TT_DEF(T) template -inline type_info type_id(BOOST_EXPLICIT_TEMPLATE_TYPE(T)) +inline type_info type_id() { return type_info( # if !defined(_MSC_VER) \ - || (!BOOST_WORKAROUND(BOOST_MSVC, <= 1300) \ - && !BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 700)) + || !BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 700) typeid(T) -# else // strip the decoration which msvc and Intel mistakenly leave in +# else // strip the decoration which Intel mistakenly leaves in python::detail::msvc_typeid((boost::type*)0) # endif ); @@ -99,7 +94,7 @@ inline type_info type_id(BOOST_EXPLICIT_TEMPLATE_TYPE(T)) # define BOOST_PYTHON_SIGNED_INTEGRAL_TYPE_ID(T) \ template <> \ -inline type_info type_id(BOOST_PYTHON_EXPLICIT_TT_DEF(T)) \ +inline type_info type_id() \ { \ return type_info(typeid(T)); \ } @@ -171,22 +166,19 @@ inline char const* type_info::name() const BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream&, type_info const&); -# if !BOOST_WORKAROUND(BOOST_MSVC, == 1200) template<> -inline type_info type_id(BOOST_PYTHON_EXPLICIT_TT_DEF(void)) +inline type_info type_id() { return type_info (typeid (void *)); } # ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS template<> -inline type_info type_id(BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile void)) +inline type_info type_id() { return type_info (typeid (void *)); } # endif -# endif - }} // namespace boost::python #endif // TYPE_ID_DWA2002517_HPP diff --git a/include/boost/python/with_custodian_and_ward.hpp b/include/boost/python/with_custodian_and_ward.hpp index 9399478f23..3431c6f22c 100644 --- a/include/boost/python/with_custodian_and_ward.hpp +++ b/include/boost/python/with_custodian_and_ward.hpp @@ -85,14 +85,10 @@ struct with_custodian_and_ward_postcall : BasePolicy_ static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) { std::size_t arity_ = detail::arity(args_); -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - if ( custodian > arity_ || ward > arity_ ) -#else // check if either custodian or ward exceeds the arity // (this weird formulation avoids "always false" warnings // for arity_ = 0) if ( (std::max)(custodian, ward) > arity_ ) -#endif { PyErr_SetString( PyExc_IndexError diff --git a/include/boost/python/wrapper.hpp b/include/boost/python/wrapper.hpp old mode 100755 new mode 100644 diff --git a/index.html b/index.html index 9c6acc885a..1e1a275312 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,13 @@ - - - + - - - - -Automatically loading index page... if nothing happens, please go to -doc/index.html. - + + + + + Automatic redirection failed, click this + link  


+

� Copyright Stefan Seefeld, 2015

+

Distributed under the Boost Software License, Version 1.0. (See accompanying + file http://www.boost.org/LICENSE_1_0.txt)

+ diff --git a/meta/libraries.json b/meta/libraries.json new file mode 100644 index 0000000000..80f20f846c --- /dev/null +++ b/meta/libraries.json @@ -0,0 +1,15 @@ +{ + "key": "python", + "name": "Python", + "authors": [ + "Dave Abrahams" + ], + "description": "The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools -- just your C++ compiler.", + "category": [ + "Inter-language" + ], + "maintainers": [ + "Stefan Seefeld " + ], + "cxxstd": "03" +} diff --git a/pyste/NEWS b/pyste/NEWS deleted file mode 100644 index 31a5ceba28..0000000000 --- a/pyste/NEWS +++ /dev/null @@ -1,212 +0,0 @@ -.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -25 April 2005 -- Fixed bug where the code for wrappers of member functions were defined outside -the pyste namespace. Reported by Dan Haffey. - -9 October 2004 -- Applied a patch by Christian Hudon that fixed an issue with files -that had a tail and relative includes. - -18 July 2004 -- Applied a patch by Paul Bridger that solves some problems for wrapper -methods. -- Applied a patch by Baptiste Lepilleur that allows the user to inject -code inside the class definition. -- Applied another patch by Baptiste Lepilleur that inserts two new command-line -options that helps with writing makefiles. - -27 May 2004 -Applied patch by Paul Bridger that solves a problem on windows regarding -spaces on paths. Thanks Paul! - -Applied another patch that fixes the module name if pyste is run from -another directory of where the .pyste file is located. Patch contributted -by Paul Bridger. - -17 May 2004 -Applied a patch by Roman Yakovenko that makes the export of unnamed enums -better. Thanks Roman! - -23 October 2003 -Fixed bug where a class would appear more than one in the generated code. - -6 October 2003 -Fixed bug reported by Niall Douglas (using his patch) about UniqueInt not -appearing correctly with --multiple. - -Added precompiled header support on windows systems (using #pragma hdrstop). -Suggested by Niall Douglas. - -Fixed a bug with -I directive and AllFromHeader. Reported by Scott Snyder. - -4 October 2003 -Added return_self, thanks for Niall Douglas for pointing out that it was -missing. - -Added --file-list, where you can pass a file where the pyste files are listed -one per line. Also suggested by Niall Douglas. - -Documentation has been finally updated, after a long wait. Please let me know -if you spot any mistake! - -2 October 2003 -Scott Snyder found a typo in ClassExporter that prevented -= and *= operators -from being exported. Thanks Scott! - -20 September 2003 -Added return_by_value in the list of policies supported. Thanks to Niall -Douglas for the remainder. - -19 September 2003 -Better support for unnamed enums, plus they are by default exported to the -parent's namespace. Normal enums can have the same behaviour using the function -export_values on the Enum object. Feature requested by Niall Douglas. - -10 September 2003 -A new variable is accessible in the Pyste files: INTERFACE_FILE contains the -full path of the pyste file. - -4 September 2003 -Now it is possible to override protected and private pure virtual functions -in Python, as requested by Roman Yakovenko. - -23 August 2003 -Fixed bug where some Imports where not writing their include files. -Now whenever the declarations change, the cache files are rebuilt -automatically. - -19 August 2003 -Fixed a bug related to the generation of the bases<> template. - -17 August 2003 -Added support for insertion of user code in the generated code. - -16 August 2003 -Applied a patch by Gottfried Ganssauge that adds exception specifiers to -wrapper functions and pointer declarations. Thanks a lot Gottfried!! - -Applied a patch by Prabhu Ramachandran that fixes ae problem with the -pure virtual method generation. Thanks again Prabhu! - -10 August 2003 -Support for incremental generation of the code has been added. This changes -how --multiple works; documentation of this new feature will follow. Thanks -to Prabhu Ramachandran, that saw the need for this feature and discussed a -solution. - -Automatically convert \ to / in Windows systems before passing the paths to -gccxml. - -Fixed a bug reported by Prabhu Ramachandran, where in some classes the virtual -methods were being definied incorrectly. Thanks a lot Prabhu! - -7 July 2003 -Applied 2 patches by Prabhu Ramachandran: a fix in the new --multiple method, -and two new functions "hold_with_shared_ptr" and its counterpart for auto_ptr. -Thanks a lot Prabhu! - -Fixed a bug where the macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID was being -called multiple times for the same type. -Thanks to Gottfried Gan�auge for reporting this! - -Fixed bug where using AllFromHeader didn't use bases<> when exporting -hierarchies. - -Fixed the staticmethod bug. - -5 July 2003 -Changed how --multiple works: now it generates one cpp file for each pyste -file, makeing easier to integrate Pyste with build systems. - -4 July 2003 -Applied patch that solved a bug in ClassExporter and added a distutils install -script (install/setup.py), both contributed by Prabhu Ramachandran. -Thanks Prabhu! - -2 July 2003 -Jim Wilson found a bug where types like "char**" were being interpreted as -"char*". Thanks Jim! - -16 June 2003 -Thanks to discussions with David Abrahams and Roman Sulzhyk, some behaviours -have changed: - -- If you export a derived class without exporting its base classes, the derived - class will explicitly export the bases's methods and attributes. Before, if - you were interested in the bases's methods, you had to export the base - classes too. - -- Added a new function, no_override. When a member function is specified as - "no_override", no virtual wrappers are generated for it, improving - performance and letting the code more clean. - -- There was a bug in which the policy of virtual member functions was being - ignored (patch by Roman Sulzhyk). - -Thanks again to Roman Sulzhyk for the patches and discussion in the c++-sig. - -4 June 2003 -Major improvements in memory usage. - -3 June 2003 -Appliced a patch from Giulio Eulisse that allows unnamed enumerations to be -exported with an AllFromHeader construct. Thanks a lot Giulio! - -2 June 2003 -Added a new construct, add_method. See documentation. - -23 May 2003 -Support for global variables added. -Various bug fixes. - -08 May 2003 -Fixed bug where in a certain cases the GCCXMLParser would end up with multiple -declarations of the same class - -22 Apr 2003 -- Now shows a warning when the user tries to export a forward-declared class. - Forward-declared classes are ignored by the AllFromHeader construct. -- Fixed a bug where classes, functions and enums where being exported, even if - excluded from a AllFromHeader construct. - -16 Apr 2003 -Added a more generic (but ugly) code to declare the smart pointer converters. - -07 Apr 2003 -- Removed the warnings about forward declarations: it was not accurate enough. - Another strategy must be thought of. -- Fixed bug in the --multiple mode, where the order of the class instantiations - could end up wrong. -- Lots of fixes in the documentation, pointed out by Dirk Gerrits. Thanks Dirk! -- Fixed support for the return_opaque_pointer policy (the support macro was not - being declared). - - -06 Apr 2003 -Support for the improved static data members support of Boost.Python. - -05 Apr 2003 -New option for generating the bindings: --multiple. - -02 Apr 2003 -Forward declarations are now detected and a warning is generated. - -24 Mar 2003 -Default policy for functions/methods that return const T& is now -return_value_policy(). - -22 Mar 2003 -Exporting virtual methods of the base classes in the derived classes too. - -21 Mar 2003 -Added manual support for boost::shared_ptr and std::auto_ptr (see doc). - -19 Mar 2003 -Added support for int, double, float and long operators acting as expected in -python. - -14 Mar 2003 -Fixed bug: Wrappers for protected and virtual methods were not being generated. diff --git a/pyste/README b/pyste/README deleted file mode 100644 index c378f39162..0000000000 --- a/pyste/README +++ /dev/null @@ -1,35 +0,0 @@ -.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -Pyste - Python Semi-Automatic Exporter -====================================== - -Pyste is a Boost.Python code generator. The user specifies the classes and -functions to be exported using a simple interface file, which following the -Boost.Python's philosophy, is simple Python code. Pyste then uses GCCXML to -parse all the headers and extract the necessary information to automatically -generate C++ code. - -The documentation can be found in the file index.html accompaning this README. - -Enjoy! -Bruno da Silva de Oliveira (nicodemus@esss.com.br) - -Thanks -====== - -- David Abrahams, creator of Boost.Python, for tips on the syntax of the interface - file and support. -- Marcelo Camelo, for design tips, support and inspiration for this project. - Also, the name was his idea. 8) -- Brad King, creator of the excellent GCCXML (http://www.gccxml.org) -- Fredrik Lundh, creator of the elementtree library (http://effbot.org) - -Bugs -==== - -Pyste is a young tool, so please help it to get better! Send bug reports to -nicodemus@esss.com.br, accompaining the stack trace in case of exceptions. -If possible, run pyste with --debug, and send the resulting xmls too (pyste -will output a xml file with the same of each header it parsed). diff --git a/pyste/TODO b/pyste/TODO deleted file mode 100644 index 0b3c9024f1..0000000000 --- a/pyste/TODO +++ /dev/null @@ -1,18 +0,0 @@ -.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -- Make Pyste accept already-generated xml files - -- throw() declaration in virtual wrapper's member functions - -- Allow protected methods to be overriden in Python - -- Expose programmability to the Pyste files (listing members of a class, for - instance) - -- Virtual operators - -- args() support - -- set policies to methods with the same name diff --git a/pyste/dist/create_build.py b/pyste/dist/create_build.py deleted file mode 100644 index a683699511..0000000000 --- a/pyste/dist/create_build.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -import os -import sys -import shutil -import fnmatch -from zipfile import ZipFile, ZIP_DEFLATED - -def findfiles(directory, mask): - def visit(files, dir, names): - for name in names: - if fnmatch.fnmatch(name, mask): - files.append(os.path.join(dir, name)) - files = [] - os.path.walk(directory, visit, files) - return files - - -def main(): - # test if PyXML is installed - try: - import _xmlplus.parsers.expat - pyxml = '--includes _xmlplus.parsers.expat' - except ImportError: - pyxml = '' - # create exe - status = os.system('python setup.py py2exe %s >& build.log' % pyxml) - if status != 0: - raise RuntimeError, 'Error creating EXE' - - # create distribution - import pyste - version = pyste.__VERSION__ - zip = ZipFile('pyste-%s.zip' % version, 'w', ZIP_DEFLATED) - # include the base files - dist_dir = 'dist/pyste' - for basefile in os.listdir(dist_dir): - zip.write(os.path.join(dist_dir, basefile), os.path.join('pyste', basefile)) - # include documentation - for doc_file in findfiles('../doc', '*.*'): - dest_name = os.path.join('pyste/doc', doc_file[3:]) - zip.write(doc_file, dest_name) - zip.write('../index.html', 'pyste/doc/index.html') - zip.close() - # cleanup - os.remove('build.log') - shutil.rmtree('build') - shutil.rmtree('dist') - - -if __name__ == '__main__': - sys.path.append('../src') - main() diff --git a/pyste/dist/setup.py b/pyste/dist/setup.py deleted file mode 100644 index fc7c74e210..0000000000 --- a/pyste/dist/setup.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -from distutils.core import setup -import py2exe -import sys - -sys.path.append('../src') -setup(name='pyste', scripts=['../src/pyste.py']) diff --git a/pyste/doc/adding_new_methods.html b/pyste/doc/adding_new_methods.html deleted file mode 100644 index afa772bcc6..0000000000 --- a/pyste/doc/adding_new_methods.html +++ /dev/null @@ -1,79 +0,0 @@ - - - -Adding New Methods - - - - - - - - - - -
- - Adding New Methods -
-
- - - - - - -
-

-Suppose that you want to add a function to a class, turning it into a member -function:

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

-Here, we want to make greet work as a member function of the class World. We do -that using the add_method construct:

-
-    W = Class("World", "hello.h")
-    add_method(W, "greet")
-
-

-Notice also that then you can rename it, set its policy, just like a regular -member function:

-
-    rename(W.greet, 'Greet')
-
-

-Now from Python:

-
-    >>> import hello
-    >>> w = hello.World()
-    >>> w.set('Ni')
-    >>> w.greet()
-    'Ni'
-    >>> print 'Oh no! The knights who say Ni!'
-    Oh no! The knights who say Ni!
-
- - - - - - -
-
-
- - diff --git a/pyste/doc/exporting_an_entire_header.html b/pyste/doc/exporting_an_entire_header.html deleted file mode 100644 index db25325cad..0000000000 --- a/pyste/doc/exporting_an_entire_header.html +++ /dev/null @@ -1,85 +0,0 @@ - - - -Exporting An Entire Header - - - - - - - - - - -
- - Exporting An Entire Header -
-
- - - - - - -
-

-Pyste also supports a mechanism to export all declarations found in a header -file. Suppose again our file, hello.h:

-
-    struct World
-    {
-        World(std::string msg): msg(msg) {} 
-        void set(std::string msg) { this->msg = msg; }
-        std::string greet() { return msg; }
-        std::string msg;
-    };
-
-    enum choice { red, blue };
-    
-    void show(choice c) { std::cout << "value: " << (int)c << std::endl; } 
-
-

-You can just use the AllFromHeader construct:

-
-    hello = AllFromHeader("hello.h")
-
-

-this will export all the declarations found in hello.h, which is equivalent -to write:

-
-    Class("World", "hello.h")
-    Enum("choice", "hello.h")
-    Function("show", "hello.h")
-
-

-Note that you can still use the functions rename, set_policy, exclude, etc. Just access -the members of the header object like this:

-
-    rename(hello.World.greet, "Greet")
-    exclude(hello.World.set, "Set")
-
- - - - -
- - AllFromHeader is broken in some cases. Until it is fixed, -use at you own risk. -
- - - - - - -
-
-
- - diff --git a/pyste/doc/global_variables.html b/pyste/doc/global_variables.html deleted file mode 100644 index 0efd2950b7..0000000000 --- a/pyste/doc/global_variables.html +++ /dev/null @@ -1,49 +0,0 @@ - - - -Global Variables - - - - - - - - - - -
- - Global Variables -
-
- - - - - - -
-

-To export global variables, use the Var construct:

-
-    Var("myglobal", "foo.h")
-
-

-Beware of non-const global variables: changes in Python won't reflect in C++! -If you really must change them in Python, you will have to write some accessor -functions, and export those.

- - - - - - -
-
-
- - diff --git a/pyste/doc/inserting_code.html b/pyste/doc/inserting_code.html deleted file mode 100644 index 97eb70f388..0000000000 --- a/pyste/doc/inserting_code.html +++ /dev/null @@ -1,72 +0,0 @@ - - - -Inserting Code - - - - - - - - - -
- - Inserting Code -
-
- - - - - - -
-

-You can insert arbitrary code in the generated cpps, just use the functions -declaration_code and module_code. This will insert the given string in the -respective sections. Example:

-
-    ##file A.pyste
-    Class("A", "A.h")
-    declaration_code("/* declaration_code() comes here */\n")
-    module_code("/* module_code() comes here */\n")
-
-

-Will generate:

-
-    // Includes ====================================================================
-    #include <boost/python.hpp>
-
-    // Using =======================================================================
-    using namespace boost::python;
-
-    // Declarations ================================================================
-
-    /* declaration_code() comes here */
-
-    // Module ======================================================================
-    BOOST_PYTHON_MODULE(A)
-    {
-        class_< A >("A", init<  >())
-            .def(init< const A& >())
-        ;
-
-    /* module_code() comes here */
-    }
-
- - - - - - -
-
-
- - diff --git a/pyste/doc/introduction.html b/pyste/doc/introduction.html deleted file mode 100644 index 9438849314..0000000000 --- a/pyste/doc/introduction.html +++ /dev/null @@ -1,73 +0,0 @@ - - - -Introduction - - - - - - - - - -
- - Introduction -
-
- - - - - - -
-

What is Pyste?

-Pyste is a -Boost.Python code generator. The user specifies the classes and -functions to be exported using a simple interface file, which following the - -Boost.Python's philosophy, is simple Python code. Pyste then uses -GCCXML to -parse all the headers and extract the necessary information to automatically -generate C++ code.

-

Example

-Let's borrow the class World from the -tutorial:

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

-Here's the interface file for it, named world.pyste:

-
-    Class("World", "world.h")
-
-

-and that's it!

-

-The next step is invoke Pyste in the command-line:

-
python pyste.py --module=hello world.pyste

-this will create a file "hello.cpp" in the directory where the command was -run.

-

-Pyste supports the following features:

-
  • Functions
  • Classes
  • Class Templates
  • Virtual Methods
  • Overloading
  • Attributes
  • Enums (both "free" enums and class enums)
  • Nested Classes
  • Support for boost::shared_ptr and std::auto_ptr
  • Global Variables
- - - - - -
-
-
- - diff --git a/pyste/doc/policies.html b/pyste/doc/policies.html deleted file mode 100644 index 3628093bd3..0000000000 --- a/pyste/doc/policies.html +++ /dev/null @@ -1,90 +0,0 @@ - - - -Policies - - - - - - - - - - -
- - Policies -
-
- - - - - - -
-

-Even thought Pyste can identify various elements in the C++ code, like virtual -member functions, attributes, and so on, one thing that it can't do is to -guess the semantics of functions that return pointers or references. In this -case, the user must manually specify the policy. Policies are explained in the - -tutorial.

-

-The policies in Pyste are named exactly as in -Boost.Python, only the syntax is -slightly different. For instance, this policy:

-
-    return_internal_reference<1, with_custodian_and_ward<1, 2> >()
-
-

-becomes in Pyste:

-
-    return_internal_reference(1, with_custodian_and_ward(1, 2))
-
-

-The user can specify policies for functions and virtual member functions with -the set_policy function:

-
-    set_policy(f, return_internal_reference())
-    set_policy(C.foo, return_value_policy(manage_new_object))
-
- - - - -
- - What if a function or member function needs a policy and -the user doesn't set one?

If a function needs a policy and one -was not set, Pyste will issue a error. The user should then go in the -interface file and set the policy for it, otherwise the generated cpp won't -compile. -
- - - - -
- - -Note that for functions that return const T&, the policy -return_value_policy<copy_const_reference>() wil be used by default, because -that's normally what you want. You can change it to something else if you need -to, though. -
- - - - - - -
-
-
- - diff --git a/pyste/doc/pyste.txt b/pyste/doc/pyste.txt deleted file mode 100644 index 186a31cba4..0000000000 --- a/pyste/doc/pyste.txt +++ /dev/null @@ -1,664 +0,0 @@ -[doc Pyste Documentation] - -[/ Copyright 2003 Bruno da Silva de Oliveira and Joel de Guzman. -Distributed under the Boost Software License, Version 1.0. (See -accompanying file LICENSE_1_0.txt or copy at -http://www.boost.org/LICENSE_1_0.txt) ] - -[def GCCXML [@http://www.gccxml.org GCCXML]] -[def Boost.Python [@../../index.html Boost.Python]] - -[page Introduction] - -[h2 What is Pyste?] - -Pyste is a Boost.Python code generator. The user specifies the classes and -functions to be exported using a simple ['interface file], which following the -Boost.Python's philosophy, is simple Python code. Pyste then uses GCCXML to -parse all the headers and extract the necessary information to automatically -generate C++ code. - -[h2 Example] - -Let's borrow the class [^World] from the [@../../doc/tutorial/doc/exposing_classes.html tutorial]: - - struct World - { - void set(std::string msg) { this->msg = msg; } - std::string greet() { return msg; } - std::string msg; - }; - -Here's the interface file for it, named [^world.pyste]: - - Class("World", "world.h") - -and that's it! - -The next step is invoke Pyste in the command-line: - -[pre python pyste.py --module=hello world.pyste] - -this will create a file "[^hello.cpp]" in the directory where the command was -run. - -Pyste supports the following features: - -* Functions -* Classes -* Class Templates -* Virtual Methods -* Overloading -* Attributes -* Enums (both "free" enums and class enums) -* Nested Classes -* Support for [^boost::shared_ptr] and [^std::auto_ptr] -* Global Variables - -[page Running Pyste] - -To run Pyste, you will need: - -* Python 2.2, available at [@http://www.python.org python's website]. -* The great [@http://effbot.org elementtree] library, from Fredrik Lundh. -* The excellent GCCXML, from Brad King. - -Installation for the tools is available in their respective webpages. - -[blurb -[$theme/note.gif] GCCXML must be accessible in the PATH environment variable, so -that Pyste can call it. How to do this varies from platform to platform. -] - -[h2 Ok, now what?] - -Well, now let's fire it up: - -[pre -''' ->python pyste.py - -Pyste version 0.9.26 - -Usage: - pyste [options] interface-files - -where options are: - --module= The name of the module that will be generated; - defaults to the first interface filename, without - the extension. - -I Add an include path - -D Define symbol - --multiple Create various cpps, instead of only one - (useful during development) - --out= Specify output filename (default: .cpp) - in --multiple mode, this will be a directory - --no-using Do not declare "using namespace boost"; - use explicit declarations instead - --pyste-ns= Set the namespace where new types will be declared; - default is the empty namespace - --debug Writes the xml for each file parsed in the current - directory - --cache-dir= Directory for cache files (speeds up future runs) - --only-create-cache Recreates all caches (doesn't generate code). - --generate-main Generates the _main.cpp file (in multiple mode) - --file-list A file with one pyste file per line. Use as a - substitute for passing the files in the command - line. - -h, --help Print this help and exit - -v, --version Print version information - -''' -] - -Options explained: - -The [^-I] and [^-D] are preprocessor flags, which are needed by GCCXML to parse -the header files correctly and by Pyste to find the header files declared in the -interface files. - -[^--out] names the output file (default: [^.cpp]), or in multiple mode, -names a output directory for the files (default: [^]). - -[^--no-using] tells Pyste to don't declare "[^using namespace boost;]" in the -generated cpp, using the namespace boost::python explicitly in all declarations. -Use only if you're having a name conflict in one of the files. - -Use [^--pyste-ns] to change the namespace where new types are declared (for -instance, the virtual wrappers). Use only if you are having any problems. By -default, Pyste uses the empty namespace. - -[^--debug] will write in the current directory a xml file as outputted by GCCXML -for each header parsed. Useful for bug reports. - -[^--file-list] names a file where each line points to a Pyste file. Use this instead -to pass the pyste files if you have a lot of them and your shell has some command line -size limit. - -The other options are explained below, in [@#multiple_mode [*Multiple Mode]] and -[@#cache [*Cache]]. - -[^-h, --help, -v, --version] are self-explaining, I believe. ;) - -So, the usage is simple enough: - -[pre >python pyste.py --module=mymodule file.pyste file2.pyste ...] - -will generate a file [^mymodule.cpp] in the same dir where the command was -executed. Now you can compile the file using the same instructions of the -[@../../doc/tutorial/doc/building_hello_world.html tutorial]. - -[h2 Wait... how do I set those I and D flags?] - -Don't worry: normally GCCXML is already configured correctly for your plataform, -so the search path to the standard libraries and the standard defines should -already be set. You only have to set the paths to other libraries that your code -needs, like Boost, for example. - -Plus, Pyste automatically uses the contents of the environment variable -[^INCLUDE] if it exists. Visual C++ users should run the [^Vcvars32.bat] file, -which for Visual C++ 6 is normally located at: - - C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat - -with that, you should have little trouble setting up the flags. - -[blurb [$theme/note.gif][*A note about Psyco][br][br] -Although you don't have to install [@http://psyco.sourceforge.net/ Psyco] to -use Pyste, if you do, Pyste will make use of it to speed up the wrapper -generation. Speed ups of 30% can be achieved, so it's highly recommended. -] - - -[h2 Multiple Mode] - -The multiple mode is useful in large projects, where the presence of multiple -classes in a single file makes the compilation unpractical (excessive memory -usage, mostly). - -The solution is make Pyste generate multiple files, more specifically one cpp -file for each Pyste file. This files will contain a function named after the -file, for instance Export_MyPysteFile, which will contain all the code to export -the classes, enums, etc. You can pass as much files as you want this way: - -[pre >python pyste.py --module=mymodule file1.pyste file2.pyste] - -This will create the files [^mymodule/file1.cpp] and [^mymodule/file2.cpp]. You -can then later do: - -[pre >python pyste.py --module=mymodule file3.pyste] - -and [^mymodule/file3.cpp] will be generated. - -But compiling and linking this files won't be sufficient to generate your -extension. You have to also generate a file named [^main.cpp]; call pyste with -[*all] the Pyste files of your extension, and use the [^--generate-main] option: - -[pre >python pyste.py --module=mymodule --generate-main file1.pyste file2.pyste file3.pyste] - -Now compile and link all this files together and your extension is ready for -use. - -[h2 Cache] - -Pyste now supports a form of cache, which is a way to speed up the code -generation. Most of the time that Pyste takes to generate the code comes from -having to execute GCCXML (since being a front-end to GCC, it has to compile the -header files) and reading back the XML generated. - -When you use the [^--cache-dir=] option, Pyste will dump in the specified -directory the generated XMLs to a file named after the Pyste file, with the -extension [^.pystec]. The next time you run with this option, Pyste will use -the cache, instead of calling GCCXML again: - -[pre >python pyste.py --module=mymodule --cache-dir=cache file1.pyste] - -Will generate [^file1.cpp] and [^cache/file1.pystec]. Next time you execute -this command, the cache file will be used. Note that Pyste doesn't do any check -to ensure that the cache is up to date, but you can configure your build system to do that for you. - -When you run Pyste with [^--only-create-cache], all the cache files will be -created again, but no code will be generated. - -[page The Interface Files] - -The interface files are the heart of Pyste. The user creates one or more -interface files declaring the classes and functions he wants to export, and then -invokes Pyste passing the interface files to it. Pyste then generates a single -cpp file with Boost.Python code, with all the classes and functions exported. - -Besides declaring the classes and functions, the user has a number of other -options, like renaming e excluding classes and member functionis. Those are -explained later on. - -[h2 Basics] - -Suppose we have a class and some functions that we want to expose to Python -declared in the header [^hello.h]: - - struct World - { - World(std::string msg): msg(msg) {} - void set(std::string msg) { this->msg = msg; } - std::string greet() { return msg; } - std::string msg; - }; - - enum choice { red, blue }; - - namespace test { - - void show(choice c) { std::cout << "value: " << (int)c << std::endl; } - - } - -We create a file named [^hello.pyste] and create instances of the classes -[^Function], [^Class] and [^Enum]: - - Function("test::show", "hello.h") - Class("World", "hello.h") - Enum("choice", "hello.h") - -That will expose the class, the free function and the enum found in [^hello.h]. - -[h2 Inheritance] - -Pyste automatically generates the correct code (specifying [^bases<>] in the -[^class_] declaration) [*if] the Class() function that exports the base classes -and their children are in the same Pyste file. If that's not the case, you have -to indicate that there's a relationship between the Pyste files using the -[^Import] function specifying the other Pyste file. - -Suppose we have two classes, [^A] and [^B], and A is a base class for B. We -create two Pyste files: - -[^A.pyste]: - - Class("A", "A.h") - -[^B.pyste]: - - Import("A.pyste") - Class("B", "B.h") - -Note that we specify that [^B] needs to know about [^A] to be properly exported. - -[page:1 Renaming and Excluding] - -You can easily rename functions, classes, member functions, attributes, etc. Just use the -function [^rename], like this: - - World = Class("World", "hello.h") - rename(World, "IWorld") - show = Function("choice", "hello.h") - rename(show, "Show") - -You can rename member functions and attributes using this syntax: - - rename(World.greet, "Greet") - rename(World.set, "Set") - choice = Enum("choice", "hello.h") - rename(choice.red, "Red") - rename(choice.blue, "Blue") - -You can exclude functions, classes, member functions, attributes, etc, in the same way, -with the function [^exclude]: - - exclude(World.greet) - exclude(World.msg) - -To access the operators of a class, access the member [^operator] like this -(supposing that [^C] is a class being exported): - - exclude(C.operator['+']) - exclude(C.operator['*']) - exclude(C.operator['<<']) - -The string inside the brackets is the same as the name of the operator in C++.[br] - -[h2 Virtual Member Functions] - -Pyste automatically generates wrappers for virtual member functions, but you may -want to disable this behaviour (for performance reasons, for instance) if you do -not plan to override the functions in Python. To do this, use the function -[^final]: - - C = Class('C', 'C.h') - final(C.foo) # C::foo is a virtual member function - -No virtual wrapper code will be generated for the virtual member function -C::foo that way. - -[page:1 Policies] - -Even thought Pyste can identify various elements in the C++ code, like virtual -member functions, attributes, and so on, one thing that it can't do is to -guess the semantics of functions that return pointers or references. In this -case, the user must manually specify the policy. Policies are explained in the -[@../../doc/tutorial/doc/call_policies.html tutorial]. - -The policies in Pyste are named exactly as in Boost.Python, only the syntax is -slightly different. For instance, this policy: - - return_internal_reference<1, with_custodian_and_ward<1, 2> >() - -becomes in Pyste: - - return_internal_reference(1, with_custodian_and_ward(1, 2)) - -The user can specify policies for functions and virtual member functions with -the [^set_policy] function: - - set_policy(f, return_internal_reference()) - set_policy(C.foo, return_value_policy(manage_new_object)) - -[blurb -[$theme/note.gif] [*What if a function or member function needs a policy and -the user doesn't set one?][br][br] If a function needs a policy and one -was not set, Pyste will issue a error. The user should then go in the -interface file and set the policy for it, otherwise the generated cpp won't -compile. -] - -[blurb -[$theme/note.gif] -Note that for functions that return [^const T&], the policy -[^return_value_policy()] wil be used by default, because -that's normally what you want. You can change it to something else if you need -to, though. -] - -[page:1 Templates] - -Template classes can easily be exported too, but you can't export the template -itself... you have to export instantiations of it! So, if you want to export a -[^std::vector], you will have to export vectors of int, doubles, etc. - -Suppose we have this code: - - template - struct Point - { - T x; - T y; - }; - -And we want to export [^Point]s of int and double: - - Point = Template("Point", "point.h") - Point("int") - Point("double") - -Pyste will assign default names for each instantiation. In this example, those -would be "[^Point_int]" and "[^Point_double]", but most of the time users will want to -rename the instantiations: - - Point("int", "IPoint") // renames the instantiation - double_inst = Point("double") // another way to do the same - rename(double_inst, "DPoint") - -Note that you can rename, exclude, set policies, etc, in the [^Template] object -like you would do with a [^Function] or a [^Class]. This changes affect all -[*future] instantiations: - - Point = Template("Point", "point.h") - Point("float", "FPoint") // will have x and y as data members - rename(Point.x, "X") - rename(Point.y, "Y") - Point("int", "IPoint") // will have X and Y as data members - Point("double", "DPoint") // also will have X and Y as data member - -If you want to change a option of a particular instantiation, you can do so: - - Point = Template("Point", "point.h") - Point("int", "IPoint") - d_inst = Point("double", "DPoint") - rename(d_inst.x, "X") // only DPoint is affect by this renames, - rename(d_inst.y, "Y") // IPoint stays intact - -[blurb [$theme/note.gif] [*What if my template accepts more than one type?] -[br][br] -When you want to instantiate a template with more than one type, you can pass -either a string with the types separated by whitespace, or a list of strings -'''("int double" or ["int", "double"]''' would both work). -] - -[page:1 Wrappers] - -Suppose you have this function: - - std::vector names(); - -But you don't want to [@../../doc/v2/faq.html#question2 to export std::vector], -you want this function to return a python list of strings. Boost.Python has -excellent support for things like that: - - list names_wrapper() - { - list result; - // call original function - vector v = names(); - // put all the strings inside the python list - vector::iterator it; - for (it = v.begin(); it != v.end(); ++it){ - result.append(*it); - } - return result; - } - - BOOST_PYTHON_MODULE(test) - { - def("names", &names_wrapper); - } - -Nice heh? Pyste supports this mechanism too. You declare the [^names_wrapper] -function in a header named "[^test_wrappers.h]" and in the interface file: - - Include("test_wrappers.h") - names = Function("names", "test.h") - set_wrapper(names, "names_wrapper") - -You can optionally declare the function in the interface file itself: - - names_wrapper = Wrapper("names_wrapper", - """ - list names_wrapper() - { - // code to call name() and convert the vector to a list... - } - """) - names = Function("names", "test.h") - set_wrapper(names, names_wrapper) - -The same mechanism can be used with member functions too. Just remember that -the first parameter of wrappers for member functions is a pointer to the -class, as in: - - struct C - { - std::vector names(); - } - - list names_wrapper(C* c) - { - // same as before, calling c->names() and converting result to a list - } - -And then in the interface file: - - C = Class("C", "test.h") - set_wrapper(C.names, "names_wrapper") - -[blurb -[$theme/note.gif]Even though Boost.Python accepts either a pointer or a -reference to the class in wrappers for member functions as the first parameter, -Pyste expects them to be a [*pointer]. Doing otherwise will prevent your -code to compile when you set a wrapper for a virtual member function. -] - -[page:1 Exporting An Entire Header] - -Pyste also supports a mechanism to export all declarations found in a header -file. Suppose again our file, [^hello.h]: - - struct World - { - World(std::string msg): msg(msg) {} - void set(std::string msg) { this->msg = msg; } - std::string greet() { return msg; } - std::string msg; - }; - - enum choice { red, blue }; - - void show(choice c) { std::cout << "value: " << (int)c << std::endl; } - -You can just use the [^AllFromHeader] construct: - - hello = AllFromHeader("hello.h") - -this will export all the declarations found in [^hello.h], which is equivalent -to write: - - Class("World", "hello.h") - Enum("choice", "hello.h") - Function("show", "hello.h") - -Note that you can still use the functions [^rename], [^set_policy], [^exclude], etc. Just access -the members of the header object like this: - - rename(hello.World.greet, "Greet") - exclude(hello.World.set, "Set") - -[blurb -[$theme/note.gif] [*AllFromHeader is broken] in some cases. Until it is fixed, -use at you own risk. -] - - -[page:1 Smart Pointers] - -Pyste for now has manual support for smart pointers. Suppose: - - struct C - { - int value; - }; - - boost::shared_ptr newC(int value) - { - boost::shared_ptr c( new C() ); - c->value = value; - return c; - } - - void printC(boost::shared_ptr c) - { - std::cout << c->value << std::endl; - } - -To make [^newC] and [^printC] work correctly, you have to tell Pyste that a -convertor for [^boost::shared_ptr] is needed. - - C = Class('C', 'C.h') - use_shared_ptr(C) - Function('newC', 'C.h') - Function('printC', 'C.h') - -For [^std::auto_ptr]'s, use the function [^use_auto_ptr]. - -This system is temporary, and in the future the converters will automatically be -exported if needed, without the need to tell Pyste about them explicitly. - -[h2 Holders] - -If only the converter for the smart pointers is not enough and you need to -specify the smart pointer as the holder for a class, use the functions -[^hold_with_shared_ptr] and [^hold_with_auto_ptr]: - - C = Class('C', 'C.h') - hold_with_shared_ptr(C) - Function('newC', 'C.h') - Function('printC', 'C.h') - -[page:1 Global Variables] - -To export global variables, use the [^Var] construct: - - Var("myglobal", "foo.h") - -Beware of non-const global variables: changes in Python won't reflect in C++! -If you really must change them in Python, you will have to write some accessor -functions, and export those. - - -[page:1 Adding New Methods] - -Suppose that you want to add a function to a class, turning it into a member -function: - - struct World - { - void set(std::string msg) { this->msg = msg; } - std::string msg; - }; - - std::string greet(World& w) - { - return w.msg; - } - -Here, we want to make [^greet] work as a member function of the class [^World]. We do -that using the [^add_method] construct: - - W = Class("World", "hello.h") - add_method(W, "greet") - -Notice also that then you can rename it, set its policy, just like a regular -member function: - - rename(W.greet, 'Greet') - -Now from Python: - - >>> import hello - >>> w = hello.World() - >>> w.set('Ni') - >>> w.greet() - 'Ni' - >>> print 'Oh no! The knights who say Ni!' - Oh no! The knights who say Ni! - - -[page:1 Inserting Code] - -You can insert arbitrary code in the generated cpps, just use the functions -[^declaration_code] and [^module_code]. This will insert the given string in the -respective sections. Example: - - # file A.pyste - Class("A", "A.h") - declaration_code("/* declaration_code() comes here */\n") - module_code("/* module_code() comes here */\n") - -Will generate: - - // Includes ==================================================================== - #include - - // Using ======================================================================= - using namespace boost::python; - - // Declarations ================================================================ - - /* declaration_code() comes here */ - - // Module ====================================================================== - BOOST_PYTHON_MODULE(A) - { - class_< A >("A", init< >()) - .def(init< const A& >()) - ; - - /* module_code() comes here */ - } diff --git a/pyste/doc/renaming_and_excluding.html b/pyste/doc/renaming_and_excluding.html deleted file mode 100644 index ce6654c4a4..0000000000 --- a/pyste/doc/renaming_and_excluding.html +++ /dev/null @@ -1,87 +0,0 @@ - - - -Renaming and Excluding - - - - - - - - - - -
- - Renaming and Excluding -
-
- - - - - - -
-

-You can easily rename functions, classes, member functions, attributes, etc. Just use the -function rename, like this:

-
-    World = Class("World", "hello.h")
-    rename(World, "IWorld")
-    show = Function("choice", "hello.h")
-    rename(show, "Show")
-
-

-You can rename member functions and attributes using this syntax:

-
-    rename(World.greet, "Greet")
-    rename(World.set, "Set")
-    choice = Enum("choice", "hello.h")
-    rename(choice.red, "Red")
-    rename(choice.blue, "Blue")
-
-

-You can exclude functions, classes, member functions, attributes, etc, in the same way, -with the function exclude:

-
-    exclude(World.greet)
-    exclude(World.msg)
-
-

-To access the operators of a class, access the member operator like this -(supposing that C is a class being exported):

-
-    exclude(C.operator['+'])
-    exclude(C.operator['*'])
-    exclude(C.operator['<<'])
-
-

-The string inside the brackets is the same as the name of the operator in C++.

-

Virtual Member Functions

-Pyste automatically generates wrappers for virtual member functions, but you may -want to disable this behaviour (for performance reasons, for instance) if you do -not plan to override the functions in Python. To do this, use the function -final:

-
-    C = Class('C', 'C.h')
-    final(C.foo) ##C::foo is a virtual member function
-
-

-No virtual wrapper code will be generated for the virtual member function -C::foo that way.

- - - - - - -
-
-
- - diff --git a/pyste/doc/running_pyste.html b/pyste/doc/running_pyste.html deleted file mode 100644 index 9bd9a3aee3..0000000000 --- a/pyste/doc/running_pyste.html +++ /dev/null @@ -1,200 +0,0 @@ - - - -Running Pyste - - - - - - - - - - -
- - Running Pyste -
-
- - - - - - -
-

-To run Pyste, you will need:

-

-Installation for the tools is available in their respective webpages.

- - - - -
- - -GCCXML must be accessible in the PATH environment variable, so -that Pyste can call it. How to do this varies from platform to platform. -
-

Ok, now what?

-Well, now let's fire it up:

-
-
->python pyste.py
-
-Pyste version 0.9.26
-
-Usage:
-    pyste [options] interface-files
-
-where options are:
-    --module=<name>         The name of the module that will be generated;
-                            defaults to the first interface filename, without
-                            the extension.
-    -I <path>               Add an include path
-    -D <symbol>             Define symbol
-    --multiple              Create various cpps, instead of only one
-                            (useful during development)
-    --out=<name>            Specify output filename (default: <module>.cpp)
-                            in --multiple mode, this will be a directory
-    --no-using              Do not declare "using namespace boost";
-                            use explicit declarations instead
-    --pyste-ns=<name>       Set the namespace where new types will be declared;
-                            default is the empty namespace
-    --debug                 Writes the xml for each file parsed in the current
-                            directory
-    --cache-dir=<dir>       Directory for cache files (speeds up future runs)
-    --only-create-cache     Recreates all caches (doesn't generate code).
-    --generate-main         Generates the _main.cpp file (in multiple mode)
-    --file-list             A file with one pyste file per line. Use as a 
-                            substitute for passing the files in the command
-                            line.
-    -h, --help              Print this help and exit
-    -v, --version           Print version information
-  
-                        
-

-Options explained:

-

-The -I and -D are preprocessor flags, which are needed by -GCCXML to parse -the header files correctly and by Pyste to find the header files declared in the -interface files.

-

---out names the output file (default: <module>.cpp), or in multiple mode, -names a output directory for the files (default: <module>).

-

---no-using tells Pyste to don't declare "using namespace boost;" in the -generated cpp, using the namespace boost::python explicitly in all declarations. -Use only if you're having a name conflict in one of the files.

-

-Use --pyste-ns to change the namespace where new types are declared (for -instance, the virtual wrappers). Use only if you are having any problems. By -default, Pyste uses the empty namespace.

-

---debug will write in the current directory a xml file as outputted by -GCCXML -for each header parsed. Useful for bug reports.

-

---file-list names a file where each line points to a Pyste file. Use this instead -to pass the pyste files if you have a lot of them and your shell has some command line -size limit.

-

-The other options are explained below, in -Multiple Mode and - -Cache.

-

--h, --help, -v, --version are self-explaining, I believe. ;)

-

-So, the usage is simple enough:

-
>python pyste.py --module=mymodule file.pyste file2.pyste ...

-will generate a file mymodule.cpp in the same dir where the command was -executed. Now you can compile the file using the same instructions of the - -tutorial.

-

Wait... how do I set those I and D flags?

-Don't worry: normally -GCCXML is already configured correctly for your plataform, -so the search path to the standard libraries and the standard defines should -already be set. You only have to set the paths to other libraries that your code -needs, like Boost, for example.

-

-Plus, Pyste automatically uses the contents of the environment variable -INCLUDE if it exists. Visual C++ users should run the Vcvars32.bat file, -which for Visual C++ 6 is normally located at:

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

-with that, you should have little trouble setting up the flags.

- - - - -
-A note about Psyco

-Although you don't have to install -Psyco to -use Pyste, if you do, Pyste will make use of it to speed up the wrapper -generation. Speed ups of 30% can be achieved, so it's highly recommended. -
-

Multiple Mode

-The multiple mode is useful in large projects, where the presence of multiple -classes in a single file makes the compilation unpractical (excessive memory -usage, mostly).

-

-The solution is make Pyste generate multiple files, more specifically one cpp -file for each Pyste file. This files will contain a function named after the -file, for instance Export_MyPysteFile, which will contain all the code to export -the classes, enums, etc. You can pass as much files as you want this way:

-
>python pyste.py --module=mymodule file1.pyste file2.pyste

-This will create the files mymodule/file1.cpp and mymodule/file2.cpp. You -can then later do:

-
>python pyste.py --module=mymodule file3.pyste

-and mymodule/file3.cpp will be generated.

-

-But compiling and linking this files won't be sufficient to generate your -extension. You have to also generate a file named main.cpp; call pyste with -all the Pyste files of your extension, and use the --generate-main option:

-
>python pyste.py --module=mymodule --generate-main file1.pyste file2.pyste file3.pyste

-Now compile and link all this files together and your extension is ready for -use.

-

Cache

-Pyste now supports a form of cache, which is a way to speed up the code -generation. Most of the time that Pyste takes to generate the code comes from -having to execute -GCCXML (since being a front-end to GCC, it has to compile the -header files) and reading back the XML generated.

-

-When you use the --cache-dir=<dir> option, Pyste will dump in the specified -directory the generated XMLs to a file named after the Pyste file, with the -extension .pystec. The next time you run with this option, Pyste will use -the cache, instead of calling -GCCXML again:

-
>python pyste.py --module=mymodule --cache-dir=cache file1.pyste

-Will generate file1.cpp and cache/file1.pystec. Next time you execute -this command, the cache file will be used. Note that Pyste doesn't do any check -to ensure that the cache is up to date, but you can configure your build system to do that for you.

-

-When you run Pyste with --only-create-cache, all the cache files will be -created again, but no code will be generated.

- - - - - - -
-
-
- - diff --git a/pyste/doc/smart_pointers.html b/pyste/doc/smart_pointers.html deleted file mode 100644 index cddc96f2f1..0000000000 --- a/pyste/doc/smart_pointers.html +++ /dev/null @@ -1,84 +0,0 @@ - - - -Smart Pointers - - - - - - - - - - -
- - Smart Pointers -
-
- - - - - - -
-

-Pyste for now has manual support for smart pointers. Suppose:

-
-    struct C
-    {
-        int value;
-    };
-
-    boost::shared_ptr<C> newC(int value)
-    {
-        boost::shared_ptr<C> c( new C() );
-        c->value = value;
-        return c;
-    }
-
-    void printC(boost::shared_ptr<C> c)
-    {
-        std::cout << c->value << std::endl;
-    }
-
-

-To make newC and printC work correctly, you have to tell Pyste that a -convertor for boost::shared_ptr<C> is needed.

-
-    C = Class('C', 'C.h')
-    use_shared_ptr(C)
-    Function('newC', 'C.h')
-    Function('printC', 'C.h')
-
-

-For std::auto_ptr's, use the function use_auto_ptr.

-

-This system is temporary, and in the future the converters will automatically be -exported if needed, without the need to tell Pyste about them explicitly.

-

Holders

-If only the converter for the smart pointers is not enough and you need to -specify the smart pointer as the holder for a class, use the functions -hold_with_shared_ptr and hold_with_auto_ptr:

-
-    C = Class('C', 'C.h')
-    hold_with_shared_ptr(C)
-    Function('newC', 'C.h')
-    Function('printC', 'C.h') 
-
- - - - - - -
-
-
- - diff --git a/pyste/doc/templates.html b/pyste/doc/templates.html deleted file mode 100644 index a1c1cfefb2..0000000000 --- a/pyste/doc/templates.html +++ /dev/null @@ -1,102 +0,0 @@ - - - -Templates - - - - - - - - - - -
- - Templates -
-
- - - - - - -
-

-Template classes can easily be exported too, but you can't export the template -itself... you have to export instantiations of it! So, if you want to export a -std::vector, you will have to export vectors of int, doubles, etc.

-

-Suppose we have this code:

-
-    template <class T>
-    struct Point
-    {
-        T x;
-        T y;
-    };
-
-

-And we want to export Points of int and double:

-
-    Point = Template("Point", "point.h")
-    Point("int")
-    Point("double")
-
-

-Pyste will assign default names for each instantiation. In this example, those -would be "Point_int" and "Point_double", but most of the time users will want to -rename the instantiations:

-
-    Point("int", "IPoint")         // renames the instantiation
-    double_inst = Point("double")  // another way to do the same
-    rename(double_inst, "DPoint")
-
-

-Note that you can rename, exclude, set policies, etc, in the Template object -like you would do with a Function or a Class. This changes affect all -future instantiations:

-
-    Point = Template("Point", "point.h")
-    Point("float", "FPoint")        // will have x and y as data members
-    rename(Point.x, "X")
-    rename(Point.y, "Y")
-    Point("int", "IPoint")          // will have X and Y as data members
-    Point("double", "DPoint")       // also will have X and Y as data member
-
-

-If you want to change a option of a particular instantiation, you can do so:

-
-    Point = Template("Point", "point.h")
-    Point("int", "IPoint")          
-    d_inst = Point("double", "DPoint")       
-    rename(d_inst.x, "X")           // only DPoint is affect by this renames,
-    rename(d_inst.y, "Y")           // IPoint stays intact
-
- - - - -
- What if my template accepts more than one type? -

-When you want to instantiate a template with more than one type, you can pass -either a string with the types separated by whitespace, or a list of strings -("int double" or ["int", "double"] would both work). -
- - - - - - -
-
-
- - diff --git a/pyste/doc/the_interface_files.html b/pyste/doc/the_interface_files.html deleted file mode 100644 index 9c0200432f..0000000000 --- a/pyste/doc/the_interface_files.html +++ /dev/null @@ -1,102 +0,0 @@ - - - -The Interface Files - - - - - - - - - - -
- - The Interface Files -
-
- - - - - - -
-

-The interface files are the heart of Pyste. The user creates one or more -interface files declaring the classes and functions he wants to export, and then -invokes Pyste passing the interface files to it. Pyste then generates a single -cpp file with -Boost.Python code, with all the classes and functions exported.

-

-Besides declaring the classes and functions, the user has a number of other -options, like renaming e excluding classes and member functionis. Those are -explained later on.

-

Basics

-Suppose we have a class and some functions that we want to expose to Python -declared in the header hello.h:

-
-    struct World
-    {
-        World(std::string msg): msg(msg) {} 
-        void set(std::string msg) { this->msg = msg; }
-        std::string greet() { return msg; }
-        std::string msg;
-    };
-
-    enum choice { red, blue };
-    
-    namespace test {
-    
-    void show(choice c) { std::cout << "value: " << (int)c << std::endl; }
-    
-    }
-
-

-We create a file named hello.pyste and create instances of the classes -Function, Class and Enum:

-
-    Function("test::show", "hello.h")
-    Class("World", "hello.h")
-    Enum("choice", "hello.h")
-
-

-That will expose the class, the free function and the enum found in hello.h.

-

Inheritance

-Pyste automatically generates the correct code (specifying bases<> in the -class_ declaration) if the Class() function that exports the base classes -and their children are in the same Pyste file. If that's not the case, you have -to indicate that there's a relationship between the Pyste files using the -Import function specifying the other Pyste file.

-

-Suppose we have two classes, A and B, and A is a base class for B. We -create two Pyste files:

-

-A.pyste:

-
-    Class("A", "A.h")
-
-

-B.pyste:

-
-    Import("A.pyste")
-    Class("B", "B.h")
-
-

-Note that we specify that B needs to know about A to be properly exported.

- - - - - - -
-
-
- - diff --git a/pyste/doc/theme/alert.gif b/pyste/doc/theme/alert.gif deleted file mode 100644 index 270764cc58..0000000000 Binary files a/pyste/doc/theme/alert.gif and /dev/null differ diff --git a/pyste/doc/theme/arrow.gif b/pyste/doc/theme/arrow.gif deleted file mode 100644 index e33db0fb4d..0000000000 Binary files a/pyste/doc/theme/arrow.gif and /dev/null differ diff --git a/pyste/doc/theme/bkd.gif b/pyste/doc/theme/bkd.gif deleted file mode 100644 index dcabcb806f..0000000000 Binary files a/pyste/doc/theme/bkd.gif and /dev/null differ diff --git a/pyste/doc/theme/bkd2.gif b/pyste/doc/theme/bkd2.gif deleted file mode 100644 index b03d9ba97c..0000000000 Binary files a/pyste/doc/theme/bkd2.gif and /dev/null differ diff --git a/pyste/doc/theme/bulb.gif b/pyste/doc/theme/bulb.gif deleted file mode 100644 index 74f3baac42..0000000000 Binary files a/pyste/doc/theme/bulb.gif and /dev/null differ diff --git a/pyste/doc/theme/bullet.gif b/pyste/doc/theme/bullet.gif deleted file mode 100644 index da787e2efb..0000000000 Binary files a/pyste/doc/theme/bullet.gif and /dev/null differ diff --git a/pyste/doc/theme/l_arr.gif b/pyste/doc/theme/l_arr.gif deleted file mode 100644 index 5b3cb1cbf0..0000000000 Binary files a/pyste/doc/theme/l_arr.gif and /dev/null differ diff --git a/pyste/doc/theme/l_arr_disabled.gif b/pyste/doc/theme/l_arr_disabled.gif deleted file mode 100644 index ed58a605a3..0000000000 Binary files a/pyste/doc/theme/l_arr_disabled.gif and /dev/null differ diff --git a/pyste/doc/theme/note.gif b/pyste/doc/theme/note.gif deleted file mode 100644 index bd92f07555..0000000000 Binary files a/pyste/doc/theme/note.gif and /dev/null differ diff --git a/pyste/doc/theme/r_arr.gif b/pyste/doc/theme/r_arr.gif deleted file mode 100644 index 2dcdad117d..0000000000 Binary files a/pyste/doc/theme/r_arr.gif and /dev/null differ diff --git a/pyste/doc/theme/r_arr_disabled.gif b/pyste/doc/theme/r_arr_disabled.gif deleted file mode 100644 index 2100f78bf3..0000000000 Binary files a/pyste/doc/theme/r_arr_disabled.gif and /dev/null differ diff --git a/pyste/doc/theme/smiley.gif b/pyste/doc/theme/smiley.gif deleted file mode 100644 index 4c848f8fe8..0000000000 Binary files a/pyste/doc/theme/smiley.gif and /dev/null differ diff --git a/pyste/doc/theme/style.css b/pyste/doc/theme/style.css deleted file mode 100644 index 643df02a94..0000000000 --- a/pyste/doc/theme/style.css +++ /dev/null @@ -1,178 +0,0 @@ -/*============================================================================= - Copyright (c) 2003 Bruno da Silva de Oliveira - - Use, modification and distribution is subject to the Boost Software - License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ - -body -{ - background-image: url(bkd.gif); - background-color: #FFFFFF; - margin: 1em 2em 1em 2em; -} - -h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; } -h2 { font: 140% sans-serif; font-weight: bold; text-align: left; } -h3 { font: 120% sans-serif; font-weight: bold; text-align: left; } -h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; } -h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; } -h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; } - -pre -{ - border-top: gray 1pt solid; - border-right: gray 1pt solid; - border-left: gray 1pt solid; - border-bottom: gray 1pt solid; - - padding-top: 2pt; - padding-right: 2pt; - padding-left: 2pt; - padding-bottom: 2pt; - - display: block; - font-family: "courier new", courier, mono; - background-color: #eeeeee; font-size: small -} - -code -{ - font-family: "Courier New", Courier, mono; - font-size: small -} - -tt -{ - display: inline; - font-family: "Courier New", Courier, mono; - color: #000099; - font-size: small -} - -p -{ - text-align: justify; - font-family: Georgia, "Times New Roman", Times, serif -} - -ul -{ - list-style-image: url(bullet.gif); - font-family: Georgia, "Times New Roman", Times, serif -} - -ol -{ - font-family: Georgia, "Times New Roman", Times, serif -} - -a -{ - font-weight: bold; - color: #003366; - text-decoration: none; -} - -a:hover { color: #8080FF; } - -.literal { color: #666666; font-style: italic} -.keyword { color: #000099} -.identifier {} -.comment { font-style: italic; color: #990000} -.special { color: #800040} -.preprocessor { color: #FF0000} -.string { font-style: italic; color: #666666} -.copyright { color: #666666; font-size: small} -.white_bkd { background-color: #FFFFFF} -.dk_grey_bkd { background-color: #999999} -.quotes { color: #666666; font-style: italic; font-weight: bold} - -.note_box -{ - display: block; - - border-top: gray 1pt solid; - border-right: gray 1pt solid; - border-left: gray 1pt solid; - border-bottom: gray 1pt solid; - - padding-right: 12pt; - padding-left: 12pt; - padding-bottom: 12pt; - padding-top: 12pt; - - font-family: Arial, Helvetica, sans-serif; - background-color: #E2E9EF; - font-size: small; text-align: justify -} - -.table_title -{ - background-color: #648CCA; - - font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF; - font-weight: bold -; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px -} - -.table_cells -{ - background-color: #E2E9EF; - - font-family: Geneva, Arial, Helvetica, san-serif; - font-size: small -; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px -} - -.toc -{ - DISPLAY: block; - background-color: #E2E9EF - font-family: Arial, Helvetica, sans-serif; - - border-top: gray 1pt solid; - border-left: gray 1pt solid; - border-bottom: gray 1pt solid; - border-right: gray 1pt solid; - - padding-top: 24pt; - padding-right: 24pt; - padding-left: 24pt; - padding-bottom: 24pt; -} - -.toc_title -{ - background-color: #648CCA; - padding-top: 4px; - padding-right: 4px; - padding-bottom: 4px; - padding-left: 4px; - font-family: Geneva, Arial, Helvetica, san-serif; - color: #FFFFFF; - font-weight: bold -} - -.toc_cells -{ - background-color: #E2E9EF; - padding-top: 4px; - padding-right: 4px; - padding-bottom: 4px; - padding-left: 4px; - font-family: Geneva, Arial, Helvetica, san-serif; - font-size: small -} - -div.logo -{ - float: right; -} - -.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } diff --git a/pyste/doc/theme/u_arr.gif b/pyste/doc/theme/u_arr.gif deleted file mode 100644 index ada3d6e043..0000000000 Binary files a/pyste/doc/theme/u_arr.gif and /dev/null differ diff --git a/pyste/doc/wrappers.html b/pyste/doc/wrappers.html deleted file mode 100644 index 534ae5529a..0000000000 --- a/pyste/doc/wrappers.html +++ /dev/null @@ -1,124 +0,0 @@ - - - -Wrappers - - - - - - - - - - -
- - Wrappers -
-
- - - - - - -
-

-Suppose you have this function:

-
-    std::vector<std::string> names();
-
-

-But you don't want to -to export std::vector<std::string>, -you want this function to return a python list of strings. -Boost.Python has -excellent support for things like that:

-
-    list names_wrapper()
-    {
-        list result;
-        // call original function
-        vector<string> v = names();
-        // put all the strings inside the python list
-        vector<string>::iterator it;
-        for (it = v.begin(); it != v.end(); ++it){
-            result.append(*it);    
-        }
-        return result;
-    }
-    
-    BOOST_PYTHON_MODULE(test)
-    {
-        def("names", &names_wrapper);
-    }
-
-

-Nice heh? Pyste supports this mechanism too. You declare the names_wrapper -function in a header named "test_wrappers.h" and in the interface file:

-
-    Include("test_wrappers.h")
-    names = Function("names", "test.h")
-    set_wrapper(names, "names_wrapper")
-
-

-You can optionally declare the function in the interface file itself:

-
-    names_wrapper = Wrapper("names_wrapper",
-    """
-    list names_wrapper()
-    {
-        // code to call name() and convert the vector to a list...
-    }
-    """)
-    names = Function("names", "test.h")
-    set_wrapper(names, names_wrapper)
-
-

-The same mechanism can be used with member functions too. Just remember that -the first parameter of wrappers for member functions is a pointer to the -class, as in:

-
-    struct C
-    {
-        std::vector<std::string> names();
-    }
-
-    list names_wrapper(C* c)
-    {
-        // same as before, calling c->names() and converting result to a list 
-    }
-
-

-And then in the interface file:

-
-    C = Class("C", "test.h")
-    set_wrapper(C.names, "names_wrapper")
-
- - - - -
- -Even though -Boost.Python accepts either a pointer or a -reference to the class in wrappers for member functions as the first parameter, -Pyste expects them to be a pointer. Doing otherwise will prevent your -code to compile when you set a wrapper for a virtual member function. -
- - - - - - -
-
-
- - diff --git a/pyste/index.html b/pyste/index.html deleted file mode 100644 index 953b37c122..0000000000 --- a/pyste/index.html +++ /dev/null @@ -1,90 +0,0 @@ - - - -Pyste Documentation - - - - - - - - - -
- - Pyste Documentation -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table of contents
- Introduction -
- Running Pyste -
- The Interface Files -
- Renaming and Excluding -
- Policies -
- Templates -
- Wrappers -
- Exporting An Entire Header -
- Smart Pointers -
- Global Variables -
- Adding New Methods -
- Inserting Code -
-
-
- - diff --git a/pyste/install/pyste.py b/pyste/install/pyste.py deleted file mode 100644 index da92623535..0000000000 --- a/pyste/install/pyste.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python - -# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -from Pyste import pyste -pyste.main() diff --git a/pyste/install/setup.py b/pyste/install/setup.py deleted file mode 100644 index c170398170..0000000000 --- a/pyste/install/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright Prabhu Ramachandran 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -from distutils.core import setup -import sys - -setup (name = "Pyste", - version = "0.9.10", - description = "Pyste - Python Semi-Automatic Exporter", - maintainer = "Bruno da Silva de Oliveira", - maintainer_email = "nicodemus@globalite.com.br", - licence = "Boost License", - long_description = "Pyste is a Boost.Python code generator", - url = "http://www.boost.org/libs/python/pyste/index.html", - platforms = ['Any'], - packages = ['Pyste'], - scripts = ['pyste.py'], - package_dir = {'Pyste': '../src/Pyste'}, - ) diff --git a/pyste/src/Pyste/ClassExporter.py b/pyste/src/Pyste/ClassExporter.py deleted file mode 100644 index decaf628e6..0000000000 --- a/pyste/src/Pyste/ClassExporter.py +++ /dev/null @@ -1,918 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import exporters -from Exporter import Exporter -from declarations import * -from settings import * -from policies import * -from SingleCodeUnit import SingleCodeUnit -from EnumExporter import EnumExporter -from utils import makeid, enumerate -import copy -import exporterutils -import re - -#============================================================================== -# ClassExporter -#============================================================================== -class ClassExporter(Exporter): - 'Generates boost.python code to export a class declaration' - - def __init__(self, info, parser_tail=None): - Exporter.__init__(self, info, parser_tail) - # sections of code - self.sections = {} - # template: each item in the list is an item into the class_<...> - # section. - self.sections['template'] = [] - # constructor: each item in the list is a parameter to the class_ - # constructor, like class_(...) - self.sections['constructor'] = [] - # inside: everything within the class_<> statement - self.sections['inside'] = [] - # scope: items outside the class statement but within its scope. - # scope* s = new scope(class<>()); - # ... - # delete s; - self.sections['scope'] = [] - # declarations: outside the BOOST_PYTHON_MODULE macro - self.sections['declaration'] = [] - self.sections['declaration-outside'] = [] - self.sections['include'] = [] - # a list of Constructor instances - self.constructors = [] - # a list of code units, generated by nested declarations - self.nested_codeunits = [] - - - def ScopeName(self): - return makeid(self.class_.FullName()) + '_scope' - - - def Name(self): - return self.info.name - - - def SetDeclarations(self, declarations): - Exporter.SetDeclarations(self, declarations) - if self.declarations: - decl = self.GetDeclaration(self.info.name) - if isinstance(decl, Typedef): - self.class_ = self.GetDeclaration(decl.type.name) - if not self.info.rename: - self.info.rename = decl.name - else: - self.class_ = decl - self.class_ = copy.deepcopy(self.class_) - else: - self.class_ = None - - - def ClassBases(self): - all_bases = [] - for level in self.class_.hierarchy: - for base in level: - all_bases.append(base) - return [self.GetDeclaration(x.name) for x in all_bases] - - - def Order(self): - '''Return the TOTAL number of bases that this class has, including the - bases' bases. Do this because base classes must be instantialized - before the derived classes in the module definition. - ''' - num_bases = len(self.ClassBases()) - return num_bases, self.class_.FullName() - - - def Export(self, codeunit, exported_names): - self.InheritMethods(exported_names) - self.MakeNonVirtual() - if not self.info.exclude: - self.ExportBasics() - self.ExportBases(exported_names) - self.ExportConstructors() - self.ExportVariables() - self.ExportVirtualMethods(codeunit) - self.ExportMethods() - self.ExportOperators() - self.ExportNestedClasses(exported_names) - self.ExportNestedEnums(exported_names) - self.ExportSmartPointer() - self.ExportOpaquePointerPolicies() - self.ExportAddedCode() - self.Write(codeunit) - exported_names[self.Name()] = 1 - - - def InheritMethods(self, exported_names): - '''Go up in the class hierarchy looking for classes that were not - exported yet, and then add their public members to this classes - members, as if they were members of this class. This allows the user to - just export one type and automatically get all the members from the - base classes. - ''' - valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration) - fullnames = [x.FullName() for x in self.class_] - pointers = [x.PointerDeclaration(True) for x in self.class_ if isinstance(x, Method)] - fullnames = dict([(x, None) for x in fullnames]) - pointers = dict([(x, None) for x in pointers]) - for level in self.class_.hierarchy: - level_exported = False - for base in level: - base = self.GetDeclaration(base.name) - if base.FullName() not in exported_names: - for member in base: - if type(member) in valid_members: - member_copy = copy.deepcopy(member) - member_copy.class_ = self.class_.FullName() - if isinstance(member_copy, Method): - pointer = member_copy.PointerDeclaration(True) - if pointer not in pointers: - self.class_.AddMember(member) - pointers[pointer] = None - elif member_copy.FullName() not in fullnames: - self.class_.AddMember(member) - else: - level_exported = True - if level_exported: - break - def IsValid(member): - return isinstance(member, valid_members) and member.visibility == Scope.public - self.public_members = [x for x in self.class_ if IsValid(x)] - - - def Write(self, codeunit): - indent = self.INDENT - boost_ns = namespaces.python - pyste_ns = namespaces.pyste - code = '' - # begin a scope for this class if needed - nested_codeunits = self.nested_codeunits - needs_scope = self.sections['scope'] or nested_codeunits - if needs_scope: - scope_name = self.ScopeName() - code += indent + boost_ns + 'scope* %s = new %sscope(\n' %\ - (scope_name, boost_ns) - # export the template section - template_params = ', '.join(self.sections['template']) - code += indent + boost_ns + 'class_< %s >' % template_params - # export the constructor section - constructor_params = ', '.join(self.sections['constructor']) - code += '(%s)\n' % constructor_params - # export the inside section - in_indent = indent*2 - for line in self.sections['inside']: - code += in_indent + line + '\n' - # write the scope section and end it - if not needs_scope: - code += indent + ';\n' - else: - code += indent + ');\n' - for line in self.sections['scope']: - code += indent + line + '\n' - # write the contents of the nested classes - for nested_unit in nested_codeunits: - code += '\n' + nested_unit.Section('module') - # close the scope - code += indent + 'delete %s;\n' % scope_name - - # write the code to the module section in the codeunit - codeunit.Write('module', code + '\n') - - # write the declarations to the codeunit - declarations = '\n'.join(self.sections['declaration']) - for nested_unit in nested_codeunits: - declarations += nested_unit.Section('declaration') - if declarations: - codeunit.Write('declaration', declarations + '\n') - declarations_outside = '\n'.join(self.sections['declaration-outside']) - if declarations_outside: - codeunit.Write('declaration-outside', declarations_outside + '\n') - - # write the includes to the codeunit - includes = '\n'.join(self.sections['include']) - for nested_unit in nested_codeunits: - includes += nested_unit.Section('include') - if includes: - codeunit.Write('include', includes) - - - def Add(self, section, item): - 'Add the item into the corresponding section' - self.sections[section].append(item) - - - def ExportBasics(self): - '''Export the name of the class and its class_ statement.''' - class_name = self.class_.FullName() - self.Add('template', class_name) - name = self.info.rename or self.class_.name - self.Add('constructor', '"%s"' % name) - - - def ExportBases(self, exported_names): - 'Expose the bases of the class into the template section' - hierarchy = self.class_.hierarchy - exported = [] - for level in hierarchy: - for base in level: - if base.visibility == Scope.public and base.name in exported_names: - exported.append(base.name) - if exported: - break - if exported: - code = namespaces.python + 'bases< %s > ' % (', '.join(exported)) - self.Add('template', code) - - - def ExportConstructors(self): - '''Exports all the public contructors of the class, plus indicates if the - class is noncopyable. - ''' - py_ns = namespaces.python - indent = self.INDENT - - def init_code(cons): - 'return the init<>() code for the given contructor' - param_list = [p.FullName() for p in cons.parameters] - min_params_list = param_list[:cons.minArgs] - max_params_list = param_list[cons.minArgs:] - min_params = ', '.join(min_params_list) - max_params = ', '.join(max_params_list) - init = py_ns + 'init< ' - init += min_params - if max_params: - if min_params: - init += ', ' - init += py_ns + ('optional< %s >' % max_params) - init += ' >()' - return init - - constructors = [x for x in self.public_members if isinstance(x, Constructor)] - # don't export copy constructors if the class is abstract - # we could remove all constructors, but this will have the effect of - # inserting no_init in the declaration, which would not allow - # even subclasses to be instantiated. - self.constructors = constructors[:] - if self.class_.abstract: - for cons in constructors: - if cons.IsCopy(): - constructors.remove(cons) - break - - if not constructors: - # declare no_init - self.Add('constructor', py_ns + 'no_init') - else: - # write the constructor with less parameters to the constructor section - smaller = None - for cons in constructors: - if smaller is None or len(cons.parameters) < len(smaller.parameters): - smaller = cons - assert smaller is not None - self.Add('constructor', init_code(smaller)) - constructors.remove(smaller) - # write the rest to the inside section, using def() - for cons in constructors: - code = '.def(%s)' % init_code(cons) - self.Add('inside', code) - - # check if the class is copyable - if not self.class_.HasCopyConstructor() or self.class_.abstract: - self.Add('template', namespaces.boost + 'noncopyable') - - - def ExportVariables(self): - 'Export the variables of the class, both static and simple variables' - vars = [x for x in self.public_members if isinstance(x, Variable)] - for var in vars: - if self.info[var.name].exclude: - continue - name = self.info[var.name].rename or var.name - fullname = var.FullName() - if var.type.const: - def_ = '.def_readonly' - else: - def_ = '.def_readwrite' - code = '%s("%s", &%s)' % (def_, name, fullname) - self.Add('inside', code) - - - def OverloadName(self, method): - 'Returns the name of the overloads struct for the given method' - name = makeid(method.FullName()) - overloads = '_overloads_%i_%i' % (method.minArgs, method.maxArgs) - return name + overloads - - - def GetAddedMethods(self): - added_methods = self.info.__added__ - result = [] - if added_methods: - for name, rename in added_methods: - decl = self.GetDeclaration(name) - self.info[name].rename = rename - result.append(decl) - return result - - - def ExportMethods(self): - '''Export all the non-virtual methods of this class, plus any function - that is to be exported as a method''' - - declared = {} - def DeclareOverloads(m): - 'Declares the macro for the generation of the overloads' - if (isinstance(m, Method) and m.static) or type(m) == Function: - func = m.FullName() - macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS' - else: - func = m.name - macro = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS' - code = '%s(%s, %s, %i, %i)\n' % (macro, self.OverloadName(m), func, m.minArgs, m.maxArgs) - if code not in declared: - declared[code] = True - self.Add('declaration', code) - - - def Pointer(m): - 'returns the correct pointer declaration for the method m' - # check if this method has a wrapper set for him - wrapper = self.info[m.name].wrapper - if wrapper: - return '&' + wrapper.FullName() - else: - return m.PointerDeclaration() - - def IsExportable(m): - 'Returns true if the given method is exportable by this routine' - ignore = (Constructor, ClassOperator, Destructor) - return isinstance(m, Function) and not isinstance(m, ignore) and not m.virtual - - methods = [x for x in self.public_members if IsExportable(x)] - methods.extend(self.GetAddedMethods()) - - staticmethods = {} - - for method in methods: - method_info = self.info[method.name] - - # skip this method if it was excluded by the user - if method_info.exclude: - continue - - # rename the method if the user requested - name = method_info.rename or method.name - - # warn the user if this method needs a policy and doesn't have one - method_info.policy = exporterutils.HandlePolicy(method, method_info.policy) - - # check for policies - policy = method_info.policy or '' - if policy: - policy = ', %s%s()' % (namespaces.python, policy.Code()) - # check for overloads - overload = '' - if method.minArgs != method.maxArgs and not method_info.wrapper: - # add the overloads for this method - DeclareOverloads(method) - overload_name = self.OverloadName(method) - overload = ', %s%s()' % (namespaces.pyste, overload_name) - - # build the .def string to export the method - pointer = Pointer(method) - code = '.def("%s", %s' % (name, pointer) - code += policy - code += overload - code += ')' - self.Add('inside', code) - # static method - if isinstance(method, Method) and method.static: - staticmethods[name] = 1 - # add wrapper code if this method has one - wrapper = method_info.wrapper - if wrapper and wrapper.code: - self.Add('declaration', wrapper.code) - - # export staticmethod statements - for name in staticmethods: - code = '.staticmethod("%s")' % name - self.Add('inside', code) - - - - def MakeNonVirtual(self): - '''Make all methods that the user indicated to no_override no more virtual, delegating their - export to the ExportMethods routine''' - for member in self.class_: - if type(member) == Method and member.virtual: - member.virtual = not self.info[member.name].no_override - - - def ExportVirtualMethods(self, codeunit): - # check if this class has any virtual methods - has_virtual_methods = False - for member in self.class_: - if type(member) == Method and member.virtual: - has_virtual_methods = True - break - - holder = self.info.holder - if has_virtual_methods: - generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info, codeunit) - if holder: - self.Add('template', holder(generator.FullName())) - else: - self.Add('template', generator.FullName()) - for definition in generator.GenerateDefinitions(): - self.Add('inside', definition) - self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT)) - else: - if holder: - self.Add('template', holder(self.class_.FullName())) - - # operators natively supported by boost - BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -= '\ - '*= /= %= ^= &= |= <<= >>='.split() - # create a map for faster lookup - BOOST_SUPPORTED_OPERATORS = dict(zip(BOOST_SUPPORTED_OPERATORS, range(len(BOOST_SUPPORTED_OPERATORS)))) - - # a dict of operators that are not directly supported by boost, but can be exposed - # simply as a function with a special name - BOOST_RENAME_OPERATORS = { - '()' : '__call__', - } - - # converters which have a special name in python - # it's a map of a regular expression of the converter's result to the - # appropriate python name - SPECIAL_CONVERTERS = { - re.compile(r'(const)?\s*double$') : '__float__', - re.compile(r'(const)?\s*float$') : '__float__', - re.compile(r'(const)?\s*int$') : '__int__', - re.compile(r'(const)?\s*long$') : '__long__', - re.compile(r'(const)?\s*char\s*\*?$') : '__str__', - re.compile(r'(const)?.*::basic_string<.*>\s*(\*|\&)?$') : '__str__', - } - - - def ExportOperators(self): - 'Export all member operators and free operators related to this class' - - def GetFreeOperators(): - 'Get all the free (global) operators related to this class' - operators = [] - for decl in self.declarations: - if isinstance(decl, Operator): - # check if one of the params is this class - for param in decl.parameters: - if param.name == self.class_.FullName(): - operators.append(decl) - break - return operators - - def GetOperand(param): - 'Returns the operand of this parameter (either "self", or "other")' - if param.name == self.class_.FullName(): - return namespaces.python + 'self' - else: - return namespaces.python + ('other< %s >()' % param.name) - - - def HandleSpecialOperator(operator): - # gatter information about the operator and its parameters - result_name = operator.result.name - param1_name = '' - if operator.parameters: - param1_name = operator.parameters[0].name - - # check for str - ostream = 'basic_ostream' - is_str = result_name.find(ostream) != -1 and param1_name.find(ostream) != -1 - if is_str: - namespace = namespaces.python + 'self_ns::' - self_ = namespaces.python + 'self' - return '.def(%sstr(%s))' % (namespace, self_) - - # is not a special operator - return None - - - - frees = GetFreeOperators() - members = [x for x in self.public_members if type(x) == ClassOperator] - all_operators = frees + members - operators = [x for x in all_operators if not self.info['operator'][x.name].exclude] - - for operator in operators: - # gatter information about the operator, for use later - wrapper = self.info['operator'][operator.name].wrapper - if wrapper: - pointer = '&' + wrapper.FullName() - if wrapper.code: - self.Add('declaration-outside', wrapper.code) - else: - pointer = operator.PointerDeclaration() - rename = self.info['operator'][operator.name].rename - - # check if this operator will be exported as a method - export_as_method = wrapper or rename or operator.name in self.BOOST_RENAME_OPERATORS - - # check if this operator has a special representation in boost - special_code = HandleSpecialOperator(operator) - has_special_representation = special_code is not None - - if export_as_method: - # export this operator as a normal method, renaming or using the given wrapper - if not rename: - if wrapper: - rename = wrapper.name - else: - rename = self.BOOST_RENAME_OPERATORS[operator.name] - policy = '' - policy_obj = self.info['operator'][operator.name].policy - if policy_obj: - policy = ', %s()' % policy_obj.Code() - self.Add('inside', '.def("%s", %s%s)' % (rename, pointer, policy)) - - elif has_special_representation: - self.Add('inside', special_code) - - elif operator.name in self.BOOST_SUPPORTED_OPERATORS: - # export this operator using boost's facilities - op = operator - is_unary = isinstance(op, Operator) and len(op.parameters) == 1 or\ - isinstance(op, ClassOperator) and len(op.parameters) == 0 - if is_unary: - self.Add('inside', '.def( %s%sself )' % \ - (operator.name, namespaces.python)) - else: - # binary operator - if len(operator.parameters) == 2: - left_operand = GetOperand(operator.parameters[0]) - right_operand = GetOperand(operator.parameters[1]) - else: - left_operand = namespaces.python + 'self' - right_operand = GetOperand(operator.parameters[0]) - self.Add('inside', '.def( %s %s %s )' % \ - (left_operand, operator.name, right_operand)) - - # export the converters. - # export them as simple functions with a pre-determined name - - converters = [x for x in self.public_members if type(x) == ConverterOperator] - - def ConverterMethodName(converter): - result_fullname = converter.result.FullName() - result_name = converter.result.name - for regex, method_name in self.SPECIAL_CONVERTERS.items(): - if regex.match(result_fullname): - return method_name - else: - # extract the last name from the full name - result_name = makeid(result_name) - return 'to_' + result_name - - for converter in converters: - info = self.info['operator'][converter.result.FullName()] - # check if this operator should be excluded - if info.exclude: - continue - - special_code = HandleSpecialOperator(converter) - if info.rename or not special_code: - # export as method - name = info.rename or ConverterMethodName(converter) - pointer = converter.PointerDeclaration() - policy_code = '' - if info.policy: - policy_code = ', %s()' % info.policy.Code() - self.Add('inside', '.def("%s", %s%s)' % (name, pointer, policy_code)) - - elif special_code: - self.Add('inside', special_code) - - - - def ExportNestedClasses(self, exported_names): - nested_classes = [x for x in self.public_members if isinstance(x, NestedClass)] - for nested_class in nested_classes: - nested_info = self.info[nested_class.name] - nested_info.include = self.info.include - nested_info.name = nested_class.FullName() - exporter = self.__class__(nested_info) - exporter.SetDeclarations(self.declarations) - codeunit = SingleCodeUnit(None, None) - exporter.Export(codeunit, exported_names) - self.nested_codeunits.append(codeunit) - - - def ExportNestedEnums(self, exported_names): - nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)] - for enum in nested_enums: - enum_info = self.info[enum.name] - enum_info.include = self.info.include - enum_info.name = enum.FullName() - exporter = EnumExporter(enum_info) - exporter.SetDeclarations(self.declarations) - codeunit = SingleCodeUnit(None, None) - exporter.Export(codeunit, exported_names) - self.nested_codeunits.append(codeunit) - - - def ExportSmartPointer(self): - smart_ptr = self.info.smart_ptr - if smart_ptr: - class_name = self.class_.FullName() - smart_ptr = smart_ptr % class_name - self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr)) - - - def ExportOpaquePointerPolicies(self): - # check all methods for 'return_opaque_pointer' policies - methods = [x for x in self.public_members if isinstance(x, Method)] - for method in methods: - return_opaque_policy = return_value_policy(return_opaque_pointer) - if self.info[method.name].policy == return_opaque_policy: - macro = exporterutils.EspecializeTypeID(method.result.name) - if macro: - self.Add('declaration-outside', macro) - - def ExportAddedCode(self): - if self.info.__code__: - for code in self.info.__code__: - self.Add('inside', code) - - -#============================================================================== -# Virtual Wrapper utils -#============================================================================== - -def _ParamsInfo(m, count=None): - if count is None: - count = len(m.parameters) - param_names = ['p%i' % i for i in range(count)] - param_types = [x.FullName() for x in m.parameters[:count]] - params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)] - #for i, p in enumerate(m.parameters[:count]): - # if p.default is not None: - # #params[i] += '=%s' % p.default - # params[i] += '=%s' % (p.name + '()') - params = ', '.join(params) - return params, param_names, param_types - - -class _VirtualWrapperGenerator(object): - 'Generates code to export the virtual methods of the given class' - - def __init__(self, class_, bases, info, codeunit): - self.class_ = copy.deepcopy(class_) - self.bases = bases[:] - self.info = info - self.wrapper_name = makeid(class_.FullName()) + '_Wrapper' - self.virtual_methods = None - self._method_count = {} - self.codeunit = codeunit - self.GenerateVirtualMethods() - - - SELF = 'py_self' - - - def DefaultImplementationNames(self, method): - '''Returns a list of default implementations for this method, one for each - number of default arguments. Always returns at least one name, and return from - the one with most arguments to the one with the least. - ''' - base_name = 'default_' + method.name - minArgs = method.minArgs - maxArgs = method.maxArgs - if minArgs == maxArgs: - return [base_name] - else: - return [base_name + ('_%i' % i) for i in range(minArgs, maxArgs+1)] - - - def Declaration(self, method, indent): - '''Returns a string with the declarations of the virtual wrapper and - its default implementations. This string must be put inside the Wrapper - body. - ''' - pyste = namespaces.pyste - python = namespaces.python - rename = self.info[method.name].rename or method.name - result = method.result.FullName() - return_str = 'return ' - if result == 'void': - return_str = '' - params, param_names, param_types = _ParamsInfo(method) - constantness = '' - if method.const: - constantness = ' const' - - # call_method callback - decl = indent + '%s %s(%s)%s%s {\n' % (result, method.name, params, constantness, method.Exceptions()) - param_names_str = ', '.join(param_names) - if param_names_str: - param_names_str = ', ' + param_names_str - - self_str = self.SELF - - decl += indent*2 + '%(return_str)s%(python)scall_method< %(result)s >' \ - '(%(self_str)s, "%(rename)s"%(param_names_str)s);\n' % locals() - decl += indent + '}\n' - - # default implementations (with overloading) - def DefaultImpl(method, param_names): - 'Return the body of a default implementation wrapper' - indent2 = indent * 2 - wrapper = self.info[method.name].wrapper - if not wrapper: - # return the default implementation of the class - return indent2 + '%s%s(%s);\n' % \ - (return_str, method.FullName(), ', '.join(param_names)) - else: - if wrapper.code: - self.codeunit.Write('declaration-outside', wrapper.code) - # return a call for the wrapper - params = ', '.join(['this'] + param_names) - return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params) - - if not method.abstract and method.visibility != Scope.private: - minArgs = method.minArgs - maxArgs = method.maxArgs - impl_names = self.DefaultImplementationNames(method) - for impl_name, argNum in zip(impl_names, range(minArgs, maxArgs+1)): - params, param_names, param_types = _ParamsInfo(method, argNum) - decl += '\n' - decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness) - decl += DefaultImpl(method, param_names) - decl += indent + '}\n' - return decl - - - def MethodDefinition(self, method): - '''Returns a list of lines, which should be put inside the class_ - statement to export this method.''' - # dont define abstract methods - pyste = namespaces.pyste - rename = self.info[method.name].rename or method.name - default_names = self.DefaultImplementationNames(method) - class_name = self.class_.FullName() - wrapper_name = pyste + self.wrapper_name - result = method.result.FullName() - is_method_unique = method.is_unique - constantness = '' - if method.const: - constantness = ' const' - - # create a list of default-impl pointers - minArgs = method.minArgs - maxArgs = method.maxArgs - if method.abstract: - default_pointers = [] - elif is_method_unique: - default_pointers = ['&%s::%s' % (wrapper_name, x) for x in default_names] - else: - default_pointers = [] - for impl_name, argNum in zip(default_names, range(minArgs, maxArgs+1)): - param_list = [x.FullName() for x in method.parameters[:argNum]] - params = ', '.join(param_list) - signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness) - default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name) - default_pointers.append(default_pointer) - - # get the pointer of the method - pointer = method.PointerDeclaration() - if method.abstract: - pointer = namespaces.python + ('pure_virtual(%s)' % pointer) - - # warn the user if this method needs a policy and doesn't have one - method_info = self.info[method.name] - method_info.policy = exporterutils.HandlePolicy(method, method_info.policy) - - # Add policy to overloaded methods also - policy = method_info.policy or '' - if policy: - policy = ', %s%s()' % (namespaces.python, policy.Code()) - - # generate the defs - definitions = [] - # basic def - if default_pointers: - definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy)) - for default_pointer in default_pointers[:-1]: - definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy)) - else: - definitions.append('.def("%s", %s%s)' % (rename, pointer, policy)) - return definitions - - - def FullName(self): - return namespaces.pyste + self.wrapper_name - - - def GenerateVirtualMethods(self): - '''To correctly export all virtual methods, we must also make wrappers - for the virtual methods of the bases of this class, as if the methods - were from this class itself. - This method creates the instance variable self.virtual_methods. - ''' - def IsVirtual(m): - if type(m) is Method: - pure_virtual = m.abstract and m.virtual - virtual = m.virtual and m.visibility != Scope.private - return virtual or pure_virtual - else: - return False - - # extract the virtual methods, avoiding duplications. The duplication - # must take in account the full signature without the class name, so - # that inherited members are correctly excluded if the subclass overrides - # them. - def MethodSig(method): - if method.const: - const = ' const' - else: - const = '' - if method.result: - result = method.result.FullName() - else: - result = '' - params = ', '.join([x.FullName() for x in method.parameters]) - return '%s %s(%s)%s%s' % ( - result, method.name, params, const, method.Exceptions()) - - already_added = {} - self.virtual_methods = [] - for member in self.class_: - if IsVirtual(member): - already_added[MethodSig(member)] = None - self.virtual_methods.append(member) - - for base in self.bases: - base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)] - for base_method in base_methods: - self.class_.AddMember(base_method) - - all_methods = [x for x in self.class_ if IsVirtual(x)] - - for member in all_methods: - sig = MethodSig(member) - if IsVirtual(member) and not sig in already_added: - self.virtual_methods.append(member) - already_added[sig] = 0 - - - def Constructors(self): - return self.class_.Constructors(publics_only=True) - - - def GenerateDefinitions(self): - defs = [] - for method in self.virtual_methods: - exclude = self.info[method.name].exclude - # generate definitions only for public methods and non-abstract methods - if method.visibility == Scope.public and not exclude: - defs.extend(self.MethodDefinition(method)) - return defs - - - def GenerateVirtualWrapper(self, indent): - 'Return the wrapper for this class' - - # generate the class code - class_name = self.class_.FullName() - code = 'struct %s: %s\n' % (self.wrapper_name, class_name) - code += '{\n' - # generate constructors (with the overloads for each one) - for cons in self.Constructors(): # only public constructors - minArgs = cons.minArgs - maxArgs = cons.maxArgs - # from the min number of arguments to the max number, generate - # all version of the given constructor - cons_code = '' - for argNum in range(minArgs, maxArgs+1): - params, param_names, param_types = _ParamsInfo(cons, argNum) - if params: - params = ', ' + params - cons_code += indent + '%s(PyObject* %s_%s):\n' % \ - (self.wrapper_name, self.SELF, params) - cons_code += indent*2 + '%s(%s), %s(%s_) {}\n\n' % \ - (class_name, ', '.join(param_names), self.SELF, self.SELF) - code += cons_code - # generate the body - body = [] - for method in self.virtual_methods: - if not self.info[method.name].exclude: - body.append(self.Declaration(method, indent)) - body = '\n'.join(body) - code += body + '\n' - # add the self member - code += indent + 'PyObject* %s;\n' % self.SELF - code += '};\n' - return code diff --git a/pyste/src/Pyste/CodeExporter.py b/pyste/src/Pyste/CodeExporter.py deleted file mode 100644 index 382fffbd58..0000000000 --- a/pyste/src/Pyste/CodeExporter.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from Exporter import Exporter - -#============================================================================== -# CodeExporter -#============================================================================== -class CodeExporter(Exporter): - - def __init__(self, info): - Exporter.__init__(self, info) - - - def Name(self): - return self.info.code - - - def Export(self, codeunit, exported_names): - codeunit.Write(self.info.section, self.info.code) - - - def WriteInclude(self, codeunit): - pass diff --git a/pyste/src/Pyste/CppParser.py b/pyste/src/Pyste/CppParser.py deleted file mode 100644 index be68a448a1..0000000000 --- a/pyste/src/Pyste/CppParser.py +++ /dev/null @@ -1,247 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from GCCXMLParser import ParseDeclarations -import tempfile -import shutil -import os -import sys -import os.path -import settings -import shutil -import shelve -from cPickle import dump, load - -#============================================================================== -# exceptions -#============================================================================== -class CppParserError(Exception): pass - -#============================================================================== -# CppParser -#============================================================================== -class CppParser: - 'Parses a header file and returns a list of declarations' - - def __init__(self, includes=None, defines=None, cache_dir=None, version=None, gccxml_path = 'gccxml'): - 'includes and defines ar the directives given to gcc' - if includes is None: - includes = [] - if defines is None: - defines = [] - self.includes = includes - self.gccxml_path = gccxml_path - self.defines = defines - self.version = version - #if cache_dir is None: - # cache_dir = tempfile.mktemp() - # self.delete_cache = True - #else: - # self.delete_cache = False - self.delete_cache = False - self.cache_dir = cache_dir - self.cache_files = [] - self.mem_cache = {} - # create the cache dir - if cache_dir: - try: - os.makedirs(cache_dir) - except OSError: pass - - - def __del__(self): - self.Close() - - - def _IncludeParams(self, filename): - includes = self.includes[:] - filedir = os.path.dirname(filename) - if not filedir: - filedir = '.' - includes.insert(0, filedir) - includes = ['-I "%s"' % self.Unixfy(x) for x in includes] - return ' '.join(includes) - - - def _DefineParams(self): - defines = ['-D "%s"' % x for x in self.defines] - return ' '.join(defines) - - - def FindHeader(self, header): - if os.path.isfile(header): - return header - for path in self.includes: - filename = os.path.join(path, header) - if os.path.isfile(filename): - return filename - else: - name = os.path.basename(header) - raise RuntimeError, 'Header file "%s" not found!' % name - - - def AppendTail(self, filename, tail): - '''Creates a temporary file, appends the text tail to it, and returns - the filename of the file. - ''' - if hasattr(tempfile, 'mkstemp'): - f_no, temp = tempfile.mkstemp('.h') - f = file(temp, 'a') - os.close(f_no) - else: - temp = tempfile.mktemp('.h') - f = file(temp, 'a') - f.write('#include "%s"\n\n' % os.path.abspath(filename)) - f.write(tail) - f.write('\n') - f.close() - return temp - - - def Unixfy(self, path): - return path.replace('\\', '/') - - - def ParseWithGCCXML(self, header, tail): - '''Parses the given header using gccxml and GCCXMLParser. - ''' - header = self.FindHeader(header) - if tail: - filename = self.AppendTail(header, tail) - else: - filename = header - xmlfile = tempfile.mktemp('.xml') - try: - # get the params - includes = self._IncludeParams(filename) - defines = self._DefineParams() - # call gccxml - cmd = '%s %s %s "%s" -fxml=%s' - filename = self.Unixfy(filename) - xmlfile = self.Unixfy(xmlfile) - status = os.system(cmd % (self.gccxml_path, includes, defines, filename, xmlfile)) - if status != 0 or not os.path.isfile(xmlfile): - raise CppParserError, 'Error executing gccxml' - # parse the resulting xml - declarations = ParseDeclarations(xmlfile) - # make the declarations' location to point to the original file - if tail: - for decl in declarations: - decl_filename = os.path.normpath(os.path.normcase(decl.location[0])) - filename = os.path.normpath(os.path.normcase(filename)) - if decl_filename == filename: - decl.location = header, decl.location[1] - # return the declarations - return declarations - finally: - if settings.DEBUG and os.path.isfile(xmlfile): - debugname = os.path.basename(header) - debugname = os.path.splitext(debugname)[0] + '.xml' - print 'DEBUG:', debugname - shutil.copy(xmlfile, debugname) - # delete the temporary files - try: - os.remove(xmlfile) - if tail: - os.remove(filename) - except OSError: pass - - - def Parse(self, header, interface, tail=None): - '''Parses the given filename related to the given interface and returns - the (declarations, headerfile). The header returned is normally the - same as the given to this method (except that it is the full path), - except if tail is not None: in this case, the header is copied to a temp - filename and the tail code is appended to it before being passed on to - gccxml. This temp filename is then returned. - ''' - if tail is None: - tail = '' - tail = tail.strip() - declarations = self.GetCache(header, interface, tail) - if declarations is None: - declarations = self.ParseWithGCCXML(header, tail) - self.CreateCache(header, interface, tail, declarations) - header_fullpath = os.path.abspath(self.FindHeader(header)) - return declarations, header_fullpath - - - def CacheFileName(self, interface): - interface_name = os.path.basename(interface) - cache_file = os.path.splitext(interface_name)[0] + '.pystec' - cache_file = os.path.join(self.cache_dir, cache_file) - return cache_file - - - def GetCache(self, header, interface, tail): - key = (header, interface, tail) - # try memory cache first - if key in self.mem_cache: - return self.mem_cache[key] - - # get the cache from the disk - if self.cache_dir is None: - return None - header = self.FindHeader(header) - cache_file = self.CacheFileName(interface) - if os.path.isfile(cache_file): - f = file(cache_file, 'rb') - try: - version = load(f) - if version != self.version: - return None - cache = load(f) - if cache.has_key(key): - self.cache_files.append(cache_file) - return cache[key] - else: - return None - finally: - f.close() - else: - return None - - - def CreateCache(self, header, interface, tail, declarations): - key = (header, interface, tail) - - # our memory cache only holds one item - self.mem_cache.clear() - self.mem_cache[key] = declarations - - # save the cache in the disk - if self.cache_dir is None: - return - header = self.FindHeader(header) - cache_file = self.CacheFileName(interface) - if os.path.isfile(cache_file): - f = file(cache_file, 'rb') - try: - version = load(f) - cache = load(f) - finally: - f.close() - else: - cache = {} - cache[key] = declarations - self.cache_files.append(cache_file) - f = file(cache_file, 'wb') - try: - dump(self.version, f, 1) - dump(cache, f, 1) - finally: - f.close() - return cache_file - - - def Close(self): - if self.delete_cache and self.cache_files: - for filename in self.cache_files: - try: - os.remove(filename) - except OSError: - pass - self.cache_files = [] - shutil.rmtree(self.cache_dir) diff --git a/pyste/src/Pyste/EnumExporter.py b/pyste/src/Pyste/EnumExporter.py deleted file mode 100644 index 0107fbee36..0000000000 --- a/pyste/src/Pyste/EnumExporter.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from Exporter import Exporter -from settings import * -import utils - -#============================================================================== -# EnumExporter -#============================================================================== -class EnumExporter(Exporter): - 'Exports enumerators' - - def __init__(self, info): - Exporter.__init__(self, info) - - - def SetDeclarations(self, declarations): - Exporter.SetDeclarations(self, declarations) - if self.declarations: - self.enum = self.GetDeclaration(self.info.name) - else: - self.enum = None - - def Export(self, codeunit, exported_names): - if self.info.exclude: - return - indent = self.INDENT - in_indent = self.INDENT*2 - rename = self.info.rename or self.enum.name - full_name = self.enum.FullName() - unnamed_enum = False - if rename.startswith('$_') or rename.startswith('._'): - unnamed_enum = True - code = '' - if not unnamed_enum: - code += indent + namespaces.python - code += 'enum_< %s >("%s")\n' % (full_name, rename) - for name in self.enum.values: - rename = self.info[name].rename or name - value_fullname = self.enum.ValueFullName(name) - if not unnamed_enum: - code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname) - else: - code += indent + namespaces.python - code += 'scope().attr("%s") = (int)%s;\n' % (rename, value_fullname ) - if self.info.export_values and not unnamed_enum: - code += in_indent + '.export_values()\n' - if not unnamed_enum: - code += indent + ';\n' - code += '\n' - codeunit.Write('module', code) - exported_names[self.enum.FullName()] = 1 - - def Name(self): - return self.info.name diff --git a/pyste/src/Pyste/Exporter.py b/pyste/src/Pyste/Exporter.py deleted file mode 100644 index d87b37c580..0000000000 --- a/pyste/src/Pyste/Exporter.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import os.path - -#============================================================================== -# Exporter -#============================================================================== -class Exporter(object): - 'Base class for objects capable to generate boost.python code.' - - INDENT = ' ' * 4 - - def __init__(self, info, parser_tail=None): - self.info = info - self.parser_tail = parser_tail - self.interface_file = None - self.declarations = [] - - - def Name(self): - raise NotImplementedError(self.__class__.__name__) - - - def Tail(self): - return self.parser_tail - - - def Parse(self, parser): - self.parser = parser - header = self.info.include - tail = self.parser_tail - declarations, parser_header = parser.parse(header, tail) - self.parser_header = parser_header - self.SetDeclarations(declarations) - - - def SetParsedHeader(self, parsed_header): - self.parser_header = parsed_header - - - def SetDeclarations(self, declarations): - self.declarations = declarations - - - def GenerateCode(self, codeunit, exported_names): - self.WriteInclude(codeunit) - self.Export(codeunit, exported_names) - - - def WriteInclude(self, codeunit): - codeunit.Write('include', '#include <%s>\n' % self.info.include) - - - def Export(self, codeunit, exported_names): - 'subclasses must override this to do the real work' - pass - - - def GetDeclarations(self, fullname): - decls = [] - for decl in self.declarations: - if decl.FullName() == fullname: - decls.append(decl) - if not decls: - raise RuntimeError, 'no %s declaration found!' % fullname - return decls - - - def GetDeclaration(self, fullname): - decls = self.GetDeclarations(fullname) - #assert len(decls) == 1 - return decls[0] - - - def Order(self): - '''Returns a string that uniquely identifies this instance. All - exporters will be sorted by Order before being exported. - ''' - return 0, self.info.name - - - def Header(self): - return self.info.include - - - def __eq__(self, other): - return type(self) is type(other) and self.Name() == other.Name() \ - and self.interface_file == other.interface_file - - def __ne__(self, other): - return not self == other diff --git a/pyste/src/Pyste/FunctionExporter.py b/pyste/src/Pyste/FunctionExporter.py deleted file mode 100644 index 5765f65e90..0000000000 --- a/pyste/src/Pyste/FunctionExporter.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from Exporter import Exporter -from policies import * -from declarations import * -from settings import * -import utils -import exporterutils - - -#============================================================================== -# FunctionExporter -#============================================================================== -class FunctionExporter(Exporter): - 'Generates boost.python code to export the given function.' - - def __init__(self, info, tail=None): - Exporter.__init__(self, info, tail) - - - def Export(self, codeunit, exported_names): - if not self.info.exclude: - decls = self.GetDeclarations(self.info.name) - for decl in decls: - self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy) - self.ExportDeclaration(decl, len(decls) == 1, codeunit) - self.ExportOpaquePointer(decl, codeunit) - self.GenerateOverloads(decls, codeunit) - exported_names[self.Name()] = 1 - - - def ExportDeclaration(self, decl, unique, codeunit): - name = self.info.rename or decl.name - defs = namespaces.python + 'def("%s", ' % name - wrapper = self.info.wrapper - if wrapper: - pointer = '&' + wrapper.FullName() - else: - pointer = decl.PointerDeclaration() - defs += pointer - defs += self.PolicyCode() - overload = self.OverloadName(decl) - if overload: - defs += ', %s()' % (namespaces.pyste + overload) - defs += ');' - codeunit.Write('module', self.INDENT + defs + '\n') - # add the code of the wrapper - if wrapper and wrapper.code: - codeunit.Write('declaration', wrapper.code + '\n') - - - def OverloadName(self, decl): - if decl.minArgs != decl.maxArgs: - return '%s_overloads_%i_%i' % \ - (decl.name, decl.minArgs, decl.maxArgs) - else: - return '' - - - def GenerateOverloads(self, declarations, codeunit): - codes = {} - for decl in declarations: - overload = self.OverloadName(decl) - if overload and overload not in codes: - code = 'BOOST_PYTHON_FUNCTION_OVERLOADS(%s, %s, %i, %i)' %\ - (overload, decl.FullName(), decl.minArgs, decl.maxArgs) - codeunit.Write('declaration', code + '\n') - codes[overload] = None - - - def PolicyCode(self): - policy = self.info.policy - if policy is not None: - assert isinstance(policy, Policy) - return ', %s()' % policy.Code() - else: - return '' - - - def ExportOpaquePointer(self, function, codeunit): - if self.info.policy == return_value_policy(return_opaque_pointer): - typename = function.result.name - macro = exporterutils.EspecializeTypeID(typename) - if macro: - codeunit.Write('declaration-outside', macro) - - - def Name(self): - return self.info.name diff --git a/pyste/src/Pyste/GCCXMLParser.py b/pyste/src/Pyste/GCCXMLParser.py deleted file mode 100644 index 4a10172043..0000000000 --- a/pyste/src/Pyste/GCCXMLParser.py +++ /dev/null @@ -1,478 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from declarations import * -try: - # try to use internal elementtree - from xml.etree.cElementTree import ElementTree -except ImportError: - # try to use cElementTree if avaiable - try: - from cElementTree import ElementTree - except ImportError: - # fall back to the normal elementtree - from elementtree.ElementTree import ElementTree -from xml.parsers.expat import ExpatError -from copy import deepcopy -from utils import enumerate - - -#============================================================================== -# Exceptions -#============================================================================== -class InvalidXMLError(Exception): pass - -class ParserError(Exception): pass - -class InvalidContextError(ParserError): pass - - -#============================================================================== -# GCCXMLParser -#============================================================================== -class GCCXMLParser(object): - 'Parse a GCC_XML file and extract the top-level declarations.' - - interested_tags = {'Class':0, 'Function':0, 'Variable':0, 'Enumeration':0} - - def Parse(self, filename): - self.elements = self.GetElementsFromXML(filename) - # high level declarations - self.declarations = [] - self._names = {} - # parse the elements - for id in self.elements: - element, decl = self.elements[id] - if decl is None: - try: - self.ParseElement(id, element) - except InvalidContextError: - pass # ignore those nodes with invalid context - # (workaround gccxml bug) - - - def Declarations(self): - return self.declarations - - - def AddDecl(self, decl): - if decl.FullName() in self._names: - decl.is_unique= False - for d in self.declarations: - if d.FullName() == decl.FullName(): - d.is_unique = False - self._names[decl.FullName()] = 0 - self.declarations.append(decl) - - - def ParseElement(self, id, element): - method = 'Parse' + element.tag - if hasattr(self, method): - func = getattr(self, method) - func(id, element) - else: - self.ParseUnknown(id, element) - - - def GetElementsFromXML(self,filename): - 'Extracts a dictionary of elements from the gcc_xml file.' - - tree = ElementTree() - try: - tree.parse(filename) - except ExpatError: - raise InvalidXMLError, 'Not a XML file: %s' % filename - - root = tree.getroot() - if root.tag != 'GCC_XML': - raise InvalidXMLError, 'Not a valid GCC_XML file' - - # build a dictionary of id -> element, None - elementlist = root.getchildren() - elements = {} - for element in elementlist: - id = element.get('id') - if id: - elements[id] = element, None - return elements - - - def GetDecl(self, id): - if id not in self.elements: - if id == '_0': - raise InvalidContextError, 'Invalid context found in the xml file.' - else: - msg = 'ID not found in elements: %s' % id - raise ParserError, msg - - elem, decl = self.elements[id] - if decl is None: - self.ParseElement(id, elem) - elem, decl = self.elements[id] - if decl is None: - raise ParserError, 'Could not parse element: %s' % elem.tag - return decl - - - def GetType(self, id): - def Check(id, feature): - pos = id.find(feature) - if pos != -1: - id = id[:pos] + id[pos+1:] - return True, id - else: - return False, id - const, id = Check(id, 'c') - volatile, id = Check(id, 'v') - restricted, id = Check(id, 'r') - decl = self.GetDecl(id) - if isinstance(decl, Type): - res = deepcopy(decl) - if const: - res.const = const - if volatile: - res.volatile = volatile - if restricted: - res.restricted = restricted - else: - res = Type(decl.FullName(), const) - res.volatile = volatile - res.restricted = restricted - return res - - - def GetLocation(self, location): - file, line = location.split(':') - file = self.GetDecl(file) - return file, int(line) - - - def Update(self, id, decl): - element, _ = self.elements[id] - self.elements[id] = element, decl - - - def ParseUnknown(self, id, element): - name = '__Unknown_Element_%s' % id - decl = Unknown(name) - self.Update(id, decl) - - - def ParseNamespace(self, id, element): - namespace = element.get('name') - context = element.get('context') - if context: - outer = self.GetDecl(context) - if not outer.endswith('::'): - outer += '::' - namespace = outer + namespace - if namespace.startswith('::'): - namespace = namespace[2:] - self.Update(id, namespace) - - - def ParseFile(self, id, element): - filename = element.get('name') - self.Update(id, filename) - - - def ParseVariable(self, id, element): - # in gcc_xml, a static Field is declared as a Variable, so we check - # this and call the Field parser. - context = self.GetDecl(element.get('context')) - if isinstance(context, Class): - self.ParseField(id, element) - elem, decl = self.elements[id] - decl.static = True - else: - namespace = context - name = element.get('name') - type_ = self.GetType(element.get('type')) - location = self.GetLocation(element.get('location')) - variable = Variable(type_, name, namespace) - variable.location = location - self.AddDecl(variable) - self.Update(id, variable) - - - def GetArguments(self, element): - args = [] - for child in element: - if child.tag == 'Argument': - type = self.GetType(child.get('type')) - type.default = child.get('default') - args.append(type) - return args - - - def GetExceptions(self, exception_list): - if exception_list is None: - return None - - exceptions = [] - for t in exception_list.split(): - exceptions.append(self.GetType(t)) - - return exceptions - - - def ParseFunction(self, id, element, functionType=Function): - '''functionType is used because a Operator is identical to a normal - function, only the type of the function changes.''' - name = element.get('name') - returns = self.GetType(element.get('returns')) - namespace = self.GetDecl(element.get('context')) - location = self.GetLocation(element.get('location')) - params = self.GetArguments(element) - incomplete = bool(int(element.get('incomplete', 0))) - throws = self.GetExceptions(element.get('throw', None)) - function = functionType(name, namespace, returns, params, throws) - function.location = location - self.AddDecl(function) - self.Update(id, function) - - - def ParseOperatorFunction(self, id, element): - self.ParseFunction(id, element, Operator) - - - def GetHierarchy(self, bases): - '''Parses the string "bases" from the xml into a list of tuples of Base - instances. The first tuple is the most direct inheritance, and then it - goes up in the hierarchy. - ''' - - if bases is None: - return [] - base_names = bases.split() - this_level = [] - next_levels = [] - for base in base_names: - # get the visibility - split = base.split(':') - if len(split) == 2: - visib = split[0] - base = split[1] - else: - visib = Scope.public - decl = self.GetDecl(base) - if not isinstance(decl, Class): - # on windows, there are some classes which "bases" points to an - # "Unimplemented" tag, but we are not interested in this classes - # anyway - continue - base = Base(decl.FullName(), visib) - this_level.append(base) - # normalize with the other levels - for index, level in enumerate(decl.hierarchy): - if index < len(next_levels): - next_levels[index] = next_levels[index] + level - else: - next_levels.append(level) - hierarchy = [] - if this_level: - hierarchy.append(tuple(this_level)) - if next_levels: - hierarchy.extend(next_levels) - return hierarchy - - - def GetMembers(self, member_list): - # members must be a string with the ids of the members - if member_list is None: - return [] - members = [] - for member in member_list.split(): - decl = self.GetDecl(member) - if type(decl) in Class.ValidMemberTypes(): - members.append(decl) - return members - - - def ParseClass(self, id, element): - name = element.get('name') - abstract = bool(int(element.get('abstract', '0'))) - location = self.GetLocation(element.get('location')) - context = self.GetDecl(element.get('context')) - incomplete = bool(int(element.get('incomplete', 0))) - if isinstance(context, str): - class_ = Class(name, context, [], abstract) - else: - # a nested class - visib = element.get('access', Scope.public) - class_ = NestedClass( - name, context.FullName(), visib, [], abstract) - class_.incomplete = incomplete - # we have to add the declaration of the class before trying - # to parse its members and bases, to avoid recursion. - self.AddDecl(class_) - class_.location = location - self.Update(id, class_) - # now we can get the members and the bases - class_.hierarchy = self.GetHierarchy(element.get('bases')) - if class_.hierarchy: - class_.bases = class_.hierarchy[0] - members = self.GetMembers(element.get('members')) - for member in members: - class_.AddMember(member) - - - def ParseStruct(self, id, element): - self.ParseClass(id, element) - - - FUNDAMENTAL_RENAME = { - 'long long int' : 'boost::int64_t', - 'long long unsigned int' : 'boost::uint64_t', - } - - def ParseFundamentalType(self, id, element): - name = element.get('name') - name = self.FUNDAMENTAL_RENAME.get(name, name) - type_ = FundamentalType(name) - self.Update(id, type_) - - - def ParseArrayType(self, id, element): - type = self.GetType(element.get('type')) - min = element.get('min') - max = element.get('max') - array = ArrayType(type.name, type.const, min, max) - self.Update(id, array) - - - def ParseReferenceType(self, id, element): - type = self.GetType(element.get('type')) - expand = not isinstance(type, FunctionType) - ref = ReferenceType(type.name, type.const, None, expand, type.suffix) - self.Update(id, ref) - - - def ParsePointerType(self, id, element): - type = self.GetType(element.get('type')) - expand = not isinstance(type, FunctionType) - ref = PointerType(type.name, type.const, None, expand, type.suffix) - self.Update(id, ref) - - - def ParseFunctionType(self, id, element): - result = self.GetType(element.get('returns')) - args = self.GetArguments(element) - func = FunctionType(result, args) - self.Update(id, func) - - - def ParseMethodType(self, id, element): - class_ = self.GetDecl(element.get('basetype')).FullName() - result = self.GetType(element.get('returns')) - args = self.GetArguments(element) - method = MethodType(result, args, class_) - self.Update(id, method) - - - def ParseField(self, id, element): - name = element.get('name') - visib = element.get('access', Scope.public) - classname = self.GetDecl(element.get('context')).FullName() - type_ = self.GetType(element.get('type')) - static = bool(int(element.get('extern', '0'))) - location = self.GetLocation(element.get('location')) - var = ClassVariable(type_, name, classname, visib, static) - var.location = location - self.Update(id, var) - - - def ParseMethod(self, id, element, methodType=Method): - name = element.get('name') - result = self.GetType(element.get('returns')) - classname = self.GetDecl(element.get('context')).FullName() - visib = element.get('access', Scope.public) - static = bool(int(element.get('static', '0'))) - virtual = bool(int(element.get('virtual', '0'))) - abstract = bool(int(element.get('pure_virtual', '0'))) - const = bool(int(element.get('const', '0'))) - location = self.GetLocation(element.get('location')) - throws = self.GetExceptions(element.get('throw', None)) - params = self.GetArguments(element) - method = methodType( - name, classname, result, params, visib, virtual, abstract, static, const, throws) - method.location = location - self.Update(id, method) - - - def ParseOperatorMethod(self, id, element): - self.ParseMethod(id, element, ClassOperator) - - - def ParseConstructor(self, id, element): - name = element.get('name') - visib = element.get('access', Scope.public) - classname = self.GetDecl(element.get('context')).FullName() - location = self.GetLocation(element.get('location')) - params = self.GetArguments(element) - artificial = element.get('artificial', False) - ctor = Constructor(name, classname, params, visib) - ctor.location = location - self.Update(id, ctor) - - - def ParseDestructor(self, id, element): - name = element.get('name') - visib = element.get('access', Scope.public) - classname = self.GetDecl(element.get('context')).FullName() - virtual = bool(int(element.get('virtual', '0'))) - location = self.GetLocation(element.get('location')) - des = Destructor(name, classname, visib, virtual) - des.location = location - self.Update(id, des) - - - def ParseConverter(self, id, element): - self.ParseMethod(id, element, ConverterOperator) - - - def ParseTypedef(self, id, element): - name = element.get('name') - type = self.GetType(element.get('type')) - context = self.GetDecl(element.get('context')) - if isinstance(context, Class): - context = context.FullName() - typedef = Typedef(type, name, context) - self.Update(id, typedef) - self.AddDecl(typedef) - - - def ParseEnumeration(self, id, element): - name = element.get('name') - location = self.GetLocation(element.get('location')) - context = self.GetDecl(element.get('context')) - incomplete = bool(int(element.get('incomplete', 0))) - if isinstance(context, str): - enum = Enumeration(name, context) - else: - visib = element.get('access', Scope.public) - enum = ClassEnumeration(name, context.FullName(), visib) - self.AddDecl(enum) - enum.location = location - for child in element: - if child.tag == 'EnumValue': - name = child.get('name') - value = int(child.get('init')) - enum.values[name] = value - enum.incomplete = incomplete - self.Update(id, enum) - - - -def ParseDeclarations(filename): - 'Returns a list of the top declarations found in the gcc_xml file.' - - parser = GCCXMLParser() - parser.Parse(filename) - return parser.Declarations() - - -if __name__ == '__main__': - ParseDeclarations(r'D:\Programming\Libraries\boost-cvs\boost\libs\python\pyste\example\test.xml') diff --git a/pyste/src/Pyste/HeaderExporter.py b/pyste/src/Pyste/HeaderExporter.py deleted file mode 100644 index 47651ba707..0000000000 --- a/pyste/src/Pyste/HeaderExporter.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from Exporter import Exporter -from ClassExporter import ClassExporter -from FunctionExporter import FunctionExporter -from EnumExporter import EnumExporter -from VarExporter import VarExporter -from infos import * -from declarations import * -import os.path -import exporters -import MultipleCodeUnit - -#============================================================================== -# HeaderExporter -#============================================================================== -class HeaderExporter(Exporter): - 'Exports all declarations found in the given header' - - def __init__(self, info, parser_tail=None): - Exporter.__init__(self, info, parser_tail) - - - def WriteInclude(self, codeunit): - pass - - - def IsInternalName(self, name): - '''Returns true if the given name looks like a internal compiler - structure''' - return name.startswith('_') - - - def Export(self, codeunit, exported_names): - header = os.path.normpath(self.parser_header) - for decl in self.declarations: - # check if this declaration is in the header - location = os.path.abspath(decl.location[0]) - if location == header and not self.IsInternalName(decl.name): - # ok, check the type of the declaration and export it accordingly - self.HandleDeclaration(decl, codeunit, exported_names) - - - def HandleDeclaration(self, decl, codeunit, exported_names): - '''Dispatch the declaration to the appropriate method, that must create - a suitable info object for a Exporter, create a Exporter, set its - declarations and append it to the list of exporters. - ''' - dispatch_table = { - Class : ClassExporter, - Enumeration : EnumExporter, - Function : FunctionExporter, - Variable : VarExporter, - } - - exporter_class = dispatch_table.get(type(decl)) - if exporter_class is not None: - self.HandleExporter(decl, exporter_class, codeunit, exported_names) - - - def HandleExporter(self, decl, exporter_type, codeunit, exported_names): - # only export complete declarations - if not decl.incomplete: - info = self.info[decl.name] - info.name = decl.FullName() - info.include = self.info.include - exporter = exporter_type(info) - exporter.SetDeclarations(self.declarations) - exporter.SetParsedHeader(self.parser_header) - if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit): - codeunit.SetCurrent(self.interface_file, exporter.Name()) - else: - codeunit.SetCurrent(exporter.Name()) - exporter.GenerateCode(codeunit, exported_names) - - - def Name(self): - return self.info.include diff --git a/pyste/src/Pyste/MultipleCodeUnit.py b/pyste/src/Pyste/MultipleCodeUnit.py deleted file mode 100644 index 65faad45de..0000000000 --- a/pyste/src/Pyste/MultipleCodeUnit.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from SingleCodeUnit import SingleCodeUnit -import os -import utils -from SmartFile import SmartFile - - -#============================================================================== -# MultipleCodeUnit -#============================================================================== -class MultipleCodeUnit(object): - ''' - Represents a bunch of cpp files, where each cpp file represents a header - to be exported by pyste. Another cpp, named .cpp is created too. - ''' - - def __init__(self, modulename, outdir): - self.modulename = modulename - self.outdir = outdir - self.codeunits = {} # maps from a (filename, function) to a SingleCodeUnit - self.functions = [] - self._current = None - self.all = SingleCodeUnit(None, None) - - - def _FunctionName(self, interface_file): - name = os.path.splitext(interface_file)[0] - return 'Export_%s' % utils.makeid(name) - - - def _FileName(self, interface_file): - filename = os.path.basename(interface_file) - filename = '_%s.cpp' % os.path.splitext(filename)[0] - return os.path.join(self.outdir, filename) - - - def SetCurrent(self, interface_file, export_name): - 'Changes the current code unit' - if export_name is None: - self._current = None - elif export_name is '__all__': - self._current = self.all - else: - filename = self._FileName(interface_file) - function = self._FunctionName(interface_file) - try: - codeunit = self.codeunits[filename] - except KeyError: - codeunit = SingleCodeUnit(None, filename) - codeunit.module_definition = 'void %s()' % function - self.codeunits[filename] = codeunit - if function not in self.functions: - self.functions.append(function) - self._current = codeunit - - - def Current(self): - return self._current - - current = property(Current, SetCurrent) - - - def Write(self, section, code): - if self._current is not None: - self.current.Write(section, code) - - - def Section(self, section): - if self._current is not None: - return self.current.Section(section) - - - def _CreateOutputDir(self): - try: - os.mkdir(self.outdir) - except OSError: pass # already created - - - def Save(self): - # create the directory where all the files will go - self._CreateOutputDir(); - # order all code units by filename, and merge them all - codeunits = {} # filename => list of codeunits - - # While ordering all code units by file name, the first code - # unit in the list of code units is used as the main unit - # which dumps all the include, declaration and - # declaration-outside sections at the top of the file. - for filename, codeunit in self.codeunits.items(): - if filename not in codeunits: - # this codeunit is the main codeunit. - codeunits[filename] = [codeunit] - codeunit.Merge(self.all) - else: - main_unit = codeunits[filename][0] - for section in ('include', 'declaration', 'declaration-outside'): - main_unit.code[section] = main_unit.code[section] + codeunit.code[section] - codeunit.code[section] = '' - codeunits[filename].append(codeunit) - - # Now write all the codeunits appending them correctly. - for file_units in codeunits.values(): - append = False - for codeunit in file_units: - codeunit.Save(append) - if not append: - append = True - - - def GenerateMain(self, interfaces): - # generate the main cpp - filename = os.path.join(self.outdir, '_main.cpp') - fout = SmartFile(filename, 'w') - fout.write(utils.left_equals('Include')) - fout.write('#include \n\n') - fout.write(utils.left_equals('Exports')) - functions = [self._FunctionName(x) for x in interfaces] - for function in functions: - fout.write('void %s();\n' % function) - fout.write('\n') - fout.write(utils.left_equals('Module')) - fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename) - fout.write('{\n') - indent = ' ' * 4 - for function in functions: - fout.write(indent) - fout.write('%s();\n' % function) - fout.write('}\n') - - - diff --git a/pyste/src/Pyste/SingleCodeUnit.py b/pyste/src/Pyste/SingleCodeUnit.py deleted file mode 100644 index 2e59dbb800..0000000000 --- a/pyste/src/Pyste/SingleCodeUnit.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from settings import namespaces -import settings -from utils import remove_duplicated_lines, left_equals -from SmartFile import SmartFile - - -#============================================================================== -# SingleCodeUnit -#============================================================================== -class SingleCodeUnit: - ''' - Represents a cpp file, where other objects can write in one of the - predefined sections. - The avaiable sections are: - pchinclude - The pre-compiled header area - include - The include area of the cpp file - declaration - The part before the module definition - module - Inside the BOOST_PYTHON_MODULE macro - ''' - - def __init__(self, modulename, filename): - self.modulename = modulename - self.filename = filename - # define the avaiable sections - self.code = {} - # include section - self.code['pchinclude'] = '' - # include section - self.code['include'] = '' - # declaration section (inside namespace) - self.code['declaration'] = '' - # declaration (outside namespace) - self.code['declaration-outside'] = '' - # inside BOOST_PYTHON_MACRO - self.code['module'] = '' - # create the default module definition - self.module_definition = 'BOOST_PYTHON_MODULE(%s)' % modulename - - - def Write(self, section, code): - 'write the given code in the section of the code unit' - if section not in self.code: - raise RuntimeError, 'Invalid CodeUnit section: %s' % section - self.code[section] += code - - - def Merge(self, other): - for section in ('include', 'declaration', 'declaration-outside', 'module'): - self.code[section] = self.code[section] + other.code[section] - - - def Section(self, section): - return self.code[section] - - - def SetCurrent(self, *args): - pass - - - def Current(self): - pass - - - def Save(self, append=False): - 'Writes this code unit to the filename' - space = '\n\n' - if not append: - flag = 'w' - else: - flag = 'a' - fout = SmartFile(self.filename, flag) - fout.write('\n') - # includes - # boost.python header - if self.code['pchinclude']: - fout.write(left_equals('PCH')) - fout.write(self.code['pchinclude']+'\n') - fout.write('#ifdef _MSC_VER\n') - fout.write('#pragma hdrstop\n') - fout.write('#endif\n') - else: - fout.write(left_equals('Boost Includes')) - fout.write('#include \n') - # include numerical boost for int64 definitions - fout.write('#include \n') - fout.write('\n') - # other includes - if self.code['include']: - fout.write(left_equals('Includes')) - includes = remove_duplicated_lines(self.code['include']) - fout.write(includes) - fout.write(space) - # using - if settings.USING_BOOST_NS and not append: - fout.write(left_equals('Using')) - fout.write('using namespace boost::python;\n\n') - # declarations - declaration = self.code['declaration'] - declaration_outside = self.code['declaration-outside'] - if declaration_outside or declaration: - fout.write(left_equals('Declarations')) - if declaration_outside: - fout.write(declaration_outside + '\n\n') - if declaration: - pyste_namespace = namespaces.pyste[:-2] - fout.write('namespace %s {\n\n' % pyste_namespace) - fout.write(declaration) - fout.write('\n}// namespace %s\n' % pyste_namespace) - fout.write(space) - # module - fout.write(left_equals('Module')) - fout.write(self.module_definition + '\n') - fout.write('{\n') - fout.write(self.code['module']) - fout.write('}\n\n') - fout.close() diff --git a/pyste/src/Pyste/SmartFile.py b/pyste/src/Pyste/SmartFile.py deleted file mode 100644 index 039579e3b1..0000000000 --- a/pyste/src/Pyste/SmartFile.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import os -import md5 - -#============================================================================== -# SmartFile -#============================================================================== -class SmartFile(object): - ''' - A file-like object used for writing files. The given file will only be - actually written to disk if there's not a file with the same name, or if - the existing file is *different* from the file to be written. - ''' - - def __init__(self, filename, mode='w'): - self.filename = filename - self.mode = mode - self._contents = [] - self._closed = False - - - def __del__(self): - if not self._closed: - self.close() - - - def write(self, string): - self._contents.append(string) - - - def _dowrite(self, contents): - f = file(self.filename, self.mode) - f.write(contents) - f.close() - - - def _GetMD5(self, string): - return md5.new(string).digest() - - - def close(self): - # if the filename doesn't exist, write the file right away - this_contents = ''.join(self._contents) - if not os.path.isfile(self.filename): - self._dowrite(this_contents) - else: - # read the contents of the file already in disk - f = file(self.filename) - other_contents = f.read() - f.close() - # test the md5 for both files - this_md5 = self._GetMD5(this_contents) - other_md5 = self._GetMD5(other_contents) - if this_md5 != other_md5: - self._dowrite(this_contents) - self._closed = True diff --git a/pyste/src/Pyste/VarExporter.py b/pyste/src/Pyste/VarExporter.py deleted file mode 100644 index d3571e7515..0000000000 --- a/pyste/src/Pyste/VarExporter.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from Exporter import Exporter -from settings import * -import utils - -#============================================================================== -# VarExporter -#============================================================================== -class VarExporter(Exporter): - '''Exports a global variable. - ''' - - def __init__(self, info): - Exporter.__init__(self, info) - - - def Export(self, codeunit, exported_names): - if self.info.exclude: return - decl = self.GetDeclaration(self.info.name) - if not decl.type.const: - msg = '---> Warning: The global variable "%s" is non-const:\n' \ - ' changes in Python will not reflect in C++.' - print msg % self.info.name - print - rename = self.info.rename or self.info.name - code = self.INDENT + namespaces.python - code += 'scope().attr("%s") = %s;\n' % (rename, self.info.name) - codeunit.Write('module', code) - - - def Order(self): - return 0, self.info.name - - - def Name(self): - return self.info.name diff --git a/pyste/src/Pyste/__init__.py b/pyste/src/Pyste/__init__.py deleted file mode 100644 index 02eec64b7d..0000000000 --- a/pyste/src/Pyste/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - - diff --git a/pyste/src/Pyste/declarations.py b/pyste/src/Pyste/declarations.py deleted file mode 100644 index 6eff97dc53..0000000000 --- a/pyste/src/Pyste/declarations.py +++ /dev/null @@ -1,653 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -''' -Defines classes that represent declarations found in C++ header files. - -''' - -# version indicates the version of the declarations. Whenever a declaration -# changes, this variable should be updated, so that the caches can be rebuilt -# automatically -version = '1.0' - -#============================================================================== -# Declaration -#============================================================================== -class Declaration(object): - '''Base class for all declarations. - @ivar name: The name of the declaration. - @ivar namespace: The namespace of the declaration. - ''' - - def __init__(self, name, namespace): - ''' - @type name: string - @param name: The name of this declaration - @type namespace: string - @param namespace: the full namespace where this declaration resides. - ''' - self.name = name - self.namespace = namespace - self.location = '', -1 # (filename, line) - self.incomplete = False - self.is_unique = True - - - def FullName(self): - ''' - Returns the full qualified name: "boost::inner::Test" - @rtype: string - @return: The full name of the declaration. - ''' - namespace = self.namespace or '' - if namespace and not namespace.endswith('::'): - namespace += '::' - return namespace + self.name - - - def __repr__(self): - return '' % (self.FullName(), id(self)) - - - def __str__(self): - return 'Declaration of %s' % self.FullName() - - -#============================================================================== -# Class -#============================================================================== -class Class(Declaration): - ''' - Represents a C++ class or struct. Iteration through it yields its members. - - @type abstract: bool - @ivar abstract: if the class has any abstract methods. - - @type bases: tuple - @ivar bases: tuple with L{Base} instances, representing the most direct - inheritance. - - @type hierarchy: list - @ivar hierarchy: a list of tuples of L{Base} instances, representing - the entire hierarchy tree of this object. The first tuple is the parent - classes, and the other ones go up in the hierarchy. - ''' - - def __init__(self, name, namespace, members, abstract): - Declaration.__init__(self, name, namespace) - self.__members = members - self.__member_names = {} - self.abstract = abstract - self.bases = () - self.hierarchy = () - self.operator = {} - - - def __iter__(self): - '''iterates through the class' members. - ''' - return iter(self.__members) - - - def Constructors(self, publics_only=True): - '''Returns a list of the constructors for this class. - @rtype: list - ''' - constructors = [] - for member in self: - if isinstance(member, Constructor): - if publics_only and member.visibility != Scope.public: - continue - constructors.append(member) - return constructors - - - def HasCopyConstructor(self): - '''Returns true if this class has a public copy constructor. - @rtype: bool - ''' - for cons in self.Constructors(): - if cons.IsCopy(): - return True - return False - - - def HasDefaultConstructor(self): - '''Returns true if this class has a public default constructor. - @rtype: bool - ''' - for cons in self.Constructors(): - if cons.IsDefault(): - return True - return False - - - def AddMember(self, member): - if member.name in self.__member_names: - member.is_unique = False - for m in self: - if m.name == member.name: - m.is_unique = False - else: - member.is_unique = True - self.__member_names[member.name] = 1 - self.__members.append(member) - if isinstance(member, ClassOperator): - self.operator[member.name] = member - - - def ValidMemberTypes(): - return (NestedClass, Method, Constructor, Destructor, ClassVariable, - ClassOperator, ConverterOperator, ClassEnumeration) - ValidMemberTypes = staticmethod(ValidMemberTypes) - - -#============================================================================== -# NestedClass -#============================================================================== -class NestedClass(Class): - '''The declaration of a class/struct inside another class/struct. - - @type class: string - @ivar class: fullname of the class where this class is contained. - - @type visibility: L{Scope} - @ivar visibility: the visibility of this class. - ''' - - def __init__(self, name, class_, visib, members, abstract): - Class.__init__(self, name, None, members, abstract) - self.class_ = class_ - self.visibility = visib - - - def FullName(self): - '''The full name of this class, like ns::outer::inner. - @rtype: string - ''' - return '%s::%s' % (self.class_, self.name) - - -#============================================================================== -# Scope -#============================================================================== -class Scope: - '''Used to represent the visibility of various members inside a class. - @cvar public: public visibility - @cvar private: private visibility - @cvar protected: protected visibility - ''' - public = 'public' - private = 'private' - protected = 'protected' - - -#============================================================================== -# Base -#============================================================================== -class Base: - '''Represents a base class of another class. - @ivar _name: the full name of the base class. - @ivar _visibility: the visibility of the derivation. - ''' - - def __init__(self, name, visibility=Scope.public): - self.name = name - self.visibility = visibility - - -#============================================================================== -# Function -#============================================================================== -class Function(Declaration): - '''The declaration of a function. - @ivar _result: instance of L{Type} or None. - @ivar _parameters: list of L{Type} instances. - @ivar _throws: exception specifiers or None - ''' - - def __init__(self, name, namespace, result, params, throws=None): - Declaration.__init__(self, name, namespace) - # the result type: instance of Type, or None (constructors) - self.result = result - # the parameters: instances of Type - self.parameters = params - # the exception specification - self.throws = throws - - - def Exceptions(self): - if self.throws is None: - return "" - else: - return " throw(%s)" % ', '.join ([x.FullName() for x in self.throws]) - - - def PointerDeclaration(self, force=False): - '''Returns a declaration of a pointer to this function. - @param force: If True, returns a complete pointer declaration regardless - if this function is unique or not. - ''' - if self.is_unique and not force: - return '&%s' % self.FullName() - else: - result = self.result.FullName() - params = ', '.join([x.FullName() for x in self.parameters]) - return '(%s (*)(%s)%s)&%s' % (result, params, self.Exceptions(), self.FullName()) - - - def MinArgs(self): - min = 0 - for arg in self.parameters: - if arg.default is None: - min += 1 - return min - - minArgs = property(MinArgs) - - - def MaxArgs(self): - return len(self.parameters) - - maxArgs = property(MaxArgs) - - - -#============================================================================== -# Operator -#============================================================================== -class Operator(Function): - '''The declaration of a custom operator. Its name is the same as the - operator name in C++, ie, the name of the declaration "operator+(..)" is - "+". - ''' - - def FullName(self): - namespace = self.namespace or '' - if not namespace.endswith('::'): - namespace += '::' - return namespace + 'operator' + self.name - - -#============================================================================== -# Method -#============================================================================== -class Method(Function): - '''The declaration of a method. - - @ivar _visibility: the visibility of this method. - @ivar _virtual: if this method is declared as virtual. - @ivar _abstract: if this method is virtual but has no default implementation. - @ivar _static: if this method is static. - @ivar _class: the full name of the class where this method was declared. - @ivar _const: if this method is declared as const. - @ivar _throws: list of exception specificiers or None - ''' - - def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const, throws=None): - Function.__init__(self, name, None, result, params, throws) - self.visibility = visib - self.virtual = virtual - self.abstract = abstract - self.static = static - self.class_ = class_ - self.const = const - - - def FullName(self): - return self.class_ + '::' + self.name - - - def PointerDeclaration(self, force=False): - '''Returns a declaration of a pointer to this member function. - @param force: If True, returns a complete pointer declaration regardless - if this function is unique or not. - ''' - if self.static: - # static methods are like normal functions - return Function.PointerDeclaration(self, force) - if self.is_unique and not force: - return '&%s' % self.FullName() - else: - result = self.result.FullName() - params = ', '.join([x.FullName() for x in self.parameters]) - const = '' - if self.const: - const = 'const' - return '(%s (%s::*)(%s) %s%s)&%s' %\ - (result, self.class_, params, const, self.Exceptions(), self.FullName()) - - -#============================================================================== -# Constructor -#============================================================================== -class Constructor(Method): - '''A class' constructor. - ''' - - def __init__(self, name, class_, params, visib): - Method.__init__(self, name, class_, None, params, visib, False, False, False, False) - - - def IsDefault(self): - '''Returns True if this constructor is a default constructor. - ''' - return len(self.parameters) == 0 and self.visibility == Scope.public - - - def IsCopy(self): - '''Returns True if this constructor is a copy constructor. - ''' - if len(self.parameters) != 1: - return False - param = self.parameters[0] - class_as_param = self.parameters[0].name == self.class_ - param_reference = isinstance(param, ReferenceType) - is_public = self.visibility == Scope.public - return param_reference and class_as_param and param.const and is_public - - - def PointerDeclaration(self, force=False): - return '' - - -#============================================================================== -# Destructor -#============================================================================== -class Destructor(Method): - 'The destructor of a class.' - - def __init__(self, name, class_, visib, virtual): - Method.__init__(self, name, class_, None, [], visib, virtual, False, False, False) - - def FullName(self): - return self.class_ + '::~' + self.name - - - def PointerDeclaration(self, force=False): - return '' - - - -#============================================================================== -# ClassOperator -#============================================================================== -class ClassOperator(Method): - 'A custom operator in a class.' - - def FullName(self): - return self.class_ + '::operator ' + self.name - - - -#============================================================================== -# ConverterOperator -#============================================================================== -class ConverterOperator(ClassOperator): - 'An operator in the form "operator OtherClass()".' - - def FullName(self): - return self.class_ + '::operator ' + self.result.FullName() - - - -#============================================================================== -# Type -#============================================================================== -class Type(Declaration): - '''Represents the type of a variable or parameter. - @ivar _const: if the type is constant. - @ivar _default: if this type has a default value associated with it. - @ivar _volatile: if this type was declared with the keyword volatile. - @ivar _restricted: if this type was declared with the keyword restricted. - @ivar _suffix: Suffix to get the full type name. '*' for pointers, for - example. - ''' - - def __init__(self, name, const=False, default=None, suffix=''): - Declaration.__init__(self, name, None) - # whatever the type is constant or not - self.const = const - # used when the Type is a function argument - self.default = default - self.volatile = False - self.restricted = False - self.suffix = suffix - - def __repr__(self): - if self.const: - const = 'const ' - else: - const = '' - return '' - - - def FullName(self): - if self.const: - const = 'const ' - else: - const = '' - return const + self.name + self.suffix - - -#============================================================================== -# ArrayType -#============================================================================== -class ArrayType(Type): - '''Represents an array. - @ivar min: the lower bound of the array, usually 0. Can be None. - @ivar max: the upper bound of the array. Can be None. - ''' - - def __init__(self, name, const, min, max): - 'min and max can be None.' - Type.__init__(self, name, const) - self.min = min - self.max = max - - - -#============================================================================== -# ReferenceType -#============================================================================== -class ReferenceType(Type): - '''A reference type.''' - - def __init__(self, name, const=False, default=None, expandRef=True, suffix=''): - Type.__init__(self, name, const, default) - if expandRef: - self.suffix = suffix + '&' - - -#============================================================================== -# PointerType -#============================================================================== -class PointerType(Type): - 'A pointer type.' - - def __init__(self, name, const=False, default=None, expandPointer=False, suffix=''): - Type.__init__(self, name, const, default) - if expandPointer: - self.suffix = suffix + '*' - - -#============================================================================== -# FundamentalType -#============================================================================== -class FundamentalType(Type): - 'One of the fundamental types, like int, void, etc.' - - def __init__(self, name, const=False, default=None): - Type.__init__(self, name, const, default) - - - -#============================================================================== -# FunctionType -#============================================================================== -class FunctionType(Type): - '''A pointer to a function. - @ivar _result: the return value - @ivar _parameters: a list of Types, indicating the parameters of the function. - @ivar _name: the name of the function. - ''' - - def __init__(self, result, parameters): - Type.__init__(self, '', False) - self.result = result - self.parameters = parameters - self.name = self.FullName() - - - def FullName(self): - full = '%s (*)' % self.result.FullName() - params = [x.FullName() for x in self.parameters] - full += '(%s)' % ', '.join(params) - return full - - -#============================================================================== -# MethodType -#============================================================================== -class MethodType(FunctionType): - '''A pointer to a member function of a class. - @ivar _class: The fullname of the class that the method belongs to. - ''' - - def __init__(self, result, parameters, class_): - self.class_ = class_ - FunctionType.__init__(self, result, parameters) - - - def FullName(self): - full = '%s (%s::*)' % (self.result.FullName(), self.class_) - params = [x.FullName() for x in self.parameters] - full += '(%s)' % ', '.join(params) - return full - - -#============================================================================== -# Variable -#============================================================================== -class Variable(Declaration): - '''Represents a global variable. - - @type _type: L{Type} - @ivar _type: The type of the variable. - ''' - - def __init__(self, type, name, namespace): - Declaration.__init__(self, name, namespace) - self.type = type - - -#============================================================================== -# ClassVariable -#============================================================================== -class ClassVariable(Variable): - '''Represents a class variable. - - @type _visibility: L{Scope} - @ivar _visibility: The visibility of this variable within the class. - - @type _static: bool - @ivar _static: Indicates if the variable is static. - - @ivar _class: Full name of the class that this variable belongs to. - ''' - - def __init__(self, type, name, class_, visib, static): - Variable.__init__(self, type, name, None) - self.visibility = visib - self.static = static - self.class_ = class_ - - - def FullName(self): - return self.class_ + '::' + self.name - - -#============================================================================== -# Enumeration -#============================================================================== -class Enumeration(Declaration): - '''Represents an enum. - - @type _values: dict of str => int - @ivar _values: holds the values for this enum. - ''' - - def __init__(self, name, namespace): - Declaration.__init__(self, name, namespace) - self.values = {} # dict of str => int - - - def ValueFullName(self, name): - '''Returns the full name for a value in the enum. - ''' - assert name in self.values - namespace = self.namespace - if namespace: - namespace += '::' - return namespace + name - - -#============================================================================== -# ClassEnumeration -#============================================================================== -class ClassEnumeration(Enumeration): - '''Represents an enum inside a class. - - @ivar _class: The full name of the class where this enum belongs. - @ivar _visibility: The visibility of this enum inside his class. - ''' - - def __init__(self, name, class_, visib): - Enumeration.__init__(self, name, None) - self.class_ = class_ - self.visibility = visib - - - def FullName(self): - return '%s::%s' % (self.class_, self.name) - - - def ValueFullName(self, name): - assert name in self.values - return '%s::%s' % (self.class_, name) - - -#============================================================================== -# Typedef -#============================================================================== -class Typedef(Declaration): - '''A Typedef declaration. - - @type _type: L{Type} - @ivar _type: The type of the typedef. - - @type _visibility: L{Scope} - @ivar _visibility: The visibility of this typedef. - ''' - - def __init__(self, type, name, namespace): - Declaration.__init__(self, name, namespace) - self.type = type - self.visibility = Scope.public - - - - - -#============================================================================== -# Unknown -#============================================================================== -class Unknown(Declaration): - '''A declaration that Pyste does not know how to handle. - ''' - - def __init__(self, name): - Declaration.__init__(self, name, None) diff --git a/pyste/src/Pyste/exporters.py b/pyste/src/Pyste/exporters.py deleted file mode 100644 index f573d01bec..0000000000 --- a/pyste/src/Pyste/exporters.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - - -# a list of Exporter instances -exporters = [] - -current_interface = None # the current interface file being processed -importing = False # whetever we are now importing a pyste file. - # exporters created here shouldn't export themselves diff --git a/pyste/src/Pyste/exporterutils.py b/pyste/src/Pyste/exporterutils.py deleted file mode 100644 index 363700d2b8..0000000000 --- a/pyste/src/Pyste/exporterutils.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -''' -Various helpers for interface files. -''' - -from settings import * -from policies import * -from declarations import * - -#============================================================================== -# FunctionWrapper -#============================================================================== -class FunctionWrapper(object): - '''Holds information about a wrapper for a function or a method. It is - divided in 2 parts: the name of the Wrapper, and its code. The code is - placed in the declaration section of the module, while the name is used to - def' the function or method (with the pyste namespace prepend to it). If - code is None, the name is left unchanged. - ''' - - def __init__(self, name, code=None): - self.name = name - self.code = code - - def FullName(self): - if self.code: - return namespaces.pyste + self.name - else: - return self.name - - -_printed_warnings = {} # used to avoid double-prints of warnings - -#============================================================================== -# HandlePolicy -#============================================================================== -def HandlePolicy(function, policy): - '''Show a warning to the user if the function needs a policy and doesn't - have one. Return a policy to the function, which is the given policy itself - if it is not None, or a default policy for this method. - ''' - - def IsString(type): - 'Return True if the Type instance can be considered a string' - return type.FullName() == 'const char*' - - def IsPyObject(type): - return type.FullName() == '_object *' # internal name of PyObject - - result = function.result - # if the function returns const char*, a policy is not needed - if IsString(result) or IsPyObject(result): - return policy - # if returns a const T&, set the default policy - if policy is None and result.const and isinstance(result, ReferenceType): - policy = return_value_policy(copy_const_reference) - # basic test if the result type demands a policy - needs_policy = isinstance(result, (ReferenceType, PointerType)) - # show a warning to the user, if needed - if needs_policy and policy is None: - global _printed_warnings - warning = '---> Error: %s returns a pointer or a reference, ' \ - 'but no policy was specified.' % function.FullName() - if warning not in _printed_warnings: - print warning - print - # avoid double prints of the same warning - _printed_warnings[warning] = 1 - return policy - - -#============================================================================== -# EspecializeTypeID -#============================================================================== -_exported_type_ids = {} -def EspecializeTypeID(typename): - global _exported_type_ids - macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)\n' % typename - if macro not in _exported_type_ids: - _exported_type_ids[macro] = 1 - return macro - else: - return None diff --git a/pyste/src/Pyste/infos.py b/pyste/src/Pyste/infos.py deleted file mode 100644 index 2a4f01eafe..0000000000 --- a/pyste/src/Pyste/infos.py +++ /dev/null @@ -1,259 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import os.path -import copy -import exporters -from ClassExporter import ClassExporter -from FunctionExporter import FunctionExporter -from EnumExporter import EnumExporter -from HeaderExporter import HeaderExporter -from VarExporter import VarExporter -from CodeExporter import CodeExporter -from exporterutils import FunctionWrapper -from utils import makeid -import warnings - -#============================================================================== -# DeclarationInfo -#============================================================================== -class DeclarationInfo: - - def __init__(self, otherInfo=None): - self.__infos = {} - self.__attributes = {} - if otherInfo is not None: - self.__infos = copy.deepcopy(otherInfo.__infos) - self.__attributes = copy.deepcopy(otherInfo.__attributes) - - - def __getitem__(self, name): - 'Used to access sub-infos' - if name.startswith('__'): - raise AttributeError - default = DeclarationInfo() - default._Attribute('name', name) - return self.__infos.setdefault(name, default) - - - def __getattr__(self, name): - return self[name] - - - def _Attribute(self, name, value=None): - if value is None: - # get value - return self.__attributes.get(name) - else: - # set value - self.__attributes[name] = value - - - def AddExporter(self, exporter): - # this was causing a much serious bug, as reported by Niall Douglas: - # another solution must be found! - #if not exporters.importing: - if exporter not in exporters.exporters: - exporters.exporters.append(exporter) - exporter.interface_file = exporters.current_interface - - -#============================================================================== -# FunctionInfo -#============================================================================== -class FunctionInfo(DeclarationInfo): - - def __init__(self, name, include, tail=None, otherOption=None, - exporter_class = FunctionExporter): - DeclarationInfo.__init__(self, otherOption) - self._Attribute('name', name) - self._Attribute('include', include) - self._Attribute('exclude', False) - # create a FunctionExporter - exporter = exporter_class(InfoWrapper(self), tail) - self.AddExporter(exporter) - - -#============================================================================== -# ClassInfo -#============================================================================== -class ClassInfo(DeclarationInfo): - - def __init__(self, name, include, tail=None, otherInfo=None, - exporter_class = ClassExporter): - DeclarationInfo.__init__(self, otherInfo) - self._Attribute('name', name) - self._Attribute('include', include) - self._Attribute('exclude', False) - # create a ClassExporter - exporter = exporter_class(InfoWrapper(self), tail) - self.AddExporter(exporter) - - -#============================================================================== -# templates -#============================================================================== -def GenerateName(name, type_list): - name = name.replace('::', '_') - names = [name] + type_list - return makeid('_'.join(names)) - - -class ClassTemplateInfo(DeclarationInfo): - - def __init__(self, name, include, - exporter_class = ClassExporter): - DeclarationInfo.__init__(self) - self._Attribute('name', name) - self._Attribute('include', include) - self._exporter_class = exporter_class - - - def Instantiate(self, type_list, rename=None): - if not rename: - rename = GenerateName(self._Attribute('name'), type_list) - # generate code to instantiate the template - types = ', '.join(type_list) - tail = 'typedef %s< %s > %s;\n' % (self._Attribute('name'), types, rename) - tail += 'void __instantiate_%s()\n' % rename - tail += '{ sizeof(%s); }\n\n' % rename - # create a ClassInfo - class_ = ClassInfo(rename, self._Attribute('include'), tail, self, - exporter_class = self._exporter_class) - return class_ - - - def __call__(self, types, rename=None): - if isinstance(types, str): - types = types.split() - return self.Instantiate(types, rename) - -#============================================================================== -# EnumInfo -#============================================================================== -class EnumInfo(DeclarationInfo): - - def __init__(self, name, include, exporter_class = EnumExporter): - DeclarationInfo.__init__(self) - self._Attribute('name', name) - self._Attribute('include', include) - self._Attribute('exclude', False) - self._Attribute('export_values', False) - exporter = exporter_class(InfoWrapper(self)) - self.AddExporter(exporter) - - -#============================================================================== -# HeaderInfo -#============================================================================== -class HeaderInfo(DeclarationInfo): - - def __init__(self, include, exporter_class = HeaderExporter): - warnings.warn('AllFromHeader is not working in all cases in the current version.') - DeclarationInfo.__init__(self) - self._Attribute('include', include) - exporter = exporter_class(InfoWrapper(self)) - self.AddExporter(exporter) - - -#============================================================================== -# VarInfo -#============================================================================== -class VarInfo(DeclarationInfo): - - def __init__(self, name, include, exporter_class = VarExporter): - DeclarationInfo.__init__(self) - self._Attribute('name', name) - self._Attribute('include', include) - exporter = exporter_class(InfoWrapper(self)) - self.AddExporter(exporter) - - -#============================================================================== -# CodeInfo -#============================================================================== -class CodeInfo(DeclarationInfo): - - def __init__(self, code, section, exporter_class = CodeExporter): - DeclarationInfo.__init__(self) - self._Attribute('code', code) - self._Attribute('section', section) - exporter = exporter_class(InfoWrapper(self)) - self.AddExporter(exporter) - - -#============================================================================== -# InfoWrapper -#============================================================================== -class InfoWrapper: - 'Provides a nicer interface for a info' - - def __init__(self, info): - self.__dict__['_info'] = info # so __setattr__ is not called - - def __getitem__(self, name): - return InfoWrapper(self._info[name]) - - def __getattr__(self, name): - return self._info._Attribute(name) - - def __setattr__(self, name, value): - self._info._Attribute(name, value) - - -#============================================================================== -# Functions -#============================================================================== -def exclude(info): - info._Attribute('exclude', True) - -def set_policy(info, policy): - info._Attribute('policy', policy) - -def rename(info, name): - info._Attribute('rename', name) - -def set_wrapper(info, wrapper): - if isinstance(wrapper, str): - wrapper = FunctionWrapper(wrapper) - info._Attribute('wrapper', wrapper) - -def instantiate(template, types, rename=None): - if isinstance(types, str): - types = types.split() - return template.Instantiate(types, rename) - -def use_shared_ptr(info): - info._Attribute('smart_ptr', 'boost::shared_ptr< %s >') - -def use_auto_ptr(info): - info._Attribute('smart_ptr', 'std::auto_ptr< %s >') - -def holder(info, function): - msg = "Expected a callable that accepts one string argument." - assert callable(function), msg - info._Attribute('holder', function) - -def add_method(info, name, rename=None): - added = info._Attribute('__added__') - if added is None: - info._Attribute('__added__', [(name, rename)]) - else: - added.append((name, rename)) - - -def class_code(info, code): - added = info._Attribute('__code__') - if added is None: - info._Attribute('__code__', [code]) - else: - added.append(code) - -def final(info): - info._Attribute('no_override', True) - - -def export_values(info): - info._Attribute('export_values', True) diff --git a/pyste/src/Pyste/policies.py b/pyste/src/Pyste/policies.py deleted file mode 100644 index 57ebd0dea7..0000000000 --- a/pyste/src/Pyste/policies.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - - - -class Policy(object): - 'Represents one of the call policies of boost.python.' - - def __init__(self): - if type(self) is Policy: - raise RuntimeError, "Can't create an instance of the class Policy" - - - def Code(self): - 'Returns the string corresponding to a instancialization of the policy.' - pass - - - def _next(self): - if self.next is not None: - return ', %s >' % self.next.Code() - else: - return ' >' - - - def __eq__(self, other): - try: - return self.Code() == other.Code() - except AttributeError: - return False - - - -class return_internal_reference(Policy): - 'Ties the return value to one of the parameters.' - - def __init__(self, param=1, next=None): - ''' - param is the position of the parameter, or None for "self". - next indicates the next policy, or None. - ''' - self.param = param - self.next=next - - - def Code(self): - c = 'return_internal_reference< %i' % self.param - c += self._next() - return c - - - -class with_custodian_and_ward(Policy): - 'Ties lifetime of two arguments of a function.' - - def __init__(self, custodian, ward, next=None): - self.custodian = custodian - self.ward = ward - self.next = next - - def Code(self): - c = 'with_custodian_and_ward< %i, %i' % (self.custodian, self.ward) - c += self._next() - return c - - - -class return_value_policy(Policy): - 'Policy to convert return values.' - - def __init__(self, which, next=None): - self.which = which - self.next = next - - - def Code(self): - c = 'return_value_policy< %s' % self.which - c += self._next() - return c - -class return_self(Policy): - - def Code(self): - return 'return_self<>' - - -# values for return_value_policy -reference_existing_object = 'reference_existing_object' -copy_const_reference = 'copy_const_reference' -copy_non_const_reference = 'copy_non_const_reference' -manage_new_object = 'manage_new_object' -return_opaque_pointer = 'return_opaque_pointer' -return_by_value = 'return_by_value' diff --git a/pyste/src/Pyste/pyste.py b/pyste/src/Pyste/pyste.py deleted file mode 100644 index cedffff554..0000000000 --- a/pyste/src/Pyste/pyste.py +++ /dev/null @@ -1,424 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -""" -Pyste version %s - -Usage: - pyste [options] interface-files - -where options are: - --module= The name of the module that will be generated; - defaults to the first interface filename, without - the extension. - -I Add an include path - -D Define symbol - --multiple Create various cpps, instead of only one - (useful during development) - --out= Specify output filename (default: .cpp) - in --multiple mode, this will be a directory - --no-using Do not declare "using namespace boost"; - use explicit declarations instead - --pyste-ns= Set the namespace where new types will be declared; - default is the empty namespace - --debug Writes the xml for each file parsed in the current - directory - --cache-dir= Directory for cache files (speeds up future runs) - --only-create-cache Recreates all caches (doesn't generate code). - --generate-main Generates the _main.cpp file (in multiple mode) - --file-list A file with one pyste file per line. Use as a - substitute for passing the files in the command - line. - --gccxml-path= Path to gccxml executable (default: gccxml) - --no-default-include Do not use INCLUDE environment variable for include - files to pass along gccxml. - -h, --help Print this help and exit - -v, --version Print version information -""" - -import sys -import os -import getopt -import exporters -import SingleCodeUnit -import MultipleCodeUnit -import infos -import exporterutils -import settings -import gc -import sys -from policies import * -from CppParser import CppParser, CppParserError -import time -import declarations - -__version__ = '0.9.30' - -def RecursiveIncludes(include): - 'Return a list containg the include dir and all its subdirectories' - dirs = [include] - def visit(arg, dir, names): - # ignore CVS dirs - if os.path.split(dir)[1] != 'CVS': - dirs.append(dir) - os.path.walk(include, visit, None) - return dirs - - -def GetDefaultIncludes(): - if 'INCLUDE' in os.environ: - include = os.environ['INCLUDE'] - return include.split(os.pathsep) - else: - return [] - - -def ProcessIncludes(includes): - if sys.platform == 'win32': - index = 0 - for include in includes: - includes[index] = include.replace('\\', '/') - index += 1 - - -def ReadFileList(filename): - f = file(filename) - files = [] - try: - for line in f: - line = line.strip() - if line: - files.append(line) - finally: - f.close() - return files - - -def ParseArguments(): - - def Usage(): - print __doc__ % __version__ - sys.exit(1) - - try: - options, files = getopt.getopt( - sys.argv[1:], - 'R:I:D:vh', - ['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=', - 'only-create-cache', 'version', 'generate-main', 'file-list=', 'help', - 'gccxml-path=', 'no-default-include']) - except getopt.GetoptError, e: - print - print 'ERROR:', e - Usage() - - default_includes = GetDefaultIncludes() - includes = [] - defines = [] - module = None - out = None - multiple = False - cache_dir = None - create_cache = False - generate_main = False - gccxml_path = 'gccxml' - - for opt, value in options: - if opt == '-I': - includes.append(value) - elif opt == '-D': - defines.append(value) - elif opt == '-R': - includes.extend(RecursiveIncludes(value)) - elif opt == '--module': - module = value - elif opt == '--out': - out = value - elif opt == '--no-using': - settings.namespaces.python = 'boost::python::' - settings.USING_BOOST_NS = False - elif opt == '--pyste-ns': - settings.namespaces.pyste = value + '::' - elif opt == '--debug': - settings.DEBUG = True - elif opt == '--multiple': - multiple = True - elif opt == '--cache-dir': - cache_dir = value - elif opt == '--only-create-cache': - create_cache = True - elif opt == '--file-list': - files += ReadFileList(value) - elif opt in ['-h', '--help']: - Usage() - elif opt in ['-v', '--version']: - print 'Pyste version %s' % __version__ - sys.exit(2) - elif opt == '--generate-main': - generate_main = True - elif opt == '--gccxml-path': - gccxml_path = value - elif opt == '--no-default-include': - default_includes = [] - else: - print 'Unknown option:', opt - Usage() - - includes[0:0] = default_includes - if not files: - Usage() - if not module: - module = os.path.splitext(os.path.basename(files[0]))[0] - if not out: - out = module - if not multiple: - out += '.cpp' - for file in files: - d = os.path.dirname(os.path.abspath(file)) - if d not in sys.path: - sys.path.append(d) - - if create_cache and not cache_dir: - print 'Error: Use --cache-dir to indicate where to create the cache files!' - Usage() - sys.exit(3) - - if generate_main and not multiple: - print 'Error: --generate-main only valid in multiple mode.' - Usage() - sys.exit(3) - - ProcessIncludes(includes) - return includes, defines, module, out, files, multiple, cache_dir, create_cache, \ - generate_main, gccxml_path - - -def PCHInclude(*headers): - code = '\n'.join(['#include <%s>' % x for x in headers]) - infos.CodeInfo(code, 'pchinclude') - - -def CreateContext(): - 'create the context where a interface file will be executed' - context = {} - context['Import'] = Import - # infos - context['Function'] = infos.FunctionInfo - context['Class'] = infos.ClassInfo - context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include') - context['PCHInclude'] = PCHInclude - context['Template'] = infos.ClassTemplateInfo - context['Enum'] = infos.EnumInfo - context['AllFromHeader'] = infos.HeaderInfo - context['Var'] = infos.VarInfo - # functions - context['rename'] = infos.rename - context['set_policy'] = infos.set_policy - context['exclude'] = infos.exclude - context['set_wrapper'] = infos.set_wrapper - context['use_shared_ptr'] = infos.use_shared_ptr - context['use_auto_ptr'] = infos.use_auto_ptr - context['holder'] = infos.holder - context['add_method'] = infos.add_method - context['final'] = infos.final - context['export_values'] = infos.export_values - # policies - context['return_internal_reference'] = return_internal_reference - context['with_custodian_and_ward'] = with_custodian_and_ward - context['return_value_policy'] = return_value_policy - context['reference_existing_object'] = reference_existing_object - context['copy_const_reference'] = copy_const_reference - context['copy_non_const_reference'] = copy_non_const_reference - context['return_opaque_pointer'] = return_opaque_pointer - context['manage_new_object'] = manage_new_object - context['return_by_value'] = return_by_value - context['return_self'] = return_self - # utils - context['Wrapper'] = exporterutils.FunctionWrapper - context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside') - context['module_code'] = lambda code: infos.CodeInfo(code, 'module') - context['class_code'] = infos.class_code - return context - - -def Begin(): - # parse arguments - includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main, gccxml_path = ParseArguments() - # run pyste scripts - for interface in interfaces: - ExecuteInterface(interface) - # create the parser - parser = CppParser(includes, defines, cache_dir, declarations.version, gccxml_path) - try: - if not create_cache: - if not generate_main: - return GenerateCode(parser, module, out, interfaces, multiple) - else: - return GenerateMain(module, out, OrderInterfaces(interfaces)) - else: - return CreateCaches(parser) - finally: - parser.Close() - - -def CreateCaches(parser): - # There is one cache file per interface so we organize the headers - # by interfaces. For each interface collect the tails from the - # exporters sharing the same header. - tails = JoinTails(exporters.exporters) - - # now for each interface file take each header, and using the tail - # get the declarations and cache them. - for interface, header in tails: - tail = tails[(interface, header)] - declarations = parser.ParseWithGCCXML(header, tail) - cachefile = parser.CreateCache(header, interface, tail, declarations) - print 'Cached', cachefile - - return 0 - - -_imported_count = {} # interface => count - -def ExecuteInterface(interface): - old_interface = exporters.current_interface - if not os.path.exists(interface): - if old_interface and os.path.exists(old_interface): - d = os.path.dirname(old_interface) - interface = os.path.join(d, interface) - if not os.path.exists(interface): - raise IOError, "Cannot find interface file %s."%interface - - _imported_count[interface] = _imported_count.get(interface, 0) + 1 - exporters.current_interface = interface - context = CreateContext() - context['INTERFACE_FILE'] = os.path.abspath(interface) - execfile(interface, context) - exporters.current_interface = old_interface - - -def Import(interface): - exporters.importing = True - ExecuteInterface(interface) - exporters.importing = False - - -def JoinTails(exports): - '''Returns a dict of {(interface, header): tail}, where tail is the - joining of all tails of all exports for the header. - ''' - tails = {} - for export in exports: - interface = export.interface_file - header = export.Header() - tail = export.Tail() or '' - if (interface, header) in tails: - all_tails = tails[(interface,header)] - all_tails += '\n' + tail - tails[(interface, header)] = all_tails - else: - tails[(interface, header)] = tail - - return tails - - - -def OrderInterfaces(interfaces): - interfaces_order = [(_imported_count[x], x) for x in interfaces] - interfaces_order.sort() - interfaces_order.reverse() - return [x for _, x in interfaces_order] - - - -def GenerateMain(module, out, interfaces): - codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out) - codeunit.GenerateMain(interfaces) - return 0 - - -def GenerateCode(parser, module, out, interfaces, multiple): - # prepare to generate the wrapper code - if multiple: - codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out) - else: - codeunit = SingleCodeUnit.SingleCodeUnit(module, out) - # stop referencing the exporters here - exports = exporters.exporters - exporters.exporters = None - exported_names = dict([(x.Name(), None) for x in exports]) - - # order the exports - order = {} - for export in exports: - if export.interface_file in order: - order[export.interface_file].append(export) - else: - order[export.interface_file] = [export] - exports = [] - interfaces_order = OrderInterfaces(interfaces) - for interface in interfaces_order: - exports.extend(order[interface]) - del order - del interfaces_order - - # now generate the code in the correct order - #print exported_names - tails = JoinTails(exports) - for i in xrange(len(exports)): - export = exports[i] - interface = export.interface_file - header = export.Header() - if header: - tail = tails[(interface, header)] - declarations, parsed_header = parser.Parse(header, interface, tail) - else: - declarations = [] - parsed_header = None - ExpandTypedefs(declarations, exported_names) - export.SetDeclarations(declarations) - export.SetParsedHeader(parsed_header) - if multiple: - codeunit.SetCurrent(export.interface_file, export.Name()) - export.GenerateCode(codeunit, exported_names) - # force collect of cyclic references - exports[i] = None - del declarations - del export - gc.collect() - # finally save the code unit - codeunit.Save() - if not multiple: - print 'Module %s generated' % module - return 0 - - -def ExpandTypedefs(decls, exported_names): - '''Check if the names in exported_names are a typedef, and add the real class - name in the dict. - ''' - for name in exported_names.keys(): - for decl in decls: - if isinstance(decl, declarations.Typedef): - exported_names[decl.type.FullName()] = None - -def UsePsyco(): - 'Tries to use psyco if possible' - try: - import psyco - psyco.profile() - except: pass - - -def main(): - start = time.clock() - UsePsyco() - status = Begin() - print '%0.2f seconds' % (time.clock()-start) - sys.exit(status) - - -if __name__ == '__main__': - main() diff --git a/pyste/src/Pyste/settings.py b/pyste/src/Pyste/settings.py deleted file mode 100644 index ba613b2343..0000000000 --- a/pyste/src/Pyste/settings.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - - -#============================================================================== -# Global information -#============================================================================== - -DEBUG = False -USING_BOOST_NS = True - -class namespaces: - boost = 'boost::' - pyste = '' - python = '' # default is to not use boost::python namespace explicitly, so - # use the "using namespace" statement instead - -import sys -msvc = sys.platform == 'win32' diff --git a/pyste/src/Pyste/utils.py b/pyste/src/Pyste/utils.py deleted file mode 100644 index a8843e3f64..0000000000 --- a/pyste/src/Pyste/utils.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -from __future__ import generators -import string -import sys - -#============================================================================== -# enumerate -#============================================================================== -def enumerate(seq): - i = 0 - for x in seq: - yield i, x - i += 1 - - -#============================================================================== -# makeid -#============================================================================== -_valid_chars = string.ascii_letters + string.digits + '_' -_valid_chars = dict(zip(_valid_chars, _valid_chars)) - -def makeid(name): - 'Returns the name as a valid identifier' - if type(name) != str: - print type(name), name - newname = [] - for char in name: - if char not in _valid_chars: - char = '_' - newname.append(char) - newname = ''.join(newname) - # avoid duplications of '_' chars - names = [x for x in newname.split('_') if x] - return '_'.join(names) - - -#============================================================================== -# remove_duplicated_lines -#============================================================================== -def remove_duplicated_lines(text): - includes = text.splitlines() - d = dict([(include, 0) for include in includes]) - includes = d.keys() - includes.sort() - return '\n'.join(includes) - - -#============================================================================== -# left_equals -#============================================================================== -def left_equals(s): - s = '// %s ' % s - return s + ('='*(80-len(s))) + '\n' - - -#============================================================================== -# post_mortem -#============================================================================== -def post_mortem(): - - def info(type, value, tb): - if hasattr(sys, 'ps1') or not sys.stderr.isatty(): - # we are in interactive mode or we don't have a tty-like - # device, so we call the default hook - sys.__excepthook__(type, value, tb) - else: - import traceback, pdb - # we are NOT in interactive mode, print the exception... - traceback.print_exception(type, value, tb) - print - # ...then start the debugger in post-mortem mode. - pdb.pm() - - sys.excepthook = info diff --git a/pyste/tests/GCCXMLParserUT.py b/pyste/tests/GCCXMLParserUT.py deleted file mode 100644 index 7175c9c684..0000000000 --- a/pyste/tests/GCCXMLParserUT.py +++ /dev/null @@ -1,341 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import sys -sys.path.append('../src') -import unittest -import tempfile -import os.path -from Pyste import GCCXMLParser -from Pyste.declarations import * - - -class Tester(unittest.TestCase): - - def TestConstructor(self, class_, method, visib): - self.assert_(isinstance(method, Constructor)) - self.assertEqual(method.FullName(), class_.FullName() + '::' + method.name) - self.assertEqual(method.result, None) - self.assertEqual(method.visibility, visib) - self.assert_(not method.virtual) - self.assert_(not method.abstract) - self.assert_(not method.static) - - def TestDefaultConstructor(self, class_, method, visib): - self.TestConstructor(class_, method, visib) - self.assert_(method.IsDefault()) - - def TestCopyConstructor(self, class_, method, visib): - self.TestConstructor(class_, method, visib) - self.assertEqual(len(method.parameters), 1) - param = method.parameters[0] - self.TestType( - param, - ReferenceType, - class_.FullName(), - 'const %s&' % class_.FullName(), - True) - self.assert_(method.IsCopy()) - - - def TestType(self, type_, classtype_, name, fullname, const): - self.assert_(isinstance(type_, classtype_)) - self.assertEqual(type_.name, name) - self.assertEqual(type_.namespace, None) - self.assertEqual(type_.FullName(), fullname) - self.assertEqual(type_.const, const) - - -class ClassBaseTest(Tester): - - def setUp(self): - self.base = GetDecl('Base') - - def testClass(self): - 'test the properties of the class Base' - self.assert_(isinstance(self.base, Class)) - self.assert_(self.base.abstract) - - - def testFoo(self): - 'test function foo in class Base' - foo = GetMember(self.base, 'foo') - self.assert_(isinstance(foo, Method)) - self.assertEqual(foo.visibility, Scope.public) - self.assert_(foo.virtual) - self.assert_(foo.abstract) - self.failIf(foo.static) - self.assertEqual(foo.class_, 'test::Base') - self.failIf(foo.const) - self.assertEqual(foo.FullName(), 'test::Base::foo') - self.assertEqual(foo.result.name, 'void') - self.assertEqual(len(foo.parameters), 1) - param = foo.parameters[0] - self.TestType(param, FundamentalType, 'int', 'int', False) - self.assertEqual(foo.namespace, None) - self.assertEqual( - foo.PointerDeclaration(1), '(void (test::Base::*)(int) )&test::Base::foo') - - def testX(self): - 'test the member x in class Base' - x = GetMember(self.base, 'x') - self.assertEqual(x.class_, 'test::Base') - self.assertEqual(x.FullName(), 'test::Base::x') - self.assertEqual(x.namespace, None) - self.assertEqual(x.visibility, Scope.private) - self.TestType(x.type, FundamentalType, 'int', 'int', False) - self.assertEqual(x.static, False) - - def testConstructors(self): - 'test constructors in class Base' - constructors = GetMembers(self.base, 'Base') - for cons in constructors: - if len(cons.parameters) == 0: - self.TestDefaultConstructor(self.base, cons, Scope.public) - elif len(cons.parameters) == 1: # copy constructor - self.TestCopyConstructor(self.base, cons, Scope.public) - elif len(cons.parameters) == 2: # other constructor - intp, floatp = cons.parameters - self.TestType(intp, FundamentalType, 'int', 'int', False) - self.TestType(floatp, FundamentalType, 'float', 'float', False) - - def testSimple(self): - 'test function simple in class Base' - simple = GetMember(self.base, 'simple') - self.assert_(isinstance(simple, Method)) - self.assertEqual(simple.visibility, Scope.protected) - self.assertEqual(simple.FullName(), 'test::Base::simple') - self.assertEqual(len(simple.parameters), 1) - param = simple.parameters[0] - self.TestType(param, ReferenceType, 'std::string', 'const std::string&', True) - self.TestType(simple.result, FundamentalType, 'bool', 'bool', False) - self.assertEqual( - simple.PointerDeclaration(1), - '(bool (test::Base::*)(const std::string&) )&test::Base::simple') - - - def testZ(self): - z = GetMember(self.base, 'z') - self.assert_(isinstance(z, Variable)) - self.assertEqual(z.visibility, Scope.public) - self.assertEqual(z.FullName(), 'test::Base::z') - self.assertEqual(z.type.name, 'int') - self.assertEqual(z.type.const, False) - self.assert_(z.static) - - -class ClassTemplateTest(Tester): - - def setUp(self): - self.template = GetDecl('Template') - - def testClass(self): - 'test the properties of the Template class' - self.assert_(isinstance(self.template, Class)) - self.assert_(not self.template.abstract) - self.assertEqual(self.template.FullName(), 'Template') - self.assertEqual(self.template.namespace, '') - self.assertEqual(self.template.name, 'Template') - - def testConstructors(self): - 'test the automatic constructors of the class Template' - constructors = GetMembers(self.template, 'Template') - for cons in constructors: - if len(cons.parameters) == 0: - self.TestDefaultConstructor(self.template, cons, Scope.public) - elif len(cons.parameters) == 1: - self.TestCopyConstructor(self.template, cons, Scope.public) - - - def testValue(self): - 'test the class variable value' - value = GetMember(self.template, 'value') - self.assert_(isinstance(value, ClassVariable)) - self.assert_(value.name, 'value') - self.TestType(value.type, FundamentalType, 'int', 'int', False) - self.assert_(not value.static) - self.assertEqual(value.visibility, Scope.public) - self.assertEqual(value.class_, 'Template') - self.assertEqual(value.FullName(), 'Template::value') - - def testBase(self): - 'test the superclasses of Template' - bases = self.template.bases - self.assertEqual(len(bases), 1) - base = bases[0] - self.assert_(isinstance(base, Base)) - self.assertEqual(base.name, 'test::Base') - self.assertEqual(base.visibility, Scope.protected) - - - -class FreeFuncTest(Tester): - - def setUp(self): - self.func = GetDecl('FreeFunc') - - def testFunc(self): - 'test attributes of FreeFunc' - self.assert_(isinstance(self.func, Function)) - self.assertEqual(self.func.name, 'FreeFunc') - self.assertEqual(self.func.FullName(), 'test::FreeFunc') - self.assertEqual(self.func.namespace, 'test') - self.assertEqual( - self.func.PointerDeclaration(1), - '(const test::Base& (*)(const std::string&, int))&test::FreeFunc') - - - def testResult(self): - 'test the return value of FreeFunc' - res = self.func.result - self.TestType(res, ReferenceType, 'test::Base', 'const test::Base&', True) - - def testParameters(self): - 'test the parameters of FreeFunc' - self.assertEqual(len(self.func.parameters), 2) - strp, intp = self.func.parameters - self.TestType(strp, ReferenceType, 'std::string', 'const std::string&', True) - self.assertEqual(strp.default, None) - self.TestType(intp, FundamentalType, 'int', 'int', False) - self.assertEqual(intp.default, '10') - - - -class testFunctionPointers(Tester): - - def testMethodPointer(self): - 'test declaration of a pointer-to-method' - meth = GetDecl('MethodTester') - param = meth.parameters[0] - fullname = 'void (test::Base::*)(int)' - self.TestType(param, PointerType, fullname, fullname, False) - - def testFunctionPointer(self): - 'test declaration of a pointer-to-function' - func = GetDecl('FunctionTester') - param = func.parameters[0] - fullname = 'void (*)(int)' - self.TestType(param, PointerType, fullname, fullname, False) - - - -# ============================================================================= -# Support routines -# ============================================================================= - -cppcode = ''' -namespace std { - class string; -} -namespace test { -class Base -{ -public: - Base(); - Base(const Base&); - Base(int, float); - - virtual void foo(int = 0.0) = 0; - static int z; -protected: - bool simple(const std::string&); -private: - int x; -}; - -void MethodTester( void (Base::*)(int) ); -void FunctionTester( void (*)(int) ); - - -const Base & FreeFunc(const std::string&, int=10); - -} - -template -struct Template: protected test::Base -{ - T value; - virtual void foo(int); -}; - -Template __aTemplateInt; -''' - -def GetXMLFile(): - '''Generates an gccxml file using the code from the global cppcode. - Returns the xml's filename.''' - # write the code to a header file - tmpfile = tempfile.mktemp() + '.h' - f = file(tmpfile, 'w') - f.write(cppcode) - f.close() - # run gccxml - outfile = tmpfile + '.xml' - if os.system('gccxml "%s" "-fxml=%s"' % (tmpfile, outfile)) != 0: - raise RuntimeError, 'Error executing GCCXML.' - # read the output file into the xmlcode - f = file(outfile) - xmlcode = f.read() - #print xmlcode - f.close() - # remove the header - os.remove(tmpfile) - return outfile - - - -def GetDeclarations(): - 'Uses the GCCXMLParser module to get the declarations.' - xmlfile = GetXMLFile() - declarations = GCCXMLParser.ParseDeclarations(xmlfile) - os.remove(xmlfile) - return declarations - -# the declarations to be analysed -declarations = GetDeclarations() - - -def GetDecl(name): - 'returns one of the top declarations given its name' - for decl in declarations: - if decl.name == name: - return decl - else: - raise RuntimeError, 'Declaration not found: %s' % name - - -def GetMember(class_, name): - 'gets the member of the given class by its name' - - res = None - multipleFound = False - for member in class_: - if member.name == name: - if res is not None: - multipleFound = True - break - res = member - if res is None or multipleFound: - raise RuntimeError, \ - 'No member or more than one member found in class %s: %s' \ - % (class_.name, name) - return res - - -def GetMembers(class_, name): - 'gets the members of the given class by its name' - res = [] - for member in class_: - if member.name == name: - res.append(member) - if len(res) in (0, 1): - raise RuntimeError, \ - 'GetMembers: 0 or 1 members found in class %s: %s' \ - % (class_.name, name) - return res - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/SmartFileUT.py b/pyste/tests/SmartFileUT.py deleted file mode 100644 index 9e4e998838..0000000000 --- a/pyste/tests/SmartFileUT.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import sys -sys.path.append('../src') -from SmartFile import * -import unittest -import tempfile -import os -import time - - -class SmartFileTest(unittest.TestCase): - - FILENAME = tempfile.mktemp() - - def setUp(self): - self._Clean() - - def tearDown(self): - self._Clean() - - def _Clean(self): - try: - os.remove(self.FILENAME) - except OSError: pass - - - def testNonExistant(self): - "Must override the file, as there's no file in the disk yet" - self.assert_(not os.path.isfile(self.FILENAME)) - f = SmartFile(self.FILENAME, 'w') - f.write('Testing 123\nTesting again.') - f.close() - self.assert_(os.path.isfile(self.FILENAME)) - - - def testOverride(self): - "Must override the file, because the contents are different" - contents = 'Contents!\nContents!' - # create the file normally first - f = file(self.FILENAME, 'w') - f.write(contents) - f.close() - file_time = os.path.getmtime(self.FILENAME) - self.assert_(os.path.isfile(self.FILENAME)) - time.sleep(2) - f = SmartFile(self.FILENAME, 'w') - f.write(contents + '_') - f.close() - new_file_time = os.path.getmtime(self.FILENAME) - self.assert_(new_file_time != file_time) - - - def testNoOverride(self): - "Must not override the file, because the contents are the same" - contents = 'Contents!\nContents!' - # create the file normally first - f = file(self.FILENAME, 'w') - f.write(contents) - f.close() - file_time = os.path.getmtime(self.FILENAME) - self.assert_(os.path.isfile(self.FILENAME)) - time.sleep(2) - f = SmartFile(self.FILENAME, 'w') - f.write(contents) - f.close() - new_file_time = os.path.getmtime(self.FILENAME) - self.assert_(new_file_time == file_time) - - - def testAutoClose(self): - "Must be closed when garbage-collected" - def foo(): - f = SmartFile(self.FILENAME) - f.write('testing') - self.assert_(not os.path.isfile(self.FILENAME)) - foo() - self.assert_(os.path.isfile(self.FILENAME)) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/abstract_test.h b/pyste/tests/abstract_test.h deleted file mode 100644 index e0fba2b244..0000000000 --- a/pyste/tests/abstract_test.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#include -#include - -namespace abstract { - -struct A { - virtual ~A() {} - virtual std::string f()=0; -}; - -struct B: A { - std::string f() { return "B::f"; } -}; - -std::string call(A* a) { return a->f(); } - -} diff --git a/pyste/tests/abstract_test.pyste b/pyste/tests/abstract_test.pyste deleted file mode 100644 index c65bb3ad64..0000000000 --- a/pyste/tests/abstract_test.pyste +++ /dev/null @@ -1,3 +0,0 @@ -Class('abstract::A', 'abstract_test.h') -Class('abstract::B', 'abstract_test.h') -Function('abstract::call', 'abstract_test.h') diff --git a/pyste/tests/abstract_testUT.py b/pyste/tests/abstract_testUT.py deleted file mode 100644 index 4dc61a2622..0000000000 --- a/pyste/tests/abstract_testUT.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _abstract_test import * - -class AbstractTest(unittest.TestCase): - - def testIt(self): - class C(A): - def f(self): - return 'C::f' - - a = A() - b = B() - c = C() - self.assertRaises(RuntimeError, a.f) - self.assertEqual(b.f(), 'B::f') - self.assertEqual(call(b), 'B::f') - self.assertEqual(c.f(), 'C::f') - self.assertEqual(call(c), 'C::f') - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/add_test.h b/pyste/tests/add_test.h deleted file mode 100644 index 447e8814c7..0000000000 --- a/pyste/tests/add_test.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -namespace add_test { - -struct C -{ - int x; -}; - -const int get_x(C& c) -{ - return c.x; -} - -} diff --git a/pyste/tests/add_test.pyste b/pyste/tests/add_test.pyste deleted file mode 100644 index cc7faa9edb..0000000000 --- a/pyste/tests/add_test.pyste +++ /dev/null @@ -1,2 +0,0 @@ -C = Class('add_test::C', 'add_test.h') -add_method(C, 'add_test::get_x') diff --git a/pyste/tests/add_testUT.py b/pyste/tests/add_testUT.py deleted file mode 100644 index 16f57a320c..0000000000 --- a/pyste/tests/add_testUT.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _add_test import * - -class AddMethodTest(unittest.TestCase): - - def testIt(self): - c = C() - c.x = 10 - self.assertEqual(c.get_x(), 10) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/basic.cpp b/pyste/tests/basic.cpp deleted file mode 100644 index d07b6da627..0000000000 --- a/pyste/tests/basic.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#include "basic.h" - -namespace basic { - - int C::static_value = 3; - const int C::const_static_value = 100; - -} diff --git a/pyste/tests/basic.h b/pyste/tests/basic.h deleted file mode 100644 index 690fed2d31..0000000000 --- a/pyste/tests/basic.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef BASIC_H -#define BASIC_H - - -#include - -namespace basic { - -struct C -{ - // test virtuallity - C(): value(1), const_value(0) {} - virtual int f(int x = 10) - { - return x*2; - } - - int foo(int x=1){ - return x+1; - } - - const std::string& get_name() { return name; } - void set_name(const std::string& name) { this->name = name; } -private: - std::string name; - -public: - // test data members - static int static_value; - static const int const_static_value; - - int value; - const int const_value; - - // test static functions - static int mul(int x, int y) { return x*y; } - static double mul(double x, double y) { return x*y; } - - static int square(int x=2) { return x*x; } -}; - -inline int call_f(C& c) -{ - return c.f(); -} - -inline int call_f(C& c, int x) -{ - return c.f(x); -} - -inline int get_static() -{ - return C::static_value; -} - -inline int get_value(C& c) -{ - return c.value; -} - -} - -#endif diff --git a/pyste/tests/basic.pyste b/pyste/tests/basic.pyste deleted file mode 100644 index 4fe0b5b315..0000000000 --- a/pyste/tests/basic.pyste +++ /dev/null @@ -1,5 +0,0 @@ -Class('basic::C', 'basic.h') -Function('basic::call_f', 'basic.h') -Function('basic::get_static', 'basic.h') -Function('basic::get_value', 'basic.h') - diff --git a/pyste/tests/basicUT.py b/pyste/tests/basicUT.py deleted file mode 100644 index 9a18bcbf33..0000000000 --- a/pyste/tests/basicUT.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _basic import * - -class BasicExampleTest(unittest.TestCase): - - def testIt(self): - - # test virtual functions - class D(C): - def f(self, x=10): - return x+1 - - d = D() - c = C() - - self.assertEqual(c.f(), 20) - self.assertEqual(c.f(3), 6) - self.assertEqual(d.f(), 11) - self.assertEqual(d.f(3), 4) - self.assertEqual(call_f(c), 20) - self.assertEqual(call_f(c, 4), 8) - self.assertEqual(call_f(d), 11) - self.assertEqual(call_f(d, 3), 4) - - # test data members - def testValue(value): - self.assertEqual(c.value, value) - self.assertEqual(d.value, value) - self.assertEqual(get_value(c), value) - self.assertEqual(get_value(d), value) - testValue(1) - c.value = 30 - d.value = 30 - testValue(30) - self.assertEqual(c.const_value, 0) - self.assertEqual(d.const_value, 0) - def set_const_value(): - c.const_value = 12 - self.assertRaises(AttributeError, set_const_value) - - # test static data-members - def testStatic(value): - self.assertEqual(C.static_value, value) - self.assertEqual(c.static_value, value) - self.assertEqual(D.static_value, value) - self.assertEqual(d.static_value, value) - self.assertEqual(get_static(), value) - testStatic(3) - C.static_value = 10 - testStatic(10) - self.assertEqual(C.const_static_value, 100) - def set_const_static(): - C.const_static_value = 1 - self.assertRaises(AttributeError, set_const_static) - - # test static function - def test_mul(result, *args): - self.assertEqual(C.mul(*args), result) - self.assertEqual(c.mul(*args), result) - test_mul(16, 8, 2) - test_mul(6.0, 2.0, 3.0) - self.assertEqual(C.square(), 4) - self.assertEqual(c.square(), 4) - self.assertEqual(C.square(3), 9) - self.assertEqual(c.square(3), 9) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/code_test.h b/pyste/tests/code_test.h deleted file mode 100644 index 0a31205a34..0000000000 --- a/pyste/tests/code_test.h +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -struct A { - int x; -}; diff --git a/pyste/tests/code_test.pyste b/pyste/tests/code_test.pyste deleted file mode 100644 index 467996fdb4..0000000000 --- a/pyste/tests/code_test.pyste +++ /dev/null @@ -1,9 +0,0 @@ -Class('A', 'code_test.h') -Include('string') -declaration_code(''' -int get(A& a) { return a.x; } - -std::string foo() { return "Hello!"; } -''') -module_code(' def("get", &get);\n') -module_code(' def("foo", &foo);\n') diff --git a/pyste/tests/code_testUT.py b/pyste/tests/code_testUT.py deleted file mode 100644 index 1059570aa9..0000000000 --- a/pyste/tests/code_testUT.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _code_test import * - -class CodeTest(unittest.TestCase): - - def testIt(self): - a = A() - a.x = 12 - self.assertEqual(get(a), 12) - self.assertEqual(foo(), "Hello!") - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/enums.h b/pyste/tests/enums.h deleted file mode 100644 index afe33ca48f..0000000000 --- a/pyste/tests/enums.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef ENUMS_H -#define ENUMS_H - -namespace enums { - -enum color { red, blue }; - -struct X -{ - enum choices - { - good = 1, - bad = 2 - }; - - int set(choices c) - { - return (int)c; - } -}; - -enum { - x = 0, - y = 1 -}; - -} - -#endif diff --git a/pyste/tests/enums.pyste b/pyste/tests/enums.pyste deleted file mode 100644 index c18a1244fa..0000000000 --- a/pyste/tests/enums.pyste +++ /dev/null @@ -1,8 +0,0 @@ -h = AllFromHeader('enums.h') -rename(h.color.red, 'Red') -rename(h.color.blue, 'Blue') -export_values(h.color) -rename(h.X.choices.bad, 'Bad') -rename(h.X.choices.good, 'Good') -rename(h.X.choices, 'Choices') - diff --git a/pyste/tests/enumsUT.py b/pyste/tests/enumsUT.py deleted file mode 100644 index 7c7720dcb5..0000000000 --- a/pyste/tests/enumsUT.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _enums import * - -class EnumsTest(unittest.TestCase): - - def testIt(self): - self.assertEqual(int(Red), 0) - self.assertEqual(int(Blue), 1) - - self.assertEqual(int(X.Choices.Good), 1) - self.assertEqual(int(X.Choices.Bad), 2) - a = X() - self.assertEqual(a.set(a.Choices.Good), 1) - self.assertEqual(a.set(a.Choices.Bad), 2) - self.assertEqual(x, 0) - self.assertEqual(y, 1) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/header_test.h b/pyste/tests/header_test.h deleted file mode 100644 index 030d0d26c2..0000000000 --- a/pyste/tests/header_test.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef HEADER_TEST_H -#define HEADER_TEST_H - -#include -#include - -namespace header_test { - -enum choice { red, blue }; - -inline std::string choice_str(choice c) -{ - std::map choice_map; - choice_map[red] = "red"; - choice_map[blue] = "blue"; - return choice_map[c]; -} - -struct C -{ - choice c; - - std::string get() - { - return choice_str(c); - } -}; - -// test the exclusion of the following - -struct ForwardDeclared; // should be excluded automatically -struct A {}; -void foo(); -enum bar { value }; - -} - -#endif diff --git a/pyste/tests/header_test.pyste b/pyste/tests/header_test.pyste deleted file mode 100644 index 3bd55501c7..0000000000 --- a/pyste/tests/header_test.pyste +++ /dev/null @@ -1,4 +0,0 @@ -h = AllFromHeader('header_test.h') -exclude(h.A) -exclude(h.foo) -exclude(h.bar) diff --git a/pyste/tests/header_testUT.py b/pyste/tests/header_testUT.py deleted file mode 100644 index aa0d4a16fe..0000000000 --- a/pyste/tests/header_testUT.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _header_test import * - -class HeaderTest(unittest.TestCase): - - def testIt(self): - self.assertEqual(choice.red, 0) - self.assertEqual(choice.blue, 1) - self.assertEqual(choice_str(choice.blue), 'blue') - self.assertEqual(choice_str(choice.red), 'red') - c = C() - c.c = choice.blue - self.assertEqual(c.get(), 'blue') - c.c = choice.red - self.assertEqual(c.get(), 'red') - # the following classes/functions should not have being exported - self.assertRaises(NameError, lambda: A()) - self.assertRaises(NameError, lambda: foo()) - self.assertRaises(NameError, lambda: bar.value) - self.assertRaises(NameError, lambda: ForwardDeclared()) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/infosUT.py b/pyste/tests/infosUT.py deleted file mode 100644 index 93769f34e3..0000000000 --- a/pyste/tests/infosUT.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import sys -from Pyste.infos import * -from Pyste.policies import * -from Pyste.exporterutils import * -import unittest - -#================================================================================ -# InfosTest -#================================================================================ -class InfosTest(unittest.TestCase): - - def testFunctionInfo(self): - info = FunctionInfo('test::foo', 'foo.h') - rename(info, 'hello') - set_policy(info, return_internal_reference()) - set_wrapper(info, FunctionWrapper('foo_wrapper')) - - info = InfoWrapper(info) - - self.assertEqual(info.rename, 'hello') - self.assertEqual(info.policy.Code(), 'return_internal_reference< 1 >') - self.assertEqual(info.wrapper.name, 'foo_wrapper') - - - def testClassInfo(self): - info = ClassInfo('test::IFoo', 'foo.h') - rename(info.name, 'Name') - rename(info.exclude, 'Exclude') - rename(info, 'Foo') - rename(info.Bar, 'bar') - set_policy(info.Baz, return_internal_reference()) - rename(info.operator['>>'], 'from_string') - exclude(info.Bar) - set_wrapper(info.Baz, FunctionWrapper('baz_wrapper')) - - info = InfoWrapper(info) - - self.assertEqual(info.rename, 'Foo') - self.assertEqual(info['Bar'].rename, 'bar') - self.assertEqual(info['name'].rename, 'Name') - self.assertEqual(info['exclude'].rename, 'Exclude') - self.assertEqual(info['Bar'].exclude, True) - self.assertEqual(info['Baz'].policy.Code(), 'return_internal_reference< 1 >') - self.assertEqual(info['Baz'].wrapper.name, 'baz_wrapper') - self.assertEqual(info['operator']['>>'].rename, 'from_string') - - - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/inherit.cpp b/pyste/tests/inherit.cpp deleted file mode 100644 index a75e838918..0000000000 --- a/pyste/tests/inherit.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#include "inherit.h" - -int inherit::C::s = 1; diff --git a/pyste/tests/inherit.h b/pyste/tests/inherit.h deleted file mode 100644 index 8f903f4fd6..0000000000 --- a/pyste/tests/inherit.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -namespace inherit { - -template -class A -{ -public: - void set(T v) { mData = v; } - - T get() const { return mData; } - -private: - T mData; -}; - - -class B : public A -{ -public: - int go() { return get(); } -}; - -struct C : B -{ - enum ab { a = 1, b = 2 }; - int f1() { return 1; } - int x; - static int s; -}; - -struct D : C -{ - int f2() { return 2; } - int y; -}; - -struct X {}; -struct E: X, D {}; -} diff --git a/pyste/tests/inherit.pyste b/pyste/tests/inherit.pyste deleted file mode 100644 index 0dc0299891..0000000000 --- a/pyste/tests/inherit.pyste +++ /dev/null @@ -1,8 +0,0 @@ -A = Template('inherit::A', 'inherit.h') -A_int = A('int', 'A_int') - -Class('inherit::B', 'inherit.h') -Class('inherit::D', 'inherit.h') -E = Class('inherit::E', 'inherit.h') -exclude(E.s) -exclude(E.ab) diff --git a/pyste/tests/inherit2.h b/pyste/tests/inherit2.h deleted file mode 100644 index af9387bd09..0000000000 --- a/pyste/tests/inherit2.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -namespace inherit2 { - -struct A -{ - int x; - int getx() { return x; } - int foo() { return 0; } - int foo(int x) { return x; } -}; - -struct B : A -{ - int y; - int gety() { return y; } - int foo() { return 1; } -}; - -struct C : B -{ - int z; - int getz() { return z; } -}; - -struct D : C -{ - int w; - int getw() { return w; } -}; - -} diff --git a/pyste/tests/inherit2.pyste b/pyste/tests/inherit2.pyste deleted file mode 100644 index 3808213980..0000000000 --- a/pyste/tests/inherit2.pyste +++ /dev/null @@ -1,2 +0,0 @@ -Class('inherit2::B', 'inherit2.h') -Class('inherit2::D', 'inherit2.h') diff --git a/pyste/tests/inherit2UT.py b/pyste/tests/inherit2UT.py deleted file mode 100644 index 85afce6179..0000000000 --- a/pyste/tests/inherit2UT.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _inherit2 import * - -class InheritExampleTest(unittest.TestCase): - - def testIt(self): - b = B() - d = D() - - self.assert_(issubclass(D, B)) - b.x, b.y = 10, 5 - self.assertEqual(b.getx(), 10) - self.assertEqual(b.gety(), 5) - d.x, d.y, d.z, d.w = 20, 15, 10, 5 - self.assertEqual(d.getx(), 20) - self.assertEqual(d.gety(), 15) - self.assertEqual(d.getz(), 10) - self.assertEqual(d.getw(), 5) - self.assertEqual(b.foo(), 1) - self.assertEqual(b.foo(3), 3) - - def wrong(): - return b.getw() - self.assertRaises(AttributeError, wrong) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/inherit3.h b/pyste/tests/inherit3.h deleted file mode 100644 index 1945fb5142..0000000000 --- a/pyste/tests/inherit3.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ - -namespace inherit3 { - -struct A -{ - A() { x = 0; } - struct X { int y; }; - int x; - virtual int foo() { return 0; } - virtual int foo(int x) { return x; } - A operator+(A o) const - { - A r; - r.x = o.x + x; - return r; - } - enum E { i, j }; - -}; - -struct B: A -{ - B() { x = 0; } - struct X { int y; }; - int x; - int foo() { return 1; } - A operator+(A o) const - { - A r; - r.x = o.x + x; - return r; - } - enum E { i, j }; - -}; - -struct C: A -{ -}; - -} diff --git a/pyste/tests/inherit3.pyste b/pyste/tests/inherit3.pyste deleted file mode 100644 index f95c06054f..0000000000 --- a/pyste/tests/inherit3.pyste +++ /dev/null @@ -1,2 +0,0 @@ -Class('inherit3::B', 'inherit3.h') -Class('inherit3::C', 'inherit3.h') diff --git a/pyste/tests/inherit3UT.py b/pyste/tests/inherit3UT.py deleted file mode 100644 index b7dba1e931..0000000000 --- a/pyste/tests/inherit3UT.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _inherit3 import * - -class testInherit3(unittest.TestCase): - - def testIt(self): - def testInst(c): - self.assertEqual(c.x, 0) - self.assertEqual(c.foo(3), 3) - x = c.X() - self.assertEqual(x.y, 0) - self.assertEqual(c.E.i, 0) - self.assertEqual(c.E.j, 1) - b = B() - c = C() - testInst(b) - testInst(c) - self.assertEqual(b.foo(), 1) - self.assertEqual(c.foo(), 0) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/inherit4.h b/pyste/tests/inherit4.h deleted file mode 100644 index a1cecfbc81..0000000000 --- a/pyste/tests/inherit4.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -namespace inherit4 { - -struct A -{ - int x; -}; - -struct B: A -{ - int y; -}; - -struct C: B -{ - int z; -}; - -} diff --git a/pyste/tests/inherit4.pyste b/pyste/tests/inherit4.pyste deleted file mode 100644 index 4809e022f1..0000000000 --- a/pyste/tests/inherit4.pyste +++ /dev/null @@ -1,3 +0,0 @@ -Class('inherit4::A', 'inherit4.h') -Class('inherit4::B', 'inherit4.h') -Class('inherit4::C', 'inherit4.h') diff --git a/pyste/tests/inherit4UT.py b/pyste/tests/inherit4UT.py deleted file mode 100644 index f2c75c553d..0000000000 --- a/pyste/tests/inherit4UT.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _inherit4 import * - -class TestInherit4(unittest.TestCase): - - def testIt(self): - self.assert_(issubclass(B, A)) - self.assert_(issubclass(C, A)) - self.assert_(issubclass(C, B)) - a = A() - a.x = 1 - b = B() - b.x = 10 - b.y = 20 - c = C() - c.x = 100 - c.y = 200 - c.z = 300 - self.assertEqual(a.x, 1) - self.assertEqual(b.x, 10) - self.assertEqual(b.y, 20) - self.assertEqual(c.x, 100) - self.assertEqual(c.y, 200) - self.assertEqual(c.z, 300) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/inheritUT.py b/pyste/tests/inheritUT.py deleted file mode 100644 index f3e7b40628..0000000000 --- a/pyste/tests/inheritUT.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _inherit import * - -class InheritExampleTest(unittest.TestCase): - - def testIt(self): - a = A_int() - b = B() - self.assert_(isinstance(b, A_int)) - self.assert_(issubclass(B, A_int)) - a.set(10) - self.assertEqual(a.get(), 10) - b.set(1) - self.assertEqual(b.go(), 1) - self.assertEqual(b.get(), 1) - - d = D() - self.assert_(issubclass(D, B)) - self.assertEqual(d.x, 0) - self.assertEqual(d.y, 0) - self.assertEqual(d.s, 1) - self.assertEqual(D.s, 1) - self.assertEqual(d.f1(), 1) - self.assertEqual(d.f2(), 2) - - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/nested.cpp b/pyste/tests/nested.cpp deleted file mode 100644 index 6e167ab069..0000000000 --- a/pyste/tests/nested.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#include "nested.h" - -int nested::X::staticXValue = 10; -int nested::X::Y::staticYValue = 20; diff --git a/pyste/tests/nested.h b/pyste/tests/nested.h deleted file mode 100644 index 13ed608562..0000000000 --- a/pyste/tests/nested.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifndef NESTED_H -#define NESTED_H - -namespace nested { - -struct X -{ - struct Y - { - int valueY; - static int staticYValue; - struct Z - { - int valueZ; - }; - }; - - static int staticXValue; - int valueX; -}; - -typedef X Root; - -} - -#endif diff --git a/pyste/tests/nested.pyste b/pyste/tests/nested.pyste deleted file mode 100644 index 48bb26b557..0000000000 --- a/pyste/tests/nested.pyste +++ /dev/null @@ -1 +0,0 @@ -Class('nested::Root', 'nested.h') diff --git a/pyste/tests/nestedUT.py b/pyste/tests/nestedUT.py deleted file mode 100644 index 06c1c7beb6..0000000000 --- a/pyste/tests/nestedUT.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _nested import * - -class NestedTest(unittest.TestCase): - - def testIt(self): - self.assertEqual(Root.staticXValue, 10) - self.assertEqual(Root.Y.staticYValue, 20) - z = Root.Y.Z() - z.valueZ = 3 - self.assertEqual(z.valueZ, 3) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/opaque.h b/pyste/tests/opaque.h deleted file mode 100644 index 1947830eaa..0000000000 --- a/pyste/tests/opaque.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef OPAQUE_H -#define OPAQUE_H - -#include - -namespace opaque { - - -struct C { - C(int v): value(v) {} - int value; -}; - - -inline C* new_C() -{ - return new C(10); -} - -inline C* new_C_zero() -{ - return new C(0); -} - -inline int get(C* c) -{ - return c->value; -} - -struct D { - D(double v): value(v) {} - double value; -}; - -struct A -{ - D* new_handle() - { - return new D(3.0); - } - - double get(D* d) - { - return d->value; - } - - int f(int x=0) { return x; } -}; - -} - -#endif diff --git a/pyste/tests/opaque.pyste b/pyste/tests/opaque.pyste deleted file mode 100644 index 8180d251ce..0000000000 --- a/pyste/tests/opaque.pyste +++ /dev/null @@ -1,7 +0,0 @@ -foo = Function('opaque::new_C', 'opaque.h') -set_policy(foo, return_value_policy(return_opaque_pointer)) -foo = Function('opaque::new_C_zero', 'opaque.h') -set_policy(foo, return_value_policy(return_opaque_pointer)) -Function('opaque::get', 'opaque.h' ) -A = Class('opaque::A', 'opaque.h') -set_policy(A.new_handle, return_value_policy(return_opaque_pointer)) diff --git a/pyste/tests/opaqueUT.py b/pyste/tests/opaqueUT.py deleted file mode 100644 index 0f3e1e073d..0000000000 --- a/pyste/tests/opaqueUT.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _opaque import * - -class OpaqueTest(unittest.TestCase): - - def testIt(self): - - c = new_C() - self.assertEqual(get(c), 10) - c = new_C_zero() - self.assertEqual(get(c), 0) - a = A() - d = a.new_handle() - self.assertEqual(a.get(d), 3.0) - self.assertEqual(a.f(), 0) - self.assertEqual(a.f(3), 3) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/operators.cpp b/pyste/tests/operators.cpp deleted file mode 100644 index cecdaca0d6..0000000000 --- a/pyste/tests/operators.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#include "operators.h" - -double operators::C::x = 10; diff --git a/pyste/tests/operators.h b/pyste/tests/operators.h deleted file mode 100644 index 5d3944216a..0000000000 --- a/pyste/tests/operators.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef OPERATORS_H -#define OPERATORS_H - - -namespace operators { - -struct C -{ - static double x; - double value; - - const C operator+(const C other) const - { - C c; - c.value = value + other.value; - return c; - } - operator int() const - { - return (int)value; - } - - double operator()() - { - return C::x; - } - - double operator()(double other) - { - return C::x + other; - } - - operator const char*() { return "C"; } -}; - -inline const C operator*(const C& lhs, const C& rhs) -{ - C c; - c.value = lhs.value * rhs.value; - return c; -} - - -} - - -#endif diff --git a/pyste/tests/operators.pyste b/pyste/tests/operators.pyste deleted file mode 100644 index 4ab7a37090..0000000000 --- a/pyste/tests/operators.pyste +++ /dev/null @@ -1,2 +0,0 @@ -C = Class('operators::C', 'operators.h') -#exclude(C.operator['+']) diff --git a/pyste/tests/operatorsUT.py b/pyste/tests/operatorsUT.py deleted file mode 100644 index beb193173e..0000000000 --- a/pyste/tests/operatorsUT.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _operators import * - -class OperatorTest(unittest.TestCase): - - def testIt(self): - c = C() - c.value = 3.0 - d = C() - d.value = 2.0 - self.assertEqual(c.x, 10) - self.assertEqual(C.x, 10) - self.assertEqual(C.x, 10) - self.assertEqual((c * d).value, 6.0) - self.assertEqual((c + d).value, 5.0) - self.assertEqual(int(c), 3) - self.assertEqual(int(d), 2) - self.assertEqual(c(), 10) - self.assertEqual(d(), 10) - self.assertEqual(c(3.0), 13.0) - self.assertEqual(d(6.0), 16.0) - self.assertEqual(str(c), "C") - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/policiesUT.py b/pyste/tests/policiesUT.py deleted file mode 100644 index 7255baeb48..0000000000 --- a/pyste/tests/policiesUT.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import sys -import unittest -from Pyste.policies import * - - -#================================================================================ -# PolicicesTest -#================================================================================ -class PoliciesTest(unittest.TestCase): - - def testReturnInternal(self): - 'tests the code from a simple internal_reference' - - x = return_internal_reference(1) - self.assertEqual(x.Code(), 'return_internal_reference< 1 >') - x = return_internal_reference(3) - self.assertEqual(x.Code(), 'return_internal_reference< 3 >') - - - def testCustodian(self): - 'tests the code from a simple custodian_and_ward' - - x = with_custodian_and_ward(1,2) - self.assertEqual(x.Code(), 'with_custodian_and_ward< 1, 2 >') - x = with_custodian_and_ward(3,4) - self.assertEqual(x.Code(), 'with_custodian_and_ward< 3, 4 >') - - - def testReturnPolicies(self): - 'tests all the return_value_policies' - - ret = 'return_value_policy< %s >' - x = return_value_policy(reference_existing_object) - self.assertEqual(x.Code(), ret % 'reference_existing_object') - x = return_value_policy(copy_const_reference) - self.assertEqual(x.Code(), ret % 'copy_const_reference') - x = return_value_policy(copy_non_const_reference) - self.assertEqual(x.Code(), ret % 'copy_non_const_reference') - x = return_value_policy(manage_new_object) - self.assertEqual(x.Code(), ret % 'manage_new_object') - x = return_value_policy(return_opaque_pointer) - self.assertEqual(x.Code(), ret % 'return_opaque_pointer') - - def testReturnWithCustodiam(self): - 'test the mix of return_internal with custodian' - - x = return_internal_reference(1, with_custodian_and_ward(3,2)) - self.assertEqual( - x.Code(), - 'return_internal_reference< 1, with_custodian_and_ward< 3, 2 > >') - - - def testReturnPoliciesWithInternal(self): - 'test the mix of return_internal with return_policy' - - x = return_internal_reference(1, return_value_policy(manage_new_object)) - self.assertEqual( - x.Code(), - 'return_internal_reference< 1, return_value_policy< manage_new_object > >') - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/runtests.py b/pyste/tests/runtests.py deleted file mode 100644 index 4bf83b3456..0000000000 --- a/pyste/tests/runtests.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -#!/usr/bin/python - -import sys -sys.path.append('../src/Pyste') -import unittest -import os.path -from glob import glob - -if __name__ == '__main__': - loader = unittest.defaultTestLoader - tests = [] - for name in glob('*UT.py'): - module = __import__(os.path.splitext(name)[0]) - tests.append(loader.loadTestsFromModule(module)) - runner = unittest.TextTestRunner() - result = runner.run(unittest.TestSuite(tests)) - sys.exit(not result.wasSuccessful()) diff --git a/pyste/tests/smart_ptr.h b/pyste/tests/smart_ptr.h deleted file mode 100644 index b230b9179c..0000000000 --- a/pyste/tests/smart_ptr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifndef SMART_PTR_H -#define SMART_PTR_H - - -#include -#include - -namespace smart_ptr { - -struct C -{ - int value; -}; - -inline boost::shared_ptr NewC() { return boost::shared_ptr( new C() ); } - -struct D -{ - boost::shared_ptr Get() { return ptr; } - void Set( boost::shared_ptr c ) { ptr = c; } -private: - boost::shared_ptr ptr; -}; - -inline std::auto_ptr NewD() { return std::auto_ptr( new D() ); } - - -// test an abstract class -struct A -{ - virtual int f() = 0; -}; - -struct B: A -{ - virtual int f(){ return 1; } -}; - -inline boost::shared_ptr NewA() { return boost::shared_ptr(new B()); } -inline int GetA(boost::shared_ptr a) { return a->f(); } - -} - -#endif diff --git a/pyste/tests/smart_ptr.pyste b/pyste/tests/smart_ptr.pyste deleted file mode 100644 index cfbdd81aee..0000000000 --- a/pyste/tests/smart_ptr.pyste +++ /dev/null @@ -1,13 +0,0 @@ -C = Class('smart_ptr::C', 'smart_ptr.h') -use_shared_ptr(C) - -D = Class('smart_ptr::D', 'smart_ptr.h') -use_auto_ptr(D) - -A = Class('smart_ptr::A', 'smart_ptr.h') -use_shared_ptr(A) - -Function('smart_ptr::NewC', 'smart_ptr.h') -Function('smart_ptr::NewD', 'smart_ptr.h') -Function('smart_ptr::NewA', 'smart_ptr.h') -Function('smart_ptr::GetA', 'smart_ptr.h') diff --git a/pyste/tests/smart_ptrUT.py b/pyste/tests/smart_ptrUT.py deleted file mode 100644 index 9d81f08dd6..0000000000 --- a/pyste/tests/smart_ptrUT.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _smart_ptr import * - -class BasicExampleTest(unittest.TestCase): - - def testIt(self): - c = NewC() - d = NewD() - c.value = 3 - d.Set(c) - c1 = d.Get() - c1.value = 6 - self.assertEqual(c.value, 6) - a = NewA() - self.assertEqual(GetA(a), 1) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/templates.h b/pyste/tests/templates.h deleted file mode 100644 index 7258e91c74..0000000000 --- a/pyste/tests/templates.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -namespace templates { - -template -struct Point -{ - T x; - T y; -}; - -} diff --git a/pyste/tests/templates.pyste b/pyste/tests/templates.pyste deleted file mode 100644 index 77eaceaa33..0000000000 --- a/pyste/tests/templates.pyste +++ /dev/null @@ -1,8 +0,0 @@ -Point = Template('templates::Point', 'templates.h') -rename(Point.x, 'i') -rename(Point.y, 'j') -IPoint = Point('int') -FPoint = Point('double', 'FPoint') -rename(IPoint, 'IPoint') -rename(IPoint.x, 'x') -rename(IPoint.y, 'y') diff --git a/pyste/tests/templatesUT.py b/pyste/tests/templatesUT.py deleted file mode 100644 index 0c4b08b50a..0000000000 --- a/pyste/tests/templatesUT.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _templates import * - -class TemplatesTest(unittest.TestCase): - - def testIt(self): - fp = FPoint() - fp.i = 3.0 - fp.j = 4.0 - ip = IPoint() - ip.x = 10 - ip.y = 3 - - self.assertEqual(fp.i, 3.0) - self.assertEqual(fp.j, 4.0) - self.assertEqual(ip.x, 10) - self.assertEqual(ip.y, 3) - self.assertEqual(type(fp.i), float) - self.assertEqual(type(fp.j), float) - self.assertEqual(type(ip.x), int) - self.assertEqual(type(ip.y), int) - - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/test_all.py b/pyste/tests/test_all.py deleted file mode 100644 index ba3c54dee7..0000000000 --- a/pyste/tests/test_all.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/python -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import os -import glob -import shutil -import sys -import time - -#============================================================================= -# win32 configuration -#============================================================================= -if sys.platform == 'win32': - - includes = '-ID:/programming/libraries/boost-cvs/boost -ID:/Bin/Python/include' - build_pyste_cmd = 'python ../src/Pyste/pyste.py --pyste-ns=pyste --cache-dir=cache %s ' % includes - compile_single_cmd = 'cl /nologo /GR /GX -c %s -I. ' % includes - link_single_cmd = 'link /nologo /DLL '\ - '/libpath:D:/programming/libraries/boost-cvs/lib /libpath:D:/Bin/Python/libs '\ - 'boost_python.lib python24.lib /out:_%s.dll ' - obj_ext = 'obj' - -#============================================================================= -# linux configuration -#============================================================================= -elif sys.platform == 'linux2': - - build_pyste_cmd = 'python ../src/Pyste/pyste.py -I. ' - compile_single_cmd = 'g++ -shared -c -I. -I/usr/include/python2.4 ' - link_single_cmd = 'g++ -shared -o _%s.so -lboost_python ' - obj_ext = 'o' - - - -def build_pyste(multiple, module): - rest = '%s --module=_%s %s.pyste' % (multiple, module, module) - execute(build_pyste_cmd + rest) - - -def compile_single(module): - module_obj = '' - if os.path.isfile(module+'.cpp'): - execute(compile_single_cmd + module+'.cpp') - module_obj = module + '.' + obj_ext - execute(compile_single_cmd + ('_%s.cpp' % module)) - link = link_single_cmd % module - execute(link + ('_%s.%s ' % (module, obj_ext)) + module_obj) - - -def compile_multiple(module): - module_obj = '' - if os.path.isfile(module+'.cpp'): - execute(compile_single_cmd + module+'.cpp') - module_obj = module + '.' + obj_ext - files = glob.glob('_%s/*.cpp' % module) - for f in files: - execute(compile_single_cmd + f) - def basename(name): - return os.path.basename(os.path.splitext(name)[0]) - objs = [basename(x) + '.' + obj_ext for x in files] - objs.append(module_obj) - execute((link_single_cmd % module) + ' '.join(objs)) - - -def execute(cmd): - os.system(cmd) - - -def run_tests(): - if os.system('python runtests.py') != 0: - raise RuntimeError, 'tests failed' - - -def cleanup(): - modules = get_modules() - extensions = '*.dll *.pyc *.obj *.exp *.lib *.o *.so' - files = [] - for module in modules: - files.append('_' + module + '.cpp') - for ext in extensions.split(): - files += glob.glob(ext) - files.append('build.log') - for file in files: - try: - os.remove(file) - except OSError: pass - - for module in modules: - try: - shutil.rmtree('_' + module) - except OSError: pass - - -def main(multiple, module=None): - if module is None: - modules = get_modules() - else: - modules = [module] - - start = time.clock() - for module in modules: - build_pyste(multiple, module) - print '-'*50 - print 'Building pyste files: %0.2f seconds' % (time.clock()-start) - print - - start = time.clock() - for module in modules: - if multiple: - compile_multiple(module) - else: - compile_single(module) - print '-'*50 - print 'Compiling files: %0.2f seconds' % (time.clock()-start) - print - if len(modules) == 1: - os.system('python %sUT.py' % modules[0]) - else: - run_tests() - #cleanup() - - -def get_modules(): - def getname(file): - return os.path.splitext(os.path.basename(file))[0] - return [getname(x) for x in glob.glob('*.pyste')] - -if __name__ == '__main__': - if len(sys.argv) > 1: - module = sys.argv[1] - else: - module = None - try: -# main('--multiple', module) - main('', module) - except RuntimeError, e: - print e diff --git a/pyste/tests/vars.cpp b/pyste/tests/vars.cpp deleted file mode 100644 index e2abcd3321..0000000000 --- a/pyste/tests/vars.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#include "vars.h" - -const Color black = Color(0, 0, 0); -const Color red = Color(255, 0, 0); -const Color green = Color(0, 255, 0); -const Color blue = Color(0, 0, 255); -Color in_use = black; diff --git a/pyste/tests/vars.h b/pyste/tests/vars.h deleted file mode 100644 index 24e87d8027..0000000000 --- a/pyste/tests/vars.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ - -struct Color -{ - Color(int r_ = 0, int g_ = 0, int b_ = 0): - r(r_), g(g_), b(b_) - {} - Color( const Color &c): - r(c.r), g(c.g), b(c.b) - {} - int r; - int g; - int b; -}; - -extern const Color black; -extern const Color red; -extern const Color green; -extern const Color blue; -extern Color in_use; diff --git a/pyste/tests/vars.pyste b/pyste/tests/vars.pyste deleted file mode 100644 index 3fd9d689d0..0000000000 --- a/pyste/tests/vars.pyste +++ /dev/null @@ -1 +0,0 @@ -AllFromHeader('vars.h') diff --git a/pyste/tests/varsUT.py b/pyste/tests/varsUT.py deleted file mode 100644 index 4c32cbb2fc..0000000000 --- a/pyste/tests/varsUT.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -import _vars - - -class VarsTest(unittest.TestCase): - - def testIt(self): - def testColor(c, r, g, b): - self.assertEqual(c.r, r) - self.assertEqual(c.g, g) - self.assertEqual(c.b, b) - testColor(_vars.black, 0, 0, 0) - testColor(_vars.red, 255, 0, 0) - testColor(_vars.green, 0, 255, 0) - testColor(_vars.blue, 0, 0, 255) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/virtual.cpp b/pyste/tests/virtual.cpp deleted file mode 100644 index 070d9d3469..0000000000 --- a/pyste/tests/virtual.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ - -// Includes ==================================================================== -#include -#include - -// Using ======================================================================= -using namespace boost::python; - -// Declarations ================================================================ - - -namespace { - - -struct virtual_C_Wrapper: virtual_::C -{ - virtual_C_Wrapper(PyObject* self_, const virtual_::C & p0): - virtual_::C(p0), self(self_) {} - - virtual_C_Wrapper(PyObject* self_): - virtual_::C(), self(self_) {} - - int f() { - return call_method< int >(self, "f"); - } - - int default_f() { - return virtual_::C::f(); - } - - void bar(int p0) { - call_method< void >(self, "bar", p0); - } - - void default_bar(int p0) { - virtual_::C::bar(p0); - } - - void bar(char * p0) { - call_method< void >(self, "bar", p0); - } - - void default_bar(char * p0) { - virtual_::C::bar(p0); - } - - int f_abs() { - return call_method< int >(self, "f_abs"); - } - - PyObject* self; -}; - - - -}// namespace - - -// Module ====================================================================== -BOOST_PYTHON_MODULE(virtual) -{ - class_< virtual_::C, boost::noncopyable, virtual_C_Wrapper >("C", init< >()) - .def("get_name", &virtual_::C::get_name) - .def("f", &virtual_::C::f, &virtual_C_Wrapper::default_f) - .def("bar", (void (virtual_::C::*)(int) )&virtual_::C::bar, (void (virtual_C_Wrapper::*)(int))&virtual_C_Wrapper::default_bar) - .def("bar", (void (virtual_::C::*)(char *) )&virtual_::C::bar, (void (virtual_C_Wrapper::*)(char *))&virtual_C_Wrapper::default_bar) - ; - - def("call_f", &virtual_::call_f); -} diff --git a/pyste/tests/virtual.h b/pyste/tests/virtual.h deleted file mode 100644 index d0bb194a18..0000000000 --- a/pyste/tests/virtual.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -namespace virtual_ { - -struct C -{ -public: - virtual int f() - { - return f_abs(); - } - - virtual void bar(int) {} - virtual void bar(char*) {} - - const char* get_name() - { - return name(); - } - virtual int dummy() { return 0; } - -protected: - virtual int f_abs() = 0; - -private: - virtual const char* name() { return "C"; } -}; - -struct D -{ - virtual int dummy() { return 0; } -}; - -inline int call_f(C& c) { return c.f(); } -inline int call_dummy(C* c) { return c->dummy(); } -inline int call_dummy(D* d) { return d->dummy(); } - -} diff --git a/pyste/tests/virtual.pyste b/pyste/tests/virtual.pyste deleted file mode 100644 index ef9664124f..0000000000 --- a/pyste/tests/virtual.pyste +++ /dev/null @@ -1,6 +0,0 @@ -C = Class('virtual_::C', 'virtual.h') -final(C.dummy) -D = Class('virtual_::D', 'virtual.h') -final(D.dummy) -Function('virtual_::call_f', 'virtual.h') -Function('virtual_::call_dummy', 'virtual.h') diff --git a/pyste/tests/virtual2.h b/pyste/tests/virtual2.h deleted file mode 100644 index a6677ad164..0000000000 --- a/pyste/tests/virtual2.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ - -namespace virtual2 { - -struct A -{ - virtual int f() { return 0; } - virtual int f1() { return 10; } - virtual A* make_new() { return new A; } -}; - -struct B: A -{ - virtual int f() { return 1; } - virtual int f2() { return 20; } - virtual A* make_new() { return new B; } -}; - -inline int call_fs(A*a) -{ - int r = a->f1(); - B* b = dynamic_cast(a); - return r + b->f2(); -} - -inline int call_f(A* a) -{ - return a->f(); -} -} diff --git a/pyste/tests/virtual2.pyste b/pyste/tests/virtual2.pyste deleted file mode 100644 index 785b819c8d..0000000000 --- a/pyste/tests/virtual2.pyste +++ /dev/null @@ -1,6 +0,0 @@ -A = Class('virtual2::A', 'virtual2.h') -set_policy(A.make_new, return_value_policy(manage_new_object)) -B = Class('virtual2::B', 'virtual2.h') -set_policy(B.make_new, return_value_policy(manage_new_object)) -Function('virtual2::call_fs', 'virtual2.h') -Function('virtual2::call_f', 'virtual2.h') diff --git a/pyste/tests/virtual2UT.py b/pyste/tests/virtual2UT.py deleted file mode 100644 index 312277d26b..0000000000 --- a/pyste/tests/virtual2UT.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import unittest -from _virtual2 import * - -class Virtual2Test(unittest.TestCase): - - def testIt(self): - a = A() - self.assertEqual(a.f1(), 10) - b = B() - self.assertEqual(b.f1(), 10) - self.assertEqual(b.f2(), 20) - self.assertEqual(call_fs(b), 30) - self.assertEqual(call_f(a), 0) - self.assertEqual(call_f(b), 1) - nb = b.make_new() - na = a.make_new() - self.assertEqual(na.f1(), 10) - self.assertEqual(nb.f1(), 10) - self.assertEqual(nb.f2(), 20) - self.assertEqual(call_fs(nb), 30) - self.assertEqual(call_f(na), 0) - self.assertEqual(call_f(nb), 1) - class C(B): - def f1(self): return 1 - def f2(self): return 2 - def f(self): return 100 - - c = C() - self.assertEqual(call_fs(c), 3) - self.assertEqual(call_fs(c), 3) - self.assertEqual(call_f(c), 100) - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/virtualUT.py b/pyste/tests/virtualUT.py deleted file mode 100644 index deff681893..0000000000 --- a/pyste/tests/virtualUT.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _virtual import * - -class VirtualTest(unittest.TestCase): - - def testIt(self): - - class E(C): - def f_abs(self): - return 3 - def dummy(self): - # override should not work - return 100 - - class F(C): - def f(self): - return 10 - def name(self): - return 'F' - - class G(D): - def dummy(self): - # override should not work - return 100 - - e = E() - f = F() - - self.assertEqual(e.f(), 3) - self.assertEqual(call_f(e), 3) - self.assertEqual(f.f(), 10) - self.assertEqual(call_f(f), 10) - self.assertEqual(e.get_name(), 'C') - #self.assertEqual(e.get_name(), 'E') check this later - - c = C() - c.bar(1) # ok - c.bar('a') # ok - self.assertRaises(TypeError, c.bar, 1.0) - - # test no_overrides - d = G() - self.assertEqual(e.dummy(), 100) - self.assertEqual(call_dummy(e), 0) - self.assertEqual(d.dummy(), 100) - self.assertEqual(call_dummy(d), 0) - - - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/wrappertest.h b/pyste/tests/wrappertest.h deleted file mode 100644 index 2304fd843d..0000000000 --- a/pyste/tests/wrappertest.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef WRAPPER_TEST -#define WRAPPER_TEST - - -#include - -namespace wrappertest { - -inline std::vector Range(int count) -{ - std::vector v; - v.reserve(count); - for (int i = 0; i < count; ++i){ - v.push_back(i); - } - return v; -} - - -struct C -{ - C() {} - - std::vector Mul(int value) - { - std::vector res; - res.reserve(value); - std::vector::const_iterator it; - std::vector v(Range(value)); - for (it = v.begin(); it != v.end(); ++it){ - res.push_back(*it * value); - } - return res; - } -}; - - -struct A -{ - virtual int f() { return 1; }; -}; - -inline int call_foo(A* a){ return a->f(); } -} -#endif - diff --git a/pyste/tests/wrappertest.pyste b/pyste/tests/wrappertest.pyste deleted file mode 100644 index 12ba47b6b2..0000000000 --- a/pyste/tests/wrappertest.pyste +++ /dev/null @@ -1,21 +0,0 @@ -Include('wrappertest_wrappers.h') - -f = Function('wrappertest::Range', 'wrappertest.h') -set_wrapper(f, 'RangeWrapper') - -mul = Wrapper('MulWrapper', -''' -list MulWrapper(wrappertest::C& c, int value){ - return VectorToList(c.Mul(value)); -} -''' -) - -C = Class('wrappertest::C', 'wrappertest.h') -set_wrapper(C.Mul, mul) - - -A = Class('wrappertest::A', 'wrappertest.h') -set_wrapper(A.f, 'f_wrapper') - -Function('wrappertest::call_foo', 'wrappertest.h') diff --git a/pyste/tests/wrappertestUT.py b/pyste/tests/wrappertestUT.py deleted file mode 100644 index d770408b7f..0000000000 --- a/pyste/tests/wrappertestUT.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright Bruno da Silva de Oliveira 2003. Use, modification and -# distribution is subject to the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) -import unittest -from _wrappertest import * - -class WrapperTest(unittest.TestCase): - - def testIt(self): - self.assertEqual(Range(10), range(10)) - self.assertEqual(C().Mul(10), [x*10 for x in range(10)]) - - a = A() - self.assertEqual(a.f(), 10) - self.assertEqual(call_foo(a), 10) - class D(A): - def f(self): return 2 - d = D() - self.assertEqual(d.f(), 2) - self.assertEqual(call_foo(d), 2) - -if __name__ == '__main__': - unittest.main() diff --git a/pyste/tests/wrappertest_wrappers.h b/pyste/tests/wrappertest_wrappers.h deleted file mode 100644 index 31570a051e..0000000000 --- a/pyste/tests/wrappertest_wrappers.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and - distribution is subject to the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef WRAPPER_TEST_WRAPPERS -#define WRAPPER_TEST_WRAPPERS - -#include -#include -#include "wrappertest.h" - -using namespace boost::python; - -template -list VectorToList(const std::vector & v) -{ - list res; - typename std::vector::const_iterator it; - for(it = v.begin(); it != v.end(); ++it){ - res.append(*it); - } - Py_XINCREF(res.ptr()); - return res; -} - -inline list RangeWrapper(int count){ - return VectorToList(wrappertest::Range(count)); -} - -inline int f_wrapper(wrappertest::A*) { return 10; } - -#endif diff --git a/release_notes.txt b/release_notes.txt deleted file mode 100644 index 1fd0f1b147..0000000000 --- a/release_notes.txt +++ /dev/null @@ -1,223 +0,0 @@ -.. Copyright David Abrahams 2006. Distributed under the Boost -.. Software License, Version 1.0. (See accompanying -.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -These are old release notes for Boost.Python v1 - -2000-11-22 10:00 - Ullrich fixed bug in operator_dispatcher. - -2000-11-21 10:00 - Changed all class and function names into lower_case. - - Ullrich updated documentation for operator wrapping. - -2000-11-20 10:00 - Ullrich renamed ExtensionClass:register_coerce() into - ExtensionClass:def_standard_coerce() and made it public - - Ullrich improved shared_pod_manager. - -2000-11-17 15:04 - Changed allocation strategy of shared_pod_manager to make it portable. - - Added pickling support + tests thanks to "Ralf W. Grosse-Kunstleve" - - - Added a specialization of Callback to prevent unsafe usage. - - Fixed Ullrich's operator_dispatcher refcount bug - - Removed const char* return values from virtual functions in tests; that - usage was unsafe. - - Ullrich changed Module::add() so that it steals a reference (fix of refcount bug) - - Ullrich added operator_dispatcher::create() optimization - - Ullrich changed design and implementation of TypeObjectBase::enable() (to eliminate low-level - code) and added shared_pod_manager optimization. - - -2000-11-15 12:01 - Fixed refcount bugs in operator calls. - - Added callback_adjust_refcount(PyObject*, Type) to account for different ownership - semantics of Callback's return types and Caller's arguments (which both use from_python()) - This bug caused refcount errors during operator calls. - - Moved operator_dispatcher into extclass.cpp - Gave it shared ownership of the objects it wraps - - Introduced sequence points in extension_class_coerce for exception-safety - - UPPER_CASE_MACRO_NAMES - - MixedCase template type argument names - - Changed internal error reporting to use Python exceptions so we don't force the - user to link in iostreams code - - Changed error return value of call_cmp to -1 - - Moved unwrap_* functions out of operator_dispatcher. This was transitional: when - I realized they didn't need to be declared in extclass.h I moved them out, but - now that operator_dispatcher itself is in extclass.cpp they could go back in. - - Numerous formatting tweaks - - Updated the BoundFunction::create() optimization and enabled it so it could actually be used! - -2000-11-15 00:26 - - Made Ullrich's operators support work with MSVC - - Cleaned up operators.h such that invalid define_operator<0> is no longer needed. - - Ullrich created operators.h to support wrapping of C++ operators (including the "__r*__" forms). - He added several auxiliary classes to extclass.h and extclass.cpp (most importantly, - py::detail::operator_dispatcher and py::operators) - -2000-11-13 22:29 - - removed obsolete ExtensionClassFromPython for good. - - removed unused class ExtensionType forward declaration - -2000-11-12 13:08 - - Added enum_as_int_converters for easier enum wrapping - - Introduced new conversion namespace macros: - PY_BEGIN_CONVERSION_NAMESPACE, - PY_END_CONVERSION_NAMESPACE, - PY_CONVERSION - - callback.h, gen_callback.py: - Added call() function so that a regular python function (as opposed to - method or other function-as-attribute) can be called. - - Added newlines for readability. - - class_wrapper.h: - Fixed a bug in add(), which allows non-method class attributes - - Ullrich has added def_raw for simple varargs and keyword support. - - Fixed version number check for __MWERKS__ - - Added tests for enums and non-method class attributes - - objects.h/objects.cpp: - Added py::String operator*= and operator* for repetition - - Change Dict::items(), keys(), and values() to return a List - - Added template versions of set_item, etc., methods so that users can optionally - use C++ types that have to_python() functions as parameters. - - Changed various Ptr by-value parameters to const Ptr& - - -======= Release ======= -2000-11-06 0:22 - Lots of documentation updates - - added 4-argument template constructor to py::Tuple - - added "add" member function to ClassWrapper<> to allow arbitrary Python - objects to be added to an extension class. - - gen_all.py now generates support for n argument member functions and n+1 - argument member functions at the suggestion of "Ralf W. Grosse-Kunstleve" - - - Added regression tests and re-ordered declare_base calls to verify that the - phantom base class issue is resolved. - -2000-11-04 17:35 - - Integrated Ullrich Koethe's brilliant from_python_experiment for better - error-reporting in many cases. - - extclass.h, gen_extclass.py: - removed special-case MSVC code - added much commentary - removed unused py_copy_to_new_value_holder - - init_function.h, gen_init_function.py: - added missing 'template' keyword on type-dependent template member usage - removed special-case MSVC code - added much commentary - -2000-11-04 0:36 - - Removed the need for the phantom base class that screwed up inheritance - hierarchies, introduced error-prone ordering dependencies, and complexified - logic in many places! - - extclass.h: Added some explanatory comments, removed wasteful m_self member - of HeldInstance - - extclass_demo.cpp: Added #pragmas which allow compilation in ansi strict - mode under Metrowerks - - functions.h: Added virtual_function as part of phantom base class removal; - expanded commentary - - pyptr.h: Added some missing 'typename's and a GCC workaround fix - - subclass.cpp: Added missing string literal const_cast<>s. - -2000-11-03 10:58 - - Fix friend function instantiation bug caught by Metrowerks (thanks - Metrowerks!) - - Add proof-of-concept for one technique of wrapping function that return a - pointer - - Worked around MSVC optimizer bug by writing to_python(double) and - to_python(float) out-of-line - -2000-11-02 23:25 - - Add /Zm200 option to vc6_prj to deal with MSVC resource limitations - - Remove conflicting /Ot option from vc6_prj release build - -======= Release ======= -2000-11-02 17:42 - - Added a fix for interactions between default virtual function - implementations and declare_base(). You still need to write your - declare_base() /after/ all member functions have been def()d for the two - classes concerned. Many, many thanks to Ullrich Koethe - for all his work on this. - - Added missing conversions: - to_python(float) - from_python(const char* const&) - from_python(const double&) - from_python(const float&) - - Added a Regression test for a reference-counting bug thanks to Mark Evans - () - - const-ify ClassBase::getattr() - - Add repr() function to Class - - Add to_python/from_python conversions for PyPtr - - Standardize set_item/get_item interfaces (instead of proxies) for Dict and List - - Add Reprable<> template to newtypes.h - - Fix a bug wherein the __module__ attribute would be lost for classes that have a - default virtual function implementation. - - Remove extra ';' in module.cpp thanks to "Ralf W. Grosse-Kunstleve" - - - Fix a bug in the code of example1.html diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index 9900602b77..ee2d5b4794 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -45,11 +45,16 @@ namespace { return PyString_Check(obj) ? PyString_AsString(obj) : 0; } -#else +#elif PY_VERSION_HEX < 0x03070000 void* convert_to_cstring(PyObject* obj) { return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0; } +#else + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? const_cast(reinterpret_cast(_PyUnicode_AsString(obj))) : 0; + } #endif // Given a target type and a SlotPolicy describing how to perform a @@ -430,6 +435,22 @@ namespace // Remember that this will be used to construct the result object static std::wstring extract(PyObject* intermediate) { + // On Windows, with Python >= 3.3, PyObject_Length cannot be used to get + // the size of the wchar_t string, because it will count the number of + // *code points*, but some characters not on the BMP will use two UTF-16 + // *code units* (surrogate pairs). + // This is not a problem on Unix, since wchar_t is 32-bit. +#if defined(_WIN32) && PY_VERSION_HEX >= 0x03030000 + BOOST_STATIC_ASSERT(sizeof(wchar_t) == 2); + + Py_ssize_t size = 0; + wchar_t *buf = PyUnicode_AsWideCharString(intermediate, &size); + if (buf == NULL) { + boost::python::throw_error_already_set(); + } + std::wstring result(buf, size); + PyMem_Free(buf); +#else std::wstring result(::PyObject_Length(intermediate), L' '); if (!result.empty()) { @@ -444,6 +465,7 @@ namespace if (err == -1) throw_error_already_set(); } +#endif return result; } static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} diff --git a/src/converter/from_python.cpp b/src/converter/from_python.cpp index 9678be1cb6..f3989ba77f 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -222,7 +222,13 @@ namespace , char const* ref_type) { handle<> holder(source); - if (source->ob_refcnt <= 1) + if ( +#if PY_VERSION_HEX < 0x03090000 + source->ob_refcnt +#else + Py_REFCNT(source) +#endif + <= 1) { handle<> msg( #if PY_VERSION_HEX >= 0x3000000 diff --git a/src/exec.cpp b/src/exec.cpp index 9fe1b23b7f..7488da1f6d 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -15,6 +15,11 @@ namespace python { object BOOST_PYTHON_DECL eval(str string, object global, object local) +{ + return eval(python::extract(string), global, local); +} + +object BOOST_PYTHON_DECL eval(char const *string, object global, object local) { // Set suitable default values for global and local dicts. if (global.is_none()) @@ -26,13 +31,18 @@ object BOOST_PYTHON_DECL eval(str string, object global, object local) } if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. - char *s = python::extract(string); + char *s = const_cast(string); PyObject* result = PyRun_String(s, Py_eval_input, global.ptr(), local.ptr()); if (!result) throw_error_already_set(); return object(detail::new_reference(result)); } object BOOST_PYTHON_DECL exec(str string, object global, object local) +{ + return exec(python::extract(string), global, local); +} + +object BOOST_PYTHON_DECL exec(char const *string, object global, object local) { // Set suitable default values for global and local dicts. if (global.is_none()) @@ -44,13 +54,18 @@ object BOOST_PYTHON_DECL exec(str string, object global, object local) } if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. - char *s = python::extract(string); + char *s = const_cast(string); PyObject* result = PyRun_String(s, Py_file_input, global.ptr(), local.ptr()); if (!result) throw_error_already_set(); return object(detail::new_reference(result)); } object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) +{ + return exec_statement(python::extract(string), global, local); +} + +object BOOST_PYTHON_DECL exec_statement(char const *string, object global, object local) { // Set suitable default values for global and local dicts. if (global.is_none()) @@ -62,7 +77,7 @@ object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) } if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. - char *s = python::extract(string); + char *s = const_cast(string); PyObject* result = PyRun_String(s, Py_single_input, global.ptr(), local.ptr()); if (!result) throw_error_already_set(); return object(detail::new_reference(result)); @@ -72,6 +87,11 @@ object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) // global and local are the global and local scopes respectively, // used during execution. object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) +{ + return exec_file(python::extract(filename), global, local); +} + +object BOOST_PYTHON_DECL exec_file(char const *filename, object global, object local) { // Set suitable default values for global and local dicts. if (global.is_none()) @@ -83,12 +103,21 @@ object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) } if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. - char *f = python::extract(filename); -#if PY_VERSION_HEX >= 0x03000000 - // TODO(bhy) temporary workaround for Python 3. - // should figure out a way to avoid binary incompatibilities as the Python 2 - // version did. - FILE *fs = fopen(f, "r"); + char *f = const_cast(filename); +#if PY_VERSION_HEX >= 0x03010000 + // Let python manage any UTF bits to avoid potential incompatibilities. + PyObject *fo = Py_BuildValue("s", f); + PyObject *fb = Py_None; + PyUnicode_FSConverter(fo, &fb); + char *f_as_uft = PyBytes_AsString(fb); + FILE *fs = fopen(f_as_uft, "r"); + Py_DECREF(fo); + Py_DECREF(fb); +#elif PY_VERSION_HEX >= 0x03000000 + // Let python open the file to avoid potential binary incompatibilities. + PyObject *fo = Py_BuildValue("s", f); + FILE *fs = fopen(fo, "r"); + Py_DECREF(fo); #else // Let python open the file to avoid potential binary incompatibilities. PyObject *pyfile = PyFile_FromString(f, const_cast("r")); @@ -99,7 +128,8 @@ object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) PyObject* result = PyRun_File(fs, f, Py_file_input, - global.ptr(), local.ptr()); + global.ptr(), local.ptr()); + fclose(fs); if (!result) throw_error_already_set(); return object(detail::new_reference(result)); } diff --git a/src/fabscript b/src/fabscript new file mode 100644 index 0000000000..0ebeac6098 --- /dev/null +++ b/src/fabscript @@ -0,0 +1,58 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from faber.feature import set +from faber.artefacts.library import library +from faber.tools.compiler import define + +root = module('..') + +bpl = library('boost_python' + root.py_suffix, + ['list.cpp', + 'long.cpp', + 'dict.cpp', + 'tuple.cpp', + 'str.cpp', + 'slice.cpp', + 'converter/from_python.cpp', + 'converter/registry.cpp', + 'converter/type_id.cpp', + 'object/enum.cpp', + 'object/class.cpp', + 'object/function.cpp', + 'object/inheritance.cpp', + 'object/life_support.cpp', + 'object/pickle_support.cpp', + 'errors.cpp', + 'module.cpp', + 'converter/builtin_converters.cpp', + 'converter/arg_to_python_base.cpp', + 'object/iterator.cpp', + 'object/stl_iterator.cpp', + 'object_protocol.cpp', + 'object_operators.cpp', + 'wrapper.cpp', + 'import.cpp', + 'exec.cpp', + 'object/function_doc_signature.cpp'], + dependencies=root.config, + features=features + define('BOOST_PYTHON_SOURCE')) + +bnl = library('boost_numpy' + root.py_suffix, + ['numpy/dtype.cpp', + 'numpy/matrix.cpp', + 'numpy/ndarray.cpp', + 'numpy/numpy.cpp', + 'numpy/scalars.cpp', + 'numpy/ufunc.cpp', + bpl], + dependencies=root.config, + features=features + define('BOOST_NUMPY_SOURCE'), + condition=set.define.contains('HAS_NUMPY')) +default = [bpl, bnl] diff --git a/src/long.cpp b/src/long.cpp index 1ec8ebc011..6aa2965e83 100644 --- a/src/long.cpp +++ b/src/long.cpp @@ -6,16 +6,16 @@ namespace boost { namespace python { namespace detail { -new_non_null_reference long_base::call(object const& arg_) +new_reference long_base::call(object const& arg_) { - return (detail::new_non_null_reference)PyObject_CallFunction( + return (detail::new_reference)PyObject_CallFunction( (PyObject*)&PyLong_Type, const_cast("(O)"), arg_.ptr()); } -new_non_null_reference long_base::call(object const& arg_, object const& base) +new_reference long_base::call(object const& arg_, object const& base) { - return (detail::new_non_null_reference)PyObject_CallFunction( + return (detail::new_reference)PyObject_CallFunction( (PyObject*)&PyLong_Type, const_cast("(OO)"), arg_.ptr(), base.ptr()); } diff --git a/src/module.cpp b/src/module.cpp index 9628481996..57675fa2df 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -21,7 +21,7 @@ namespace object m_obj(((borrowed_reference_t*)m)); scope current_module(m_obj); - handle_exception(init_function); + if (handle_exception(init_function)) return NULL; } return m; diff --git a/src/numeric.cpp b/src/numeric.cpp deleted file mode 100644 index c8a5f071d9..0000000000 --- a/src/numeric.cpp +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include -#include -#include - -namespace boost { namespace python { namespace numeric { - -namespace -{ - enum state_t { failed = -1, unknown, succeeded }; - state_t state = unknown; - std::string module_name; - std::string type_name; - - handle<> array_module; - handle<> array_type; - handle<> array_function; - - void throw_load_failure() - { - PyErr_Format( - PyExc_ImportError - , "No module named '%s' or its type '%s' did not follow the NumPy protocol" - , module_name.c_str(), type_name.c_str()); - throw_error_already_set(); - - } - - bool load(bool throw_on_error) - { - if (!state) - { - if (module_name.size() == 0) - { - module_name = "numarray"; - type_name = "NDArray"; - if (load(false)) - return true; - module_name = "Numeric"; - type_name = "ArrayType"; - } - - state = failed; - PyObject* module = ::PyImport_Import(object(module_name).ptr()); - if (module) - { - PyObject* type = ::PyObject_GetAttrString(module, const_cast(type_name.c_str())); - - if (type && PyType_Check(type)) - { - array_type = handle<>(type); - PyObject* function = ::PyObject_GetAttrString(module, const_cast("array")); - - if (function && PyCallable_Check(function)) - { - array_function = handle<>(function); - state = succeeded; - } - } - } - } - - if (state == succeeded) - return true; - - if (throw_on_error) - throw_load_failure(); - - PyErr_Clear(); - return false; - } - - object demand_array_function() - { - load(true); - return object(array_function); - } -} - -void array::set_module_and_type(char const* package_name, char const* type_attribute_name) -{ - state = unknown; - module_name = package_name ? package_name : "" ; - type_name = type_attribute_name ? type_attribute_name : "" ; -} - -std::string array::get_module_name() -{ - load(false); - return module_name; -} - -namespace aux -{ - bool array_object_manager_traits::check(PyObject* obj) - { - if (!load(false)) - return false; - return ::PyObject_IsInstance(obj, array_type.get()); - } - - python::detail::new_non_null_reference - array_object_manager_traits::adopt(PyObject* obj) - { - load(true); - return detail::new_non_null_reference( - pytype_check(downcast(array_type.get()), obj)); - } - - PyTypeObject const* array_object_manager_traits::get_pytype() - { - load(false); - if(!array_type) return 0; - return downcast(array_type.get()); - } - -# define BOOST_PYTHON_AS_OBJECT(z, n, _) object(x##n) -# define BOOST_PP_LOCAL_MACRO(n) \ - array_base::array_base(BOOST_PP_ENUM_PARAMS(n, object const& x)) \ - : object(demand_array_function()(BOOST_PP_ENUM_PARAMS(n, x))) \ - {} -# define BOOST_PP_LOCAL_LIMITS (1, 6) -# include BOOST_PP_LOCAL_ITERATE() -# undef BOOST_PYTHON_AS_OBJECT - - array_base::array_base(BOOST_PP_ENUM_PARAMS(7, object const& x)) - : object(demand_array_function()(BOOST_PP_ENUM_PARAMS(7, x))) - {} - - object array_base::argmax(long axis) - { - return attr("argmax")(axis); - } - - object array_base::argmin(long axis) - { - return attr("argmin")(axis); - } - - object array_base::argsort(long axis) - { - return attr("argsort")(axis); - } - - object array_base::astype(object const& type) - { - return attr("astype")(type); - } - - void array_base::byteswap() - { - attr("byteswap")(); - } - - object array_base::copy() const - { - return attr("copy")(); - } - - object array_base::diagonal(long offset, long axis1, long axis2) const - { - return attr("diagonal")(offset, axis1, axis2); - } - - void array_base::info() const - { - attr("info")(); - } - - bool array_base::is_c_array() const - { - return extract(attr("is_c_array")()); - } - - bool array_base::isbyteswapped() const - { - return extract(attr("isbyteswapped")()); - } - - array array_base::new_(object type) const - { - return extract(attr("new")(type))(); - } - - void array_base::sort() - { - attr("sort")(); - } - - object array_base::trace(long offset, long axis1, long axis2) const - { - return attr("trace")(offset, axis1, axis2); - } - - object array_base::type() const - { - return attr("type")(); - } - - char array_base::typecode() const - { - return extract(attr("typecode")()); - } - - object array_base::factory( - object const& sequence - , object const& typecode - , bool copy - , bool savespace - , object type - , object shape - ) - { - return attr("factory")(sequence, typecode, copy, savespace, type, shape); - } - - object array_base::getflat() const - { - return attr("getflat")(); - } - - long array_base::getrank() const - { - return extract(attr("getrank")()); - } - - object array_base::getshape() const - { - return attr("getshape")(); - } - - bool array_base::isaligned() const - { - return extract(attr("isaligned")()); - } - - bool array_base::iscontiguous() const - { - return extract(attr("iscontiguous")()); - } - - long array_base::itemsize() const - { - return extract(attr("itemsize")()); - } - - long array_base::nelements() const - { - return extract(attr("nelements")()); - } - - object array_base::nonzero() const - { - return attr("nonzero")(); - } - - void array_base::put(object const& indices, object const& values) - { - attr("put")(indices, values); - } - - void array_base::ravel() - { - attr("ravel")(); - } - - object array_base::repeat(object const& repeats, long axis) - { - return attr("repeat")(repeats, axis); - } - - void array_base::resize(object const& shape) - { - attr("resize")(shape); - } - - void array_base::setflat(object const& flat) - { - attr("setflat")(flat); - } - - void array_base::setshape(object const& shape) - { - attr("setshape")(shape); - } - - void array_base::swapaxes(long axis1, long axis2) - { - attr("swapaxes")(axis1, axis2); - } - - object array_base::take(object const& sequence, long axis) const - { - return attr("take")(sequence, axis); - } - - void array_base::tofile(object const& file) const - { - attr("tofile")(file); - } - - str array_base::tostring() const - { - return str(attr("tostring")()); - } - - void array_base::transpose(object const& axes) - { - attr("transpose")(axes); - } - - object array_base::view() const - { - return attr("view")(); - } -} - -}}} // namespace boost::python::numeric diff --git a/src/numpy/dtype.cpp b/src/numpy/dtype.cpp new file mode 100644 index 0000000000..1ce8c6ec32 --- /dev/null +++ b/src/numpy/dtype.cpp @@ -0,0 +1,201 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _MSC_VER +#include +#endif +#define BOOST_PYTHON_NUMPY_INTERNAL +#include + +#define DTYPE_FROM_CODE(code) \ + dtype(python::detail::new_reference(reinterpret_cast(PyArray_DescrFromType(code)))) + +#define BUILTIN_INT_DTYPE(bits) \ + template <> struct builtin_int_dtype \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_INT ## bits);} \ + }; \ + template <> struct builtin_int_dtype \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits);} \ + }; \ + template BOOST_NUMPY_DECL dtype get_int_dtype(); \ + template BOOST_NUMPY_DECL dtype get_int_dtype() + +#define BUILTIN_FLOAT_DTYPE(bits) \ + template <> struct builtin_float_dtype \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits);} \ + }; \ + template BOOST_NUMPY_DECL dtype get_float_dtype() + +#define BUILTIN_COMPLEX_DTYPE(bits) \ + template <> struct builtin_complex_dtype \ + { \ + static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits);} \ + }; \ + template BOOST_NUMPY_DECL dtype get_complex_dtype() + +namespace boost { namespace python { namespace converter { +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, numpy::dtype) +} // namespace boost::python::converter + +namespace numpy { +namespace detail { + +dtype builtin_dtype::get() { return DTYPE_FROM_CODE(NPY_BOOL); } + +template struct builtin_int_dtype; +template struct builtin_float_dtype; +template struct builtin_complex_dtype; + +template dtype get_int_dtype() { + return builtin_int_dtype::get(); +} +template dtype get_float_dtype() { return builtin_float_dtype::get(); } +template dtype get_complex_dtype() { return builtin_complex_dtype::get(); } + +BUILTIN_INT_DTYPE(8); +BUILTIN_INT_DTYPE(16); +BUILTIN_INT_DTYPE(32); +BUILTIN_INT_DTYPE(64); +#ifdef NPY_FLOAT16 +BUILTIN_FLOAT_DTYPE(16); +#endif +BUILTIN_FLOAT_DTYPE(32); +BUILTIN_FLOAT_DTYPE(64); +BUILTIN_COMPLEX_DTYPE(64); +BUILTIN_COMPLEX_DTYPE(128); +#if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE +template <> struct builtin_float_dtype< NPY_BITSOF_LONGDOUBLE > { + static dtype get() { return DTYPE_FROM_CODE(NPY_LONGDOUBLE); } +}; +template dtype get_float_dtype< NPY_BITSOF_LONGDOUBLE >(); +template <> struct builtin_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE > { + static dtype get() { return DTYPE_FROM_CODE(NPY_CLONGDOUBLE); } +}; +template dtype get_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE >(); +#endif + +} // namespace detail + +python::detail::new_reference dtype::convert(object const & arg, bool align) +{ + PyArray_Descr* obj=NULL; + if (align) + { + if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0) + throw_error_already_set(); + } + else + { + if (PyArray_DescrConverter(arg.ptr(), &obj) < 0) + throw_error_already_set(); + } + return python::detail::new_reference(reinterpret_cast(obj)); +} + +int dtype::get_itemsize() const { +#if NPY_ABI_VERSION < 0x02000000 + return reinterpret_cast(ptr())->elsize; +#else + return PyDataType_ELSIZE(reinterpret_cast(ptr())); +#endif +} + +bool equivalent(dtype const & a, dtype const & b) { + return a == b; +} + +namespace +{ + +namespace pyconv = boost::python::converter; + +template +class array_scalar_converter +{ +public: + + static PyTypeObject const * get_pytype() + { + // This implementation depends on the fact that get_builtin returns pointers to objects + // NumPy has declared statically, and that the typeobj member also refers to a static + // object. That means we don't need to do any reference counting. + // In fact, I'm somewhat concerned that increasing the reference count of any of these + // might cause leaks, because I don't think Boost.Python ever decrements it, but it's + // probably a moot point if everything is actually static. + return reinterpret_cast(dtype::get_builtin().ptr())->typeobj; + } + + static void * convertible(PyObject * obj) + { + if (obj->ob_type == get_pytype()) + { + return obj; + } + else + { + dtype dt(python::detail::borrowed_reference(obj->ob_type)); + if (equivalent(dt, dtype::get_builtin())) + { + return obj; + } + } + return 0; + } + + static void convert(PyObject * obj, pyconv::rvalue_from_python_stage1_data* data) + { + void * storage = reinterpret_cast*>(data)->storage.bytes; + // We assume std::complex is a "standard layout" here and elsewhere; not guaranteed by + // C++03 standard, but true in every known implementation (and guaranteed by C++11). + PyArray_ScalarAsCtype(obj, reinterpret_cast(storage)); + data->convertible = storage; + } + + static void declare() + { + pyconv::registry::push_back(&convertible, &convert, python::type_id() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &get_pytype +#endif + ); + } + +}; + +} // anonymous + +void dtype::register_scalar_converters() +{ + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); +#ifdef _MSC_VER + // Since the npy_(u)int32 types are defined as long types and treated + // as being different from the int32 types, these converters must be declared + // explicitely. + array_scalar_converter::declare(); + array_scalar_converter::declare(); +#endif + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter::declare(); + array_scalar_converter< std::complex >::declare(); + array_scalar_converter< std::complex >::declare(); +#if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE + array_scalar_converter::declare(); + array_scalar_converter< std::complex >::declare(); +#endif +} + +}}} // namespace boost::python::numpy diff --git a/src/numpy/matrix.cpp b/src/numpy/matrix.cpp new file mode 100644 index 0000000000..47d2261637 --- /dev/null +++ b/src/numpy/matrix.cpp @@ -0,0 +1,63 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include +#include + +namespace boost { namespace python { namespace numpy +{ +namespace detail +{ +inline object get_matrix_type() +{ + object module = import("numpy"); + return module.attr("matrix"); +} +} // namespace boost::python::numpy::detail +} // namespace boost::python::numpy + +namespace converter +{ + +PyTypeObject const * object_manager_traits::get_pytype() +{ + return reinterpret_cast(numpy::detail::get_matrix_type().ptr()); +} + +} // namespace boost::python::converter + +namespace numpy +{ + +object matrix::construct(object const & obj, dtype const & dt, bool copy) +{ + return numpy::detail::get_matrix_type()(obj, dt, copy); +} + +object matrix::construct(object const & obj, bool copy) +{ + return numpy::detail::get_matrix_type()(obj, object(), copy); +} + +matrix matrix::view(dtype const & dt) const +{ + return matrix(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("view"), const_cast("O"), dt.ptr()))); +} + +matrix matrix::copy() const +{ + return matrix(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("copy"), const_cast("")))); +} + +matrix matrix::transpose() const +{ + return matrix(extract(ndarray::transpose())); +} + +}}} // namespace boost::python::numpy diff --git a/src/numpy/ndarray.cpp b/src/numpy/ndarray.cpp new file mode 100644 index 0000000000..af09ecc338 --- /dev/null +++ b/src/numpy/ndarray.cpp @@ -0,0 +1,301 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include +#include + +namespace boost { namespace python { +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArray_Type, numpy::ndarray) +} // namespace boost::python::converter + +namespace numpy +{ +namespace detail +{ + +ndarray::bitflag numpy_to_bitflag(int const f) +{ + ndarray::bitflag r = ndarray::NONE; + if (f & NPY_ARRAY_C_CONTIGUOUS) r = (r | ndarray::C_CONTIGUOUS); + if (f & NPY_ARRAY_F_CONTIGUOUS) r = (r | ndarray::F_CONTIGUOUS); + if (f & NPY_ARRAY_ALIGNED) r = (r | ndarray::ALIGNED); + if (f & NPY_ARRAY_WRITEABLE) r = (r | ndarray::WRITEABLE); + return r; +} + +int bitflag_to_numpy(ndarray::bitflag f) +{ + int r = 0; + if (f & ndarray::C_CONTIGUOUS) r |= NPY_ARRAY_C_CONTIGUOUS; + if (f & ndarray::F_CONTIGUOUS) r |= NPY_ARRAY_F_CONTIGUOUS; + if (f & ndarray::ALIGNED) r |= NPY_ARRAY_ALIGNED; + if (f & ndarray::WRITEABLE) r |= NPY_ARRAY_WRITEABLE; + return r; +} + +bool is_c_contiguous(std::vector const & shape, + std::vector const & strides, + int itemsize) +{ + std::vector::const_reverse_iterator j = strides.rbegin(); + int total = itemsize; + for (std::vector::const_reverse_iterator i = shape.rbegin(); i != shape.rend(); ++i, ++j) + { + if (total != *j) return false; + total *= (*i); + } + return true; +} + +bool is_f_contiguous(std::vector const & shape, + std::vector const & strides, + int itemsize) +{ + std::vector::const_iterator j = strides.begin(); + int total = itemsize; + for (std::vector::const_iterator i = shape.begin(); i != shape.end(); ++i, ++j) + { + if (total != *j) return false; + total *= (*i); + } + return true; +} + +bool is_aligned(std::vector const & strides, + int itemsize) +{ + for (std::vector::const_iterator i = strides.begin(); i != strides.end(); ++i) + { + if (*i % itemsize) return false; + } + return true; +} + +inline PyArray_Descr * incref_dtype(dtype const & dt) +{ + Py_INCREF(dt.ptr()); + return reinterpret_cast(dt.ptr()); +} + +ndarray from_data_impl(void * data, + dtype const & dt, + python::object const & shape, + python::object const & strides, + python::object const & owner, + bool writeable) +{ + std::vector shape_(len(shape)); + std::vector strides_(len(strides)); + if (shape_.size() != strides_.size()) + { + PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match."); + python::throw_error_already_set(); + } + for (std::size_t i = 0; i < shape_.size(); ++i) + { + shape_[i] = python::extract(shape[i]); + strides_[i] = python::extract(strides[i]); + } + return from_data_impl(data, dt, shape_, strides_, owner, writeable); +} + +ndarray from_data_impl(void * data, + dtype const & dt, + std::vector const & shape, + std::vector const & strides, + python::object const & owner, + bool writeable) +{ + if (shape.size() != strides.size()) + { + PyErr_SetString(PyExc_ValueError, "Length of shape and strides arrays do not match."); + python::throw_error_already_set(); + } + int itemsize = dt.get_itemsize(); + int flags = 0; + if (writeable) flags |= NPY_ARRAY_WRITEABLE; + if (is_c_contiguous(shape, strides, itemsize)) flags |= NPY_ARRAY_C_CONTIGUOUS; + if (is_f_contiguous(shape, strides, itemsize)) flags |= NPY_ARRAY_F_CONTIGUOUS; + if (is_aligned(strides, itemsize)) flags |= NPY_ARRAY_ALIGNED; + ndarray r(python::detail::new_reference + (PyArray_NewFromDescr(&PyArray_Type, + incref_dtype(dt), + shape.size(), + const_cast(&shape.front()), + const_cast(&strides.front()), + data, + flags, + NULL))); + r.set_base(owner); + return r; +} + +} // namespace detail + +namespace { + int normalize_index(int n,int nlim) // wraps [-nlim:nlim) into [0:nlim), throw IndexError otherwise + { + if (n<0) + n += nlim; // negative indices work backwards from end + if (n < 0 || n >= nlim) + { + PyErr_SetObject(PyExc_IndexError, Py_None); + throw_error_already_set(); + } + return n; + } +} + +Py_intptr_t ndarray::shape(int n) const +{ + return get_shape()[normalize_index(n,get_nd())]; +} + +Py_intptr_t ndarray::strides(int n) const +{ + return get_strides()[normalize_index(n,get_nd())]; +} + +ndarray ndarray::view(dtype const & dt) const +{ + return ndarray(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("view"), const_cast("O"), dt.ptr()))); +} + +ndarray ndarray::astype(dtype const & dt) const +{ + return ndarray(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("astype"), const_cast("O"), dt.ptr()))); +} + +ndarray ndarray::copy() const +{ + return ndarray(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("copy"), const_cast("")))); +} + +dtype ndarray::get_dtype() const +{ + return dtype(python::detail::borrowed_reference(get_struct()->descr)); +} + +python::object ndarray::get_base() const +{ + if (get_struct()->base == NULL) return object(); + return python::object(python::detail::borrowed_reference(get_struct()->base)); +} + +void ndarray::set_base(object const & base) +{ + Py_XDECREF(get_struct()->base); + if (base.ptr()) + { + Py_INCREF(base.ptr()); + get_struct()->base = base.ptr(); + } + else + { + get_struct()->base = NULL; + } +} + +ndarray::bitflag ndarray::get_flags() const +{ + return numpy::detail::numpy_to_bitflag(get_struct()->flags); +} + +ndarray ndarray::transpose() const +{ + return ndarray(python::detail::new_reference + (PyArray_Transpose(reinterpret_cast(this->ptr()), NULL))); +} + +ndarray ndarray::squeeze() const +{ + return ndarray(python::detail::new_reference + (PyArray_Squeeze(reinterpret_cast(this->ptr())))); +} + +ndarray ndarray::reshape(python::tuple const & shape) const +{ + return ndarray(python::detail::new_reference + (PyArray_Reshape(reinterpret_cast(this->ptr()), shape.ptr()))); +} + +python::object ndarray::scalarize() const +{ + Py_INCREF(ptr()); + return python::object(python::detail::new_reference(PyArray_Return(reinterpret_cast(ptr())))); +} + +ndarray zeros(python::tuple const & shape, dtype const & dt) +{ + int nd = len(shape); + boost::scoped_array dims(new Py_intptr_t[nd]); + for (int n=0; n(shape[n]); + return ndarray(python::detail::new_reference + (PyArray_Zeros(nd, dims.get(), detail::incref_dtype(dt), 0))); +} + +ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt) +{ + return ndarray(python::detail::new_reference + (PyArray_Zeros(nd, const_cast(shape), detail::incref_dtype(dt), 0))); +} + +ndarray empty(python::tuple const & shape, dtype const & dt) +{ + int nd = len(shape); + boost::scoped_array dims(new Py_intptr_t[nd]); + for (int n=0; n(shape[n]); + return ndarray(python::detail::new_reference + (PyArray_Empty(nd, dims.get(), detail::incref_dtype(dt), 0))); +} + +ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt) +{ + return ndarray(python::detail::new_reference + (PyArray_Empty(nd, const_cast(shape), detail::incref_dtype(dt), 0))); +} + +ndarray array(python::object const & obj) +{ + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), NULL, 0, 0, NPY_ARRAY_ENSUREARRAY, NULL))); +} + +ndarray array(python::object const & obj, dtype const & dt) +{ + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), detail::incref_dtype(dt), 0, 0, NPY_ARRAY_ENSUREARRAY, NULL))); +} + +ndarray from_object(python::object const & obj, dtype const & dt, int nd_min, int nd_max, ndarray::bitflag flags) +{ + int requirements = detail::bitflag_to_numpy(flags); + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), + detail::incref_dtype(dt), + nd_min, nd_max, + requirements, + NULL))); +} + +ndarray from_object(python::object const & obj, int nd_min, int nd_max, ndarray::bitflag flags) +{ + int requirements = detail::bitflag_to_numpy(flags); + return ndarray(python::detail::new_reference + (PyArray_FromAny(obj.ptr(), + NULL, + nd_min, nd_max, + requirements, + NULL))); +} + +}}} // namespace boost::python::numpy diff --git a/src/numpy/numpy.cpp b/src/numpy/numpy.cpp new file mode 100644 index 0000000000..3ae2295e39 --- /dev/null +++ b/src/numpy/numpy.cpp @@ -0,0 +1,34 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_PYTHON_NUMPY_INTERNAL_MAIN +#include +#include + +namespace boost { namespace python { namespace numpy { + +#if PY_MAJOR_VERSION == 2 +static void wrap_import_array() +{ + import_array(); +} +#else +static void * wrap_import_array() +{ + import_array(); + return NULL; +} +#endif + +void initialize(bool register_scalar_converters) +{ + wrap_import_array(); + import_ufunc(); + if (register_scalar_converters) + dtype::register_scalar_converters(); +} + +}}} // namespace boost::python::numpy diff --git a/src/numpy/scalars.cpp b/src/numpy/scalars.cpp new file mode 100644 index 0000000000..3947c06f2c --- /dev/null +++ b/src/numpy/scalars.cpp @@ -0,0 +1,36 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include + +namespace boost { namespace python { +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyVoidArrType_Type, numpy::void_) +} // namespace boost::python::converter + +namespace numpy +{ + +void_::void_(Py_ssize_t size) + : object(python::detail::new_reference + (PyObject_CallFunction((PyObject*)&PyVoidArrType_Type, const_cast("i"), size))) +{} + +void_ void_::view(dtype const & dt) const +{ + return void_(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("view"), const_cast("O"), dt.ptr()))); +} + +void_ void_::copy() const +{ + return void_(python::detail::new_reference + (PyObject_CallMethod(this->ptr(), const_cast("copy"), const_cast("")))); +} + +}}} // namespace boost::python::numpy diff --git a/src/numpy/ufunc.cpp b/src/numpy/ufunc.cpp new file mode 100644 index 0000000000..173d7213ec --- /dev/null +++ b/src/numpy/ufunc.cpp @@ -0,0 +1,65 @@ +// Copyright Jim Bosch 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_PYTHON_NUMPY_INTERNAL +#include +#include + +namespace boost { namespace python { +namespace converter +{ +NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayMultiIter_Type, numpy::multi_iter) +} // namespace boost::python::converter + +namespace numpy +{ + +multi_iter make_multi_iter(object const & a1) +{ + return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(1, a1.ptr()))); +} + + multi_iter make_multi_iter(object const & a1, object const & a2) +{ + return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(2, a1.ptr(), a2.ptr()))); +} + +multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3) +{ + return multi_iter(python::detail::new_reference(PyArray_MultiIterNew(3, a1.ptr(), a2.ptr(), a3.ptr()))); +} + +void multi_iter::next() +{ + PyArray_MultiIter_NEXT(ptr()); +} + +bool multi_iter::not_done() const +{ + return PyArray_MultiIter_NOTDONE(ptr()); +} + +char * multi_iter::get_data(int i) const +{ + return reinterpret_cast(PyArray_MultiIter_DATA(ptr(), i)); +} + +int multi_iter::get_nd() const +{ + return reinterpret_cast(ptr())->nd; +} + +Py_intptr_t const * multi_iter::get_shape() const +{ + return reinterpret_cast(ptr())->dimensions; +} + +Py_intptr_t multi_iter::shape(int n) const +{ + return reinterpret_cast(ptr())->dimensions[n]; +} + +}}} // namespace boost::python::numpy diff --git a/src/object/class.cpp b/src/object/class.cpp index aeef688e28..e03d4e009a 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -5,6 +5,7 @@ #include #include // #including this first is an intel6 workaround +#include #include #include @@ -208,7 +209,7 @@ namespace objects { if (static_data_object.tp_dict == 0) { - Py_TYPE(&static_data_object) = &PyType_Type; + Py_SET_TYPE(&static_data_object, &PyType_Type); static_data_object.tp_base = &PyProperty_Type; if (PyType_Ready(&static_data_object)) return 0; @@ -316,7 +317,7 @@ namespace objects { if (class_metatype_object.tp_dict == 0) { - Py_TYPE(&class_metatype_object) = &PyType_Type; + Py_SET_TYPE(&class_metatype_object, &PyType_Type); class_metatype_object.tp_base = &PyType_Type; if (PyType_Ready(&class_metatype_object)) return type_handle(); @@ -332,8 +333,9 @@ namespace objects for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) { next = p->next(); + void* q = dynamic_cast(p); p->~instance_holder(); - instance_holder::deallocate(inst, dynamic_cast(p)); + instance_holder::deallocate(inst, q); } // Python 2.2.1 won't add weak references automatically when @@ -374,12 +376,7 @@ namespace objects // like, so we'll store the total size of the object // there. A negative number indicates that the extra // instance memory is not yet allocated to any holders. -#if PY_VERSION_HEX >= 0x02060000 - Py_SIZE(result) = -#else - result->ob_size = -#endif - -(static_cast(offsetof(instance<>,storage) + instance_size)); + Py_SET_SIZE(result,-static_cast(offsetof(instance<>,storage) + instance_size)); } return (PyObject*)result; } @@ -470,7 +467,7 @@ namespace objects { if (class_type_object.tp_dict == 0) { - Py_TYPE(&class_type_object) = incref(class_metatype().get()); + Py_SET_TYPE(&class_type_object, incref(class_metatype().get())); class_type_object.tp_base = &PyBaseObject_Type; if (PyType_Ready(&class_type_object)) return type_handle(); @@ -506,6 +503,16 @@ namespace objects ); } + object qualname(const char *name) + { +#if PY_VERSION_HEX >= 0x03030000 + if (PyObject_HasAttrString(scope().ptr(), "__qualname__")) { + return str("%s.%s" % make_tuple(scope().attr("__qualname__"), name)); + } +#endif + return str(name); + } + namespace { // Find a registered class object corresponding to id. Return a @@ -568,6 +575,9 @@ namespace objects object m = module_prefix(); if (m) d["__module__"] = m; +#if PY_VERSION_HEX >= 0x03030000 + d["__qualname__"] = qualname(name); +#endif if (doc != 0) d["__doc__"] = doc; @@ -618,7 +628,7 @@ namespace objects { object property( (python::detail::new_reference) - PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast("Osss"), fget.ptr(), 0, 0, docstr)); + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast("Osss"), fget.ptr(), (char*)NULL, (char*)NULL, docstr)); this->setattr(name, property); } @@ -628,7 +638,7 @@ namespace objects { object property( (python::detail::new_reference) - PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast("OOss"), fget.ptr(), fset.ptr(), 0, docstr)); + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast("OOss"), fget.ptr(), fset.ptr(), (char*)NULL, docstr)); this->setattr(name, property); } @@ -726,28 +736,46 @@ namespace objects } // namespace objects -void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) +typedef unsigned int alignment_marker_t; + +void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size, std::size_t alignment) { assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); objects::instance<>* self = (objects::instance<>*)self_; - int total_size_needed = holder_offset + holder_size; + int total_size_needed = holder_offset + holder_size + alignment - 1; if (-Py_SIZE(self) >= total_size_needed) { // holder_offset should at least point into the variable-sized part assert(holder_offset >= offsetof(objects::instance<>,storage)); + size_t allocated = holder_size + alignment; + void* storage = (char*)self + holder_offset; + void* aligned_storage = ::boost::alignment::align(alignment, holder_size, storage, allocated); + // Record the fact that the storage is occupied, noting where it starts - Py_SIZE(self) = holder_offset; - return (char*)self + holder_offset; + const size_t offset = reinterpret_cast(aligned_storage) - reinterpret_cast(storage) + holder_offset; + Py_SET_SIZE(self, offset); + return (char*)self + offset; } else { - void* const result = PyMem_Malloc(holder_size); - if (result == 0) + const size_t base_allocation = sizeof(alignment_marker_t) + holder_size + alignment - 1; + void* const base_storage = PyMem_Malloc(base_allocation); + if (base_storage == 0) throw std::bad_alloc(); - return result; + + const uintptr_t x = reinterpret_cast(base_storage) + sizeof(alignment_marker_t); + // Padding required to align the start of a data structure is: (alignment - (x % alignment)) % alignment + // Since the alignment is a power of two, the formula can be simplified with bitwise AND operator as follow: + const uintptr_t padding = (alignment - (x & (alignment - 1))) & (alignment - 1); + const size_t aligned_offset = sizeof(alignment_marker_t) + padding; + void* const aligned_storage = (char *)base_storage + aligned_offset; + BOOST_ASSERT((char *) aligned_storage + holder_size <= (char *)base_storage + base_allocation); + alignment_marker_t* const marker_storage = reinterpret_cast((char *)aligned_storage - sizeof(alignment_marker_t)); + *marker_storage = static_cast(padding); + return aligned_storage; } } @@ -757,7 +785,9 @@ void instance_holder::deallocate(PyObject* self_, void* storage) throw() objects::instance<>* self = (objects::instance<>*)self_; if (storage != (char*)self + Py_SIZE(self)) { - PyMem_Free(storage); + alignment_marker_t* marker_storage = reinterpret_cast((char *)storage - sizeof(alignment_marker_t)); + void *malloced_storage = (char *) storage - sizeof(alignment_marker_t) - (*marker_storage); + PyMem_Free(malloced_storage); } } diff --git a/src/object/enum.cpp b/src/object/enum.cpp index 3063320cb0..94df8e4aea 100644 --- a/src/object/enum.cpp +++ b/src/object/enum.cpp @@ -34,16 +34,24 @@ static PyMemberDef enum_members[] = { extern "C" { + static void + enum_dealloc(enum_object* self) + { + Py_XDECREF(self->name); + Py_TYPE(self)->tp_free((PyObject*)self); + } + static PyObject* enum_repr(PyObject* self_) { - // XXX(bhy) Potentional memory leak here since PyObject_GetAttrString returns a new reference - // const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast("__module__"))); PyObject *mod = PyObject_GetAttrString( self_, "__module__"); + object auto_free = object(handle<>(mod)); enum_object* self = downcast(self_); if (!self->name) { return -#if PY_VERSION_HEX >= 0x03000000 +#if PY_VERSION_HEX >= 0x03030000 + PyUnicode_FromFormat("%S.%S(%ld)", mod, ((PyHeapTypeObject*)(self_->ob_type))->ht_qualname, PyLong_AsLong(self_)); +#elif PY_VERSION_HEX >= 0x03000000 PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_)); #else PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_)); @@ -56,7 +64,9 @@ extern "C" return 0; return -#if PY_VERSION_HEX >= 0x03000000 +#if PY_VERSION_HEX >= 0x03030000 + PyUnicode_FromFormat("%S.%S.%S", mod, ((PyHeapTypeObject*)(self_->ob_type))->ht_qualname, name); +#elif PY_VERSION_HEX >= 0x03000000 PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name); #else PyString_FromFormat("%s.%s.%s", @@ -88,7 +98,7 @@ static PyTypeObject enum_type_object = { const_cast("Boost.Python.enum"), sizeof(enum_object), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + (destructor) enum_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -107,7 +117,6 @@ static PyTypeObject enum_type_object = { #if PY_VERSION_HEX < 0x03000000 | Py_TPFLAGS_CHECKTYPES #endif - | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ @@ -140,6 +149,7 @@ static PyTypeObject enum_type_object = { }; object module_prefix(); +object qualname(const char *name); namespace { @@ -147,7 +157,7 @@ namespace { if (enum_type_object.tp_dict == 0) { - Py_TYPE(&enum_type_object) = incref(&PyType_Type); + Py_SET_TYPE(&enum_type_object, incref(&PyType_Type)); #if PY_VERSION_HEX >= 0x03000000 enum_type_object.tp_base = &PyLong_Type; #else @@ -170,6 +180,11 @@ namespace object module_name = module_prefix(); if (module_name) d["__module__"] = module_name; +#if PY_VERSION_HEX >= 0x03030000 + object q = qualname(name); + if (q) + d["__qualname__"] = q; +#endif if (doc) d["__doc__"] = doc; diff --git a/src/object/function.cpp b/src/object/function.cpp index 5c59cc7798..fec56768da 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -107,7 +107,7 @@ function::function( PyObject* p = this; if (Py_TYPE(&function_type) == 0) { - Py_TYPE(&function_type) = &PyType_Type; + Py_SET_TYPE(&function_type, &PyType_Type); ::PyType_Ready(&function_type); } @@ -158,15 +158,9 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const { // no argument preprocessing } - else if (n_actual > max_arity) - { - // too many arguments - inner_args = handle<>(); - } else { // build a new arg tuple, will adjust its size later - assert(max_arity <= static_cast(ssize_t_max)); inner_args = handle<>( PyTuple_New(static_cast(max_arity))); @@ -424,6 +418,30 @@ namespace detail extern char cpp_signature_tag[]; } +object const& function::add_doc(object const& attribute, char const* doc) +{ + str _doc; + + if (docstring_options::show_py_signatures_) + { + _doc += str(const_cast(detail::py_signature_tag)); + } + if (doc != 0 && docstring_options::show_user_defined_) + _doc += doc; + + if (docstring_options::show_cpp_signatures_) + { + _doc += str(const_cast(detail::cpp_signature_tag)); + } + if(_doc) + { + object mutable_attribute(attribute); + mutable_attribute.attr("__doc__")= _doc; + } + + return attribute; +} + void function::add_to_namespace( object const& name_space, char const* name_, object const& attribute, char const* doc) { @@ -449,7 +467,9 @@ void function::add_to_namespace( if (dict == 0) throw_error_already_set(); + assert(!PyErr_Occurred()); handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr()))); + PyErr_Clear(); if (existing) { @@ -490,16 +510,28 @@ void function::add_to_namespace( if (new_func->name().is_none()) new_func->m_name = name; + assert(!PyErr_Occurred()); handle<> name_space_name( - allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast("__name__")))); + allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast( +#if PY_VERSION_HEX < 0x03030000 + "__name__" +#else + "__qualname__" +#endif + )))); + PyErr_Clear(); if (name_space_name) new_func->m_namespace = object(name_space_name); + + object module_name( + PyObject_IsInstance(name_space.ptr(), upcast(&PyModule_Type)) + ? object(name_space.attr("__name__")) + : api::getattr(name_space, "__module__", str()) + ); + new_func->m_module = module_name; } - // The PyObject_GetAttrString() or PyObject_GetItem calls above may - // have left an active error - PyErr_Clear(); if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0) throw_error_already_set(); @@ -536,24 +568,7 @@ void function::add_to_namespace( "C++ signature:", f->signature(true))); } */ - str _doc; - - if (docstring_options::show_py_signatures_) - { - _doc += str(const_cast(detail::py_signature_tag)); - } - if (doc != 0 && docstring_options::show_user_defined_) - _doc += doc; - - if (docstring_options::show_cpp_signatures_) - { - _doc += str(const_cast(detail::cpp_signature_tag)); - } - if(_doc) - { - object mutable_attribute(attribute); - mutable_attribute.attr("__doc__")= _doc; - } + add_doc(attribute, doc); } BOOST_PYTHON_DECL void add_to_namespace( @@ -568,6 +583,18 @@ BOOST_PYTHON_DECL void add_to_namespace( function::add_to_namespace(name_space, name, attribute, doc); } +BOOST_PYTHON_DECL object const& add_doc(object const& attribute, char const* doc) +{ +#if PY_VERSION_HEX >= 0x03000000 + if (PyInstanceMethod_Check(attribute.ptr())) { +#else + if (PyMethod_Check(attribute.ptr())) { +#endif + return attribute; + } + return function::add_doc(attribute, doc); +} + namespace { @@ -674,7 +701,7 @@ extern "C" static PyObject* function_get_module(PyObject* op, void*) { function* f = downcast(op); - object const& ns = f->get_namespace(); + object const& ns = f->get_module(); if (!ns.is_none()) { return python::incref(ns.ptr()); } diff --git a/src/object/function_doc_signature.cpp b/src/object/function_doc_signature.cpp index 41695285ac..18d458698d 100644 --- a/src/object/function_doc_signature.cpp +++ b/src/object/function_doc_signature.cpp @@ -114,23 +114,47 @@ namespace boost { namespace python { namespace objects { return res; } - const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s) + static str get_qualname(const PyTypeObject *py_type) + { +# if PY_VERSION_HEX >= 0x03030000 + if ( py_type->tp_flags & Py_TPFLAGS_HEAPTYPE ) + return str(handle<>(borrowed(((PyHeapTypeObject*)(py_type))->ht_qualname))); +# endif + return str(py_type->tp_name); + } + + str function_doc_signature_generator::py_type_str(const python::detail::signature_element &s, const object ¤t_module_name) { if (s.basename==std::string("void")){ static const char * none = "None"; - return none; + return str(none); } PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0; - if ( py_type ) - return py_type->tp_name; - else{ + if ( py_type ) { + str name(get_qualname(py_type)); + if ( py_type->tp_flags & Py_TPFLAGS_HEAPTYPE ) { + // Qualify the type name if it is defined in a different module. + PyObject *type_module_name = PyDict_GetItemString(py_type->tp_dict, "__module__"); + if ( + type_module_name + && PyObject_RichCompareBool( + type_module_name, + current_module_name.ptr(), + Py_NE + ) != 0 + ) { + return str("%s.%s" % make_tuple(handle<>(borrowed(type_module_name)), name)); + } + } + return name; + } else { static const char * object = "object"; - return object; + return str(object); } } - str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types) + str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, const object& current_module_name, bool cpp_types) { str param; @@ -156,12 +180,12 @@ namespace boost { namespace python { namespace objects { { object kv; if ( arg_names && (kv = arg_names[n-1]) ) - param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) ); + param = str( " (%s)%s" % make_tuple(py_type_str(s[n], current_module_name),kv[0]) ); else - param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) ); + param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n], current_module_name),"arg", n) ); } else //we are processing the return type - param = py_type_str(f.get_return_type()); + param = py_type_str(f.get_return_type(), current_module_name); } //an argument - check for default value and append it @@ -199,7 +223,7 @@ namespace boost { namespace python { namespace objects { str param; formal_params.append( - parameter_string(impl, n, f->m_arg_names, cpp_types) + parameter_string(impl, n, f->m_arg_names, f->get_module(), cpp_types) ); // find all the arguments with default values preceeding the arity-n_overloads diff --git a/src/object/inheritance.cpp b/src/object/inheritance.cpp index 7dc9db1cd7..a7b3156e41 100644 --- a/src/object/inheritance.cpp +++ b/src/object/inheritance.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -184,6 +184,7 @@ namespace // map a type to a position in the index inline type_index_t::iterator type_position(class_id type) { + using namespace boost::placeholders; typedef index_entry entry; return std::lower_bound( diff --git a/src/object/iterator.cpp b/src/object/iterator.cpp index 3f6c4adacd..6b885a982c 100644 --- a/src/object/iterator.cpp +++ b/src/object/iterator.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include namespace boost { namespace python { namespace objects { diff --git a/src/object/life_support.cpp b/src/object/life_support.cpp index b7e9aa861e..281c3bffc5 100644 --- a/src/object/life_support.cpp +++ b/src/object/life_support.cpp @@ -93,7 +93,7 @@ PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) if (Py_TYPE(&life_support_type) == 0) { - Py_TYPE(&life_support_type) = &PyType_Type; + Py_SET_TYPE(&life_support_type, &PyType_Type); PyType_Ready(&life_support_type); } diff --git a/src/slice.cpp b/src/slice.cpp index ee55f94846..5ff56185de 100644 --- a/src/slice.cpp +++ b/src/slice.cpp @@ -34,4 +34,14 @@ slice_base::step() const ((PySliceObject*)this->ptr())->step)); } +static struct register_slice_pytype_ptr +{ + register_slice_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PySlice_Type; + } +}register_slice_pytype_ptr_; + } } } // !namespace boost::python::detail diff --git a/src/str.cpp b/src/str.cpp index 0bc225aa22..5122f7f57f 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -162,6 +162,22 @@ bool str_base::endswith(object_cref suffix) const return result; } +bool str_base::endswith(object_cref suffix, object_cref start) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix,start).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + +bool str_base::endswith(object_cref suffix, object_cref start, object_cref end) const +{ + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix,start,end).ptr()); + if (PyErr_Occurred()) + throw_error_already_set(); + return result; +} + BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 0) BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 1) diff --git a/src/wrapper.cpp b/src/wrapper.cpp old mode 100755 new mode 100644 index f8feaef947..8b1b884769 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -25,7 +25,7 @@ namespace detail if ( PyMethod_Check(m.get()) - && ((PyMethodObject*)m.get())->im_self == this->m_self + && PyMethod_GET_SELF(m.get()) == this->m_self && class_object->tp_dict != 0 ) { @@ -34,7 +34,7 @@ namespace detail } - if (borrowed_f != ((PyMethodObject*)m.get())->im_func) + if (borrowed_f != PyMethod_GET_FUNCTION(m.get())) return override(m); } } diff --git a/test/Jamfile.v2 b/test/Jamfile similarity index 76% rename from test/Jamfile.v2 rename to test/Jamfile index 5524188003..40115d86cb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile @@ -2,13 +2,16 @@ # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +require-b2 5.0.1 ; +import-search /boost/config/checks ; + import python ; import os ; +import config : requires ; lib socket ; -use-project /boost/python : ../build ; -project /boost/python/test +project : requirements gcc:-Wextra qnxnto:socket @@ -27,7 +30,7 @@ rule py-run ( sources * : input-file ? ) : $(input-file) : #requirements BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION - + ] ; } @@ -49,6 +52,20 @@ rule require-windows ( properties * ) } } +if [ python.configured ] +{ +alias base_deps : usage-requirements + /boost/align//boost_align + /boost/assert//boost_assert + /boost/config//boost_config + /boost/core//boost_core + /boost/detail//boost_detail + /boost/function//boost_function + /boost/mpl//boost_mpl + /boost/preprocessor//boost_preprocessor + /boost/static_assert//boost_static_assert + /boost/type_traits//boost_type_traits + ; test-suite python : @@ -85,33 +102,40 @@ bpl-test crossmod_exception [ bpl-test properties ] [ bpl-test return_arg ] [ bpl-test staticmethod ] -[ bpl-test shared_ptr ] +[ bpl-test boost_shared_ptr ] +[ bpl-test shared_ptr + : # sources + : [ requires cxx11_smart_ptr ] +] [ bpl-test enable_shared_from_this ] [ bpl-test andreas_beyer ] [ bpl-test wrapper_held_type ] -[ bpl-test polymorphism2_auto_ptr - : polymorphism2_auto_ptr.py polymorphism2.py polymorphism2_auto_ptr.cpp +[ bpl-test polymorphism2_auto_ptr + : polymorphism2_auto_ptr.py polymorphism2.py polymorphism2_auto_ptr.cpp + : [ requires auto_ptr ] ] [ bpl-test polymorphism ] [ bpl-test polymorphism2 ] -[ bpl-test auto_ptr ] +[ bpl-test auto_ptr + : # files + : [ requires auto_ptr ] +] [ bpl-test minimal ] [ bpl-test args ] [ bpl-test raw_ctor ] -[ bpl-test numpy : printer.py numeric_tests.py numarray_tests.py numpy.py numpy.cpp ] -[ bpl-test enum ] +[ bpl-test enum : test_enum.py enum_ext.cpp ] [ bpl-test exception_translator ] [ bpl-test pearu1 : test_cltree.py cltree.cpp ] [ bpl-test try : newtest.py m1.cpp m2.cpp ] [ bpl-test const_argument ] [ bpl-test keywords : keywords.cpp keywords_test.py ] - -[ python-extension builtin_converters_ext : test_builtin_converters.cpp /boost/python//boost_python ] + +[ python-extension builtin_converters_ext : builtin_converters.cpp /boost/python//boost_python ] [ bpl-test builtin_converters : test_builtin_converters.py builtin_converters_ext ] [ bpl-test test_pointer_adoption ] @@ -122,6 +146,7 @@ bpl-test crossmod_exception [ bpl-test object ] [ bpl-test class ] +[ bpl-test aligned_class ] [ bpl-test list ] [ bpl-test long ] [ bpl-test dict ] @@ -181,13 +206,13 @@ bpl-test crossmod_opaque # Whenever the cause for the failure of the polymorphism test is found # and fixed, this should be retested. hp_cxx:no ] - + [ python-extension map_indexing_suite_ext : map_indexing_suite.cpp int_map_indexing_suite.cpp a_map_indexing_suite.cpp /boost/python//boost_python ] -[ bpl-test +[ bpl-test map_indexing_suite : map_indexing_suite.py map_indexing_suite_ext ] - + [ run import_.cpp /boost/python//boost_python $(PY) : : import_.py ] # if $(TEST_BIENSTMAN_NON_BUGS) @@ -201,28 +226,29 @@ bpl-test crossmod_opaque # --- unit tests of library components --- -[ compile indirect_traits_test.cpp ] -[ run destroy_test.cpp ] +[ compile indirect_traits_test.cpp : base_deps ] +[ run destroy_test.cpp : : : base_deps ] [ py-run pointer_type_id_test.cpp ] [ py-run bases.cpp ] -[ run if_else.cpp ] +[ run if_else.cpp : : : base_deps ] [ py-run pointee.cpp ] -[ run result.cpp ] +[ run result.cpp : : : base_deps ] -[ compile string_literal.cpp ] +[ compile string_literal.cpp : base_deps ] [ py-compile borrowed.cpp ] [ py-compile object_manager.cpp ] [ py-compile copy_ctor_mutates_rhs.cpp ] [ py-run upcast.cpp ] - + [ py-compile select_holder.cpp ] - -[ run select_from_python_test.cpp ../src/converter/type_id.cpp - : + +[ run select_from_python_test.cpp ../src/converter/type_id.cpp + : : : BOOST_PYTHON_STATIC_LIB $(PY) + base_deps ] @@ -233,4 +259,15 @@ bpl-test crossmod_opaque [ py-compile-fail ./as_to_python_function.cpp ] [ py-compile-fail ./object_fail1.cpp ] +# --- NumPy tests --- + +[ numpy-test numpy/dtype ] +[ numpy-test numpy/ufunc ] +[ numpy-test numpy/templates ] +[ numpy-test numpy/ndarray ] +[ numpy-test numpy/indexing ] +[ numpy-test numpy/shapes ] + + ; +} diff --git a/test/aligned_class.cpp b/test/aligned_class.cpp new file mode 100644 index 0000000000..55f0fa3c70 --- /dev/null +++ b/test/aligned_class.cpp @@ -0,0 +1,33 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include +#include +#include +#include + +using namespace boost::python; + +struct BOOST_ALIGNMENT(32) X +{ + int x; + BOOST_ALIGNMENT(32) float f; + X(int n, float _f) : x(n), f(_f) + { + BOOST_ASSERT((reinterpret_cast(&f) % 32) == 0); + } +}; + +int x_function(X& x) { return x.x;} +float f_function(X& x) { return x.f;} + +BOOST_PYTHON_MODULE(aligned_class_ext) +{ + class_("X", init()); + def("x_function", x_function); + def("f_function", f_function); +} + +#include "module_tail.cpp" diff --git a/test/aligned_class.py b/test/aligned_class.py new file mode 100755 index 0000000000..eb27ac1e96 --- /dev/null +++ b/test/aligned_class.py @@ -0,0 +1,44 @@ +# Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from aligned_class_ext import * + +Ensure sanity: + + >>> x = X(42, 16) + >>> x_function(x) + 42 + >>> f_function(x) + 16.0 + +Demonstrate extraction in the presence of metaclass changes: + + >>> class MetaX(X.__class__): + ... def __new__(cls, *args): + ... return super(MetaX, cls).__new__(cls, *args) + >>> class XPlusMetatype(X): + ... __metaclass__ = MetaX + >>> x = XPlusMetatype(42, 16) + >>> x_function(x) + 42 + >>> f_function(x) + 16.0 + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/test/andreas_beyer.py b/test/andreas_beyer.py index 84a54fbd9f..0c24969bd5 100644 --- a/test/andreas_beyer.py +++ b/test/andreas_beyer.py @@ -17,8 +17,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/args.py b/test/args.py index 44a9cd2529..5d89921467 100644 --- a/test/args.py +++ b/test/args.py @@ -4,11 +4,16 @@ """ >>> from args_ext import * ->>> raw(3, 4, foo = 'bar', baz = 42) -((3, 4), {'foo': 'bar', 'baz': 42}) +>>> args, kwargs = raw(3, 4, foo = 'bar', baz = 42) +>>> args +(3, 4) +>>> kwargs['foo'] +'bar' +>>> kwargs['baz'] +42 Prove that we can handle empty keywords and non-keywords - + >>> raw(3, 4) ((3, 4), {}) @@ -26,7 +31,7 @@ >>> try: f(1, 2, 'hello', bar = 'baz') ... except TypeError: pass -... else: print 'expected an exception: unknown keyword' +... else: print('expected an exception: unknown keyword') Exercise the functions using default stubs @@ -72,10 +77,10 @@ >>> try: q.f(1, 2, 'hello', bar = 'baz') ... except TypeError: pass -... else: print 'expected an exception: unknown keyword' +... else: print('expected an exception: unknown keyword') Exercise member functions using default stubs - + >>> q.f1(z = 'nix', y = .125, x = 2) (2, 0.125, 'nix') >>> q.f1(y = .125, x = 2) @@ -95,10 +100,10 @@ >>> xfuncs = (X.inner0, X.inner1, X.inner2, X.inner3, X.inner4, X.inner5) >>> for f in xfuncs: -... print f(q,1).value(), -... print f(q, n = 1).value(), -... print f(q, n = 0).value(), -... print f.__doc__.splitlines()[1:5] +... print(f(q,1).value(), end=' ') +... print(f(q, n = 1).value(), end=' ') +... print(f(q, n = 0).value(), end=' ') +... print(f.__doc__.splitlines()[1:5]) 1 1 0 ['inner0( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] 1 1 0 ['inner1( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] 1 1 0 ['inner2( (X)self, (bool)n) -> Y :', ' docstring', '', ' C++ signature :'] @@ -122,10 +127,16 @@ 1 >>> y = Y(value = 33) ->>> y.raw(this = 1, that = 'the other')[1] -{'this': 1, 'that': 'the other'} +>>> _, kwargs = y.raw(this = 1, that = 'the other') +>>> kwargs['this'] +1 +>>> kwargs['that'] +'the other' """ + +from __future__ import print_function + def run(args = None): import sys import doctest @@ -135,13 +146,10 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") import args_ext help(args_ext) sys.exit(status) - - - diff --git a/test/auto_ptr.py b/test/auto_ptr.py index 2e4bed61df..12e977d062 100644 --- a/test/auto_ptr.py +++ b/test/auto_ptr.py @@ -28,7 +28,7 @@ >>> if not broken_auto_ptr: ... try: x.value() ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> x = make() >>> look(x) @@ -51,7 +51,7 @@ >>> try: maybe_steal(y, 0) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> y.value() 42 @@ -62,24 +62,24 @@ >>> if not broken_auto_ptr: ... try: y.value() ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') ->>> print look.__doc__.splitlines()[1] +>>> print(look.__doc__.splitlines()[1]) look( (X)arg1) -> int : ->>> print steal.__doc__.splitlines()[1] +>>> print(steal.__doc__.splitlines()[1]) steal( (X)arg1) -> int : ->>> print maybe_steal.__doc__.splitlines()[1] +>>> print(maybe_steal.__doc__.splitlines()[1]) maybe_steal( (X)arg1, (bool)arg2) -> int : ->>> print make.__doc__.splitlines()[1] +>>> print(make.__doc__.splitlines()[1]) make() -> X : ->>> print callback.__doc__.splitlines()[1] +>>> print(callback.__doc__.splitlines()[1]) callback( (object)arg1) -> X : ->>> print extract.__doc__.splitlines()[1] +>>> print(extract.__doc__.splitlines()[1]) extract( (object)arg1) -> X : ''' @@ -93,8 +93,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/back_reference.cpp b/test/back_reference.cpp index 266ed29125..11e47b3321 100644 --- a/test/back_reference.cpp +++ b/test/back_reference.cpp @@ -99,7 +99,7 @@ BOOST_PYTHON_MODULE(back_reference_ext) .def("set", &Y::set) ; - class_ >("Z", init()) + class_ >("Z", init()) .def("value", &Z::value) .def("set", &Z::set) ; diff --git a/test/back_reference.py b/test/back_reference.py index 6705ee7b79..4a283a3e3e 100644 --- a/test/back_reference.py +++ b/test/back_reference.py @@ -17,7 +17,7 @@ >>> y_equality(y, y) 1 ->>> print y_identity.__doc__.splitlines()[1] +>>> print(y_identity.__doc__.splitlines()[1]) y_identity( (Y)arg1) -> object : ''' @@ -30,8 +30,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/bases.cpp b/test/bases.cpp index 84beb06129..4e00f5448a 100644 --- a/test/bases.cpp +++ b/test/bases.cpp @@ -4,7 +4,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #include #include -#include +#include struct A; struct B; @@ -42,8 +42,8 @@ int main() int , boost::python::detail::select_bases::type > collected1; - BOOST_STATIC_ASSERT((boost::is_same >::value)); - BOOST_STATIC_ASSERT((boost::is_same::type,boost::python::bases<> >::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same >::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::type,boost::python::bases<> >::value)); typedef boost::python::detail::select_bases< int @@ -55,8 +55,8 @@ int main() >::type > collected2; - BOOST_STATIC_ASSERT((boost::is_same >::value)); - BOOST_STATIC_ASSERT((boost::is_same,long>::type,boost::python::bases >::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same >::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same,long>::type,boost::python::bases >::value)); return 0; } diff --git a/test/bienstman1.py b/test/bienstman1.py index 06f0fff8ce..16dc47b2d1 100644 --- a/test/bienstman1.py +++ b/test/bienstman1.py @@ -16,8 +16,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/bienstman2.py b/test/bienstman2.py index 359987d198..931fae8f74 100644 --- a/test/bienstman2.py +++ b/test/bienstman2.py @@ -13,8 +13,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/bienstman3.py b/test/bienstman3.py index 4f3e871148..d0d250aea9 100644 --- a/test/bienstman3.py +++ b/test/bienstman3.py @@ -6,10 +6,10 @@ >>> try: ... V() -... except RuntimeError, x: -... print x +... except RuntimeError as x: +... print(x) ... else: -... print 'expected an exception' +... print('expected an exception') ... This class cannot be instantiated from Python @@ -23,8 +23,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/bienstman4.py b/test/bienstman4.py index e2a5b0659e..eea33ba2a8 100644 --- a/test/bienstman4.py +++ b/test/bienstman4.py @@ -16,8 +16,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/bienstman5.py b/test/bienstman5.py index 59a9bc93f1..a6735d9422 100644 --- a/test/bienstman5.py +++ b/test/bienstman5.py @@ -14,8 +14,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/class.cpp b/test/boost_shared_ptr.cpp similarity index 50% rename from class.cpp rename to test/boost_shared_ptr.cpp index 078bebdf64..57e50aa3c1 100644 --- a/class.cpp +++ b/test/boost_shared_ptr.cpp @@ -1,28 +1,20 @@ +// Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) + #include -#include -#include #include +#include +#include +#include +#include +#include -using namespace boost::python; - -struct X -{ - int x; - X(int n) : x(n) { } -}; - -int x_function(X& x) -{ return x.x; -} - - -BOOST_PYTHON_MODULE(class_ext) -{ - class_("X", init()); - def("x_function", x_function); -} +using boost::shared_ptr; +#define MODULE boost_shared_ptr_ext +#include "shared_ptr.hpp" #include "module_tail.cpp" + diff --git a/test/boost_shared_ptr.py b/test/boost_shared_ptr.py new file mode 100644 index 0000000000..31a2ad3d25 --- /dev/null +++ b/test/boost_shared_ptr.py @@ -0,0 +1,130 @@ +# Copyright David Abrahams 2004. Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from boost_shared_ptr_ext import * + + Test that shared_ptr can be converted to shared_ptr + +>>> Y.store(YYY(42)) + +>>> x = X(17) +>>> null_x = null(x) +>>> null_x # should be None +>>> identity(null_x) # should also be None + +>>> a = New(1) +>>> A.call_f(a) +1 +>>> New(0) + +>>> type(factory(3)) + +>>> type(factory(42)) + + +>>> class P(Z): +... def v(self): +... return -Z.v(self); +... def __del__(self): +... print('bye') +... +>>> p = P(12) +>>> p.value() +12 +>>> p.v() +-12 +>>> look(p) +12 +>>> try: modify(p) +... except TypeError: pass +... else: 'print(expected a TypeError)' +>>> look(None) +-1 +>>> store(p) +>>> del p +>>> Z.get().v() +-12 +>>> Z.count() +1 +>>> Z.look_store() +12 +>>> Z.release() +bye +>>> Z.count() +0 + +>>> z = Z(13) +>>> z.value() +13 +>>> z.v() +13 +>>> try: modify(z) +... except TypeError: pass +... else: 'print(expected a TypeError)' + +>>> Z.get() # should be None +>>> store(z) +>>> assert Z.get() is z # show that deleter introspection works +>>> del z +>>> Z.get().value() +13 +>>> Z.count() +1 +>>> Z.look_store() +13 +>>> Z.release() +>>> Z.count() +0 + +>>> x = X(17) +>>> x.value() +17 +>>> look(x) +17 +>>> try: modify(x) +... except TypeError: pass +... else: 'print(expected a TypeError)' +>>> look(None) +-1 +>>> store(x) +>>> del x +>>> X.count() +1 +>>> X.look_store() +17 +>>> X.release() +>>> X.count() +0 + + +>>> y = Y(19) +>>> y.value() +19 +>>> modify(y) +>>> look(y) +-1 +>>> store(Y(23)) +>>> Y.count() +1 +>>> Y.look_store() +23 +>>> Y.release() +>>> Y.count() +0 +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) diff --git a/test/borrowed.cpp b/test/borrowed.cpp old mode 100755 new mode 100644 diff --git a/test/test_builtin_converters.cpp b/test/builtin_converters.cpp similarity index 100% rename from test/test_builtin_converters.cpp rename to test/builtin_converters.cpp diff --git a/test/callbacks.py b/test/callbacks.py index 640eb1551a..cf876a89d5 100644 --- a/test/callbacks.py +++ b/test/callbacks.py @@ -19,11 +19,11 @@ >>> try: apply_to_string_literal(identity) ... except ReferenceError: pass # expected -... else: print 'expected an exception!' +... else: print('expected an exception!') >>> try: apply_X_ref_handle(lambda ignored:X(42), None) ... except ReferenceError: pass # expected -... else: print 'expected an exception!' +... else: print('expected an exception!') >>> x = X(42) >>> x.y = X(7) @@ -104,15 +104,15 @@ ... >>> try: apply_X_ref_handle(new_x, 1) ... except ReferenceError: pass -... else: print 'no error' +... else: print('no error') >>> try: apply_X_ptr_handle_cref(new_x, 1) ... except ReferenceError: pass -... else: print 'no error' +... else: print('no error') >>> try: apply_cstring_cstring(identity, 'hello') ... except ReferenceError: pass -... else: print 'no error' +... else: print('no error') >>> apply_char_char(identity, 'x') 'x' @@ -140,8 +140,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/calling_conventions.cpp b/test/calling_conventions.cpp index 54f49aebc3..c1c2b5a411 100644 --- a/test/calling_conventions.cpp +++ b/test/calling_conventions.cpp @@ -17,9 +17,11 @@ //------------------------------------------------------------------------------ // this section is the main body of the test extension module -#define BOOST_PYTHON_ENABLE_CDECL -#define BOOST_PYTHON_ENABLE_STDCALL -#define BOOST_PYTHON_ENABLE_FASTCALL +#if defined(_WIN32) && !defined(_WIN64) +# define BOOST_PYTHON_ENABLE_CDECL +# define BOOST_PYTHON_ENABLE_STDCALL +# define BOOST_PYTHON_ENABLE_FASTCALL +#endif #include #include #include diff --git a/test/calling_conventions.py b/test/calling_conventions.py index ce74a84330..c57142448b 100644 --- a/test/calling_conventions.py +++ b/test/calling_conventions.py @@ -74,8 +74,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/calling_conventions_mf.cpp b/test/calling_conventions_mf.cpp index 80ccc4068b..83a97acfef 100644 --- a/test/calling_conventions_mf.cpp +++ b/test/calling_conventions_mf.cpp @@ -17,9 +17,11 @@ //------------------------------------------------------------------------------ // this section is the main body of the test extension module -#define BOOST_PYTHON_ENABLE_CDECL -#define BOOST_PYTHON_ENABLE_STDCALL -#define BOOST_PYTHON_ENABLE_FASTCALL +#if defined(_WIN32) && !defined(_WIN64) +# define BOOST_PYTHON_ENABLE_CDECL +# define BOOST_PYTHON_ENABLE_STDCALL +# define BOOST_PYTHON_ENABLE_FASTCALL +#endif #include #include #include diff --git a/test/calling_conventions_mf.py b/test/calling_conventions_mf.py index 1ec9c2b6cc..7e28484b9b 100644 --- a/test/calling_conventions_mf.py +++ b/test/calling_conventions_mf.py @@ -77,8 +77,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/class.py b/test/class.py old mode 100755 new mode 100644 index d68ff43787..15594a105b --- a/test/class.py +++ b/test/class.py @@ -33,8 +33,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/cltree.cpp b/test/cltree.cpp old mode 100755 new mode 100644 diff --git a/test/const_argument.cpp b/test/const_argument.cpp index 6c5a894563..279c3dc1ae 100644 --- a/test/const_argument.cpp +++ b/test/const_argument.cpp @@ -9,10 +9,8 @@ * compiler's bug. */ #include -#include using namespace boost::python; -BOOST_TT_BROKEN_COMPILER_SPEC( object ) #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) bool accept_const_arg( object ); diff --git a/test/const_argument.py b/test/const_argument.py index 15e87e8024..1d241953b3 100644 --- a/test/const_argument.py +++ b/test/const_argument.py @@ -16,8 +16,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/copy_ctor_mutates_rhs.cpp b/test/copy_ctor_mutates_rhs.cpp old mode 100755 new mode 100644 index 41eac495e4..be52c4f327 --- a/test/copy_ctor_mutates_rhs.cpp +++ b/test/copy_ctor_mutates_rhs.cpp @@ -9,14 +9,13 @@ struct foo { - operator std::auto_ptr&() const; + operator std::shared_ptr&() const; }; int main() { using namespace boost::python::detail; BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs::value); - BOOST_STATIC_ASSERT(copy_ctor_mutates_rhs >::value); BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs::value); BOOST_STATIC_ASSERT(!copy_ctor_mutates_rhs::value); return 0; diff --git a/test/crossmod_exception.py b/test/crossmod_exception.py index dd50dae276..4820f29e96 100644 --- a/test/crossmod_exception.py +++ b/test/crossmod_exception.py @@ -2,7 +2,7 @@ # Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy # at http://www.boost.org/LICENSE_1_0.txt) -print "running..." +print("running...") import crossmod_exception_a import crossmod_exception_b @@ -16,4 +16,4 @@ except IndexError: pass -print "Done." +print("Done.") diff --git a/test/crossmod_exception_a.cpp b/test/crossmod_exception_a.cpp old mode 100755 new mode 100644 diff --git a/test/crossmod_exception_b.cpp b/test/crossmod_exception_b.cpp old mode 100755 new mode 100644 diff --git a/test/crossmod_opaque.py b/test/crossmod_opaque.py index a7a3cf2cba..533ac16fe1 100644 --- a/test/crossmod_opaque.py +++ b/test/crossmod_opaque.py @@ -1,11 +1,11 @@ -# -*- coding: latin-1 -*- -# Copyright Gottfried Gan�auge 2006. +# -*- coding: utf-8 -*- +# Copyright Gottfried Ganßauge 2006. # Distributed under the Boost Software License, Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if __name__ == '__main__': - print "running..." + print("running...") import crossmod_opaque_a import crossmod_opaque_b @@ -13,4 +13,4 @@ crossmod_opaque_a.get() crossmod_opaque_b.get() - print "Done." + print("Done.") diff --git a/test/crossmod_opaque_a.cpp b/test/crossmod_opaque_a.cpp index 80283f47fd..62ed433111 100644 --- a/test/crossmod_opaque_a.cpp +++ b/test/crossmod_opaque_a.cpp @@ -1,4 +1,4 @@ -// Copyright Gottfried Gan�auge 2006. +// Copyright Gottfried Ganßauge 2006. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/test/crossmod_opaque_b.cpp b/test/crossmod_opaque_b.cpp index 1e3e18bcb6..3d661339ce 100644 --- a/test/crossmod_opaque_b.cpp +++ b/test/crossmod_opaque_b.cpp @@ -1,4 +1,4 @@ -// Copyright Gottfried Gan�auge 2006. +// Copyright Gottfried Ganßauge 2006. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/test/data_members.py b/test/data_members.py index 70784853ed..74b655eb56 100644 --- a/test/data_members.py +++ b/test/data_members.py @@ -163,7 +163,7 @@ 42 >>> try: x.x = 77 ... except AttributeError: pass -... else: print 'no error' +... else: print('no error') >>> x.fair_value 42.0 @@ -208,8 +208,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/defaults.py b/test/defaults.py index cd51a4a4d2..cf3cfd38f3 100644 --- a/test/defaults.py +++ b/test/defaults.py @@ -106,19 +106,19 @@ ... doc = obj.__doc__.splitlines() ... return "\\n".join(["|"+doc[i] for i in args]) ->>> print selected_doc(X.__init__, 1, 2, 4, 7, 9) +>>> print(selected_doc(X.__init__, 1, 2, 4, 7, 9)) |__init__( (object)self [, (int)a [, (str)b [, (str)c [, (float)d]]]]) -> None : | doc of init | C++ signature : |__init__( (object)self, (str)s, (bool)b) -> None : | C++ signature : ->>> print selected_doc(Y.__init__, 1, 2, 4) +>>> print(selected_doc(Y.__init__, 1, 2, 4)) |__init__( (object)arg1) -> None : | doc of Y init | C++ signature : ->>> print selected_doc(X.bar2, 1, 2, 4) +>>> print(selected_doc(X.bar2, 1, 2, 4)) |bar2( (X)arg1 [, (int)arg2 [, (str)arg3 [, (str)arg4 [, (float)arg5]]]]) -> Y : | doc of X::bar2 | C++ signature : @@ -133,8 +133,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/destroy_test.cpp b/test/destroy_test.cpp index cae95ae919..57501604b3 100644 --- a/test/destroy_test.cpp +++ b/test/destroy_test.cpp @@ -38,7 +38,6 @@ void assert_destructions(int n) int main() { assert_destructions(0); - typedef int a[2]; foo* f1 = new foo; boost::python::detail::destroy_referent(f1); diff --git a/test/dict.cpp b/test/dict.cpp index 375905d69a..4f3490a421 100644 --- a/test/dict.cpp +++ b/test/dict.cpp @@ -21,11 +21,13 @@ object new_dict() object data_dict() { dict tmp1; - tmp1["key1"] = "value1"; dict tmp2; tmp2["key2"] = "value2"; tmp1[1] = tmp2; + + tmp1["key1"] = "value1"; + return tmp1; } @@ -60,22 +62,20 @@ void work_with_dict(dict data1, dict data2) void test_templates(object print) { std::string key = "key"; - + dict tmp; - tmp[1] = "a test string"; - print(tmp.get(1)); - //print(tmp[1]); tmp[1.5] = 13; print(tmp.get(1.5)); + tmp[1] = "a test string"; + print(tmp.get(1)); print(tmp.get(44)); print(tmp); print(tmp.get(2,"default")); print(tmp.setdefault(3,"default")); BOOST_ASSERT(!tmp.has_key(key)); - //print(tmp[3]); } - + BOOST_PYTHON_MODULE(dict_ext) { def("new_dict", new_dict); diff --git a/test/dict.py b/test/dict.py index a321beea97..9b1149ae60 100644 --- a/test/dict.py +++ b/test/dict.py @@ -4,31 +4,33 @@ """ >>> from dict_ext import * >>> def printer(*args): -... for x in args: print x, -... print +... for x in args: print(x, end='') +... print('') ... ->>> print new_dict() +>>> print(new_dict()) {} ->>> print data_dict() +>>> print(data_dict()) {1: {'key2': 'value2'}, 'key1': 'value1'} >>> tmp = data_dict() ->>> print dict_keys(tmp) +>>> print(dict_keys(tmp)) [1, 'key1'] ->>> print dict_values(tmp) +>>> print(dict_values(tmp)) [{'key2': 'value2'}, 'value1'] ->>> print dict_items(tmp) +>>> print(dict_items(tmp)) [(1, {'key2': 'value2'}), ('key1', 'value1')] ->>> print dict_from_sequence([(1,1),(2,2),(3,3)]) +>>> print(dict_from_sequence([(1,1),(2,2),(3,3)])) {1: 1, 2: 2, 3: 3} >>> test_templates(printer) #doctest: +NORMALIZE_WHITESPACE -a test string 13 +a test string None {1.5: 13, 1: 'a test string'} default default """ +from __future__ import print_function + def run(args = None): import sys import doctest @@ -36,10 +38,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/docstring.py b/test/docstring.py index 528ce84568..2727bd6d5e 100644 --- a/test/docstring.py +++ b/test/docstring.py @@ -8,14 +8,14 @@ ... doc = obj.__doc__.splitlines() ... return "\\n".join(["|"+doc[i] for i in args]) ->>> print selected_doc(X.__init__, 1, 2, 3, 4, 5) +>>> print(selected_doc(X.__init__, 1, 2, 3, 4, 5)) |__init__( (object)self, (int)value) -> None : | this is the __init__ function | its documentation has two lines. | | C++ signature : ->>> print selected_doc(X.value, 1, 2, 4, 7, 8, 10) +>>> print(selected_doc(X.value, 1, 2, 4, 7, 8, 10)) |value( (X)self) -> int : | gets the value of the object | C++ signature : @@ -23,13 +23,13 @@ | also gets the value of the object | C++ signature : ->>> print selected_doc(create, 1, 2, 3, 4) +>>> print(selected_doc(create, 1, 2, 3, 4)) |create( (int)value) -> X : | creates a new X object | | C++ signature : ->>> print selected_doc(fact, 1, 2, 3, 4) +>>> print(selected_doc(fact, 1, 2, 3, 4)) |fact( (int)n) -> int : | compute the factorial | @@ -37,23 +37,23 @@ >>> len(fact_usr_off_1.__doc__.splitlines()) 5 ->>> print selected_doc(fact_usr_off_1, 1, 3) +>>> print(selected_doc(fact_usr_off_1, 1, 3)) |fact_usr_off_1( (int)n) -> int : | C++ signature : >>> len(fact_usr_on_1.__doc__.splitlines()) 6 ->>> print selected_doc(fact_usr_on_1, 1, 2, 4) +>>> print(selected_doc(fact_usr_on_1, 1, 2, 4)) |fact_usr_on_1( (int)n) -> int : | usr on 1 | C++ signature : >>> len(fact_usr_off_2.__doc__.splitlines()) 5 ->>> print selected_doc(fact_usr_off_2, 1, 3) +>>> print(selected_doc(fact_usr_off_2, 1, 3)) |fact_usr_off_2( (int)n) -> int : | C++ signature : >>> len(fact_usr_on_2.__doc__.splitlines()) 6 ->>> print selected_doc(fact_usr_on_2, 1, 2, 4) +>>> print(selected_doc(fact_usr_on_2, 1, 2, 4)) |fact_usr_on_2( (int)n) -> int : | usr on 2 | C++ signature : @@ -61,59 +61,59 @@ >>> len(fact_sig_off_1.__doc__.splitlines()) 2 ->>> print selected_doc(fact_sig_off_1, 1) +>>> print(selected_doc(fact_sig_off_1, 1)) |sig off 1 >>> len(fact_sig_on_1.__doc__.splitlines()) 6 ->>> print selected_doc(fact_sig_on_1, 1, 2, 4) +>>> print(selected_doc(fact_sig_on_1, 1, 2, 4)) |fact_sig_on_1( (int)n) -> int : | sig on 1 | C++ signature : >>> len(fact_sig_off_2.__doc__.splitlines()) 2 ->>> print selected_doc(fact_sig_off_2, 1) +>>> print(selected_doc(fact_sig_off_2, 1)) |sig off 2 >>> len(fact_sig_on_2.__doc__.splitlines()) 6 ->>> print selected_doc(fact_sig_on_2, 1, 2, 4) +>>> print(selected_doc(fact_sig_on_2, 1, 2, 4)) |fact_sig_on_2( (int)n) -> int : | sig on 2 | C++ signature : ->>> print fact_usr_off_sig_off_1.__doc__ +>>> print(fact_usr_off_sig_off_1.__doc__) None >>> len(fact_usr_on_sig_on_1.__doc__.splitlines()) 6 ->>> print selected_doc(fact_usr_on_sig_on_1, 1, 2, 4) +>>> print(selected_doc(fact_usr_on_sig_on_1, 1, 2, 4)) |fact_usr_on_sig_on_1( (int)n) -> int : | usr on sig on 1 | C++ signature : >>> len(fact_usr_on_sig_off_1.__doc__.splitlines()) 2 ->>> print selected_doc(fact_usr_on_sig_off_1, 1) +>>> print(selected_doc(fact_usr_on_sig_off_1, 1)) |usr on sig off 1 >>> len(fact_usr_on_sig_on_2.__doc__.splitlines()) 6 ->>> print selected_doc(fact_usr_on_sig_on_2, 1, 2, 4) +>>> print(selected_doc(fact_usr_on_sig_on_2, 1, 2, 4)) |fact_usr_on_sig_on_2( (int)n) -> int : | usr on sig on 2 | C++ signature : ->>> print selected_doc(fact_usr_on_psig_on_csig_off_1, 1, 2) +>>> print(selected_doc(fact_usr_on_psig_on_csig_off_1, 1, 2)) |fact_usr_on_psig_on_csig_off_1( (int)n) -> int : | usr on psig on csig off 1 ->>> print selected_doc(fact_usr_on_psig_off_csig_on_1, 1, 3) +>>> print(selected_doc(fact_usr_on_psig_off_csig_on_1, 1, 3)) |usr on psig off csig on 1 |C++ signature : ->>> print fact_usr_off_psig_on_csig_off_1.__doc__.splitlines()[1] +>>> print(fact_usr_off_psig_on_csig_off_1.__doc__.splitlines()[1]) fact_usr_off_psig_on_csig_off_1( (int)n) -> int ->>> print selected_doc(fact_usr_off_psig_off_csig_on_1,1) +>>> print(selected_doc(fact_usr_off_psig_off_csig_on_1,1)) |C++ signature : @@ -134,11 +134,11 @@ def run(args = None): import re docmodule = lambda m: re.sub(".\10", "", pydoc.text.docmodule(m)) try: - print 'printing module help:' - print docmodule(docstring_ext) - except object, x: - print '********* failed **********' - print x + print('printing module help:') + print(docmodule(docstring_ext)) + except object as x: + print('********* failed **********') + print(x) result = list(result) result[0] += 1 return tuple(result) @@ -146,8 +146,8 @@ def run(args = None): return result if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/enable_shared_from_this.py b/test/enable_shared_from_this.py old mode 100755 new mode 100644 index cca46ec813..d7ac7a9999 --- a/test/enable_shared_from_this.py +++ b/test/enable_shared_from_this.py @@ -18,9 +18,9 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/enum.cpp b/test/enum_ext.cpp similarity index 90% rename from test/enum.cpp rename to test/enum_ext.cpp index e5c4f4fa91..74224f1d77 100644 --- a/test/enum.cpp +++ b/test/enum_ext.cpp @@ -7,7 +7,7 @@ #include #include #if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) -# include +#include # include #endif using namespace boost::python; @@ -17,7 +17,7 @@ enum color { red = 1, green = 2, blue = 4, blood = 1 }; #if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) namespace boost // Pro7 has a hard time detecting enums { - template <> struct is_enum : boost::mpl::true_ {}; + template <> struct boost::python::detail::is_enum : boost::mpl::true_ {}; } #endif diff --git a/test/exception_translator.py b/test/exception_translator.py index 9537c6f6f1..1d80aba3a2 100644 --- a/test/exception_translator.py +++ b/test/exception_translator.py @@ -5,10 +5,10 @@ >>> from exception_translator_ext import * >>> try: ... throw_error(); -... except RuntimeError, x: -... print x +... except RuntimeError as x: +... print(x) ... else: -... print 'Expected a RuntimeError!' +... print('Expected a RuntimeError!') !!!error!!! ''' def run(args = None): @@ -20,8 +20,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/exec.cpp b/test/exec.cpp index 9fb005ea5f..72ff571bd6 100644 --- a/test/exec.cpp +++ b/test/exec.cpp @@ -58,16 +58,6 @@ void eval_test() void exec_test() { - // Register the module with the interpreter - if (PyImport_AppendInittab(const_cast("embedded_hello"), -#if PY_VERSION_HEX >= 0x03000000 - PyInit_embedded_hello -#else - initembedded_hello -#endif - ) == -1) - throw std::runtime_error("Failed to add embedded_hello to the interpreter's " - "builtin modules"); // Retrieve the main module python::object main = python::import("__main__"); @@ -152,6 +142,20 @@ int main(int argc, char **argv) { BOOST_TEST(argc == 2 || argc == 3); std::string script = argv[1]; + + // Register the module with the interpreter + if (PyImport_AppendInittab(const_cast("embedded_hello"), +#if PY_VERSION_HEX >= 0x03000000 + PyInit_embedded_hello +#else + initembedded_hello +#endif + ) == -1) + { + BOOST_ERROR("Failed to add embedded_hello to the interpreter's " + "builtin modules"); + } + // Initialize the interpreter Py_Initialize(); diff --git a/test/extract.py b/test/extract.py index 842a9f6e4d..feda93a1d5 100644 --- a/test/extract.py +++ b/test/extract.py @@ -21,11 +21,11 @@ >>> assert not check_list(2) >>> try: x = extract_list(2) - ... except TypeError, x: + ... except TypeError as x: ... if str(x) != 'Expecting an object of type list; got an object of type int instead': - ... print x + ... print(x) ... else: - ... print 'expected an exception, got', x, 'instead' + ... print('expected an exception, got', x, 'instead') Can't extract a list from a tuple. Use list(x) to convert a sequence to a list: @@ -47,7 +47,7 @@ >>> try: x = extract_cstring(1) ... except TypeError: pass ... else: - ... print 'expected an exception, got', x, 'instead' + ... print('expected an exception, got', x, 'instead') Extract an std::string (class) rvalue from a native Python type @@ -100,8 +100,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/fabscript b/test/fabscript new file mode 100644 index 0000000000..a002fb2bf0 --- /dev/null +++ b/test/fabscript @@ -0,0 +1,176 @@ +# -*- python -*- +# +# Copyright (c) 2016 Stefan Seefeld +# All rights reserved. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from faber import platform +from faber.feature import set +from faber.tools.compiler import runpath +from faber.tools.python import python, pythonpath +from faber.artefacts.object import object +from faber.artefacts.binary import binary +from faber.artefacts.python import extension +from faber.test import test, report, fail + +src = module('..src') + +python_libs=python.instance().libs +features |= runpath(src.bpl.path, base='') + +def extension_test(name, exts=[], script=None, numpy=False, + features=features, condition=None): + """Create a Python extension test `name`. + Arguments: + * name: the name of the test. + * exts: extensions to be compiled, if none are given. + * script: the test script to execute, .py if none is given. + * numpy: if true, add boost_numpy to sources + * features: pre-defined features + * condition: any condition under which to run the test + Return: + * the test artefact""" + + features=features.copy() + extensions = [] + libs = [src.bnl, src.bpl] if numpy else [src.bpl] + for ext in exts or [name]: + if type(ext) is str: # build from a single source file + ext_name = ext if ext != name else ext + '_ext' + sources = [ext + '.cpp'] + else: # build from a list of source files + ext_name = ext[0] if ext[0] != name else ext[0] + '_ext' + sources = [source + '.cpp' for source in ext] + ext = extension(ext_name, sources + libs, features=features) + features |= pythonpath(ext.path, base='') + extensions.append(ext) + if not script: + script = name+'.py' + return test(name, script, run=python.run, dependencies=extensions, + features=features, condition=condition) + +tests = [] +for t in [('injected',), + ('properties',), + ('return_arg',), + ('staticmethod',), + ('boost_shared_ptr',), + ('enable_shared_from_this',), + ('andreas_beyer',), + ('polymorphism',), + ('polymorphism2',), + ('wrapper_held_type',), + ('minimal',), + ('args',), + ('raw_ctor',), + ('exception_translator',), + ('module_init_exception',), + ('test_enum', ['enum_ext']), + ('test_cltree', ['cltree']), + ('newtest', ['m1', 'm2']), + ('const_argument',), + ('keywords_test', ['keywords']), + ('test_pointer_adoption',), + ('operators',), + ('operators_wrapper',), + ('callbacks',), + ('defaults',), + ('object',), + ('class',), + ('aligned_class',), + ('list',), + ('long',), + ('dict',), + ('tuple',), + ('str',), + ('slice',), + ('virtual_functions',), + ('back_reference',), + ('implicit',), + ('data_members',), + ('ben_scott1',), + ('bienstman1',), + ('bienstman2',), + ('bienstman3',), + ('multi_arg_constructor',), + ('iterator', ['iterator', 'input_iterator']), + ('stl_iterator',), + ('extract',), + ('crossmod_opaque', ['crossmod_opaque_a', 'crossmod_opaque_b']), + ('opaque',), + ('voidptr',), + ('pickle1',), + ('pickle2',), + ('pickle3',), + ('pickle4',), + ('nested',), + ('docstring',), + ('pytype_function',), + ('vector_indexing_suite',), + ('pointer_vector',), + ('builtin_converters', [], 'test_builtin_converters.py'), + ('map_indexing_suite', + [['map_indexing_suite', 'int_map_indexing_suite', 'a_map_indexing_suite']])]: + tests.append(extension_test(*t)) + +tests.append(extension_test('shared_ptr', + condition=set.define.contains('HAS_CXX11'))) +#tests.append(extension_test('polymorphism2_auto_ptr', +# condition=set.define.contains('HAS_CXX11').not_())) +#tests.append(extension_test('auto_ptr', +# condition=set.define.contains('HAS_CXX11'))) + +import_ = binary('import_', ['import_.cpp', src.bpl], features=features|python_libs) +if platform.os == 'Windows': + command = """set PATH=$(runpath);%PATH% +$(>[0]) $(>[1])""" +else: + command = 'LD_LIBRARY_PATH=$(runpath) $(>[0]) $(>[1])' + +tests.append(test('import', [import_, 'import_.py'], + run=action('run', command), + features=features)) + +tests.append(extension_test('calling_conventions', + condition=platform.os == 'Windows')) +tests.append(extension_test('calling_conventions_mf', + condition=platform.os == 'Windows')) + +for t in ['destroy_test', + 'pointer_type_id_test', + 'bases', + 'pointee', + 'if_else', + 'pointee', + 'result', + 'upcast', + 'select_from_python_test']: + tests.append(test(t, binary(t, [t + '.cpp', src.bpl], features=features), features=features, run=True)) +for t in ['indirect_traits_test', + 'string_literal', + 'borrowed', + 'object_manager', + 'copy_ctor_mutates_rhs', + 'select_holder', + 'select_arg_to_python_test']: + tests.append(test(t, object(t, [t + '.cpp'], features=features))) + +for t in ['raw_pyobject_fail1', + 'raw_pyobject_fail2', + 'as_to_python_function', + 'object_fail1']: + tests.append(test(t, object(t, [t + '.cpp'], features=features), expected=fail)) + +for t in ['numpy/dtype', + 'numpy/ufunc', + 'numpy/templates', + 'numpy/ndarray', + 'numpy/indexing', + 'numpy/shapes']: + tests.append(extension_test(t, numpy=True, + condition=set.define.contains('HAS_NUMPY'))) + +default = report('report', tests, fail_on_failures=True) diff --git a/test/if_else.cpp b/test/if_else.cpp index 1c6258db70..60cc53192d 100644 --- a/test/if_else.cpp +++ b/test/if_else.cpp @@ -4,7 +4,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #include #include -#include +#include typedef char c1; typedef char c2[2]; @@ -35,10 +35,10 @@ struct choose int main() { - BOOST_STATIC_ASSERT((boost::is_same::type,c1>::value)); - BOOST_STATIC_ASSERT((boost::is_same::type,c2>::value)); - BOOST_STATIC_ASSERT((boost::is_same::type,c3>::value)); - BOOST_STATIC_ASSERT((boost::is_same::type,c4>::value)); - BOOST_STATIC_ASSERT((boost::is_same::type,void*>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::type,c1>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::type,c2>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::type,c3>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::type,c4>::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::type,void*>::value)); return 0; } diff --git a/test/implicit.py b/test/implicit.py index ac82d94864..f2aa3e1d36 100644 --- a/test/implicit.py +++ b/test/implicit.py @@ -12,18 +12,18 @@ 42 >>> try: make_x('fool') ... except TypeError: pass -... else: print 'no error' +... else: print('no error') ->>> print x_value.__doc__.splitlines()[1] +>>> print(x_value.__doc__.splitlines()[1]) x_value( (X)arg1) -> int : ->>> print make_x.__doc__.splitlines()[1] +>>> print(make_x.__doc__.splitlines()[1]) make_x( (object)arg1) -> X : ->>> print X.value.__doc__.splitlines()[1] +>>> print(X.value.__doc__.splitlines()[1]) value( (X)arg1) -> int : ->>> print X.set.__doc__.splitlines()[1] +>>> print(X.set.__doc__.splitlines()[1]) set( (X)arg1, (object)arg2) -> None : ''' @@ -37,8 +37,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/import_.cpp b/test/import_.cpp index 3e21de0bad..8e03d9b448 100644 --- a/test/import_.cpp +++ b/test/import_.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/test/indirect_traits_test.cpp b/test/indirect_traits_test.cpp index 594cfe5559..da4cc24569 100644 --- a/test/indirect_traits_test.cpp +++ b/test/indirect_traits_test.cpp @@ -4,7 +4,6 @@ //#include #define BOOST_ENABLE_ASSERT_HANDLER #include -#include #include #include #include diff --git a/test/injected.cpp b/test/injected.cpp old mode 100755 new mode 100644 index 73e1e14baa..82db3e82e6 --- a/test/injected.cpp +++ b/test/injected.cpp @@ -17,7 +17,7 @@ typedef test_class<> X; X* empty() { return new X(1000); } -std::auto_ptr sum(int a, int b) { return std::auto_ptr(new X(a+b)); } +std::shared_ptr sum(int a, int b) { return std::shared_ptr(new X(a+b)); } boost::shared_ptr product(int a, int b, int c) { diff --git a/test/injected.py b/test/injected.py index 32ea0bf9da..c502150483 100644 --- a/test/injected.py +++ b/test/injected.py @@ -20,9 +20,9 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/int_map_indexing_suite.cpp b/test/int_map_indexing_suite.cpp old mode 100755 new mode 100644 diff --git a/test/iterator.py b/test/iterator.py index 96f5fd04bd..0d75100a09 100644 --- a/test/iterator.py +++ b/test/iterator.py @@ -11,30 +11,30 @@ >>> x.push_back(3) >>> x.push_back(5) >>> for y in x: -... print y +... print(y) 1 3 5 >>> z = range(x) >>> for y in z: -... print y +... print(y) 1 3 5 Range2 wraps a transform_iterator which doubles the elements it traverses. This proves we can wrap input iterators - + >>> z2 = range2(x) >>> for y in z2: -... print y +... print(y) 2 6 10 >>> l2 = two_lists() >>> for y in l2.primes: -... print y +... print(y) 2 3 5 @@ -42,7 +42,7 @@ 11 13 >>> for y in l2.evens: -... print y +... print(y) 2 4 6 @@ -55,12 +55,15 @@ >>> ll.push_back(x) >>> for a in ll: #doctest: +NORMALIZE_WHITESPACE ... for b in a: -... print b, -... print +... print(b, end=' ') +... print('') ... 1 3 5 1 3 5 7 ''' + +from __future__ import print_function + def run(args = None): import sys import doctest @@ -68,10 +71,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/keywords.cpp b/test/keywords.cpp old mode 100755 new mode 100644 diff --git a/test/keywords_test.py b/test/keywords_test.py index 261de0b392..bac7d17c1f 100644 --- a/test/keywords_test.py +++ b/test/keywords_test.py @@ -98,9 +98,9 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/list.py b/test/list.py index 8be2112389..f6cf87096f 100644 --- a/test/list.py +++ b/test/list.py @@ -25,7 +25,7 @@ >>> try: result = apply_object_list(identity, 5) ... except TypeError: pass -... else: print 'expected an exception, got', result, 'instead' +... else: print('expected an exception, got', result, 'instead') >>> assert apply_list_list(identity, letters) is letters @@ -33,24 +33,24 @@ >>> try: result = apply_list_list(len, letters) ... except TypeError: pass -... else: print 'expected an exception, got', result, 'instead' +... else: print('expected an exception, got', result, 'instead') >>> append_object(letters, '.') >>> letters ['h', 'e', 'l', 'l', 'o', '.'] tuples do not automatically convert to lists when passed as arguments - + >>> try: append_list(letters, (1,2)) ... except TypeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') >>> append_list(letters, [1,2]) >>> letters ['h', 'e', 'l', 'l', 'o', '.', [1, 2]] Check that subclass functions are properly called - + >>> class mylist(list): ... def append(self, o): ... list.append(self, o) @@ -68,8 +68,8 @@ 2 >>> def printer(*args): -... for x in args: print x, -... print +... for x in args: print( x,) +... print('') ... >>> y = X(42) @@ -102,6 +102,8 @@ ['y', 'x', 'o', 'l', 'l', 'h', 'e', '.'] ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -109,10 +111,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/long.py b/test/long.py index 13d8775bba..157dc57aa9 100644 --- a/test/long.py +++ b/test/long.py @@ -3,20 +3,24 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ''' >>> from long_ext import * ->>> print new_long() +>>> print(new_long()) 0 ->>> print longify(42) +>>> print(longify(42)) 42 ->>> print longify_string('300') +>>> print(longify_string('300')) 300 ->>> is_long(20L) +>>> is_long(long(20)) 'yes' >>> is_long('20') 0 ->>> x = Y(4294967295L) +>>> x = Y(long(4294967295)) ''' +import sys +if (sys.version_info.major >= 3): + long = int + def run(args = None): import sys import doctest @@ -24,10 +28,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/map_indexing_suite.py b/test/map_indexing_suite.py index 9d9e2b26fa..6d3e57a102 100644 --- a/test/map_indexing_suite.py +++ b/test/map_indexing_suite.py @@ -24,7 +24,7 @@ # test that a string is implicitly convertible # to an X ->>> x_value('bochi bochi') +>>> x_value('bochi bochi') 'gotya bochi bochi' ##################################################################### @@ -32,11 +32,11 @@ ##################################################################### >>> def print_xmap(xmap): ... s = '[ ' -... for x in xmap: +... for x in xmap: ... s += repr(x) -... s += ' ' +... s += ' ' ... s += ']' -... print s +... print(s) ##################################################################### # Setting (adding entries) @@ -134,7 +134,7 @@ >>> assert not 12345 in xm ##################################################################### -# Some references to the container elements +# Some references to the container elements ##################################################################### >>> z0 = xm['joel'] @@ -155,7 +155,7 @@ kiwi ##################################################################### -# Delete some container element +# Delete some container element ##################################################################### >>> del xm['tenji'] @@ -167,7 +167,7 @@ [ (joel, apple) (kim, kiwi) (mariel, grape) ] ##################################################################### -# Show that the references are still valid +# Show that the references are still valid ##################################################################### >>> z0 # proxy apple @@ -198,7 +198,7 @@ >>> print_xmap(tm) [ (joel, aaa) (kimpo, bbb) ] >>> for el in tm: #doctest: +NORMALIZE_WHITESPACE -... print el.key(), +... print(el.key(), end=' ') ... dom = el.data() joel kimpo @@ -215,11 +215,19 @@ 4 ##################################################################### -# END.... +# Test signature... +##################################################################### + +>>> AMap.__iter__.__doc__.strip().split("\\n")[0] +'__iter__( (AMap)arg1) -> __main__.iterator :' + +##################################################################### +# END.... ##################################################################### ''' +from __future__ import print_function def run(args = None): import sys @@ -230,13 +238,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print 'running...' + print('running...') import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) - - - - - diff --git a/test/minimal.py b/test/minimal.py index 28e7918f7a..ee75e3705b 100644 --- a/test/minimal.py +++ b/test/minimal.py @@ -1,7 +1,7 @@ # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -print "IMPORTING minimal_ext" +print("IMPORTING minimal_ext") import minimal_ext -print "DONE IMPORTING minimal_ext" +print("DONE IMPORTING minimal_ext") diff --git a/test/module_init_exception.cpp b/test/module_init_exception.cpp new file mode 100644 index 0000000000..d8cec57d3a --- /dev/null +++ b/test/module_init_exception.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2003 Rational Discovery LLC +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +using namespace boost::python; + +BOOST_PYTHON_MODULE(module_init_exception_ext) +{ + throw std::runtime_error("Module init failed"); +} diff --git a/test/module_init_exception.py b/test/module_init_exception.py new file mode 100644 index 0000000000..3da53e1956 --- /dev/null +++ b/test/module_init_exception.py @@ -0,0 +1,12 @@ +# Copyright (C) 2003 Rational Discovery LLC. Distributed under the Boost +# Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +# at http://www.boost.org/LICENSE_1_0.txt) + +print("running...") + +try: + import module_init_exception_ext +except RuntimeError as e: + print(e) + +print("Done.") diff --git a/test/multi_arg_constructor.py b/test/multi_arg_constructor.py index eb8d338b35..5d8b4a516c 100644 --- a/test/multi_arg_constructor.py +++ b/test/multi_arg_constructor.py @@ -14,8 +14,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/nested.cpp b/test/nested.cpp index de656d2b8b..3a0d05e5ea 100644 --- a/test/nested.cpp +++ b/test/nested.cpp @@ -4,6 +4,8 @@ // http://www.boost.org/LICENSE_1_0.txt) #include #include +#include +#include #include #include #include "test_class.hpp" @@ -16,6 +18,8 @@ typedef test_class<> X; typedef test_class<1> Y; +enum color { red = 0, blue = 1, green = 2 }; + std::ostream& operator<<(std::ostream& s, X const& x) { return s << x.value(); @@ -26,11 +30,13 @@ std::ostream& operator<<(std::ostream& s, Y const& x) return s << x.value(); } +void test_function(const X& x, const Y& y) {} BOOST_PYTHON_MODULE(nested_ext) { using namespace boost::python; + { // Establish X as the current scope. scope x_class = class_("X", init()) @@ -42,6 +48,17 @@ BOOST_PYTHON_MODULE(nested_ext) class_("Y", init()) .def(str(self)) ; + + // so will the enum `color` + enum_("color") + .value("red", red) + .value("green", green) + .value("blue", blue) + ; + } + + // The generated docstring will use the fully-qualified name of Y + def("test_function", &test_function); } diff --git a/test/nested.py b/test/nested.py index c3446e848d..657d100a71 100644 --- a/test/nested.py +++ b/test/nested.py @@ -13,14 +13,35 @@ >>> X.__name__ 'X' - >>> X.Y + >>> X.Y # doctest: +py2 + + >>> X.Y # doctest: +py3 + >>> X.Y.__module__ 'nested_ext' >>> X.Y.__name__ 'Y' + + >>> getattr(X.color, "__qualname__", None) # doctest: +py3 + 'X.color' + + >>> repr(X.color.red) # doctest: +py2 + 'nested_ext.color.red' + + >>> repr(X.color.red) # doctest: +py3 + 'nested_ext.X.color.red' + + >>> repr(X.color(1)) # doctest: +py2 + 'nested_ext.color(1)' + + >>> repr(X.color(1)) # doctest: +py3 + 'nested_ext.X.color(1)' + + >>> test_function.__doc__.strip().split('\\n')[0] # doctest: +py3 + 'test_function( (X)arg1, (X.Y)arg2) -> None :' ''' @@ -30,11 +51,27 @@ def run(args = None): if args is not None: sys.argv = args - return doctest.testmod(sys.modules.get(__name__)) + + py2 = doctest.register_optionflag("py2") + py3 = doctest.register_optionflag("py3") + + class ConditionalChecker(doctest.OutputChecker): + def check_output(self, want, got, optionflags): + if (optionflags & py3) and (sys.version_info[0] < 3): + return True + if (optionflags & py2) and (sys.version_info[0] >= 3): + return True + return doctest.OutputChecker.check_output(self, want, got, optionflags) + + runner = doctest.DocTestRunner(ConditionalChecker()) + for test in doctest.DocTestFinder().find(sys.modules.get(__name__)): + runner.run(test) + + return doctest.TestResults(runner.failures, runner.tries) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/newtest.py b/test/newtest.py index 1862dcb498..b878d51924 100644 --- a/test/newtest.py +++ b/test/newtest.py @@ -12,11 +12,11 @@ >>> def check_unregistered(f, msgprefix): ... try: ... f(1) -... except TypeError, x: +... except TypeError as x: ... if not str(x).startswith(msgprefix): -... print str(x) +... print(str(x)) ... else: -... print 'expected a TypeError' +... print('expected a TypeError') ... >>> check_unregistered(make_unregistered, 'No to_python (by-value) converter found for C++ type') >>> check_unregistered(make_unregistered2, 'No Python class registered for C++ class') @@ -42,7 +42,7 @@ >>> try: ... unwrap_int_ref(7) ... except: pass -... else: print 'no exception' +... else: print('no exception') >>> unwrap_int_const_ref(9) 9 @@ -52,7 +52,7 @@ try: wrap_int_ref(n) ... except: pass -... else: print 'no exception' +... else: print('no exception') >>> wrap_int_const_ref(n) 42 @@ -105,7 +105,7 @@ >>> try: A.__dict__['name'](None) ... except TypeError: pass -... else: print 'expected an exception!' +... else: print('expected an exception!') >>> a = A() @@ -120,17 +120,17 @@ >>> try: ... take_b(a) ... except: pass -... else: print 'no exception' +... else: print('no exception') >>> try: ... take_c(a) ... except: pass -... else: print 'no exception' +... else: print('no exception') >>> try: ... take_d(a) ... except: pass -... else: print 'no exception' +... else: print('no exception') ------ >>> take_a(b).name() @@ -142,12 +142,12 @@ >>> try: ... take_c(b) ... except: pass -... else: print 'no exception' +... else: print('no exception') >>> try: ... take_d(b) ... except: pass -... else: print 'no exception' +... else: print('no exception') ------- >>> take_a(c).name() @@ -156,7 +156,7 @@ >>> try: ... take_b(c) ... except: pass -... else: print 'no exception' +... else: print('no exception') >>> take_c(c).name() 'C' @@ -164,7 +164,7 @@ >>> try: ... take_d(c) ... except: pass -... else: print 'no exception' +... else: print('no exception') ------- >>> take_a(d).name() @@ -183,7 +183,7 @@ >>> dd = take_d(d_as_a) >>> dd.name() 'D' ->>> print g.__doc__.splitlines()[1] +>>> print(g.__doc__.splitlines()[1]) g( (Simple)arg1) -> Simple : """ @@ -199,8 +199,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/numarray_tests.py b/test/numarray_tests.py deleted file mode 100644 index be3d9d4e48..0000000000 --- a/test/numarray_tests.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -import printer - -# So we can coerce portably across Python versions -bool = type(1 == 1) - -''' ->>> from numpy_ext import * ->>> x = new_array() ->>> y = x.copy() ->>> p = _printer() ->>> check = p.check ->>> exercise_numarray(x, p) - ->>> check(str(y)) - ->>> check(y.argmax()); ->>> check(y.argmax(0)); - ->>> check(y.argmin()); ->>> check(y.argmin(0)); - ->>> check(y.argsort()); ->>> check(y.argsort(1)); - ->>> y.byteswap(); ->>> check(y); - ->>> check(y.diagonal()); ->>> check(y.diagonal(1)); ->>> check(y.diagonal(0, 0)); ->>> check(y.diagonal(0, 1, 0)); - ->>> check(y.is_c_array()); - -# coerce because numarray still returns an int and the C++ interface forces -# the return type to bool ->>> check( bool(y.isbyteswapped()) ); - ->>> check(y.trace()); ->>> check(y.trace(1)); ->>> check(y.trace(0, 0)); ->>> check(y.trace(0, 1, 0)); - ->>> check(y.new('D').getshape()); ->>> check(y.new('D').type()); ->>> y.sort(); ->>> check(y); ->>> check(y.type()); - ->>> check(y.factory((1.2, 3.4))); ->>> check(y.factory((1.2, 3.4), "f8")) ->>> check(y.factory((1.2, 3.4), "f8", true)) ->>> check(y.factory((1.2, 3.4), "f8", true, false)) ->>> check(y.factory((1.2, 3.4), "f8", true, false, None)) ->>> check(y.factory((1.2, 3.4), "f8", true, false, None, (1,2,1))) - ->>> p.results -[] ->>> del p -''' diff --git a/test/numeric_tests.py b/test/numeric_tests.py deleted file mode 100644 index 569ec19e58..0000000000 --- a/test/numeric_tests.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -import printer -''' ->>> from numpy_ext import * ->>> x = new_array() ->>> x[1,1] = 0.0 - ->>> try: take_array(3) -... except TypeError: pass -... else: print 'expected a TypeError' - ->>> take_array(x) - ->>> print x -[[1 2 3] - [4 0 6] - [7 8 9]] - ->>> y = x.copy() - - ->>> p = _printer() ->>> check = p.check ->>> exercise(x, p) ->>> y[2,1] = 3 ->>> check(y); - ->>> check(y.astype('D')); - ->>> check(y.copy()); - ->>> check(y.typecode()); - ->>> p.results -[] ->>> del p -''' diff --git a/test/numpy.cpp b/test/numpy.cpp deleted file mode 100644 index 9472f92ed2..0000000000 --- a/test/numpy.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include -#include - -using namespace boost::python; -namespace py = boost::python; - -// See if we can invoke array() from C++ -numeric::array new_array() -{ - return numeric::array( - py::make_tuple( - py::make_tuple(1,2,3) - , py::make_tuple(4,5,6) - , py::make_tuple(7,8,9) - ) - ); -} - -// test argument conversion -void take_array(numeric::array /*x*/) -{ -} - -// A separate function to invoke the info() member. Must happen -// outside any doctests since this prints directly to stdout and the -// result text includes the address of the 'self' array. -void info(numeric::array const& z) -{ - z.info(); -} - -namespace -{ - object handle_error() - { - PyObject* type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); - handle<> ty(type), v(value), tr(traceback); - return object("exception"); - str format("exception type: %sn"); - format += "exception value: %sn"; - format += "traceback:n%s" ; - object ret = format % py::make_tuple(ty, v, tr); - return ret; - } -} -#define CHECK(expr) \ -{ \ - object result; \ - try { result = object(expr); } \ - catch(error_already_set) \ - { \ - result = handle_error(); \ - } \ - check(result); \ -} - -// Tests which work on both Numeric and numarray array objects. Of -// course all of the operators "just work" since numeric::array -// inherits that behavior from object. -void exercise(numeric::array& y, object check) -{ - y[py::make_tuple(2,1)] = 3; - CHECK(y); - CHECK(y.astype('D')); - CHECK(y.copy()); - CHECK(y.typecode()); -} - -// numarray-specific tests. check is a callable object which we can -// use to record intermediate results, which are later compared with -// the results of corresponding python operations. -void exercise_numarray(numeric::array& y, object check) -{ - CHECK(str(y)); - - CHECK(y.argmax()); - CHECK(y.argmax(0)); - - CHECK(y.argmin()); - CHECK(y.argmin(0)); - - CHECK(y.argsort()); - CHECK(y.argsort(1)); - - y.byteswap(); - CHECK(y); - - CHECK(y.diagonal()); - CHECK(y.diagonal(1)); - CHECK(y.diagonal(0, 0)); - CHECK(y.diagonal(0, 1, 0)); - - CHECK(y.is_c_array()); - CHECK(y.isbyteswapped()); - - CHECK(y.trace()); - CHECK(y.trace(1)); - CHECK(y.trace(0, 0)); - CHECK(y.trace(0, 1, 0)); - - CHECK(y.new_("D").getshape()); - CHECK(y.new_("D").type()); - y.sort(); - CHECK(y); - CHECK(y.type()); - - CHECK(y.factory(py::make_tuple(1.2, 3.4))); - CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8")); - CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8", true)); - CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8", true, false)); - CHECK(y.factory(py::make_tuple(1.2, 3.4), "f8", true, false, object())); - CHECK (y.factory(py::make_tuple(1.2, 3.4), "f8", true, false, object(), py::make_tuple(1,2,1))); - -} - -BOOST_PYTHON_MODULE(numpy_ext) -{ - def("new_array", new_array); - def("take_array", take_array); - def("exercise", exercise); - def("exercise_numarray", exercise_numarray); - def("set_module_and_type", &numeric::array::set_module_and_type); - def("get_module_name", &numeric::array::get_module_name); - def("info", info); -} - -#include "module_tail.cpp" diff --git a/test/numpy.py b/test/numpy.py deleted file mode 100644 index 84e8313d17..0000000000 --- a/test/numpy.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright David Abrahams 2004. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -false = 0; -true = 1; - -import doctest, numeric_tests -def _count_failures(test_modules = (numeric_tests,)): - failures = 0 - for m in test_modules: - failures += doctest.testmod(m)[0] - return failures - -def _run(args = None): - import sys, numarray_tests, numeric_tests - - if args is not None: - sys.argv = args - - # See which of the numeric modules are installed - has_numeric = 0 - try: import Numeric - except ImportError: pass - else: - has_numeric = 1 - m = Numeric - - has_numarray = 0 - try: import numarray - except ImportError: pass - else: - has_numarray = 1 - m = numarray - - # Bail if neither one is installed - if not (has_numeric or has_numarray): - return 0 - - # test the info routine outside the doctest. See numpy.cpp for an - # explanation - import numpy_ext - if (has_numarray): - numpy_ext.info(m.array((1,2,3))) - - failures = 0 - - # - # Run tests 4 different ways if both modules are installed, just - # to show that set_module_and_type() is working properly - # - - # run all the tests with default module search - print 'testing default extension module:', \ - numpy_ext.get_module_name() or '[numeric support not installed]' - - failures += _count_failures() - - # test against Numeric if installed - if has_numeric: - print 'testing Numeric module explicitly' - numpy_ext.set_module_and_type('Numeric', 'ArrayType') - - failures += _count_failures() - - if has_numarray: - print 'testing numarray module explicitly' - numpy_ext.set_module_and_type('numarray', 'NDArray') - # Add the _numarray_tests to the list of things to test in - # this case. - failures += _count_failures((numarray_tests, numeric_tests)) - - # see that we can go back to the default - numpy_ext.set_module_and_type('', '') - print 'testing default module again:', \ - numpy_ext.get_module_name() or '[numeric support not installed]' - - failures += _count_failures() - - return failures - -if __name__ == '__main__': - print "running..." - import sys - status = _run() - if (status == 0): print "Done." - sys.exit(status) diff --git a/test/numpy/dtype.cpp b/test/numpy/dtype.cpp new file mode 100644 index 0000000000..3a011a25e2 --- /dev/null +++ b/test/numpy/dtype.cpp @@ -0,0 +1,49 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +template +np::dtype accept(T) { + return np::dtype::get_builtin(); +} + +BOOST_PYTHON_MODULE(dtype_ext) +{ + np::initialize(); + // wrap dtype equivalence test, since it isn't available in Python API. + p::def("equivalent", np::equivalent); + // integers, by number of bits + p::def("accept_int8", accept); + p::def("accept_uint8", accept); + p::def("accept_int16", accept); + p::def("accept_uint16", accept); + p::def("accept_int32", accept); + p::def("accept_uint32", accept); + p::def("accept_int64", accept); + p::def("accept_uint64", accept); + // integers, by C name according to NumPy + p::def("accept_bool_", accept); + p::def("accept_byte", accept); + p::def("accept_ubyte", accept); + p::def("accept_short", accept); + p::def("accept_ushort", accept); + p::def("accept_intc", accept); + p::def("accept_uintc", accept); + // floats and complex + p::def("accept_float32", accept); + p::def("accept_complex64", accept< std::complex >); + p::def("accept_float64", accept); + p::def("accept_complex128", accept< std::complex >); + if (sizeof(long double) > sizeof(double)) { + p::def("accept_longdouble", accept); + p::def("accept_clongdouble", accept< std::complex >); + } +} diff --git a/test/numpy/dtype.py b/test/numpy/dtype.py new file mode 100644 index 0000000000..a2eabb58e2 --- /dev/null +++ b/test/numpy/dtype.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import dtype_ext +import unittest +import numpy +import sys +if (sys.version_info.major >= 3): + long = int + +class DtypeTestCase(unittest.TestCase): + + def assertEquivalent(self, a, b): + return self.assertTrue(dtype_ext.equivalent(a, b), "%r is not equivalent to %r") + + def testIntegers(self): + for bits in (8, 16, 32, 64): + s = getattr(numpy, "int%d" % bits) + u = getattr(numpy, "uint%d" % bits) + fs = getattr(dtype_ext, "accept_int%d" % bits) + fu = getattr(dtype_ext, "accept_uint%d" % bits) + self.assertEquivalent(fs(s(1)), numpy.dtype(s)) + self.assertEquivalent(fu(u(1)), numpy.dtype(u)) + # these should just use the regular Boost.Python converters + self.assertEquivalent(fs(True), numpy.dtype(s)) + self.assertEquivalent(fu(True), numpy.dtype(u)) + self.assertEquivalent(fs(int(1)), numpy.dtype(s)) + self.assertEquivalent(fu(int(1)), numpy.dtype(u)) + self.assertEquivalent(fs(long(1)), numpy.dtype(s)) + self.assertEquivalent(fu(long(1)), numpy.dtype(u)) + for name in ("bool_", "byte", "ubyte", "short", "ushort", "intc", "uintc"): + t = getattr(numpy, name) + ft = getattr(dtype_ext, "accept_%s" % name) + self.assertEquivalent(ft(t(1)), numpy.dtype(t)) + # these should just use the regular Boost.Python converters + self.assertEquivalent(ft(True), numpy.dtype(t)) + if name != "bool_": + self.assertEquivalent(ft(int(1)), numpy.dtype(t)) + self.assertEquivalent(ft(long(1)), numpy.dtype(t)) + + + def testFloats(self): + f = numpy.float32 + c = numpy.complex64 + self.assertEquivalent(dtype_ext.accept_float32(f(numpy.pi)), numpy.dtype(f)) + self.assertEquivalent(dtype_ext.accept_complex64(c(1+2j)), numpy.dtype(c)) + f = numpy.float64 + c = numpy.complex128 + self.assertEquivalent(dtype_ext.accept_float64(f(numpy.pi)), numpy.dtype(f)) + self.assertEquivalent(dtype_ext.accept_complex128(c(1+2j)), numpy.dtype(c)) + if hasattr(numpy, "longdouble") and hasattr(dtype_ext, "accept_longdouble"): + f = numpy.longdouble + c = numpy.clongdouble + self.assertEquivalent(dtype_ext.accept_longdouble(f(numpy.pi)), numpy.dtype(f)) + self.assertEquivalent(dtype_ext.accept_clongdouble(c(1+2j)), numpy.dtype(c)) + + +if __name__=="__main__": + unittest.main() diff --git a/test/numpy/indexing.cpp b/test/numpy/indexing.cpp new file mode 100644 index 0000000000..f3cc457178 --- /dev/null +++ b/test/numpy/indexing.cpp @@ -0,0 +1,28 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +p::object single(np::ndarray ndarr, int i) { return ndarr[i];} +p::object slice(np::ndarray ndarr, p::slice sl) { return ndarr[sl];} +p::object indexarray(np::ndarray ndarr, np::ndarray d1) { return ndarr[d1];} +p::object indexarray_2d(np::ndarray ndarr, np::ndarray d1,np::ndarray d2) { return ndarr[p::make_tuple(d1,d2)];} +p::object indexslice(np::ndarray ndarr, np::ndarray d1, p::slice sl) { return ndarr[p::make_tuple(d1, sl)];} + +BOOST_PYTHON_MODULE(indexing_ext) +{ + np::initialize(); + p::def("single", single); + p::def("slice", slice); + p::def("indexarray", indexarray); + p::def("indexarray", indexarray_2d); + p::def("indexslice", indexslice); + +} diff --git a/test/numpy/indexing.py b/test/numpy/indexing.py new file mode 100644 index 0000000000..3fb9adb4c0 --- /dev/null +++ b/test/numpy/indexing.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import unittest +import numpy +import indexing_ext + +class TestIndexing(unittest.TestCase): + + def testSingle(self): + x = numpy.arange(0,10) + for i in range(0,10): + numpy.testing.assert_equal(indexing_ext.single(x,i), i) + for i in range(-10,0): + numpy.testing.assert_equal(indexing_ext.single(x,i),10+i) + + def testSlice(self): + x = numpy.arange(0,10) + sl = slice(3,8) + b = [3,4,5,6,7] + numpy.testing.assert_equal(indexing_ext.slice(x,sl), b) + + def testStepSlice(self): + x = numpy.arange(0,10) + sl = slice(3,8,2) + b = [3,5,7] + numpy.testing.assert_equal(indexing_ext.slice(x,sl), b) + + def testIndex(self): + x = numpy.arange(0,10) + chk = numpy.array([3,4,5,6]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,chk),chk) + chk = numpy.array([[0,1],[2,3]]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,chk),chk) + x = numpy.arange(9).reshape(3,3) + y = numpy.array([0,1]) + z = numpy.array([0,2]) + chk = numpy.array([0,5]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,y,z),chk) + x = numpy.arange(0,10) + b = x>4 + chk = numpy.array([5,6,7,8,9]) + numpy.testing.assert_equal(indexing_ext.indexarray(x,b),chk) + x = numpy.arange(9).reshape(3,3) + b = numpy.array([0,2]) + sl = slice(0,3) + chk = numpy.array([[0,1,2],[6,7,8]]) + numpy.testing.assert_equal(indexing_ext.indexslice(x,b,sl),chk) + +if __name__=="__main__": + unittest.main() diff --git a/test/numpy/ndarray.cpp b/test/numpy/ndarray.cpp new file mode 100644 index 0000000000..75a1010435 --- /dev/null +++ b/test/numpy/ndarray.cpp @@ -0,0 +1,51 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +np::ndarray zeros(p::tuple shape, np::dtype dt) { return np::zeros(shape, dt);} +np::ndarray array2(p::object obj, np::dtype dt) { return np::array(obj,dt);} +np::ndarray array1(p::object obj) { return np::array(obj);} +np::ndarray empty1(p::tuple shape, np::dtype dt) { return np::empty(shape,dt);} + +np::ndarray c_empty(p::tuple shape, np::dtype dt) +{ + // convert 'shape' to a C array so we can test the corresponding + // version of the constructor + unsigned len = p::len(shape); + Py_intptr_t *c_shape = new Py_intptr_t[len]; + for (unsigned i = 0; i != len; ++i) + c_shape[i] = p::extract(shape[i]); + np::ndarray result = np::empty(len, c_shape, dt); + delete [] c_shape; + return result; +} + +np::ndarray transpose(np::ndarray arr) { return arr.transpose();} +np::ndarray squeeze(np::ndarray arr) { return arr.squeeze();} +np::ndarray reshape(np::ndarray arr,p::tuple tup) { return arr.reshape(tup);} + +Py_intptr_t shape_index(np::ndarray arr,int k) { return arr.shape(k); } +Py_intptr_t strides_index(np::ndarray arr,int k) { return arr.strides(k); } + +BOOST_PYTHON_MODULE(ndarray_ext) +{ + np::initialize(); + p::def("zeros", zeros); + p::def("zeros_matrix", zeros, np::as_matrix<>()); + p::def("array", array2); + p::def("array", array1); + p::def("empty", empty1); + p::def("c_empty", c_empty); + p::def("transpose", transpose); + p::def("squeeze", squeeze); + p::def("reshape", reshape); + p::def("shape_index", shape_index); + p::def("strides_index", strides_index); +} diff --git a/test/numpy/ndarray.py b/test/numpy/ndarray.py new file mode 100644 index 0000000000..13f3c73e42 --- /dev/null +++ b/test/numpy/ndarray.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import ndarray_ext +import unittest +import numpy + +class TestNdarray(unittest.TestCase): + + def testNdzeros(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.zeros(60, dtype=dtp) + dt = numpy.dtype(dtp) + for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)): + a1 = ndarray_ext.zeros(shape,dt) + a2 = v.reshape(a1.shape) + self.assertEqual(shape,a1.shape) + self.assertTrue((a1 == a2).all()) + + def testNdzeros_matrix(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + dt = numpy.dtype(dtp) + shape = (6, 10) + a1 = ndarray_ext.zeros_matrix(shape, dt) + a2 = numpy.matrix(numpy.zeros(shape, dtype=dtp)) + self.assertEqual(shape,a1.shape) + self.assertTrue((a1 == a2).all()) + self.assertEqual(type(a1), type(a2)) + + def testNdarray(self): + a = range(0,60) + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.array(a, dtype=dtp) + dt = numpy.dtype(dtp) + a1 = ndarray_ext.array(a) + a2 = ndarray_ext.array(a,dt) + self.assertTrue((a1 == v).all()) + self.assertTrue((a2 == v).all()) + for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)): + a1 = a1.reshape(shape) + self.assertEqual(shape,a1.shape) + a2 = a2.reshape(shape) + self.assertEqual(shape,a2.shape) + + def testNdempty(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + dt = numpy.dtype(dtp) + for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)): + a1 = ndarray_ext.empty(shape,dt) + a2 = ndarray_ext.c_empty(shape,dt) + self.assertEqual(shape,a1.shape) + self.assertEqual(shape,a2.shape) + + def testTranspose(self): + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + dt = numpy.dtype(dtp) + for shape in ((6,10),(4,3,5),(2,2,3,5)): + a1 = numpy.empty(shape,dt) + a2 = a1.transpose() + a1 = ndarray_ext.transpose(a1) + self.assertEqual(a1.shape,a2.shape) + + def testSqueeze(self): + a1 = numpy.array([[[3,4,5]]]) + a2 = a1.squeeze() + a1 = ndarray_ext.squeeze(a1) + self.assertEqual(a1.shape,a2.shape) + + def testReshape(self): + a1 = numpy.empty((2,2)) + a2 = ndarray_ext.reshape(a1,(1,4)) + self.assertEqual(a2.shape,(1,4)) + + def testShapeIndex(self): + a = numpy.arange(24) + a.shape = (1,2,3,4) + def shape_check(i): + print(i) + self.assertEqual(ndarray_ext.shape_index(a,i) ,a.shape[i] ) + for i in range(4): + shape_check(i) + for i in range(-1,-5,-1): + shape_check(i) + try: + ndarray_ext.shape_index(a,4) # out of bounds -- should raise IndexError + self.assertTrue(False) + except IndexError: + pass + + def testStridesIndex(self): + a = numpy.arange(24) + a.shape = (1,2,3,4) + def strides_check(i): + print(i) + self.assertEqual(ndarray_ext.strides_index(a,i) ,a.strides[i] ) + for i in range(4): + strides_check(i) + for i in range(-1,-5,-1): + strides_check(i) + try: + ndarray_ext.strides_index(a,4) # out of bounds -- should raise IndexError + self.assertTrue(False) + except IndexError: + pass + + +if __name__=="__main__": + unittest.main() diff --git a/test/numpy/shapes.cpp b/test/numpy/shapes.cpp new file mode 100644 index 0000000000..a245df155c --- /dev/null +++ b/test/numpy/shapes.cpp @@ -0,0 +1,22 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +np::ndarray reshape(np::ndarray old_array, p::tuple shape) +{ + np::ndarray local_shape = old_array.reshape(shape); + return local_shape; +} + +BOOST_PYTHON_MODULE(shapes_ext) +{ + np::initialize(); + p::def("reshape", reshape); +} diff --git a/test/numpy/shapes.py b/test/numpy/shapes.py new file mode 100644 index 0000000000..28c74b7b18 --- /dev/null +++ b/test/numpy/shapes.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import shapes_ext +import unittest +import numpy + +class TestShapes(unittest.TestCase): + + def testShapes(self): + a1 = numpy.array([(0,1),(2,3)]) + a1_shape = (1,4) + a1 = shapes_ext.reshape(a1,a1_shape) + self.assertEqual(a1_shape,a1.shape) + +if __name__=="__main__": + unittest.main() diff --git a/test/numpy/templates.cpp b/test/numpy/templates.cpp new file mode 100644 index 0000000000..83de6bd2f0 --- /dev/null +++ b/test/numpy/templates.cpp @@ -0,0 +1,63 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +struct ArrayFiller +{ + + typedef boost::mpl::vector< short, int, float, std::complex > TypeSequence; + typedef boost::mpl::vector_c< int, 1, 2 > DimSequence; + + explicit ArrayFiller(np::ndarray const & arg) : argument(arg) {} + + template + void apply() const + { + if (N == 1) + { + char * p = argument.get_data(); + int stride = argument.strides(0); + int size = argument.shape(0); + for (int n = 0; n != size; ++n, p += stride) + *reinterpret_cast(p) = static_cast(n); + } + else + { + char * row_p = argument.get_data(); + int row_stride = argument.strides(0); + int col_stride = argument.strides(1); + int rows = argument.shape(0); + int cols = argument.shape(1); + int i = 0; + for (int n = 0; n != rows; ++n, row_p += row_stride) + { + char * col_p = row_p; + for (int m = 0; m != cols; ++i, ++m, col_p += col_stride) + *reinterpret_cast(col_p) = static_cast(i); + } + } + } + + np::ndarray argument; +}; + +void fill(np::ndarray const & arg) +{ + ArrayFiller filler(arg); + np::invoke_matching_array(arg, filler); +} + +BOOST_PYTHON_MODULE(templates_ext) +{ + np::initialize(); + p::def("fill", fill); +} diff --git a/test/numpy/templates.py b/test/numpy/templates.py new file mode 100755 index 0000000000..9c21622881 --- /dev/null +++ b/test/numpy/templates.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import templates_ext +import unittest +import numpy + +class TestTemplates(unittest.TestCase): + + def testTemplates(self): + for dtype in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.arange(12, dtype=dtype) + for shape in ((12,), (4, 3), (2, 6)): + a1 = numpy.zeros(shape, dtype=dtype) + a2 = v.reshape(a1.shape) + templates_ext.fill(a1) + self.assertTrue((a1 == a2).all()) + a1 = numpy.zeros((12,), dtype=numpy.float64) + self.assertRaises(TypeError, templates_ext.fill, a1) + a1 = numpy.zeros((12,2,3), dtype=numpy.float32) + self.assertRaises(TypeError, templates_ext.fill, a1) + +if __name__=="__main__": + unittest.main() diff --git a/test/numpy/ufunc.cpp b/test/numpy/ufunc.cpp new file mode 100644 index 0000000000..3a9d43cbbe --- /dev/null +++ b/test/numpy/ufunc.cpp @@ -0,0 +1,36 @@ +// Copyright Jim Bosch & Ankit Daftery 2010-2012. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +namespace p = boost::python; +namespace np = boost::python::numpy; + +struct UnaryCallable +{ + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * 2;} +}; + +struct BinaryCallable +{ + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a, double b) const { return a * 2 + b * 3;} +}; + +BOOST_PYTHON_MODULE(ufunc_ext) +{ + np::initialize(); + p::class_("UnaryCallable") + .def("__call__", np::unary_ufunc::make()); + p::class_< BinaryCallable>("BinaryCallable") + .def("__call__", np::binary_ufunc::make()); +} diff --git a/test/numpy/ufunc.py b/test/numpy/ufunc.py new file mode 100755 index 0000000000..1fa3090b3e --- /dev/null +++ b/test/numpy/ufunc.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# Copyright Jim Bosch & Ankit Daftery 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import ufunc_ext +import unittest +import numpy +try: + from numpy.testing import assert_array_almost_equal +except ImportError: + from numpy.testing.utils import assert_array_almost_equal + +class TestUnary(unittest.TestCase): + + def testScalar(self): + f = ufunc_ext.UnaryCallable() + assert_array_almost_equal(f(1.0), 2.0) + assert_array_almost_equal(f(3.0), 6.0) + + def testArray(self): + f = ufunc_ext.UnaryCallable() + a = numpy.arange(5, dtype=float) + b = f(a) + assert_array_almost_equal(b, a*2.0) + c = numpy.zeros(5, dtype=float) + d = f(a,output=c) + self.assertTrue((c == d).all()) + assert_array_almost_equal(d, a*2.0) + + def testList(self): + f = ufunc_ext.UnaryCallable() + a = range(5) + b = f(a) + assert_array_almost_equal(b/2.0, a) + +class TestBinary(unittest.TestCase): + + def testScalar(self): + f = ufunc_ext.BinaryCallable() + assert_array_almost_equal(f(1.0, 3.0), 11.0) + assert_array_almost_equal(f(3.0, 2.0), 12.0) + + def testArray(self): + f = ufunc_ext.BinaryCallable() + a = numpy.random.randn(5) + b = numpy.random.randn(5) + assert_array_almost_equal(f(a,b), (a*2+b*3)) + c = numpy.zeros(5, dtype=float) + d = f(a,b,output=c) + self.assertTrue((c == d).all()) + assert_array_almost_equal(d, a*2 + b*3) + assert_array_almost_equal(f(a, 2.0), a*2 + 6.0) + assert_array_almost_equal(f(1.0, b), 2.0 + b*3) + + +if __name__=="__main__": + unittest.main() diff --git a/test/object.py b/test/object.py index 84972e64f3..cf6c2de0c5 100644 --- a/test/object.py +++ b/test/object.py @@ -8,7 +8,7 @@ >>> def print1(x): -... print x +... print(x) >>> call_object_3(print1) 3 >>> message() @@ -33,10 +33,10 @@ >>> try: obj_getattr(x, 'foo') ... except AttributeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') >>> try: obj_objgetattr(x, 'objfoo') ... except AttributeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') >>> obj_setattr(x, 'foo', 1) >>> x.foo @@ -44,7 +44,7 @@ >>> obj_objsetattr(x, 'objfoo', 1) >>> try:obj_objsetattr(x, 1) ... except TypeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') >>> x.objfoo 1 >>> obj_getattr(x, 'foo') @@ -53,7 +53,7 @@ 1 >>> try:obj_objgetattr(x, 1) ... except TypeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') >>> obj_const_getattr(x, 'foo') 1 >>> obj_const_objgetattr(x, 'objfoo') @@ -92,10 +92,10 @@ >>> obj_objdelattr(x, 'objfoo') >>> try:obj_delattr(x, 'foo') ... except AttributeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') >>> try:obj_objdelattr(x, 'objfoo') ... except AttributeError: pass -... else: print 'expected an exception' +... else: print('expected an exception') Items @@ -129,14 +129,14 @@ 1 Slices - + >>> assert check_string_slice() Operators ->>> def print_args(*args, **kwds): -... print args, kwds ->>> test_call(print_args, (0, 1, 2, 3), {'a':'A'}) +>>> def print_args(*args, **kwds): +... print(args, kwds) +>>> test_call(print_args, (0, 1, 2, 3), {'a':'A'}) (0, 1, 2, 3) {'a': 'A'} @@ -144,16 +144,16 @@ >>> class X: pass ... ->>> assert check_inplace(range(3), X()) +>>> assert check_inplace(list(range(3)), X()) Now make sure that object is actually managing reference counts - + >>> import weakref >>> class Z: pass ... >>> z = Z() ->>> def death(r): print 'death' +>>> def death(r): print('death') ... >>> r = weakref.ref(z, death) >>> z.foo = 1 @@ -163,6 +163,8 @@ death ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -170,10 +172,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/object_fail1.cpp b/test/object_fail1.cpp old mode 100755 new mode 100644 diff --git a/test/object_manager.cpp b/test/object_manager.cpp old mode 100755 new mode 100644 diff --git a/test/opaque.py b/test/opaque.py index 2ee0aa0c0c..9f5663723d 100644 --- a/test/opaque.py +++ b/test/opaque.py @@ -1,5 +1,5 @@ -# -*- coding: latin-1 -*- -# Copyright Gottfried Gan�auge 2003..2006. Distributed under the Boost +# -*- coding: utf-8 -*- +# Copyright Gottfried Ganßauge 2003..2006. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -35,13 +35,13 @@ >>> try: use(0) ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') ... and from strings to opaque objects >>> try: use("") ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') Now check the same for another opaque pointer type @@ -52,19 +52,19 @@ RuntimeError: success >>> try: use2(0) ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') >>> try: use2("") ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') Check that opaque types are distinct >>> try: use(get2()) ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') >>> try: use2(get()) ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') This used to result in a segmentation violation @@ -80,8 +80,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/operators.cpp b/test/operators.cpp old mode 100755 new mode 100644 diff --git a/test/operators.py b/test/operators.py index f39134b664..5b369803c6 100644 --- a/test/operators.py +++ b/test/operators.py @@ -95,8 +95,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/operators_wrapper.cpp b/test/operators_wrapper.cpp index 12f30048d0..e62ead16f8 100644 --- a/test/operators_wrapper.cpp +++ b/test/operators_wrapper.cpp @@ -36,7 +36,7 @@ BOOST_PYTHON_MODULE( operators_wrapper_ext ) ; scope().attr("v") = vector(); - std::auto_ptr dp(new dvector); - register_ptr_to_python< std::auto_ptr >(); + std::shared_ptr dp(new dvector); + register_ptr_to_python< std::shared_ptr >(); scope().attr("d") = dp; } diff --git a/test/pickle1.py b/test/pickle1.py index 8369768d67..0df59a4b3a 100644 --- a/test/pickle1.py +++ b/test/pickle1.py @@ -9,19 +9,21 @@ 1 >>> pickle1_ext.world.__name__ 'world' - >>> pickle1_ext.world('Hello').__reduce__() + >>> pickle1_ext.world('Hello').__reduce__() # doctest: +PY310 (, ('Hello',)) + >>> pickle1_ext.world('Hello').__reduce__() # doctest: +PY311 + (, ('Hello',), None) >>> wd = pickle1_ext.world('California') >>> pstr = pickle.dumps(wd) >>> wl = pickle.loads(pstr) - >>> print wd.greet() + >>> print(wd.greet()) Hello from California! - >>> print wl.greet() + >>> print(wl.greet()) Hello from California! >>> noop = pickle1_ext.noop() >>> try: pickle.dumps(noop) - ... except RuntimeError, e: print str(e)[:55] + ... except RuntimeError as e: print(str(e)[:55]) Pickling of "pickle1_ext.noop" instances is not enabled ''' @@ -31,11 +33,31 @@ def run(args = None): if args is not None: sys.argv = args - return doctest.testmod(sys.modules.get(__name__)) + + # > https://docs.python.org/3.11/library/pickle.html#object.__reduce__ + # object.__reduce__() returns + # - python 3.10 or prior: a 2-element tuple + # - python 3.11 or later: a 3-element tuple (object's state added) + PY310 = doctest.register_optionflag("PY310") + PY311 = doctest.register_optionflag("PY311") + + class ConditionalChecker(doctest.OutputChecker): + def check_output(self, want, got, optionflags): + if (optionflags & PY311) and (sys.version_info[:2] < (3, 11)): + return True + if (optionflags & PY310) and (sys.version_info[:2] >= (3, 11)): + return True + return doctest.OutputChecker.check_output(self, want, got, optionflags) + + runner = doctest.DocTestRunner(ConditionalChecker()) + for test in doctest.DocTestFinder().find(sys.modules.get(__name__)): + runner.run(test) + + return doctest.TestResults(runner.failures, runner.tries) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/pickle2.py b/test/pickle2.py index 2ad663fffe..4c11ef3a85 100644 --- a/test/pickle2.py +++ b/test/pickle2.py @@ -16,8 +16,8 @@ ... wd.set_secret_number(number) ... pstr = pickle.dumps(wd) ... wl = pickle.loads(pstr) - ... print wd.greet(), wd.get_secret_number() - ... print wl.greet(), wl.get_secret_number() + ... 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 @@ -29,11 +29,13 @@ >>> wd.__dict__ {'x': 1} >>> try: pstr = pickle.dumps(wd) - ... except RuntimeError, err: print err + ... except RuntimeError as err: print(err) ... Incomplete pickle support (__getstate_manages_dict__ not set) ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -41,10 +43,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/pickle3.py b/test/pickle3.py index 6be3128c58..391e3d00f1 100644 --- a/test/pickle3.py +++ b/test/pickle3.py @@ -21,14 +21,16 @@ ... wd.z = 3. * number ... pstr = pickle.dumps(wd) ... wl = pickle.loads(pstr) - ... print wd.greet(), wd.get_secret_number(), wd.x, wd.y, wd.z - ... print wl.greet(), wl.get_secret_number(), wl.x, wl.y, wl.z + ... print(wd.greet(), wd.get_secret_number(), wd.x, wd.y, wd.z) + ... print(wl.greet(), wl.get_secret_number(), wl.x, wl.y, wl.z) Hello from California! 24 48 yyyyyyyyyyyyyyyyyyyyyyyy 72.0 Hello from California! 24 48 yyyyyyyyyyyyyyyyyyyyyyyy 72.0 Hello from California! 42 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 Hello from California! 0 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -36,10 +38,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/pickle4.py b/test/pickle4.py index a5069c90de..3cf4d7241f 100644 --- a/test/pickle4.py +++ b/test/pickle4.py @@ -12,14 +12,16 @@ 1 >>> pickle4_ext.world.__name__ 'world' - >>> pickle4_ext.world('Hello').__reduce__() + >>> pickle4_ext.world('Hello').__reduce__() # doctest: +PY310 (, ('Hello',)) + >>> pickle4_ext.world('Hello').__reduce__() # doctest: +PY311 + (, ('Hello',), None) >>> wd = pickle4_ext.world('California') >>> pstr = pickle.dumps(wd) >>> wl = pickle.loads(pstr) - >>> print wd.greet() + >>> print(wd.greet()) Hello from California! - >>> print wl.greet() + >>> print(wl.greet()) Hello from California! ''' @@ -29,11 +31,31 @@ def run(args = None): if args is not None: sys.argv = args - return doctest.testmod(sys.modules.get(__name__)) + + # > https://docs.python.org/3.11/library/pickle.html#object.__reduce__ + # object.__reduce__() returns + # - python 3.10 or prior: a 2-element tuple + # - python 3.11 or later: a 3-element tuple (object's state added) + PY310 = doctest.register_optionflag("PY310") + PY311 = doctest.register_optionflag("PY311") + + class ConditionalChecker(doctest.OutputChecker): + def check_output(self, want, got, optionflags): + if (optionflags & PY311) and (sys.version_info[:2] < (3, 11)): + return True + if (optionflags & PY310) and (sys.version_info[:2] >= (3, 11)): + return True + return doctest.OutputChecker.check_output(self, want, got, optionflags) + + runner = doctest.DocTestRunner(ConditionalChecker()) + for test in doctest.DocTestFinder().find(sys.modules.get(__name__)): + runner.run(test) + + return doctest.TestResults(runner.failures, runner.tries) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/pointee.cpp b/test/pointee.cpp index d962e79f56..2aa5dc3d88 100644 --- a/test/pointee.cpp +++ b/test/pointee.cpp @@ -3,7 +3,7 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include #include #include #include @@ -13,19 +13,19 @@ struct A; int main() { BOOST_STATIC_ASSERT( - (boost::is_same< + (boost::python::detail::is_same< boost::python::pointee >::type , char** >::value)); BOOST_STATIC_ASSERT( - (boost::is_same< + (boost::python::detail::is_same< boost::python::pointee >::type , A>::value)); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION BOOST_STATIC_ASSERT( - (boost::is_same< + (boost::python::detail::is_same< boost::python::pointee::type , char >::value)); diff --git a/test/pointer_vector.py b/test/pointer_vector.py index 16900e8eb6..234eff2c0b 100644 --- a/test/pointer_vector.py +++ b/test/pointer_vector.py @@ -21,10 +21,10 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print 'running...' + print('running...') import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/polymorphism.py b/test/polymorphism.py index 0218b81080..e3c66ea279 100644 --- a/test/polymorphism.py +++ b/test/polymorphism.py @@ -17,23 +17,23 @@ def testReturnCpp(self): # Python Created B Object and Cpp B Object # Should have same result by calling f() - self.failUnlessEqual ('B::f()', a.f()) - self.failUnlessEqual ('B::f()', call_f(a)) - self.failUnlessEqual ('A::f()', call_f(A())) + self.assertEqual ('B::f()', a.f()) + self.assertEqual ('B::f()', call_f(a)) + self.assertEqual ('A::f()', call_f(A())) def test_references(self): # B is not exposed to Python a = getBCppObj() - self.failUnlessEqual(type(a), A) + self.assertEqual(type(a), A) # C is exposed to Python c = getCCppObj() - self.failUnlessEqual(type(c), C) + self.assertEqual(type(c), C) def test_factory(self): - self.failUnlessEqual(type(factory(0)), A) - self.failUnlessEqual(type(factory(1)), A) - self.failUnlessEqual(type(factory(2)), C) + self.assertEqual(type(factory(0)), A) + self.assertEqual(type(factory(1)), A) + self.assertEqual(type(factory(2)), C) def test_return_py(self): @@ -43,26 +43,26 @@ def f(self): x = X() - self.failUnlessEqual ('X.f', x.f()) - self.failUnlessEqual ('X.f', call_f(x)) + self.assertEqual ('X.f', x.f()) + self.assertEqual ('X.f', call_f(x)) def test_wrapper_downcast(self): a = pass_a(D()) - self.failUnlessEqual('D::g()', a.g()) + self.assertEqual('D::g()', a.g()) def test_pure_virtual(self): p = P() self.assertRaises(RuntimeError, p.f) q = Q() - self.failUnlessEqual ('Q::f()', q.f()) + self.assertEqual ('Q::f()', q.f()) class R(P): def f(self): return 'R.f' r = R() - self.failUnlessEqual ('R.f', r.f()) + self.assertEqual ('R.f', r.f()) if __name__ == "__main__": diff --git a/test/polymorphism2.cpp b/test/polymorphism2.cpp old mode 100755 new mode 100644 diff --git a/test/polymorphism2.py b/test/polymorphism2.py index 2690bac9a1..cf7384fab8 100644 --- a/test/polymorphism2.py +++ b/test/polymorphism2.py @@ -17,23 +17,23 @@ def testReturnCpp(self): # Python Created B Object and Cpp B Object # Should have same result by calling f() - self.failUnlessEqual ('B::f()', a.f()) - self.failUnlessEqual ('B::f()', call_f(a)) - self.failUnlessEqual ('A::f()', call_f(A())) + self.assertEqual ('B::f()', a.f()) + self.assertEqual ('B::f()', call_f(a)) + self.assertEqual ('A::f()', call_f(A())) def test_references(self): # B is not exposed to Python a = getBCppObj() - self.failUnlessEqual(type(a), A) + self.assertEqual(type(a), A) # C is exposed to Python c = getCCppObj() - self.failUnlessEqual(type(c), C) + self.assertEqual(type(c), C) def test_factory(self): - self.failUnlessEqual(type(factory(0)), A) - self.failUnlessEqual(type(factory(1)), A) - self.failUnlessEqual(type(factory(2)), C) + self.assertEqual(type(factory(0)), A) + self.assertEqual(type(factory(1)), A) + self.assertEqual(type(factory(2)), C) def test_return_py(self): @@ -43,8 +43,8 @@ def f(self): x = X() - self.failUnlessEqual ('X.f', x.f()) - self.failUnlessEqual ('X.f', call_f(x)) + self.assertEqual ('X.f', x.f()) + self.assertEqual ('X.f', call_f(x)) def test_self_default(self): @@ -54,28 +54,28 @@ def f(self): x = X() - self.failUnlessEqual ('X.f() -> A::f()', x.f()) + self.assertEqual ('X.f() -> A::f()', x.f()) # This one properly raises the "dangling reference" exception # self.failUnlessEqual ('X.f() -> A::f()', call_f(x)) def test_wrapper_downcast(self): a = pass_a(D()) - self.failUnlessEqual('D::g()', a.g()) + self.assertEqual('D::g()', a.g()) def test_pure_virtual(self): p = P() self.assertRaises(RuntimeError, p.f) q = Q() - self.failUnlessEqual ('Q::f()', q.f()) + self.assertEqual ('Q::f()', q.f()) class R(P): def f(self): return 'R.f' r = R() - self.failUnlessEqual ('R.f', r.f()) + self.assertEqual ('R.f', r.f()) def test(): diff --git a/test/polymorphism2_auto_ptr.cpp b/test/polymorphism2_auto_ptr.cpp old mode 100755 new mode 100644 diff --git a/test/printer.py b/test/printer.py deleted file mode 100644 index e08f7c453f..0000000000 --- a/test/printer.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright David Abrahams 2006. Distributed under the Boost -# Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -class _printer(object): - def __init__(self): - self.results = []; - def __call__(self, *stuff): - for x in stuff: - self.results.append(str(x)) - def check(self, x): - if self.results[0] != str(x): - print ' Expected:\n %s\n but the C++ interface gave:\n %s' % (x, self.results[0]) - del self.results[0] diff --git a/test/properties.cpp b/test/properties.cpp old mode 100755 new mode 100644 index d338beb915..aa1b0a05cf --- a/test/properties.cpp +++ b/test/properties.cpp @@ -64,6 +64,7 @@ BOOST_PYTHON_MODULE(properties_ext) class_("X", init() ) //defining read only property .add_property( "value_r", &X::get_value ) + .add_property( "value_r_f", make_function(&X::get_value) ) .add_property( "value_r_ds", &X::get_value, "value_r_ds is read-only") //defining read \ write property .add_property( "value_rw", &X::get_value, &X::set_value ) diff --git a/test/properties.py b/test/properties.py index 720fb85989..e95d59bef2 100644 --- a/test/properties.py +++ b/test/properties.py @@ -20,6 +20,9 @@ >>> x1.value_r 1 +>>> x1.value_r_f +1 + value read - write >>> x1.value_rw 1 @@ -53,11 +56,10 @@ class instance count from object: 1 as expected you can't assign new value to read only property ->>> x1.value_r = 2 +>>> x1.value_r = 2 # doctest: +ELLIPSIS Traceback (most recent call last): - File "properties.py", line 49, in ? - x1.value_r = 2 -AttributeError: can't set attribute + ... +AttributeError: ... setting value_rw to 2. value_direct: >>> x1.value_rw = 2 @@ -84,8 +86,27 @@ class instance count from object: >>> assert properties.X.value_rw_ds.__doc__ == "value_rw_ds is read-write" +>>> properties.X.value_r_f.fget.__doc__.strip().split("\\n")[0] +'None( (properties_ext.X)arg1) -> int :' + +>>> properties.X.value_rw_ds.fget.__doc__.strip().split("\\n")[0] +'None( (properties_ext.X)arg1) -> int :' + +>>> properties.X.value_rw_ds.fset.__doc__.strip().split("\\n")[0] +'None( (properties_ext.X)arg1, (int)arg2) -> None :' + +>>> properties.X.value_rw_ds.fget.__doc__.strip().split("\\n")[0] +'None( (properties_ext.X)arg1) -> int :' + +>>> properties.X.value_direct.fset.__doc__.strip().split("\\n")[0] +'None( (properties_ext.X)arg1, (int)arg2) -> None :' + +>>> properties.X.value_direct.fget.__doc__.strip().split("\\n")[0] +'None( (properties_ext.X)arg1) -> int :' """ +# FIXME: cases to cover: pointer-to-member, preconstructed function + #import sys; sys.path.append(r'P:\Actimize4.0\smart_const\py_smart_const___Win32_Debug') import properties_ext as properties @@ -99,8 +120,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/pyrun.py b/test/pyrun.py index e033069ebd..d330773eae 100644 --- a/test/pyrun.py +++ b/test/pyrun.py @@ -4,4 +4,4 @@ scriptfile = sys.argv[2] sys.argv = sys.argv[2:] sys.path.append(pythonpath) -execfile(scriptfile) +exec(compile(open(scriptfile).read(), scriptfile, 'exec')) diff --git a/test/pytype_function.py b/test/pytype_function.py old mode 100755 new mode 100644 index 83674632a1..a7101fb996 --- a/test/pytype_function.py +++ b/test/pytype_function.py @@ -4,13 +4,13 @@ """ >>> from pytype_function_ext import * ->>> print func.__doc__.splitlines()[1] +>>> print(func.__doc__.splitlines()[1]) func( (A)arg1) -> A : ->>> print func.__module__ +>>> print(func.__module__) pytype_function_ext ->>> print func.__name__ +>>> print(func.__name__) func """ def run(args = None): @@ -22,10 +22,10 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/raw_ctor.cpp b/test/raw_ctor.cpp old mode 100755 new mode 100644 diff --git a/test/raw_ctor.py b/test/raw_ctor.py index 686948ff0d..1e9a9192a4 100644 --- a/test/raw_ctor.py +++ b/test/raw_ctor.py @@ -12,7 +12,7 @@ >>> f = Foo(1, 2, 'a', bar = 3, baz = 4) >>> f.args (1, 2, 'a') ->>> f.kw.items() +>>> sorted(f.kw.items()) [('bar', 3), ('baz', 4)] """ def run(args = None): @@ -24,10 +24,10 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/raw_pyobject_fail1.cpp b/test/raw_pyobject_fail1.cpp old mode 100755 new mode 100644 diff --git a/test/raw_pyobject_fail2.cpp b/test/raw_pyobject_fail2.cpp old mode 100755 new mode 100644 diff --git a/test/result.cpp b/test/result.cpp old mode 100755 new mode 100644 diff --git a/test/return_arg.cpp b/test/return_arg.cpp old mode 100755 new mode 100644 diff --git a/test/return_arg.py b/test/return_arg.py index f191d59641..e66a0b8d93 100644 --- a/test/return_arg.py +++ b/test/return_arg.py @@ -20,8 +20,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/select_holder.cpp b/test/select_holder.cpp index 4ecc52e7a8..77aac67868 100644 --- a/test/select_holder.cpp +++ b/test/select_holder.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -29,7 +29,7 @@ namespace boost { namespace python template void assert_same(U* = 0, T* = 0) { - BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::python::detail::is_same::value)); } @@ -62,14 +62,14 @@ int test_main(int, char * []) assert_holder >(); - assert_holder - ,pointer_holder,Base> >(); + assert_holder + ,pointer_holder,Base> >(); - assert_holder - ,pointer_holder_back_reference,Base> >(); + assert_holder + ,pointer_holder_back_reference,Base> >(); - assert_holder - ,pointer_holder_back_reference,BR> > (); + assert_holder + ,pointer_holder_back_reference,BR> > (); return 0; } diff --git a/test/shared_ptr.cpp b/test/shared_ptr.cpp index e5f20a7320..f72e6f0297 100644 --- a/test/shared_ptr.cpp +++ b/test/shared_ptr.cpp @@ -1,4 +1,5 @@ // Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -8,210 +9,11 @@ #include #include #include -#include -#include "test_class.hpp" - #include -using namespace boost::python; -using boost::shared_ptr; - -typedef test_class<> X; -typedef test_class<1> Y; - -template -struct functions -{ - static int look(shared_ptr const& x) - { - return (x.get()) ? x->value() : -1; - } - - static void store(shared_ptr x) - { - storage = x; - } - - static void release_store() - { - store(shared_ptr()); - } - - static void modify(shared_ptr& x) - { - x.reset(); - } - - static shared_ptr get() { return storage; } - static shared_ptr &get1() { return storage; } - - static int look_store() - { - return look(get()); - } - - template - static void expose(C const& c) - { - def("look", &look); - def("store", &store); - def("modify", &modify); - def("identity", &identity); - def("null", &null); - - const_cast(c) - .def("look", &look) - .staticmethod("look") - .def("store", &store) - .staticmethod("store") - .def("modify", &modify) - .staticmethod("modify") - .def("look_store", &look_store) - .staticmethod("look_store") - .def("identity", &identity) - .staticmethod("identity") - .def("null", &null) - .staticmethod("null") - .def("get1", &get1, return_internal_reference<>()) - .staticmethod("get1") - .def("get", &get) - .staticmethod("get") - .def("count", &T::count) - .staticmethod("count") - .def("release", &release_store) - .staticmethod("release") - ; - } - - static shared_ptr identity(shared_ptr x) { return x; } - static shared_ptr null(T const&) { return shared_ptr(); } - - - static shared_ptr storage; -}; - -template shared_ptr functions::storage; - -struct Z : test_class<2> -{ - Z(int x) : test_class<2>(x) {} - virtual int v() { return this->value(); } -}; - -struct ZWrap : Z -{ - ZWrap(PyObject* self, int x) - : Z(x), m_self(self) {} - - - virtual int v() { return call_method(m_self, "v"); } - int default_v() { return Z::v(); } - - - PyObject* m_self; -}; - -struct YY : Y -{ - YY(int n) : Y(n) {} -}; - -struct YYY : Y -{ - YYY(int n) : Y(n) {} -}; - -shared_ptr factory(int n) -{ - return shared_ptr(n < 42 ? new Y(n) : new YY(n)); -} - -// regressions from Nicodemus - struct A - { - virtual ~A() {}; // silence compiler warnings - virtual int f() = 0; - static int call_f(shared_ptr& a) { return a->f(); } - }; - - struct B: A - { - int f() { return 1; } - }; - - boost::shared_ptr New(bool make) - { - return boost::shared_ptr( make ? new B() : 0 ); - } - - struct A_Wrapper: A - { - A_Wrapper(PyObject* self_): - A(), self(self_) {} - - int f() { - return call_method< int >(self, "f"); - } - - PyObject* self; - }; - -// ------ - -// from Neal Becker - -struct Test { - boost::shared_ptr x; -}; -// ------ - - -BOOST_PYTHON_MODULE(shared_ptr_ext) -{ - class_, boost::noncopyable>("A") - .def("call_f", &A::call_f) - .staticmethod("call_f") - ; - - // This is the ugliness required to register a to-python converter - // for shared_ptr. - objects::class_value_wrapper< - shared_ptr - , objects::make_ptr_instance,A> > - >(); - - def("New", &New); - - def("factory", factory); - - functions::expose( - class_("X", init()) - .def("value", &X::value) - ); - - functions::expose( - class_ >("Y", init()) - .def("value", &Y::value) - ); - - class_, boost::noncopyable>("YY", init()) - ; - - class_, bases >("YYY", init()) - ; - - functions::expose( - class_("Z", init()) - .def("value", &Z::value) - .def("v", &Z::v, &ZWrap::default_v) - ); - -// from Neal Becker - class_ ("Test") - .def_readonly ("x", &Test::x, "x") - ; -// ------ -} +using std::shared_ptr; +#define MODULE shared_ptr_ext +#include "shared_ptr.hpp" #include "module_tail.cpp" diff --git a/test/shared_ptr.hpp b/test/shared_ptr.hpp new file mode 100644 index 0000000000..9f9a4b69e3 --- /dev/null +++ b/test/shared_ptr.hpp @@ -0,0 +1,206 @@ +// Copyright David Abrahams 2002. +// Copyright Stefan Seefeld 2016. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "test_class.hpp" + +using namespace boost::python; + +typedef test_class<> X; +typedef test_class<1> Y; + +template +struct functions +{ + static int look(shared_ptr const& x) + { + return (x.get()) ? x->value() : -1; + } + + static void store(shared_ptr x) + { + storage = x; + } + + static void release_store() + { + store(shared_ptr()); + } + + static void modify(shared_ptr& x) + { + x.reset(); + } + + static shared_ptr get() { return storage; } + static shared_ptr &get1() { return storage; } + + static int look_store() + { + return look(get()); + } + + template + static void expose(C const& c) + { + def("look", &look); + def("store", &store); + def("modify", &modify); + def("identity", &identity); + def("null", &null); + + const_cast(c) + .def("look", &look) + .staticmethod("look") + .def("store", &store) + .staticmethod("store") + .def("modify", &modify) + .staticmethod("modify") + .def("look_store", &look_store) + .staticmethod("look_store") + .def("identity", &identity) + .staticmethod("identity") + .def("null", &null) + .staticmethod("null") + .def("get1", &get1, return_internal_reference<>()) + .staticmethod("get1") + .def("get", &get) + .staticmethod("get") + .def("count", &T::count) + .staticmethod("count") + .def("release", &release_store) + .staticmethod("release") + ; + } + + static shared_ptr identity(shared_ptr x) { return x; } + static shared_ptr null(T const&) { return shared_ptr(); } + + + static shared_ptr storage; +}; + +template shared_ptr functions::storage; + +struct Z : test_class<2> +{ + Z(int x) : test_class<2>(x) {} + virtual int v() { return this->value(); } +}; + +struct ZWrap : Z +{ + ZWrap(PyObject* self, int x) + : Z(x), m_self(self) {} + + + virtual int v() { return call_method(m_self, "v"); } + int default_v() { return Z::v(); } + + + PyObject* m_self; +}; + +struct YY : Y +{ + YY(int n) : Y(n) {} +}; + +struct YYY : Y +{ + YYY(int n) : Y(n) {} +}; + +shared_ptr factory(int n) +{ + return shared_ptr(n < 42 ? new Y(n) : new YY(n)); +} + +// regressions from Nicodemus + struct A + { + virtual ~A() {}; // silence compiler warnings + virtual int f() = 0; + static int call_f(shared_ptr& a) { return a->f(); } + }; + + struct B: A + { + int f() { return 1; } + }; + + shared_ptr New(bool make) + { + return shared_ptr( make ? new B() : 0 ); + } + + struct A_Wrapper: A + { + A_Wrapper(PyObject* self_): + A(), self(self_) {} + + int f() { + return call_method< int >(self, "f"); + } + + PyObject* self; + }; + +// ------ + +// from Neal Becker + +struct Test { + shared_ptr x; +}; +// ------ + + +BOOST_PYTHON_MODULE(MODULE) +{ + class_, boost::noncopyable>("A") + .def("call_f", &A::call_f) + .staticmethod("call_f") + ; + + // This is the ugliness required to register a to-python converter + // for shared_ptr. + objects::class_value_wrapper< + shared_ptr + , objects::make_ptr_instance,A> > + >(); + + def("New", &New); + + def("factory", factory); + + functions::expose( + class_("X", init()) + .def("value", &X::value) + ); + + functions::expose( + class_ >("Y", init()) + .def("value", &Y::value) + ); + + class_, boost::noncopyable>("YY", init()) + ; + + class_, bases >("YYY", init()) + ; + + functions::expose( + class_("Z", init()) + .def("value", &Z::value) + .def("v", &Z::v, &ZWrap::default_v) + ); + +// from Neal Becker + class_ ("Test") + .def_readonly ("x", &Test::x, "x") + ; +// ------ +} diff --git a/test/shared_ptr.py b/test/shared_ptr.py index 554b4a6b61..4ef88f78d8 100644 --- a/test/shared_ptr.py +++ b/test/shared_ptr.py @@ -5,7 +5,7 @@ >>> from shared_ptr_ext import * Test that shared_ptr can be converted to shared_ptr - + >>> Y.store(YYY(42)) >>> x = X(17) @@ -27,7 +27,7 @@ ... def v(self): ... return -Z.v(self); ... def __del__(self): -... print 'bye' +... print('bye') ... >>> p = P(12) >>> p.value() @@ -38,7 +38,7 @@ 12 >>> try: modify(p) ... except TypeError: pass -... else: 'print expected a TypeError' +... else: print('expected a TypeError') >>> look(None) -1 >>> store(p) @@ -61,7 +61,7 @@ 13 >>> try: modify(z) ... except TypeError: pass -... else: 'print expected a TypeError' +... else: print('expected a TypeError') >>> Z.get() # should be None >>> store(z) @@ -84,7 +84,7 @@ 17 >>> try: modify(x) ... except TypeError: pass -... else: 'print expected a TypeError' +... else: print('expected a TypeError') >>> look(None) -1 >>> store(x) @@ -121,10 +121,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/slice.cpp b/test/slice.cpp index 5072d7f7c7..b1b965fa10 100644 --- a/test/slice.cpp +++ b/test/slice.cpp @@ -52,47 +52,6 @@ bool check_string_rich_slice() return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2); \ else -// These tests work with Python 2.2, but you must have Numeric installed. -object check_numeric_array_rich_slice( - char const* module_name, char const* array_type_name, object all) -{ - using numeric::array; - array::set_module_and_type(module_name, array_type_name); - - array original = array( make_tuple( make_tuple( 11, 12, 13, 14), - make_tuple( 21, 22, 23, 24), - make_tuple( 31, 32, 33, 34), - make_tuple( 41, 42, 43, 44))); - array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12), - make_tuple( 21, 22))); - array odd_cells = array( make_tuple( make_tuple( 11, 13), - make_tuple( 31, 33))); - array even_cells = array( make_tuple( make_tuple( 22, 24), - make_tuple( 42, 44))); - array lower_right_quadrant_reversed = array( - make_tuple( make_tuple(44, 43), - make_tuple(34, 33))); - - // The following comments represent equivalent Python expressions used - // to validate the array behavior. - // original[::] == original - ASSERT_EQUAL(original[slice()],original); - - // original[:2,:2] == array( [[11, 12], [21, 22]]) - ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant); - - // original[::2,::2] == array( [[11, 13], [31, 33]]) - ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells); - - // original[1::2, 1::2] == array( [[22, 24], [42, 44]]) - ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells); - - // original[:-3:-1, :-3,-1] == array( [[44, 43], [34, 33]]) - ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed); - - return object(1); -} - // Verify functions accepting a slice argument can be called bool accept_slice( slice) { return true; } @@ -134,7 +93,6 @@ int check_slice_get_indices( BOOST_PYTHON_MODULE(slice_ext) { def( "accept_slice", accept_slice); - def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice); def( "check_string_rich_slice", check_string_rich_slice); def( "check_slice_get_indices", check_slice_get_indices); } diff --git a/test/slice.py b/test/slice.py index 95f4883b09..041934cf57 100644 --- a/test/slice.py +++ b/test/slice.py @@ -7,34 +7,18 @@ 1 >>> try: ... accept_slice(list((1,2))) -... print "test failed" +... print("test failed") ... except: -... print "test passed" +... print("test passed") ... test passed ->>> try: -... from Numeric import array -... except: -... print 1 -... else: -... check_numeric_array_rich_slice('Numeric', 'ArrayType', lambda x:x) -... -1 ->>> try: -... from numarray import array, all -... except: -... print 1 -... else: -... check_numeric_array_rich_slice('numarray', 'NDArray', all) -... -1 >>> import sys >>> if sys.version_info[0] == 2 and sys.version_info[1] >= 3: ... check_string_rich_slice() ... elif sys.version_info[0] > 2: ... check_string_rich_slice() ... else: -... print 1 +... print(1) ... 1 >>> check_slice_get_indices( slice(None)) @@ -49,11 +33,11 @@ 0 >>> check_slice_get_indices( slice( -2, -5, -2)) 6 +>>> check_slice_get_indices.__doc__.strip().split('\\n')[0] +'check_slice_get_indices( (slice)arg1) -> int :' """ -# Performs an affirmative and negative argument resolution check, -# checks the operation of extended slicing in Numeric arrays -# (only performed if Numeric.array or numarray.array can be found). +# Performs an affirmative and negative argument resolution check. # checks the operation of extended slicing in new strings (Python 2.3 only). def run(args = None): @@ -65,8 +49,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/staticmethod.py b/test/staticmethod.py index cc2fb6a7b3..3dd355b133 100644 --- a/test/staticmethod.py +++ b/test/staticmethod.py @@ -50,8 +50,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/stl_iterator.cpp b/test/stl_iterator.cpp old mode 100755 new mode 100644 diff --git a/test/stl_iterator.py b/test/stl_iterator.py index 2c324c0abb..4743ed632a 100644 --- a/test/stl_iterator.py +++ b/test/stl_iterator.py @@ -6,7 +6,7 @@ >>> x = list_int() >>> x.assign(iter([1,2,3,4,5])) >>> for y in x: -... print y +... print(y) 1 2 3 @@ -15,12 +15,12 @@ >>> def generator(): ... yield 1 ... yield 2 -... raise RuntimeError, "oops" +... raise RuntimeError("oops") >>> try: ... x.assign(iter(generator())) -... print "NOT OK" +... print("NOT OK") ... except RuntimeError: -... print "OK" +... print("OK") OK ''' def run(args = None): @@ -32,8 +32,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/str.py b/test/str.py index 5f10580cf6..bfb4994959 100644 --- a/test/str.py +++ b/test/str.py @@ -4,8 +4,8 @@ """ >>> from str_ext import * >>> def printer(*args): -... for x in args: print x, -... print +... for x in args: print(x, end=' ') +... print('') ... >>> work_with_string(printer) #doctest: +NORMALIZE_WHITESPACE ['this', 'is', 'a', 'demo', 'string'] @@ -37,6 +37,8 @@ aaaaaaaaaaaaaaaaaaaaa """ +from __future__ import print_function + def run(args = None): import sys import doctest @@ -44,10 +46,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/test_builtin_converters.py b/test/test_builtin_converters.py index 5a6c8c50ad..0f1b4ded75 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -10,18 +11,18 @@ ... return [[-base, -1, 1, base - 1], [-base - 1, base]] >>> def _unsigned_values(s): ... base = 2 ** (8 * s) -... return [[1, base - 1], [-1L, -1, base]] +... return [[1, base - 1], [long(-1), -1, base]] # Wrappers to simplify tests >>> def should_pass(method, values): -... result = map(method, values[0]) +... result = list(map(method, values[0])) ... if result != values[0]: -... print "Got %s but expected %s" % (result, values[0]) +... print("Got %s but expected %s" % (result, values[0])) >>> def test_overflow(method, values): ... for v in values[1]: ... try: method(v) ... except OverflowError: pass -... else: print "OverflowError expected" +... else: print("OverflowError expected") # Synthesize idendity functions in case long long not supported >>> if not 'rewrap_value_long_long' in dir(): @@ -73,8 +74,8 @@ test unsigned long values which don't fit in a signed long. strip any 'L' characters in case the platform has > 32 bit longs - ->>> hex(rewrap_value_unsigned_long(0x80000001L)).replace('L','') + +>>> hex(rewrap_value_unsigned_long(long(0x80000001))).replace('L','') '0x80000001' >>> rewrap_value_long_long(42) == 42 @@ -82,7 +83,7 @@ >>> rewrap_value_unsigned_long_long(42) == 42 True - show that we have range checking. + show that we have range checking. >>> should_pass(rewrap_value_signed_char, _signed_values(char_size())) >>> should_pass(rewrap_value_short, _signed_values(short_size())) @@ -113,7 +114,7 @@ >>> for v in _unsigned_values(long_long_size())[1]: ... try: rewrap_value_unsigned_long_long(v) ... except (OverflowError, TypeError): pass -... else: print "OverflowError or TypeError expected" +... else: print("OverflowError or TypeError expected") >>> assert abs(rewrap_value_float(4.2) - 4.2) < .000001 >>> rewrap_value_double(4.2) - 4.2 @@ -130,16 +131,16 @@ >>> rewrap_value_string('yo, wassup?') 'yo, wassup?' ->>> print rewrap_value_wstring(u'yo, wassup?') +>>> print(rewrap_value_wstring(u'yo, wassup?')) yo, wassup? test that overloading on unicode works: ->>> print rewrap_value_string(u'yo, wassup?') +>>> print(rewrap_value_string(u'yo, wassup?')) yo, wassup? wrap strings with embedded nulls: - + >>> rewrap_value_string('yo,\0wassup?') 'yo,\x00wassup?' @@ -151,7 +152,7 @@ Note that we can currently get a mutable pointer into an immutable Python string: - + >>> rewrap_value_mutable_cstring('hello, world') 'hello, world' @@ -162,7 +163,7 @@ >>> try: rewrap_const_reference_bool('yes') ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> rewrap_const_reference_char('x') 'x' @@ -225,26 +226,26 @@ >>> try: rewrap_const_reference_string(None) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') Now check implicit conversions between floating/integer types >>> rewrap_const_reference_float(42) 42.0 ->>> rewrap_const_reference_float(42L) +>>> rewrap_const_reference_float(long(42)) 42.0 >>> try: rewrap_const_reference_int(42.0) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> rewrap_value_float(42) 42.0 >>> try: rewrap_value_int(42.0) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') Check that classic classes also work @@ -260,19 +261,19 @@ >>> try: rewrap_const_reference_float(FortyTwo()) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> try: rewrap_value_int(FortyTwo()) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> try: rewrap_const_reference_string(FortyTwo()) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') >>> try: rewrap_value_complex_double(FortyTwo()) ... except TypeError: pass -... else: print 'expected a TypeError exception' +... else: print('expected a TypeError exception') # show that arbitrary handle instantiations can be returned >>> assert get_type(1) is type(1) @@ -280,23 +281,27 @@ >>> assert return_null_handle() is None """ +import sys +if (sys.version_info.major >= 3): + long = int + def run(args = None): import sys import doctest import builtin_converters_ext - + if 'rewrap_value_long_long' in dir(builtin_converters_ext): - print 'LONG_LONG supported, testing...' + print('LONG_LONG supported, testing...') else: - print 'LONG_LONG not supported, skipping those tests...' - + print('LONG_LONG not supported, skipping those tests...') + if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/test_class.hpp b/test/test_class.hpp index 5404fdba27..a9324e9c47 100644 --- a/test/test_class.hpp +++ b/test/test_class.hpp @@ -4,17 +4,17 @@ // http://www.boost.org/LICENSE_1_0.txt) #ifndef TEST_CLASS_DWA2002326_HPP # define TEST_CLASS_DWA2002326_HPP -# include +# include template struct test_class { explicit test_class(int x) : x(x), magic(7654321 + n) { ++counter; } test_class(test_class const& rhs) : x(rhs.x), magic(7654321 + n) { ++counter; } - virtual ~test_class() { BOOST_TEST(magic == 7654321 + n); magic = 6666666; x = 9999; --counter; } + virtual ~test_class() { BOOST_ASSERT(magic == 7654321 + n); magic = 6666666; x = 9999; --counter; } - void set(int _x) { BOOST_TEST(magic == 7654321 + n); this->x = _x; } - int value() const { BOOST_TEST(magic == 7654321 + n); return x; } + void set(int _x) { BOOST_ASSERT(magic == 7654321 + n); this->x = _x; } + int value() const { BOOST_ASSERT(magic == 7654321 + n); return x; } operator int() const { return x; } static int count() { return counter; } diff --git a/test/test_cltree.py b/test/test_cltree.py index 016cf63d15..d5df6fc5a0 100644 --- a/test/test_cltree.py +++ b/test/test_cltree.py @@ -1,7 +1,7 @@ # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#!/usr/bin/env python +#!/usr/bin/env python3 from cltree import basic,symbol,constant,variable @@ -30,14 +30,14 @@ assert not isinstance(v,constant) assert isinstance(v,variable) -print 'b=',b +print('b=',b) assert repr(b)=='cltree.basic()' -print 's=',s +print('s=',s) assert repr(s)!='cltree.wrapped_symbol()' # because not isinstance(s,basic) -print 'c=',c +print('c=',c) assert repr(c)=='cltree.constant()' -print 'v=',v +print('v=',v) assert repr(v)=='cltree.wrapped_variable()' -print 'ok' +print('ok') diff --git a/test/enum.py b/test/test_enum.py similarity index 94% rename from test/enum.py rename to test/test_enum.py index c3ba3fe7ea..e4ad70bd5b 100644 --- a/test/enum.py +++ b/test/test_enum.py @@ -38,7 +38,7 @@ >>> try: identity(1) ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') >>> c = colorized() >>> c.x @@ -78,8 +78,8 @@ def run(args = None): return doctest.testmod(self) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/test_pointer_adoption.py b/test/test_pointer_adoption.py index 5bb9dd6dc3..0fdf3b98e9 100644 --- a/test/test_pointer_adoption.py +++ b/test/test_pointer_adoption.py @@ -86,8 +86,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/tuple.py b/test/tuple.py index 9d25aef41c..e2cd5eb179 100644 --- a/test/tuple.py +++ b/test/tuple.py @@ -4,10 +4,10 @@ """ >>> from tuple_ext import * >>> def printer(*args): -... for x in args: print x, -... print +... for x in args: print(x,) +... print('') ... ->>> print convert_to_tuple("this is a test string") +>>> print(convert_to_tuple("this is a test string")) ('t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g') >>> t1 = convert_to_tuple("this is") >>> t2 = (1,2,3,4) @@ -21,6 +21,8 @@ ('hello', 42) """ +from __future__ import print_function + def run(args = None): import sys import doctest @@ -28,10 +30,10 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/upcast.cpp b/test/upcast.cpp index 255429f168..e005900410 100644 --- a/test/upcast.cpp +++ b/test/upcast.cpp @@ -13,7 +13,7 @@ int main() { PyTypeObject o; Y y; - BOOST_TEST(&Py_REFCNT(boost::python::upcast(&o)) == &Py_REFCNT(&o)); - BOOST_TEST(&Py_REFCNT(boost::python::upcast(&y)) == &Py_REFCNT(&y)); + BOOST_TEST(boost::python::upcast(&o) == reinterpret_cast(&o)); + BOOST_TEST(boost::python::upcast(&y) == &y); return boost::report_errors(); } diff --git a/test/vector_indexing_suite.py b/test/vector_indexing_suite.py index 5fe2efe4d2..478cd01516 100644 --- a/test/vector_indexing_suite.py +++ b/test/vector_indexing_suite.py @@ -32,7 +32,7 @@ ... s += repr(x) ... s += ' ' ... s += ']' -... print s +... print(s) ##################################################################### # Replace all the contents using slice syntax @@ -339,7 +339,7 @@ ##################################################################### >>> sv = StringVec() >>> sv.append('a') ->>> print sv[0] +>>> print(sv[0]) a ##################################################################### @@ -358,10 +358,10 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print 'running...' + print('running...') import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/virtual_functions.py b/test/virtual_functions.py index 1372f9afb3..cba21edd62 100644 --- a/test/virtual_functions.py +++ b/test/virtual_functions.py @@ -52,12 +52,12 @@ # Call f indirectly from C++ >>> try: a2.call_f(y1) ... except AttributeError: pass -... else: print 'no exception' +... else: print('no exception') # Call f directly from Python >>> try: a2.call_f(y2) ... except AttributeError: pass -... else: print 'no exception' +... else: print('no exception') ############# Concrete Tests ############ @@ -103,8 +103,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/voidptr.cpp b/test/voidptr.cpp old mode 100755 new mode 100644 diff --git a/test/voidptr.py b/test/voidptr.py index da1fa9c143..0e189c9655 100644 --- a/test/voidptr.py +++ b/test/voidptr.py @@ -30,13 +30,13 @@ >>> try: use(0) ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') ... and from strings to opaque objects >>> try: use("") ... except TypeError: pass -... else: print 'expected a TypeError' +... else: print('expected a TypeError') """ def run(args = None): import sys @@ -47,8 +47,8 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/test/wrapper_held_type.cpp b/test/wrapper_held_type.cpp old mode 100755 new mode 100644 index e99422796e..ef494924b9 --- a/test/wrapper_held_type.cpp +++ b/test/wrapper_held_type.cpp @@ -20,12 +20,12 @@ struct data } }; -std::auto_ptr create_data() +std::shared_ptr create_data() { - return std::auto_ptr( new data ); + return std::shared_ptr( new data ); } -void do_nothing( std::auto_ptr& ){} +void do_nothing( std::shared_ptr& ){} namespace bp = boost::python; @@ -59,7 +59,7 @@ struct data_wrapper : data, bp::wrapper< data > BOOST_PYTHON_MODULE(wrapper_held_type_ext) { - bp::class_< data_wrapper, std::auto_ptr< data > >( "data" ) + bp::class_< data_wrapper, std::shared_ptr< data > >( "data" ) .def( "id", &data::id, &::data_wrapper::default_id ); bp::def( "do_nothing", &do_nothing ); diff --git a/test/wrapper_held_type.py b/test/wrapper_held_type.py index 4b33ff738b..ff1bd1d245 100644 --- a/test/wrapper_held_type.py +++ b/test/wrapper_held_type.py @@ -4,16 +4,16 @@ ''' >>> from wrapper_held_type_ext import * >>> d = data() ->>> print d.id() +>>> print(d.id()) 42 >>> do_nothing( d ) ->>> print d.id() +>>> print(d.id()) 42 >>> d = create_data() ->>> print d.id() +>>> print(d.id()) 42 >>> do_nothing( d ) ->>> print d.id() +>>> print(d.id()) 42 ''' @@ -26,9 +26,9 @@ def run(args = None): return doctest.testmod(sys.modules.get(__name__)) if __name__ == '__main__': - print "running..." + print("running...") import sys status = run()[0] - if (status == 0): print "Done." + if (status == 0): print("Done.") sys.exit(status) diff --git a/todo.html b/todo.html deleted file mode 100755 index c2c4bdf7b8..0000000000 --- a/todo.html +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - -Boost.Python TODO list Boost - - - - - - -