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/get-py-env.py b/.github/get-py-env.py new file mode 100755 index 0000000000..a6c41460d8 --- /dev/null +++ b/.github/get-py-env.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Determine info about the Python install and write shell code to stdout, to +# set env variables. This will set the variables PY_LDFLAGS, PY_CFLAGS and +# PY_INC_PATH. +# +# The python3-config tool is used as the source of this info. In theory we +# could use sysconfig as well but the setup-python action from github appears +# to patch python3-config but not patch the sysconfig info. +# +# Usage: +# eval $(python3 get-py-env.py) + +import os +import re +import subprocess + + +def get_output(cmd): + rv = subprocess.run( + cmd, + capture_output=True, # Capture stdout and stderr + text=True, # Decode output as text (UTF-8) + check=True, # Raise an error if the command fails + ) + return rv.stdout + + +def extract_flags(cmd, prefix): + flags = [] + for part in get_output(cmd).split(): + part = part.strip() + if part.startswith(prefix): + flags.append(part) + return ' '.join(flags) + + +def find_python_h(): + """Find the include path that has Python.h contained inside. + We could use INCLUDEPY from sysconfig but github patches + python3-config but not the sysconfig info (after moving the + install). + """ + c_flags = extract_flags(['python3-config', '--cflags'], '-I') + for part in c_flags.split(): + m = re.search(r'-I(\S+)', part) + if not m: + continue + inc_path = m.group(1) + if os.path.exists(os.path.join(inc_path, 'Python.h')): + return inc_path + raise SystemExit('cannot find Python.h') + + +def main(): + ld_flags = extract_flags(['python3-config', '--ldflags'], '-L') + c_flags = extract_flags(['python3-config', '--cflags'], '-I') + include_path = find_python_h() + print(f'PY_LDFLAGS="{ld_flags}"') + print(f'PY_CFLAGS="{c_flags}"') + print(f'PY_INC_PATH="{include_path}"') + + +if __name__ == '__main__': + main() diff --git a/.github/run-faber.sh b/.github/run-faber.sh new file mode 100755 index 0000000000..5cb78be6dd --- /dev/null +++ b/.github/run-faber.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +set -eu + +echo "cxx version: $CXX $($CXX --version)" +echo "cxx std: $CXX_STD" +echo "python3 path: $(which python3)" +echo "python3 version: $(python3 --version)" + +if ! which faber > /dev/null; then + echo "Installing faber..." + python3 -m pip install --upgrade pip + python3 -m pip install -U faber +fi +echo "faber version: $(faber -v)" + +# find and set PY_LDFLAGS and PY_INC_PATH +eval $(python3 .github/get-py-env.py) + +echo "PY_INC_PATH=$PY_INC_PATH" +echo "PY_LDFLAGS=$PY_LDFLAGS" + +case $(python3-config --abiflags) in + *t*) + # When running with free-threaded, we always want to disable the GIL + # even for extensions without the mod_gil_not_used() flag + export PYTHON_GIL=0 + ;; +esac + +# this could be set by LD_LIBRARY_PATH but faber overrides it +prefix=$(python3-config --prefix) +echo "${prefix}/lib" > /etc/ld.so.conf.d/boost-ci.conf && ldconfig + +sed -e "s/\$PYTHON/python3/g" .ci/faber > $HOME/.faber + +faber \ + --with-boost-include=${BOOST_PY_DEPS} \ + --builddir=build \ + cxx.name="${CXX}" \ + cxxflags="-std=${CXX_STD}" \ + cppflags="-std=${CXX_STD}" \ + include="${PY_INC_PATH}" \ + ldflags="${PY_LDFLAGS}" \ + -j`nproc` \ + "$@" 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..31637de5ef --- /dev/null +++ b/.github/workflows/test-ubuntu.yml @@ -0,0 +1,94 @@ +# Test on Ubuntu with various compiler and language standard versions. +name: Test Ubuntu + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: ['3.14'] + cxx: [g++, clang++] + std: [c++11, c++14, c++17] + include: + - python-version: '2.7' + cxx: g++ + std: c++11 + - python-version: '3.10' + cxx: g++ + std: c++17 + - python-version: '3.11' + cxx: g++ + std: c++17 + - python-version: '3.12' + cxx: g++ + std: c++17 + - python-version: '3.13' + cxx: g++ + std: c++17 + # Also test with free-threaded build of Python + - python-version: '3.14t' + cxx: clang++ + std: c++17 + + container: + # Add the appropriate docker image for the compiler. + # The images from teeks99/boost-python-test already have boost::python + # pre-reqs installed, see: + # https://github.com/teeks99/boost-python-test-docker + image: ${{ matrix.cxx == 'g++' && + 'teeks99/boost-python-test:gcc-15_1.89.0' || + 'teeks99/boost-python-test:clang-21_1.89.0' }} + + steps: + - uses: actions/checkout@v5 + - name: setup python + if: "${{ matrix.python-version != '2.7' }}" + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - 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 + echo "CXX=${{ matrix.cxx }}" >> "$GITHUB_ENV" + echo "CXX_STD=${{ matrix.std }}" >> "$GITHUB_ENV" + - name: build-py2 + if: "${{ matrix.python-version == '2.7' }}" + run: | + python --version + ${{ matrix.cxx }} --version + faber -v + sed -e "s/\$PYTHON/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: build-py3 + if: "${{ matrix.python-version != '2.7' }}" + run: | + .github/run-faber.sh + - name: test-py2 + if: "${{ matrix.python-version == '2.7' }}" + 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 + - name: test-py3 + if: "${{ matrix.python-version != '2.7' }}" + run: | + .github/run-faber.sh 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/.travis.yml b/.travis.yml deleted file mode 100644 index 0f528684de..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -# -*- 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) - -language: cpp - -env: -- PYTHON=python CCFLAGS=-std=c++98 -- PYTHON=python CCFLAGS=-std=c++11 -- PYTHON=python3 CCFLAGS=-std=c++98 -- PYTHON=python3 CCFLAGS=-std=c++11 - -compiler: -- gcc - - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.8 - - g++-4.8 - - clang - - python-dev python-pip - - python3-dev - - libboost-all-dev - -before_install: - - sudo pip install future - -install: -- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi - -script: scons config --python=$PYTHON && scons && scons test - 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/SConscript b/SConscript deleted file mode 100644 index a773cde3ac..0000000000 --- a/SConscript +++ /dev/null @@ -1,34 +0,0 @@ -# -*- python -*- - -Import("env") - -env.Append(CPPPATH = "#/include",CPPDEFINES = ["BOOST_ALL_NO_LIB=1"]) - -env.AppendUnique(CPPDEFINES = ["${LINK_DYNAMIC and 'BOOST_PYTHON_DYN_LINK=1' or []}"]) -for variant in env["variant"]: - env["current_variant"] = variant - env.SetProperty(profile = False) - if variant == "release": - env.SetProperty(optimize = "speed", debug = False) - elif variant == "debug": - env.SetProperty(optimize = "no", debug = True) - elif variant == "profile": - env.SetProperty(optimize = "speed", profile = True, debug = True) - for linking in env["link"]: - env["linking"] = linking - if linking == "dynamic": - env["LINK_DYNAMIC"] = True - else: - env["LINK_DYNAMIC"] = False - for threading in env["threading"]: - env["current_threading"] = threading - env.SetProperty(threading = threading) - variant_dir=env.subst("$BOOST_CURRENT_VARIANT_DIR") - - env.SConscript("src/SConscript", variant_dir=variant_dir + '/src', - exports = { "env" : env.Clone(BOOST_LIB = 'python') }) - if GetOption("test"): - test_env = env.Clone(BOOST_LIB = 'python', BOOST_TEST = True) - test_env.BoostUseLib('python') - env.SConscript("test/SConscript", variant_dir=variant_dir + '/test', - exports = { "env" : test_env }) diff --git a/SConstruct b/SConstruct deleted file mode 100644 index 1e60db7a4a..0000000000 --- a/SConstruct +++ /dev/null @@ -1,82 +0,0 @@ -# -*- 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) - -import SCons.Script.Main -import config -import config.ui -import platform -import os - - -# -# We try to mimic the typical autotools-workflow. -# -# * In a 'configure' step all the essential build parameters are established -# (either by explicit command-line arguments or from configure checks) -# * A subsequent build step can then simply read the cached variables, so -# users don't have to memorize and re-issue the arguments on each subsequent -# invocation, and neither do the config checks need to be re-run. -# -# The essential part here is to define a 'config' target, which removes any -# caches that may still be lingering around, then runs the checks. - -if 'config' in COMMAND_LINE_TARGETS: - # Clear the cache - try: os.remove('bin.SCons/config.py') - except: pass -if not os.path.exists('bin.SCons/'): - os.mkdir('bin.SCons/') -vars = Variables('bin.SCons/config.py', ARGUMENTS) -config.add_options(vars) -arch = ARGUMENTS.get('arch', platform.machine()) -env = Environment(toolpath=['config/tools'], - tools=['default', 'libs', 'tests'], - variables=vars, - TARGET_ARCH=arch) - -Help(config.ui.help(vars, env) + """ -Variables are saved in bin.SCons/config.py and persist between scons invocations. -""") - -if GetOption('help'): - Return() - -build_dir = config.prepare_build_dir(env) -config_log = '{}/config.log'.format(build_dir) - -# configure -SConsignFile('{}/.sconsign'.format(build_dir)) -#env.Decider('MD5-timestamp') -env.Decider('timestamp-newer') -checks = config.get_checks() -if 'config' in COMMAND_LINE_TARGETS: - conf=env.Configure(custom_tests=checks, log_file=config_log, conf_dir=build_dir) - if False in (getattr(conf, c)() for c in checks): - Exit(1) - env = conf.Finish() - vars.Save('bin.SCons/config.py', env) - -if not os.path.exists(config_log): - print('Please run `scons config` first. (See `scons -h` for available options.)') - Exit(1) - -if not GetOption('verbose'): - config.ui.pretty_output(env) - -# build -env['BPL_VERSION'] = '1.61' -for e in config.variants(env): - variant_dir=e.subst("$BOOST_CURRENT_VARIANT_DIR") - e.SConscript('src/SConscript', variant_dir=variant_dir + '/src', - exports = { 'env' : e.Clone(BOOST_LIB = 'python') }) - if 'test' in COMMAND_LINE_TARGETS: - test_env = e.Clone(BOOST_LIB = 'python', BOOST_TEST = True) - test_env.BoostUseLib('python') - e.SConscript('test/SConscript', variant_dir=variant_dir + '/test', - exports = { 'env' : test_env }) 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/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/config/__init__.py b/config/__init__.py deleted file mode 100644 index 192e33f609..0000000000 --- a/config/__init__.py +++ /dev/null @@ -1,116 +0,0 @@ -# -# 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 SCons.Variables import * -from SCons.Script import AddOption -from collections import OrderedDict -import platform -from . import ui -from . import python -from . import boost - -def add_options(vars): - ui.add_option('-V', '--verbose', dest='verbose', action='store_true', help='verbose mode: print full commands.') - python.add_options(vars) - boost.add_options(vars) - - vars.Add('CPPPATH', converter=lambda v:v.split()) - vars.Add('CCFLAGS', converter=lambda v:v.split()) - vars.Add('LIBPATH', converter=lambda v:v.split()) - vars.Add('LIBS', converter=lambda v:v.split()) - vars.Add('PYTHON') - vars.Add('PYTHONLIBS') - - ui.add_variable(vars, ("arch", "target architeture", platform.machine())) - ui.add_variable(vars, ("toolchain", "toolchain to use", 'gcc')) - ui.add_variable(vars, ListVariable("variant", "Build configuration", "release", ["release", "debug", "profile"])) - ui.add_variable(vars, ListVariable("link", "Library linking", "dynamic", ["static", "dynamic"])) - ui.add_variable(vars, ListVariable("threading", "Multi-threading support", "multi", ["single", "multi"])) - ui.add_variable(vars, EnumVariable("layout", "Layout of library names and header locations", "versioned", ["versioned", "system"])) - ui.add_variable(vars, PathVariable("stagedir", "If --stage is passed install only compiled library files in this location", "stage", PathVariable.PathAccept)) - ui.add_variable(vars, PathVariable("prefix", "Install prefix", "/usr/local", PathVariable.PathAccept)) - - -def get_checks(): - checks = OrderedDict() - checks['python'] = python.check - checks['boost'] = boost.check - return checks - - -def set_property(env, **kw): - - from toolchains.gcc import features as gcc_features - from toolchains.msvc import features as msvc_features - - if 'gcc' in env['TOOLS']: features = gcc_features - elif 'msvc' in env['TOOLS']: features = msvc_features - else: raise Error('unknown toolchain') - features.init_once(env) - for (prop,value) in kw.items(): - getattr(features, prop, lambda x, y : None)(env, value) - env[prop.upper()] = value - - -def boost_suffix(env): - suffix = str() - - if env["layout"] == "versioned": - if "gcc" in env["TOOLS"]: - suffix += "-gcc" + "".join(env["CCVERSION"].split(".")[0:2]) - if env["THREADING"] == "multi": - suffix += "-mt" - if env["DEBUG"]: - suffix += "-d" - if env["layout"] == "versioned": - suffix += "-" + "_".join(env["BPL_VERSION"].split(".")) - - return suffix - - -def prepare_build_dir(env): - - vars = {} - env["boost_suffix"] = boost_suffix - build_dir="bin.SCons" - if "gcc" in env["TOOLS"]: - build_dir+="/gcc-%s"%env["CCVERSION"] - vars['CXXFLAGS'] = ['-ftemplate-depth-128', '-Wall'] - - elif "msvc" in env["TOOLS"]: - build_dir+="/msvc-%s"%env["MSVS_VERSION"] - vars['BOOST_BUILD_DIR'] = build_dir - vars['BOOST_SUFFIX'] = "${boost_suffix(__env__)}" - env.Replace(**vars) - return build_dir - - -def variants(env): - - env.Prepend(CPPPATH = "#/include", CPPDEFINES = ["BOOST_ALL_NO_LIB=1"]) - set_property(env, architecture = env['TARGET_ARCH']) - for variant in env["variant"]: - e = env.Clone() - e["current_variant"] = variant - set_property(env, profile = False) - if variant == "release": - set_property(e, optimize = "speed", debug = False) - elif variant == "debug": - set_property(e, optimize = "no", debug = True) - elif variant == "profile": - set_property(e, optimize = "speed", profile = True, debug = True) - for linking in env["link"]: - e["linking"] = linking - if linking == "dynamic": - e["LINK_DYNAMIC"] = True - else: - e["LINK_DYNAMIC"] = False - for threading in e["threading"]: - e["current_threading"] = threading - set_property(e, threading = threading) - yield e diff --git a/config/boost.py b/config/boost.py deleted file mode 100644 index 7548bf89bc..0000000000 --- a/config/boost.py +++ /dev/null @@ -1,40 +0,0 @@ -# -# 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 . import ui -import os - -def add_options(vars): - - ui.add_option("--boost-prefix", dest="boost_prefix", type="string", nargs=1, action="store", - metavar="DIR", default=os.environ.get("BOOST_DIR"), - help="prefix for Boost libraries; should have 'include' and 'lib' subdirectories, 'boost' and 'stage\\lib' subdirectories on Windows") - ui.add_option("--boost-include", dest="boost_include", type="string", nargs=1, action="store", - metavar="DIR", help="location of Boost header files") - - -def check(context): - - boost_source_file = r"#include " - - context.Message('Checking for Boost...') - - boost_prefix = context.env.GetOption('boost_prefix') - boost_include = context.env.GetOption('boost_include') - incpath=None - if boost_include: - incpath=boost_include - elif boost_prefix: - incpath=boost_prefix - if incpath: - context.env.AppendUnique(CPPPATH=[incpath]) - if not context.TryCompile(boost_source_file, '.cpp'): - context.Result(0) - return False - context.Result(1) - return True diff --git a/config/python.py b/config/python.py deleted file mode 100644 index 0aff24ee6d..0000000000 --- a/config/python.py +++ /dev/null @@ -1,98 +0,0 @@ -# -# 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 . import ui - -def add_options(vars): - - ui.add_option('--python', help='the python executable') - - -def check(context): - - python_source_file = r""" -// If defined, enforces linking againg PythonXXd.lib, which -// is usually not included in Python environments. -#undef _DEBUG -#include "Python.h" -int main() -{ - Py_Initialize(); - Py_Finalize(); - return 0; -} -""" - - import platform - import subprocess - import re, os - - def check_python(cmd): - return subprocess.check_output([python, '-c', cmd]).strip() - - def check_sysconfig(cmd): - r = check_python('import distutils.sysconfig as c; print(c.%s)'%cmd) - return r if r != 'None' else '' - - context.Message('Checking for Python...') - python = context.env.GetOption('python') or 'python' - context.env['PYTHON'] = python - incpath = check_sysconfig('get_python_inc()') - context.env.AppendUnique(CPPPATH=[incpath]) - if platform.system() == 'Windows': - version = check_python('import sys; print("%d%d"%sys.version_info[0:2])') - prefix = check_python('import sys; print(sys.prefix)') - libfile = os.path.join(prefix, 'libs', 'python%s.lib'%version) - libpath = os.path.join(prefix, 'libs') - lib = 'python%s'%version - context.env.AppendUnique(LIBS=[lib]) - else: - libpath = check_sysconfig('get_config_var("LIBDIR")') - libfile = check_sysconfig('get_config_var("LIBRARY")') - match = re.search('(python.*)\.(a|so|dylib)', libfile) - lib = None - if match: - lib = match.group(1) - context.env.AppendUnique(PYTHONLIBS=[lib]) - if match.group(2) == 'a': - flags = check_sysconfig('get_config_var("LINKFORSHARED")') - if flags is not None: - context.env.AppendUnique(LINKFLAGS=flags.split()) - context.env.AppendUnique(LIBPATH=[libpath]) - oldlibs = context.AppendLIBS([lib]) - flags = check_sysconfig('get_config_var("MODLIBS")') - flags += ' ' + check_sysconfig('get_config_var("SHLIBS")') - flags = [f[2:] for f in flags.strip().split() if f.startswith('-l')] - if flags: - context.AppendLIBS([flags]) - result = context.TryLink(python_source_file,'.cpp') - if not result and context.env['PLATFORM'] == 'darwin': - # Sometimes we need some extra stuff on Mac OS - frameworkDir = libpath # search up the libDir tree for the proper home for frameworks - while frameworkDir and frameworkDir != "/": - frameworkDir, d2 = os.path.split(frameworkDir) - if d2 == "Python.framework": - if not "Python" in os.listdir(os.path.join(frameworkDir, d2)): - context.Result(0) - print(( - "Expected to find Python in framework directory %s, but it isn't there" - % frameworkDir)) - return False - break - context.env.AppendUnique(LINKFLAGS="-F%s" % frameworkDir) - result = context.TryLink(python_source_file,'.cpp') - if not result: - context.Result(0) - print("Cannot link program with Python.") - return False - if context.env['PLATFORM'] == 'darwin': - context.env['LDMODULESUFFIX'] = '.so' - context.Result(1) - context.SetLIBS(oldlibs) - context.env.AppendUnique(PYTHONLIBS=[lib] + flags) - return True diff --git a/config/toolchains/__init__.py b/config/toolchains/__init__.py deleted file mode 100644 index af38285a65..0000000000 --- a/config/toolchains/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# 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) - -import traceback - -def append_feature_flag(env, **kw): - stack = traceback.extract_stack(limit = 3) - feature = stack[0][2].upper() - for (key, val) in kw.items(): - feature_var = feature + "_" + key - env.AppendUnique(**{ key : "$" + feature_var }) - env[feature_var] = val - diff --git a/config/toolchains/gcc.py b/config/toolchains/gcc.py deleted file mode 100644 index 200ecb6a7e..0000000000 --- a/config/toolchains/gcc.py +++ /dev/null @@ -1,55 +0,0 @@ -# -# 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 . import append_feature_flag - -class features: - - @classmethod - def init_once(cls, env): - pass - - @staticmethod - def architecture(env, arch): - if arch: - flag = {'x86' : '-m32', - 'x86_64' : '-m64',}.get(arch) - if flag: - append_feature_flag(env, CCFLAGS = flag) - - @staticmethod - def optimize(env, optimize): - if not optimize or optimize == "no": - append_feature_flag(env, CCFLAGS = "-O0 -fno-inline") - elif optimize == "speed": - append_feature_flag(env, CCFLAGS = "-O3 -finline-functions -Wno-inline") - elif optimize == "space": - append_feature_flag(env, CCFLAGS = "-Os") - else: - append_feature_flag(env, CCFLAGS = "") - - @staticmethod - def profile(env, profile): - if profile: - append_feature_flag(env, CCFLAGS = "-pg", LINKFLAGS = "-pg") - else: - append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "") - - @staticmethod - def threading(env, threading): - if threading == "multi": - append_feature_flag(env, CCFLAGS = "-pthread", LINKFLAGS = "-pthread") - else: - append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "") - - @staticmethod - def debug(env, debug): - if debug: - append_feature_flag(env, CCFLAGS = "-g", CPPDEFINES = []) - else: - append_feature_flag(env, CCFLAGS = "", CPPDEFINES = "NDEBUG") diff --git a/config/toolchains/msvc.py b/config/toolchains/msvc.py deleted file mode 100644 index 576ff819c6..0000000000 --- a/config/toolchains/msvc.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# 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 . import append_feature_flag - -class features: - - @classmethod - def init_once(cls, env): - env.AppendUnique(CCFLAGS = ['-TP', '/Z7', '/W3' ,'/GR', '/MDd', '/Zc:forScope', '/Zc:wchar_t', '/wd4675', '/EHs']) - env.AppendUnique(LINKFLAGS = ['/subsystem:console']) - - @staticmethod - def architecture(env, arch): - if arch: - flag = {'x86' : '/MACHINE:X86', - 'x86_64' : '/MACHINE:X64',}.get(arch) - if flag: - append_feature_flag(env, LINKFLAGS = flag) - - @staticmethod - def optimize(env, optimize): - #if not optimize or optimize == "no": - # append_feature_flag(env, CCFLAGS = "-O0 -fno-inline") - #elif optimize == "speed": - # append_feature_flag(env, CCFLAGS = "-O3 -finline-functions -Wno-inline") - #elif optimize == "space": - # append_feature_flag(env, CCFLAGS = "-Os") - #else: - append_feature_flag(env, CCFLAGS = "") - - @staticmethod - def profile(env, profile): - #if profile: - # append_feature_flag(env, CCFLAGS = "-pg", LINKFLAGS = "-pg") - #else: - append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "") - - @staticmethod - def threading(env, threading): - #if threading == "multi": - # append_feature_flag(env, CCFLAGS = "/MT") - #else: - # append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "") - pass - - @staticmethod - def debug(env, debug): - #if debug: - # append_feature_flag(env, CCFLAGS = "-g", CPPDEFINES = []) - #else: - append_feature_flag(env, CCFLAGS = "", CPPDEFINES = "NDEBUG") diff --git a/config/tools/clang.py b/config/tools/clang.py deleted file mode 100644 index 9af06708e6..0000000000 --- a/config/tools/clang.py +++ /dev/null @@ -1,44 +0,0 @@ -# -# 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) - -# Based on SCons/Tool/gcc.py - -import os -import re -import subprocess - -import SCons.Util -import SCons.Tool.cc - -compilers = ['clang'] - -def generate(env): - """Add Builders and construction variables for clang to an Environment.""" - SCons.Tool.cc.generate(env) - - env['CC'] = env.Detect(compilers) or 'clang' - if env['PLATFORM'] in ['cygwin', 'win32']: - env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') - else: - env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC') - # determine compiler version - if env['CC']: - #pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'], - pipe = SCons.Action._subproc(env, [env['CC'], '--version'], - stdin = 'devnull', - stderr = 'devnull', - stdout = subprocess.PIPE) - if pipe.wait() != 0: return - # clang -dumpversion is of no use - line = pipe.stdout.readline() - match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line) - if match: - env['CCVERSION'] = match.group(1) - -def exists(env): - return env.Detect(compilers) diff --git a/config/tools/libs.py b/config/tools/libs.py deleted file mode 100644 index a376bb069a..0000000000 --- a/config/tools/libs.py +++ /dev/null @@ -1,83 +0,0 @@ -# -# 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 SCons.Script import AddOption, COMMAND_LINE_TARGETS, BUILD_TARGETS -import distutils.sysconfig -import platform - - -def BoostLibrary(env, lib, sources, make_aliases = True, **kw): - if env["LINK_DYNAMIC"]: - lib_node = env.SharedLibrary("boost_" + lib + env["BOOST_SUFFIX"], sources, **kw) - else: - lib_node = env.StaticLibrary("boost_" + lib + env["BOOST_SUFFIX"], sources, **kw) - - if make_aliases: - if env.GetOption("stage"): - env.Alias(lib, env.Install(env.Dir("$stagedir", "#"), lib_node)) - env.Default(env.Alias(lib, lib_node)) - - if env.GetOption("install"): - env.Alias(lib, env.Install("$prefix/lib", lib_node)) - return lib_node - - -def BoostUseLib(env, lib): - build_dir = env.Dir('$BOOST_CURRENT_VARIANT_DIR/src') - env.AppendUnique(LIBPATH = [build_dir], - LIBS = ["boost_" + lib + env["BOOST_SUFFIX"]]) - if env.get("BOOST_TEST"): - env.AppendUnique(RPATH = [build_dir]) - if platform.system() == 'Windows': - env.PrependENVPath('PATH', build_dir.abspath) - else: - env.PrependENVPath('LD_LIBRARY_PATH', build_dir.abspath) - - -def PythonExtension(env, lib, sources, **kw): - if env["LINK_DYNAMIC"]: - ext = env.SharedLibrary(lib, sources, SHLIBPREFIX='', SHLIBSUFFIX=distutils.sysconfig.get_config_var("SO"), **kw) - return ext - - -def boost_copy_func(dest, source, env): - import os, stat, shutil - - if os.path.isdir(source): - if os.path.exists(dest): - if not os.path.isdir(dest): - raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source)) - else: - os.makedirs(dest) - for file in os.listdir(source): - if file == ".svn": continue - boost_copy_func(os.path.join(dest, file), os.path.join(source, file), env) - else: - shutil.copy2(source, dest) - st = os.stat(source) - os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) - - return 0 - - -def exists(env): - return True - - -def generate(env): - env.AddMethod(BoostLibrary) - env.AddMethod(BoostUseLib) - env.AddMethod(PythonExtension) - - env.Replace( - INSTALL = boost_copy_func, - BOOST_CURRENT_VARIANT_DIR = "#/$BOOST_BUILD_DIR/$current_variant/$linking/threading-$current_threading" - ) - - AddOption('--stage', dest='stage', action="store_true") - AddOption('--install', dest='install', action="store_true") diff --git a/config/tools/tests.py b/config/tools/tests.py deleted file mode 100644 index a2e8e08465..0000000000 --- a/config/tools/tests.py +++ /dev/null @@ -1,123 +0,0 @@ -# -# 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 SCons.Script import AddOption, Flatten -from SCons.Script import Builder -from SCons.Action import Action -from subprocess import check_output, STDOUT, CalledProcessError -import sys -import os - - -def BoostCompileTest(env, test, source = None, **kw): - - def gen_result(target, source, env=env): - target_file = target[0].abspath - result_file = os.path.splitext(target_file)[0] + '.result' - if sys.stdout.isatty(): - env['RESULT']='\033[92mPASS\033[0m' - else: - env['RESULT']='PASS' - - with open(result_file, 'w+') as result: - result.write('Result: {}\n'.format('pass')) - - obj = env.Object(test, source if source is not None else test + '.cpp') - env.AddPostAction(obj, Action(gen_result, cmdstr=None)) - env.AddPostAction(obj, Action('@echo $RESULT')) - return obj - -def BoostRun(env, prog, target, command = '$SOURCE'): - - def call(target, source, env=env): - cmd = env.subst(command, target=target, source=source) - result_file = env.subst('$TARGET', target=target) - output='' - try: - output=check_output(cmd, stderr=STDOUT, shell=True, env=env['ENV']) - success=True - except CalledProcessError as e: - output=e.output - success=False - with open(result_file, 'w+') as result: - result.write('Result: {}\n'.format(success and 'pass' or 'fail')) - result.write('Output: {}\n'.format(output)) - if sys.stdout.isatty(): - env['RESULT']=success and '\033[92mPASS\033[0m' or '\033[91mFAIL\033[0m' - else: - env['RESULT']=success and 'PASS' or 'FAIL' - - testcomstr = env.get('TESTCOMSTR') - if testcomstr: - run = env.Command(target, prog, Action(call, cmdstr=testcomstr)) - else: - run = env.Command(target, prog, Action(call, cmdstr=command)) - env.AddPostAction(target, Action('@echo $RESULT')) - return run - - -def BoostRunPythonScript(env, script): - return env.BoostRun(env.File(script), script.replace('.py', '.result'), '"${PYTHON}" $SOURCE') - - -def BoostRunTest(env, test, source = None, command = '$SOURCE', command_sources = [], **kw): - test_prog = env.Program(test, (source is None) and (test + ".cpp") or source, **kw) - command += '> $TARGET' - run = env.BoostRun([test_prog, command_sources], test + '.result', command) - return run - - -def BoostRunTests(env, tests, **kw): - run = [] - for test in Flatten(tests): - run += env.BoostRunTest(test, **kw) - return run - -def BoostCompileTests(env, tests, **kw): - comp = [] - for test in Flatten(tests): - comp += env.BoostCompileTest(test, **kw) - return comp - - -def BoostTestSummary(env, tests, **kw): - - def print_summary(target, source, **kw): - results = tests - failures = [r for r in results - if r.get_path().endswith('.result') and not 'Result: pass' in r.get_contents()] - print('%s tests; %s pass; %s fails'%(len(results), len(results)-len(failures), len(failures))) - if failures: - print('For detailed failure reports, see:') - for f in failures: - print(f.get_path()) - - testsumcomstr = env.get('TESTSUMCOMSTR') - if testsumcomstr: - run = env.Command('summary', tests, Action(print_summary, cmdstr=testsumcomstr)) - else: - run = env.Command('summary', tests, print_summary, cmdstr='') - - - - - -def exists(env): - return True - - -def generate(env): - AddOption('--test', dest='test', action="store_true") - - env.AddMethod(BoostCompileTest) - env.AddMethod(BoostRun) - env.AddMethod(BoostRunPythonScript) - env.AddMethod(BoostRunTest) - env.AddMethod(BoostRunTests) - env.AddMethod(BoostCompileTests) - env.AddMethod(BoostTestSummary) diff --git a/config/ui.py b/config/ui.py deleted file mode 100644 index e6e4f24f72..0000000000 --- a/config/ui.py +++ /dev/null @@ -1,96 +0,0 @@ -# -# 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 SCons.Script import AddOption -import sys - -variables=[] # remember 'public' variables -options=[] - -def add_option(*args, **kwds): - """Capture the help messages so we can produce a helpful usage text.""" - options.append('{:25} {}'.format(', '.join(args), kwds.get('help', ''))) - AddOption(*args, **kwds) - -def add_variable(vars, var): - variables.append(var[0]) - vars.Add(var) - - -def options_help(env): - - return '\n '.join(options) - - -def variables_help(vars, env): - """This is cloned from SCons' Variables.GenerateHelpText, to only report 'public' variables.""" - - opts = [o for o in vars.options if o.key in variables] - - def format(opt): - if opt.key in env: - actual = env.subst('${%s}' % opt.key) - else: - actual = None - return vars.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases) - text = ''.join([f for f in map(format, opts) if f]) - lines = [' %s'%l for l in text.split('\n')] # Add some indentation - return '\n'.join(lines) - - - -def help(vars, env): - - return """Usage: scons [--option...] [variable=value...] [target...] - -available options: - - {} - -available variables: - {} -""".format(options_help(env), variables_help(vars, env)) - -def pretty_output(env): - - colors = {} - colors['red'] = '\033[31m' - colors['green'] = '\033[32m' - colors['blue'] = '\033[34m' - colors['yellow'] = '\033[93m' - colors['Red'] = '\033[91m' - colors['Green'] = '\033[92m' - colors['Blue'] = '\033[94m' - colors['Purple'] = '\033[95m' - colors['Cyan'] = '\033[96m' - colors['end'] = '\033[0m' - - #If the output is not a terminal, remove the colors - if not sys.stdout.isatty(): - for key, value in colors.iteritems(): - colors[key] = '' - - compile_source_message = '{green}Compiling $TARGET{end}'.format(**colors) - compile_shared_source_message = '{green}Compiling $TARGET{end}'.format(**colors) - link_program_message = '{blue}Linking $TARGET{end}'.format(**colors) - link_library_message = '{blue}Linking $TARGET{end}'.format(**colors) - ranlib_library_message = '{blue}Ranlib $TARGET{end}'.format(**colors) - link_shared_library_message = '{blue}Linking $TARGET{end}'.format(**colors) - test_message = '{blue}Testing $SOURCE{end}'.format(**colors) - testsum_message = '{Blue}Test Summary{end}'.format(**colors) - - env.Replace(CXXCOMSTR = compile_source_message, - CCCOMSTR = compile_source_message, - SHCCCOMSTR = compile_shared_source_message, - SHCXXCOMSTR = compile_shared_source_message, - ARCOMSTR = link_library_message, - RANLIBCOMSTR = ranlib_library_message, - SHLINKCOMSTR = link_shared_library_message, - LINKCOMSTR = link_program_message, - TESTCOMSTR = test_message, - TESTSUMCOMSTR = testsum_message) diff --git a/doc/Jamfile b/doc/Jamfile index d97b9559d2..735ef22e6f 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -4,10 +4,14 @@ # Distributed under the 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 @@ -17,9 +21,16 @@ project python/doc html:chunk.section.depth=1 ; -import boostbook ; -import quickbook ; -import docutils ; +make numpy : numpy/index.rst : @sphinx-build ; + +if [ os.name ] = NT +{ + actions sphinx-build { chdir "$(>:D)" && make clean && make html} +} +else +{ + actions sphinx-build { make -C "$(>:D)" clean html} +} boostbook python : python.qbk : html:$(here)/html @@ -47,3 +58,9 @@ 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/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/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/html/images/python_cpp_mix.png b/doc/html/images/python_cpp_mix.png old mode 100755 new mode 100644 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/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/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/python.qbk b/doc/python.qbk index b3e7eceb58..b8b0926def 100644 --- a/doc/python.qbk +++ b/doc/python.qbk @@ -1,5 +1,5 @@ [book Boost.Python - [quickbook 1.7] + [quickbook 1.6] [authors [Abrahams, David], [Seefeld, Stefan]] [copyright 2002 - 2015 David Abrahams, Stefan Seefeld] [category inter-language support] @@ -43,6 +43,7 @@ The development of these features was funded in part by grants to `Boost Consult [section Contents] +* [link rn Release Notes] * _tutorial_ * [link building Building and Testing] * _reference_ @@ -50,6 +51,7 @@ The development of these features was funded in part by grants to `Boost Consult * [link glossary Glossary] * [link support Support Resources] * [link faq Frequently Asked Questions (FAQs)] +* [@numpy/index.html NumPy Extension Documentation] [endsect] @@ -57,6 +59,7 @@ The development of these features was funded in part by grants to `Boost Consult [@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] diff --git a/doc/reference.qbk b/doc/reference.qbk index bc5ecf6e94..ae97393cad 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -1,5 +1,5 @@ [book Boost.Python Reference Manual - [quickbook 1.7] + [quickbook 1.6] [authors [Abrahams, David], [Seefeld, Stefan]] [copyright 2002 2003 2004 2005 2015 David Abrahams, Stefan Seefeld] [id reference] diff --git a/doc/reference/call_method.qbk b/doc/reference/call_method.qbk index 926763cebc..fcf68667d0 100644 --- a/doc/reference/call_method.qbk +++ b/doc/reference/call_method.qbk @@ -20,6 +20,8 @@ C++ Module Definition `` #include #include +#include +#include #include #include @@ -28,7 +30,7 @@ class Base { public: virtual char const* class_name() const { return "Base"; } - virtual ~Base(); + virtual ~Base() {}; }; bool is_base(Base* b) @@ -56,7 +58,7 @@ BOOST_PYTHON_MODULE(my_module) { def("is_base", is_base); - class_("Base") + class_("Base") .def("class_name", &Base_callback::Base_name) ; diff --git a/doc/reference/indexing.qbk b/doc/reference/indexing.qbk index 0cfc7c7f5d..4f3a55cbf0 100644 --- a/doc/reference/indexing.qbk +++ b/doc/reference/indexing.qbk @@ -38,7 +38,7 @@ The `indexing_suite` class is the base class for the management of C++ container [[__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 [@http://www.python.org/doc/current/lib/typeiter.html Iterator Types] in the [@http://www.python.org/doc/current/lib/lib.html Python Library Reference].]] +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.]] diff --git a/doc/reference/numeric.qbk b/doc/reference/numeric.qbk deleted file mode 100644 index 4ccb0d3879..0000000000 --- a/doc/reference/numeric.qbk +++ /dev/null @@ -1,153 +0,0 @@ -[section boost/python/numeric.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 array] type. -[endsect] -[section Class `array`] -Provides access to the array types of [@http://www.pfdubois.com/numpy/ Numerical Python]\ 's [@http://www.pfdubois.com/numpy/#Numeric Numeric] and [@http://stsdas.stsci.edu/numarray/index.html 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 [link concepts.objectwrapper.typewrapper_concept_requirements 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. -`` -namespace boost { namespace python { namespace numeric -{ - class array : public object - { - public: - object astype(); - template - object astype(Type const& type_); - - template - array new_(Type const& type_) const; - - template - void resize(Sequence const& x); - void resize(long x1); - void resize(long x1, long x2); - ... - void resize(long x1, long x2,...long xn); - - template - void setshape(Sequence const& x); - void setshape(long x1); - void setshape(long x1, long x2); - ... - void setshape(long x1, long x2,...long xn); - - template - void put(Indices const& indices, Values const& values); - - template - object take(Sequence const& sequence, long axis = 0); - - template - void tofile(File const& f) const; - - object factory(); - template - object factory(Sequence const&); - template - object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false); - template - object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&); - template - object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&, Shape const&); - - template - explicit array(T1 const& x1); - template - explicit array(T1 const& x1, T2 const& x2); - ... - template - 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; - }; -}}} -`` -[endsect] -[section Class `array` observer functions] -`` -object factory(); -template -object factory(Sequence const&); -template -object factory(Sequence const&, Typecode const&, bool copy = true, bool savespace = false); -template -object factory(Sequence const&, Typecode const&, bool copy, bool savespace, Type const&); -template -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 -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++. -[endsect] -[section Class `array` static functions] -`` -static void set_module_and_type(char const* package_path, char const* type_name); -static void set_module_and_type(); -`` -[variablelist -[[Requires][package_path and type_name, if supplied, is an [link 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()`` -[variablelist -[[Effects][Returns the name of the module containing the class that will be held by new `numeric::array` instances.]] -] -[endsect] -[section Example] -`` -#include -#include - -// sets the first element in a 2d numeric array -void set_first_element(numeric::array& y, double value) -{ - y[make_tuple(0,0)] = value; -} -`` -[endsect] -[endsect] diff --git a/doc/reference/objects.qbk b/doc/reference/objects.qbk index 80ce257ce4..c57b02d03d 100644 --- a/doc/reference/objects.qbk +++ b/doc/reference/objects.qbk @@ -5,7 +5,6 @@ [include dict.qbk] [include list.qbk] [include long.qbk] -[include numeric.qbk] [include object.qbk] [include str.qbk] [include slice.qbk] diff --git a/doc/reference/operators.qbk b/doc/reference/operators.qbk index 892d33b7d2..8276f68190 100644 --- a/doc/reference/operators.qbk +++ b/doc/reference/operators.qbk @@ -86,8 +86,8 @@ The column of Python Expressions illustrates the expressions that will be suppor [[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`][`__nq__`][`x != y`][`x != y`, `y != x`]] -[[`l != self`][`__nq__`][`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`]] diff --git a/doc/reference/pickle.qbk b/doc/reference/pickle.qbk index 7f89c2d1c3..23d25ede7c 100644 --- a/doc/reference/pickle.qbk +++ b/doc/reference/pickle.qbk @@ -4,7 +4,7 @@ Pickle is a Python module for object serialization, also known as persistence, m 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 [@http://www.python.org/doc/current/lib/module-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. +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: diff --git a/doc/reference/slice.qbk b/doc/reference/slice.qbk index 32e3363f44..19dbe4d97e 100644 --- a/doc/reference/slice.qbk +++ b/doc/reference/slice.qbk @@ -105,14 +105,6 @@ 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 const& Foo, const slice index) { 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/tutorial.qbk b/doc/tutorial.qbk index 3992a50e01..197470013e 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -1,5 +1,5 @@ [article Boost.Python Tutorial - [quickbook 1.7] + [quickbook 1.6] [authors [de Guzman, Joel], [Abrahams, David]] [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams] [category inter-language support] @@ -92,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. @@ -117,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 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] @@ -1417,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 @@ -1758,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 @@ -1869,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 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 9b8d19e07a..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/src subdirectory of your -# Boost installation. Absolute paths work, too. -boost-build ../../../tools/build/src ; 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/Jamroot b/example/quickstart/Jamfile similarity index 51% rename from example/quickstart/Jamroot rename to example/quickstart/Jamfile index 8425638c20..6dd3513019 100644 --- a/example/quickstart/Jamroot +++ b/example/quickstart/Jamfile @@ -1,23 +1,15 @@ -# 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 - ; +# 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) -# Make the definition of the python-extension rule available import python ; +import testing ; + +project quickstart + : requirements + . + ; # Declare a Python extension called hello. python-extension extending : extending.cpp ; @@ -25,8 +17,6 @@ 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 ; diff --git a/example/quickstart/boost-build.jam b/example/quickstart/boost-build.jam deleted file mode 100644 index cf910e7955..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/src subdirectory of your -# Boost installation. Absolute paths work, too. -boost-build ../../../../tools/build/src ; 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 11067c1702..e484034103 100644 --- a/include/boost/python.hpp +++ b/include/boost/python.hpp @@ -42,7 +42,6 @@ # 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 55d1283b5a..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 @@ -116,9 +113,9 @@ 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)); 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 614d62232b..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 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 bad7e28240..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 @@ -76,9 +75,9 @@ namespace detail 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 70ca6d01b3..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 @@ -53,7 +50,6 @@ # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING # include -# include # endif namespace boost { namespace python { @@ -84,8 +80,8 @@ namespace detail template struct is_data_member_pointer : mpl::and_< - is_member_pointer - , mpl::not_ > + detail::is_member_pointer + , mpl::not_ > > {}; @@ -138,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 BOOST_ATTRIBUTE_UNUSED; + typedef typename assertion >::failed test1 BOOST_ATTRIBUTE_UNUSED; # endif - typedef typename assertion >::failed test2 BOOST_ATTRIBUTE_UNUSED; + typedef typename assertion >::failed test2 BOOST_ATTRIBUTE_UNUSED; not_a_derived_class_member(Fn()); } }; @@ -376,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 @@ -387,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 index 61bbaad570..0c0daabc1f 100644 --- 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++ 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/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 index 4668245545..b2271a7ea2 100644 --- 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 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 ad9a00b313..98013052ec 100644 --- a/include/boost/python/converter/registered.hpp +++ b/include/boost/python/converter/registered.hpp @@ -1,19 +1,19 @@ // 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 @@ -42,8 +42,8 @@ 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 > { @@ -75,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*) @@ -112,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 974cb6d810..28b2988c7f 100644 --- a/include/boost/python/converter/registered_pointee.hpp +++ b/include/boost/python/converter/registered_pointee.hpp @@ -7,8 +7,7 @@ # include # include # include -# include -# include +# include namespace boost { namespace python { namespace converter { @@ -17,9 +16,9 @@ struct registration; 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 > 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/data_members.hpp b/include/boost/python/data_members.hpp index 5d3309cf97..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,7 +260,7 @@ 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) @@ -276,7 +269,7 @@ 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(__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_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 fcc242a924..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 @@ -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 index d91d05c90f..7d78739ed9 100644 --- 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 { 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 11c16308fb..e2ac827040 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -57,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 @@ -96,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)) @@ -118,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: // @@ -131,6 +126,9 @@ #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 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 d32dd0fdbe..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 { @@ -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 92db09ed7b..24f9c5cdb2 100644 --- a/include/boost/python/detail/def_helper.hpp +++ b/include/boost/python/detail/def_helper.hpp @@ -6,12 +6,11 @@ # define DEF_HELPER_DWA200287_HPP # include -# include # include +# include # include # include # include -# include # include # include # include @@ -73,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/destroy.hpp b/include/boost/python/detail/destroy.hpp index 3ea6455330..d35b2b536e 100644 --- a/include/boost/python/detail/destroy.hpp +++ b/include/boost/python/detail/destroy.hpp @@ -5,7 +5,7 @@ #ifndef DESTROY_DWA2002221_HPP # define DESTROY_DWA2002221_HPP -# include +# include # include namespace boost { namespace python { namespace detail { @@ -30,7 +30,7 @@ struct value_destroyer for (T const volatile* p = first; p != first + sizeof(A)/sizeof(T); ++p) { value_destroyer< - boost::is_array::value + is_array::value >::execute(p); } } @@ -48,7 +48,7 @@ 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) + (is_array::value) >::execute((const volatile T*)p); } 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/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/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/pymutex.hpp b/include/boost/python/detail/pymutex.hpp new file mode 100644 index 0000000000..2d2e2d6266 --- /dev/null +++ b/include/boost/python/detail/pymutex.hpp @@ -0,0 +1,103 @@ +// Copyright 2025 Boost.Python Contributors +// Distributed under the 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_PYMUTEX_HPP +#define BOOST_PYTHON_DETAIL_PYMUTEX_HPP + +#include +#ifdef Py_GIL_DISABLED +// needed for pymutex wrapper +#include +#include +#endif + +namespace boost { namespace python { namespace detail { + +#ifdef Py_GIL_DISABLED + +// Re-entrant wrapper around PyMutex for free-threaded Python +// Similar to _PyRecursiveMutex or threading.RLock +class pymutex { + PyMutex m_mutex; + std::atomic m_owner; + std::size_t m_level; + +public: + pymutex() : m_mutex({}), m_owner(0), m_level(0) {} + + // Non-copyable, non-movable + pymutex(const pymutex&) = delete; + pymutex& operator=(const pymutex&) = delete; + + void lock() { + unsigned long thread = PyThread_get_thread_ident(); + if (m_owner.load(std::memory_order_relaxed) == thread) { + m_level++; + return; + } + PyMutex_Lock(&m_mutex); + m_owner.store(thread, std::memory_order_relaxed); + // m_level should be 0 when we acquire the lock + } + + void unlock() { + unsigned long thread = PyThread_get_thread_ident(); + // Verify current thread owns the lock + if (m_owner.load(std::memory_order_relaxed) != thread) { + // This should never happen - programming error + return; + } + if (m_level > 0) { + m_level--; + return; + } + m_owner.store(0, std::memory_order_relaxed); + PyMutex_Unlock(&m_mutex); + } + + bool is_locked_by_current_thread() const { + unsigned long thread = PyThread_get_thread_ident(); + return m_owner.load(std::memory_order_relaxed) == thread; + } +}; + + +// RAII lock guard for pymutex +class pymutex_guard { + pymutex& m_mutex; + +public: + explicit pymutex_guard(pymutex& mutex) : m_mutex(mutex) { + m_mutex.lock(); + } + + ~pymutex_guard() { + m_mutex.unlock(); + } + + // Non-copyable, non-movable + pymutex_guard(const pymutex_guard&) = delete; + pymutex_guard& operator=(const pymutex_guard&) = delete; +}; + +// Global mutex for protecting all Boost.Python internal state +// Similar to pybind11's internals.mutex +BOOST_PYTHON_DECL pymutex& get_global_mutex(); + +// Macro for acquiring the global lock +// Similar to pybind11's PYBIND11_LOCK_INTERNALS +#define BOOST_PYTHON_LOCK_STATE() \ + ::boost::python::detail::pymutex_guard lock(::boost::python::detail::get_global_mutex()) + +#else + +// No-op macro when not in free-threaded mode +#define BOOST_PYTHON_LOCK_STATE() + +#endif // Py_GIL_DISABLED + +}}} // namespace boost::python::detail + +#endif // BOOST_PYTHON_DETAIL_PYMUTEX_HPP 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 2cddf696d5..f646d2ae1d 100644 --- a/include/boost/python/detail/referent_storage.hpp +++ b/include/boost/python/detail/referent_storage.hpp @@ -5,39 +5,21 @@ #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; @@ -50,15 +32,12 @@ union aligned_storage std::size_t, value = sizeof(T)); }; - // 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 8ccc3c5029..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 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 a56e72ec6b..0961ec7c4e 100644 --- a/include/boost/python/detail/string_literal.hpp +++ b/include/boost/python/detail/string_literal.hpp @@ -7,8 +7,7 @@ # include # include -# include -# include +# include # include # include 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_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 fbb9defd0b..e270f89ca3 100644 --- a/include/boost/python/detail/value_is_xxx.hpp +++ b/include/boost/python/detail/value_is_xxx.hpp @@ -9,11 +9,11 @@ # include # include - -# 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 \ @@ -24,9 +24,10 @@ struct value_is_##name \ typename remove_reference::type \ >::type \ >::value); \ - typedef mpl::bool_ type; \ + typedef mpl::bool_ type; \ \ }; +}}} // 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 9fdb222c68..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,6 +90,7 @@ // than MSVC on Win32 // #if defined(_WIN32) || defined(__CYGWIN__) + # if defined(__GNUC__) && defined(__CYGWIN__) # if defined(__LP64__) @@ -138,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 @@ -193,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 75ed0e1eec..1aa1465bdf 100644 --- a/include/boost/python/exception_translator.hpp +++ b/include/boost/python/exception_translator.hpp @@ -7,7 +7,7 @@ # include -# include +# include # include # include # include @@ -18,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/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 792de58e80..0ee763cc26 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include 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 093703bb84..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); diff --git a/include/boost/python/manage_new_object.hpp b/include/boost/python/manage_new_object.hpp index 9585b13a6f..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 { @@ -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..390db82cf4 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -11,11 +11,41 @@ # ifndef BOOST_PYTHON_MODULE_INIT -namespace boost { namespace python { namespace detail { +namespace boost { namespace python { + +#ifdef HAS_CXX11 +// Use to activate the Py_MOD_GIL_NOT_USED flag. +class mod_gil_not_used { +public: + explicit mod_gil_not_used(bool flag = true) : flag_(flag) {} + bool flag() const { return flag_; } + +private: + bool flag_; +}; + +namespace detail { + +inline bool gil_not_used_option() { return false; } +template +bool gil_not_used_option(F &&, O &&...o); +template +inline bool gil_not_used_option(mod_gil_not_used f, O &&...o) { + return f.flag() || gil_not_used_option(o...); +} +template +inline bool gil_not_used_option(F &&, O &&...o) { + return gil_not_used_option(o...); +} + +} +#endif // HAS_CXX11 + +namespace detail { # if PY_VERSION_HEX >= 0x03000000 -BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef&, void(*)()); +BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef&, void(*)(), bool gil_not_used = false); #else @@ -27,7 +57,37 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); # if PY_VERSION_HEX >= 0x03000000 -# define _BOOST_PYTHON_MODULE_INIT(name) \ +# ifdef HAS_CXX11 +# define _BOOST_PYTHON_MODULE_INIT(name, ...) \ + PyObject* BOOST_PP_CAT(PyInit_, name)() \ + { \ + static PyModuleDef_Base initial_m_base = { \ + PyObject_HEAD_INIT(NULL) \ + 0, /* m_init */ \ + 0, /* m_index */ \ + 0 /* m_copy */ }; \ + static PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; \ + \ + static struct PyModuleDef moduledef = { \ + initial_m_base, \ + BOOST_PP_STRINGIZE(name), \ + 0, /* m_doc */ \ + -1, /* m_size */ \ + initial_methods, \ + 0, /* m_reload */ \ + 0, /* m_traverse */ \ + 0, /* m_clear */ \ + 0, /* m_free */ \ + }; \ + \ + return boost::python::detail::init_module( \ + moduledef, BOOST_PP_CAT(init_module_, name), \ + boost::python::detail::gil_not_used_option(__VA_ARGS__) ); \ + } \ + void BOOST_PP_CAT(init_module_, name)() + +# else // !HAS_CXX11 +# define _BOOST_PYTHON_MODULE_INIT(name) \ PyObject* BOOST_PP_CAT(PyInit_, name)() \ { \ static PyModuleDef_Base initial_m_base = { \ @@ -53,6 +113,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); moduledef, BOOST_PP_CAT(init_module_, name) ); \ } \ void BOOST_PP_CAT(init_module_, name)() +# endif // HAS_CXX11 # else @@ -66,25 +127,15 @@ 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) - +# if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x03000000) +# define BOOST_PYTHON_MODULE_INIT(name, ...) \ + void BOOST_PP_CAT(init_module_,name)(); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name, __VA_ARGS__) # 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 // HAS_CXX11 && Python 3 # 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 5009c176e8..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,7 +50,7 @@ struct register_base_of template inline void operator()(Base*) const { - BOOST_MPL_ASSERT_NOT((is_same)); + BOOST_MPL_ASSERT_NOT((boost::python::detail::is_same)); // Register the Base class register_dynamic_id(); @@ -62,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); } @@ -80,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); } // @@ -102,7 +103,7 @@ struct select_held_type : mpl::if_< mpl::or_< python::detail::specifies_bases - , is_same + , boost::python::detail::is_same > , Prev , T @@ -149,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; // @@ -160,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 mpl::bool_::value> 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. @@ -178,7 +179,7 @@ struct class_metadata typedef mpl::bool_< mpl::or_< has_back_reference - , is_same + , boost::python::detail::is_same , is_base_and_derived >::value > use_back_reference; @@ -207,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()); } @@ -220,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()); @@ -237,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 >()); @@ -282,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()); } @@ -292,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 30613d8ebd..c6515bb55b 100644 --- a/include/boost/python/object/forward.hpp +++ b/include/boost/python/object/forward.hpp @@ -6,11 +6,9 @@ # define FORWARD_DWA20011215_HPP # include -# include -# include -# include # include # include +# include # include # include @@ -22,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; } @@ -36,7 +35,7 @@ struct reference_to_value template struct forward : mpl::if_< - mpl::or_, is_scalar > + mpl::or_, boost::python::detail::is_scalar > , T , reference_to_value > @@ -65,7 +64,7 @@ struct unforward_cref template struct unforward_cref > - : add_reference::type> + : boost::python::detail::add_lvalue_reference::type> { }; 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 db5224713f..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 { @@ -202,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/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index 27d95193a0..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; @@ -107,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_core.hpp b/include/boost/python/object_core.hpp index 6185779667..074360d415 100644 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -31,10 +31,7 @@ # include # include # include - -# include -# include -# include +# include namespace boost { namespace python { @@ -165,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()); @@ -208,8 +205,8 @@ namespace api template struct is_derived - : is_convertible< - typename remove_reference::type* + : boost::python::detail::is_convertible< + typename detail::remove_reference::type* , U const* > {}; @@ -280,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()); } @@ -298,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()); } @@ -422,6 +419,17 @@ inline api::object_base& api::object_base::operator=(api::object_base const& rhs inline api::object_base::~object_base() { +#ifdef Py_GIL_DISABLED + // This is a not very elegant fix for a problem that occurs with the + // free-threaded build of Python. If this is called when the interpreter + // has already been finalized, the thread-state can be null. Unlike the + // GIL-enabled build, Py_DECREF() requires a valid thread-state. This + // causes a memory leak, rather than crash, which seems preferable. + if (PyThreadState_GetUnchecked() == NULL) { + return; + } +#endif + assert( Py_REFCNT(m_ptr) > 0 ); Py_DECREF(m_ptr); } 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/opaque_pointer_converter.hpp b/include/boost/python/opaque_pointer_converter.hpp index e95c49bbfe..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 diff --git a/include/boost/python/other.hpp b/include/boost/python/other.hpp index 24a24ad8d1..26ebb426ba 100644 --- 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,8 +7,6 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -# pragma once - # include namespace boost { namespace python { @@ -51,4 +49,4 @@ namespace detail }} // 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/ptr.hpp b/include/boost/python/ptr.hpp index 287daba458..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,8 +11,6 @@ // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // Copyright (C) 2001 Peter Dimov -# pragma once - # include # include @@ -64,4 +62,4 @@ class unwrap_pointer > }} // 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 index 58e9aedef1..f3b298de2c 100644 --- a/include/boost/python/pure_virtual.hpp +++ b/include/boost/python/pure_virtual.hpp @@ -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 8c2410715b..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 { @@ -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/return_arg.hpp b/include/boost/python/return_arg.hpp index e869a58d12..de23993987 100644 --- 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 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_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 de4c512614..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; @@ -111,7 +111,6 @@ struct most_derived // 'default' calling convention # define BOOST_PYTHON_FN_CC -# define BOOST_PYTHON_FN_CC_IS_DEFAULT # define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PYTHON_MAX_ARITY, )) @@ -119,7 +118,6 @@ struct most_derived # include BOOST_PP_ITERATE() # undef BOOST_PYTHON_FN_CC -# undef BOOST_PYTHON_FN_CC_IS_DEFAULT // __cdecl calling convention @@ -143,7 +141,6 @@ struct most_derived # if defined(BOOST_PYTHON_ENABLE_STDCALL) # define BOOST_PYTHON_FN_CC __stdcall -# define BOOST_PYTHON_FN_CC_IS_STDCALL # define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PYTHON_MAX_ARITY, )) @@ -151,7 +148,6 @@ struct most_derived # include BOOST_PP_ITERATE() # undef BOOST_PYTHON_FN_CC -# undef BOOST_PYTHON_FN_CC_IS_STDCALL # endif // defined(BOOST_PYTHON_ENABLE_STDCALL) @@ -160,14 +156,12 @@ struct most_derived # if defined(BOOST_PYTHON_ENABLE_FASTCALL) # define BOOST_PYTHON_FN_CC __fastcall -# define BOOST_PYTHON_FN_CC_IS_FASTCALL # define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PYTHON_MAX_ARITY, )) # include BOOST_PP_ITERATE() -# undef BOOST_PYTHON_FN_CC_IS_FASTCALL # undef BOOST_PYTHON_FN_CC # endif // defined(BOOST_PYTHON_ENABLE_FASTCALL) @@ -190,8 +184,8 @@ struct most_derived // as 'get_signature(RT(*)(T0...TN), void* = 0)' is the same // function as 'get_signature(RT(__cdecl *)(T0...TN), void* = 0)', - // we don't define it multiple times (i.e. for __cdecl, __stdcall ...) -# if defined(BOOST_PYTHON_FN_CC_IS_DEFAULT) + // we don't define it twice +# if !defined(BOOST_PYTHON_FN_CC_IS_CDECL) template < class RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)> @@ -204,7 +198,7 @@ get_signature(RT(BOOST_PYTHON_FN_CC *)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)), void* = >(); } -# endif // BOOST_PYTHON_FN_CC_IS_DEFAULT +# endif // !defined(BOOST_PYTHON_FN_CC_IS_CDECL) # undef N @@ -212,13 +206,11 @@ get_signature(RT(BOOST_PYTHON_FN_CC *)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)), void* = (3, (0, 3, )) # include BOOST_PP_ITERATE() -#else // BOOST_PP_ITERATION_DEPTH() != 1 +#else # define N BOOST_PP_RELATIVE_ITERATION(1) # define Q BOOST_PYTHON_CV_QUALIFIER(BOOST_PP_ITERATION()) -# if defined(BOOST_PYTHON_FN_CC_IS_DEFAULT) - template < class RT, class ClassT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)> inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))< @@ -253,8 +245,6 @@ get_signature( >(); } -# endif // BOOST_PYTHON_FN_CC_IS_DEFAULT - # undef Q # undef N 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 40301fdff5..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,10 +122,10 @@ 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 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 aaabb9cf75..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 }; } @@ -168,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 38b7f7b453..601601c311 100644 --- a/include/boost/python/type_id.hpp +++ b/include/boost/python/type_id.hpp @@ -14,7 +14,7 @@ # include # include # include -# include +# include # ifndef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE # if defined(__GNUC__) \ 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 index e2f2a05472..80f20f846c 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -10,5 +10,6 @@ ], "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/SConscript b/src/SConscript deleted file mode 100644 index a1d3de6baf..0000000000 --- a/src/SConscript +++ /dev/null @@ -1,44 +0,0 @@ -# -*- 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) - -Import('env') - -env.AppendUnique(CPPDEFINES = ["${LINK_DYNAMIC and 'BOOST_PYTHON_DYN_LINK=1' or ''}"]) -env.AppendUnique(CPPDEFINES = ['BOOST_PYTHON_SOURCE']) - -env.BoostLibrary( - 'python', - ['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']) 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..53a149fa72 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -145,6 +146,8 @@ namespace inline bool visit(rvalue_from_python_chain const* chain) { + BOOST_PYTHON_LOCK_STATE(); + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); if (p != visited.end() && *p == chain) return false; @@ -157,9 +160,11 @@ namespace { unvisit(rvalue_from_python_chain const* chain) : chain(chain) {} - + ~unvisit() { + BOOST_PYTHON_LOCK_STATE(); + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); assert(p != visited.end()); visited.erase(p); @@ -222,7 +227,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/converter/registry.cpp b/src/converter/registry.cpp index aa20c3f685..1b23dbef48 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -112,9 +113,9 @@ registration::~registration() namespace // { typedef registration entry; - + typedef std::set registry_t; - + #ifndef BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND registry_t& entries() { @@ -181,6 +182,8 @@ namespace // entry* get(type_info type, bool is_shared_ptr = false) { + BOOST_PYTHON_LOCK_STATE(); + # ifdef BOOST_PYTHON_TRACE_REGISTRY registry_t::iterator p = entries().find(entry(type)); @@ -293,6 +296,8 @@ namespace registry registration const* query(type_info type) { + BOOST_PYTHON_LOCK_STATE(); + registry_t::iterator p = entries().find(entry(type)); # ifdef BOOST_PYTHON_TRACE_REGISTRY std::cout << "querying " << type diff --git a/src/converter/type_id.cpp b/src/converter/type_id.cpp index c6a8bf7a04..fafb13619c 100644 --- a/src/converter/type_id.cpp +++ b/src/converter/type_id.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -81,7 +82,7 @@ namespace { free_mem(char*p) : p(p) {} - + ~free_mem() { std::free(p); @@ -92,6 +93,7 @@ namespace bool cxxabi_cxa_demangle_is_broken() { + BOOST_PYTHON_LOCK_STATE(); static bool was_tested = false; static bool is_broken = false; if (!was_tested) { @@ -109,6 +111,8 @@ namespace detail { BOOST_PYTHON_DECL char const* gcc_demangle(char const* mangled) { + BOOST_PYTHON_LOCK_STATE(); + typedef std::vector< std::pair > mangling_map; diff --git a/src/dict.cpp b/src/dict.cpp index 77d840d455..296bc21e9c 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -68,8 +68,16 @@ object dict_base::get(object_cref k) const { if (check_exact(this)) { +#ifdef Py_GIL_DISABLED + PyObject* result; + if (PyDict_GetItemRef(this->ptr(),k.ptr(),&result) < 0) { + throw_error_already_set(); + } + return object(detail::new_reference(result ? result : Py_None)); +#else PyObject* result = PyDict_GetItem(this->ptr(),k.ptr()); return object(detail::borrowed_reference(result ? result : Py_None)); +#endif } else { diff --git a/src/errors.cpp b/src/errors.cpp index 34ea22f43e..7f6b1880d5 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -10,9 +10,21 @@ #include #include #include +#include namespace boost { namespace python { +#ifdef Py_GIL_DISABLED +namespace detail { + // Global mutex for protecting all Boost.Python internal state + pymutex& get_global_mutex() + { + static pymutex mutex; + return mutex; + } +} +#endif + error_already_set::~error_already_set() {} // IMPORTANT: this function may only be called from within a catch block! @@ -20,8 +32,13 @@ BOOST_PYTHON_DECL bool handle_exception_impl(function0 f) { try { - if (detail::exception_handler::chain) - return detail::exception_handler::chain->handle(f); + detail::exception_handler* handler_chain = nullptr; + { + BOOST_PYTHON_LOCK_STATE(); + handler_chain = detail::exception_handler::chain; + } + if (handler_chain) + return handler_chain->handle(f); f(); return false; } @@ -80,6 +97,7 @@ exception_handler::exception_handler(handler_function const& impl) : m_impl(impl) , m_next(0) { + BOOST_PYTHON_LOCK_STATE(); if (chain != 0) tail->m_next = this; else diff --git a/src/exec.cpp b/src/exec.cpp index fa2860e40e..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,15 +103,23 @@ 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); - // Let python open the file to avoid potential binary incompatibilities. -#if PY_VERSION_HEX >= 0x03040000 - FILE *fs = _Py_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 = _Py_fopen(fo, "r"); + 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")); if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file"); python::handle<> file(pyfile); @@ -101,6 +129,7 @@ object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) f, Py_file_input, 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..c32f4187bc 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; @@ -38,10 +38,17 @@ BOOST_PYTHON_DECL void scope_setattr_doc(char const* name, object const& x, char #if PY_VERSION_HEX >= 0x03000000 -BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, void(*init_function)()) +BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, + void(*init_function)(), bool gil_not_used) { + PyObject *mod = PyModule_Create(&moduledef); +#ifdef Py_GIL_DISABLED + if (mod != NULL && gil_not_used) { + PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); + } +#endif return init_module_in_scope( - PyModule_Create(&moduledef), + mod, init_function); } 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..76b620dcb9 100644 --- a/src/object/function_doc_signature.cpp +++ b/src/object/function_doc_signature.cpp @@ -114,23 +114,58 @@ 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; +#if PY_VERSION_HEX >= 0x030D0000 + if (PyDict_GetItemStringRef(py_type->tp_dict, "__module__", &type_module_name) < 0) { + throw_error_already_set(); + } +#else + type_module_name = PyDict_GetItemString(py_type->tp_dict, "__module__"); + Py_XINCREF(type_module_name); +#endif + if ( + type_module_name + && PyObject_RichCompareBool( + type_module_name, + current_module_name.ptr(), + Py_NE + ) != 0 + ) { + str result = str("%s.%s" % make_tuple(handle<>(type_module_name), name)); + return result; + } + // Clean up the strong reference if we didn't use it + Py_XDECREF(type_module_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 +191,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 +234,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..44062875a4 100644 --- a/src/object/inheritance.cpp +++ b/src/object/inheritance.cpp @@ -4,6 +4,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #include #include +#include #include #if _MSC_FULL_VER >= 13102171 && _MSC_FULL_VER <= 13102179 # include @@ -11,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -184,6 +185,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( @@ -389,6 +391,8 @@ namespace inline void* convert_type(void* const p, class_id src_t, class_id dst_t, bool polymorphic) { + BOOST_PYTHON_LOCK_STATE(); + // Quickly rule out unregistered types index_entry* src_p = seek_type(src_t); if (src_p == 0) @@ -451,6 +455,8 @@ BOOST_PYTHON_DECL void* find_static_type(void* p, class_id src_t, class_id dst_t BOOST_PYTHON_DECL void add_cast( class_id src_t, class_id dst_t, cast_function cast, bool is_downcast) { + BOOST_PYTHON_LOCK_STATE(); + // adding an edge will invalidate any record of unreachability in // the cache. static std::size_t expected_cache_len = 0; @@ -489,6 +495,7 @@ BOOST_PYTHON_DECL void add_cast( BOOST_PYTHON_DECL void register_dynamic_id_aux( class_id static_id, dynamic_id_function get_dynamic_id) { + BOOST_PYTHON_LOCK_STATE(); tuples::get(*demand_type(static_id)) = get_dynamic_id; } 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..2b053d8311 --- a/src/wrapper.cpp +++ b/src/wrapper.cpp @@ -21,20 +21,28 @@ namespace detail this->m_self, const_cast(name)))) ) { - PyObject* borrowed_f = 0; - + PyObject* class_f = 0; + 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 ) { - borrowed_f = ::PyDict_GetItemString( +#if PY_VERSION_HEX >= 0x030D0000 + if (::PyDict_GetItemStringRef( + class_object->tp_dict, const_cast(name), &class_f) < 0) { + throw_error_already_set(); + } +#else + class_f = ::PyDict_GetItemString( class_object->tp_dict, const_cast(name)); - - + Py_XINCREF(class_f); +#endif } - if (borrowed_f != ((PyMethodObject*)m.get())->im_func) + bool is_override = (class_f != PyMethod_GET_FUNCTION(m.get())); + Py_XDECREF(class_f); + if (is_override) return override(m); } } diff --git a/test/Jamfile.v2 b/test/Jamfile similarity index 77% rename from test/Jamfile.v2 rename to test/Jamfile index 4ce1613590..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 : 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/SConscript b/test/SConscript deleted file mode 100644 index 896783c805..0000000000 --- a/test/SConscript +++ /dev/null @@ -1,138 +0,0 @@ -# -*- 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) - -import platform - -Import('env') - -# libs needed for embedding -ELIBS=env['LIBS'] + env['PYTHONLIBS'] - -def BPLTest(env, name, sources = None, deps = None): - run = env.BoostRunPythonScript(name + '.py') - if sources: - for source in sources: - Depends(run, - env.PythonExtension(source != name and source or (source + '_ext'), source + '.cpp') - ) - else: - Depends(run, env.PythonExtension(name + '_ext', name + '.cpp')) - if deps: - Depends(run, deps) - return run - -env.AddMethod(BPLTest) - -env.AppendENVPath('PYTHONPATH', Dir('.').path) - -tests=[] -tests+=env.BPLTest('crossmod_exception', ['crossmod_exception_a', 'crossmod_exception_b']) - -for test in [('injected',), - ('properties',), - ('return_arg',), - ('staticmethod',), - ('shared_ptr',), - ('enable_shared_from_this',), - ('andreas_beyer',), - ('polymorphism',), - ('polymorphism2',), - ('wrapper_held_type',), - ('polymorphism2_auto_ptr',), - ('auto_ptr',), - ('minimal',), - ('args',), - ('raw_ctor',), - ('numpy',None, ['printer.py', 'numeric_tests.py', 'numarray_tests.py']), - ('exception_translator',), - ('test_enum', ['enum_ext']), - ('test_cltree', ['cltree']), - ('newtest', ['m1', 'm2']), - ('const_argument',), - ('keywords_test', ['keywords']), - ('test_pointer_adoption',), - ('operators',), - ('operators_wrapper',), - ('callbacks',), - ('defaults',), - ('object',), - ('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',)]: - tests+=env.BPLTest(*test) - -test = env.BoostRunPythonScript('test_builtin_converters.py') -Depends( - test, - env.PythonExtension('builtin_converters_ext', ['test_builtin_converters.cpp']) - ) -tests+=test -test = env.BoostRunPythonScript('map_indexing_suite.py') -Depends( - test, - env.PythonExtension('map_indexing_suite_ext', [ - 'map_indexing_suite.cpp', - 'int_map_indexing_suite.cpp', - 'a_map_indexing_suite.cpp']) - ) -tests+=test - -tests+=env.BoostRunTest('import_', 'import_.cpp', '${SOURCES[0]} ${SOURCES[1]}', 'import_.py', LIBS=ELIBS) - -tests+=env.BoostCompileTest('indirect_traits_test') -tests+=env.BoostRunTests(['destroy_test', - 'pointer_type_id_test', - 'bases', - 'if_else', - 'pointee', - 'result'], LIBS=ELIBS) - -tests+=env.BoostCompileTests(['string_literal', - 'borrowed', - 'object_manager', - 'copy_ctor_mutates_rhs']) - -tests+=env.BoostRunTest('upcast', LIBS=ELIBS) -tests+=env.BoostCompileTest('select_holder') -tests+=env.BoostRunTest('select_from_python_test', LIBS=ELIBS) -tests+=env.BoostCompileTest('select_arg_to_python_test') - -if platform.system() == 'Windows': - tests+=env.BPLTest('calling_conventions') - tests+=env.BPLTest('calling_conventions_mf') - -env.BoostTestSummary(tests) -AlwaysBuild(tests) 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/args.py b/test/args.py index e884c06bea..5d89921467 100644 --- a/test/args.py +++ b/test/args.py @@ -1,15 +1,19 @@ # 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 __future__ import print_function """ >>> 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), {}) @@ -76,7 +80,7 @@ ... 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) @@ -123,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 @@ -143,6 +153,3 @@ def run(args = None): import args_ext help(args_ext) 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/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/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/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_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/class.py b/test/class.py old mode 100755 new mode 100644 diff --git a/test/cltree.cpp b/test/cltree.cpp old mode 100755 new mode 100644 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_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 e542fa6d3c..533ac16fe1 100644 --- a/test/crossmod_opaque.py +++ b/test/crossmod_opaque.py @@ -1,5 +1,5 @@ -# -*- 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) 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/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 72c37d99e1..9b1149ae60 100644 --- a/test/dict.py +++ b/test/dict.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function """ >>> from dict_ext import * >>> def printer(*args): @@ -22,14 +21,16 @@ >>> 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 @@ -37,7 +38,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys diff --git a/test/enable_shared_from_this.py b/test/enable_shared_from_this.py old mode 100755 new mode 100644 diff --git a/test/enum_ext.cpp b/test/enum_ext.cpp index e5c4f4fa91..74224f1d77 100644 --- a/test/enum_ext.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/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/fabscript b/test/fabscript new file mode 100644 index 0000000000..7cf22f9c09 --- /dev/null +++ b/test/fabscript @@ -0,0 +1,177 @@ +# -*- 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',), + ('module_nogil',), + ('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/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/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 314a356767..0d75100a09 100644 --- a/test/iterator.py +++ b/test/iterator.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function ''' >>> from iterator_ext import * >>> from input_iterator import * @@ -25,7 +24,7 @@ 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) @@ -56,12 +55,15 @@ >>> ll.push_back(x) >>> for a in ll: #doctest: +NORMALIZE_WHITESPACE ... for b in a: -... print(b, end='') +... print(b, end=' ') ... print('') ... 1 3 5 1 3 5 7 ''' + +from __future__ import print_function + def run(args = None): import sys import doctest @@ -69,7 +71,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys diff --git a/test/keywords.cpp b/test/keywords.cpp old mode 100755 new mode 100644 diff --git a/test/list.py b/test/list.py index 913032db8a..f6cf87096f 100644 --- a/test/list.py +++ b/test/list.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function ''' >>> from list_ext import * @@ -41,7 +40,7 @@ ['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') @@ -51,7 +50,7 @@ ['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) @@ -103,6 +102,8 @@ ['y', 'x', 'o', 'l', 'l', 'h', 'e', '.'] ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -110,7 +111,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys diff --git a/test/long.py b/test/long.py index 3e5881de3f..157dc57aa9 100644 --- a/test/long.py +++ b/test/long.py @@ -1,9 +1,6 @@ # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -import sys -if (sys.version_info.major >= 3): - from past.builtins import long ''' >>> from long_ext import * >>> print(new_long()) @@ -20,6 +17,10 @@ >>> x = Y(long(4294967295)) ''' +import sys +if (sys.version_info.major >= 3): + long = int + def run(args = None): import sys import doctest diff --git a/test/map_indexing_suite.py b/test/map_indexing_suite.py index a5750a833f..6d3e57a102 100644 --- a/test/map_indexing_suite.py +++ b/test/map_indexing_suite.py @@ -1,7 +1,6 @@ # Copyright Joel de Guzman 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -from __future__ import print_function ''' ##################################################################### @@ -25,7 +24,7 @@ # test that a string is implicitly convertible # to an X ->>> x_value('bochi bochi') +>>> x_value('bochi bochi') 'gotya bochi bochi' ##################################################################### @@ -33,9 +32,9 @@ ##################################################################### >>> def print_xmap(xmap): ... s = '[ ' -... for x in xmap: +... for x in xmap: ... s += repr(x) -... s += ' ' +... s += ' ' ... s += ']' ... print(s) @@ -135,7 +134,7 @@ >>> assert not 12345 in xm ##################################################################### -# Some references to the container elements +# Some references to the container elements ##################################################################### >>> z0 = xm['joel'] @@ -156,7 +155,7 @@ kiwi ##################################################################### -# Delete some container element +# Delete some container element ##################################################################### >>> del xm['tenji'] @@ -168,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 @@ -199,7 +198,7 @@ >>> print_xmap(tm) [ (joel, aaa) (kimpo, bbb) ] >>> for el in tm: #doctest: +NORMALIZE_WHITESPACE -... print(el.key(), end='') +... print(el.key(), end=' ') ... dom = el.data() joel kimpo @@ -216,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 @@ -236,8 +243,3 @@ def run(args = None): status = run()[0] if (status == 0): print("Done.") sys.exit(status) - - - - - 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/module_nogil.cpp b/test/module_nogil.cpp new file mode 100644 index 0000000000..331a73cf31 --- /dev/null +++ b/test/module_nogil.cpp @@ -0,0 +1,25 @@ +// Test for BOOST_PYTHON_MODULE with optional mod_gil_not_used argument + +#include +#include + +// Simple function to export +int get_value() { + return 1234; +} + +#if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x03000000) +// C++11 build with Python 3: test with mod_gil_not_used option +BOOST_PYTHON_MODULE(module_nogil_ext, boost::python::mod_gil_not_used()) +{ + using namespace boost::python; + def("get_value", get_value); +} +#else +// C++98 build or Python 2: test without optional arguments +BOOST_PYTHON_MODULE(module_nogil_ext) +{ + using namespace boost::python; + def("get_value", get_value); +} +#endif diff --git a/test/module_nogil.py b/test/module_nogil.py new file mode 100644 index 0000000000..c035436014 --- /dev/null +++ b/test/module_nogil.py @@ -0,0 +1,29 @@ +""" +>>> from module_nogil_ext import * +>>> get_value() +1234 +>>> import sys, sysconfig +>>> Py_GIL_DISABLED = bool(sysconfig.get_config_var('Py_GIL_DISABLED')) +>>> if Py_GIL_DISABLED and sys._is_gil_enabled(): +... print('GIL is enabled and should not be') +... else: +... print('okay') +okay +""" + +from __future__ import print_function + +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/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 720790173c..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,7 +51,23 @@ 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...") 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 f5019212aa..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 49cc213a00..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 67a46d9362..cf6c2de0c5 100644 --- a/test/object.py +++ b/test/object.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function ''' >>> from object_ext import * @@ -130,14 +129,14 @@ 1 Slices - + >>> assert check_string_slice() Operators ->>> def print_args(*args, **kwds): +>>> def print_args(*args, **kwds): ... print(args, kwds) ->>> test_call(print_args, (0, 1, 2, 3), {'a':'A'}) +>>> test_call(print_args, (0, 1, 2, 3), {'a':'A'}) (0, 1, 2, 3) {'a': 'A'} @@ -149,7 +148,7 @@ Now make sure that object is actually managing reference counts - + >>> import weakref >>> class Z: pass ... @@ -164,6 +163,8 @@ death ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -171,7 +172,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys 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 311b1893a5..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) diff --git a/test/operators.cpp b/test/operators.cpp old mode 100755 new mode 100644 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 b8f4efd9b0..0df59a4b3a 100644 --- a/test/pickle1.py +++ b/test/pickle1.py @@ -9,8 +9,10 @@ 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) @@ -31,7 +33,27 @@ 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...") diff --git a/test/pickle2.py b/test/pickle2.py index f4788d3b89..4c11ef3a85 100644 --- a/test/pickle2.py +++ b/test/pickle2.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function r'''>>> import pickle2_ext >>> import pickle >>> pickle2_ext.world.__module__ @@ -35,6 +34,8 @@ Incomplete pickle support (__getstate_manages_dict__ not set) ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -42,7 +43,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys diff --git a/test/pickle3.py b/test/pickle3.py index 932e30f3cd..391e3d00f1 100644 --- a/test/pickle3.py +++ b/test/pickle3.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function r'''>>> import pickle3_ext >>> import pickle >>> pickle3_ext.world.__module__ @@ -30,6 +29,8 @@ Hello from California! 0 84 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 126.0 ''' +from __future__ import print_function + def run(args = None): import sys import doctest @@ -37,7 +38,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys diff --git a/test/pickle4.py b/test/pickle4.py index be813bbb13..3cf4d7241f 100644 --- a/test/pickle4.py +++ b/test/pickle4.py @@ -12,8 +12,10 @@ 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) @@ -29,7 +31,27 @@ 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...") 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/polymorphism2.cpp b/test/polymorphism2.cpp old mode 100755 new mode 100644 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 46e064af3e..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 1bc7a624ba..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 diff --git a/test/pytype_function.py b/test/pytype_function.py old mode 100755 new mode 100644 diff --git a/test/raw_ctor.cpp b/test/raw_ctor.cpp old mode 100755 new mode 100644 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/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 c70b317406..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) @@ -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,7 +121,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys 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 92cb5c9f3a..041934cf57 100644 --- a/test/slice.py +++ b/test/slice.py @@ -12,22 +12,6 @@ ... 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() @@ -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): diff --git a/test/stl_iterator.cpp b/test/stl_iterator.cpp old mode 100755 new mode 100644 diff --git a/test/str.py b/test/str.py index 4eba0e8769..bfb4994959 100644 --- a/test/str.py +++ b/test/str.py @@ -1,11 +1,10 @@ # 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 __future__ import print_function """ >>> from str_ext import * >>> def printer(*args): -... for x in args: print(x, end='') +... for x in args: print(x, end=' ') ... print('') ... >>> work_with_string(printer) #doctest: +NORMALIZE_WHITESPACE @@ -38,6 +37,8 @@ aaaaaaaaaaaaaaaaaaaaa """ +from __future__ import print_function + def run(args = None): import sys import doctest @@ -45,7 +46,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys diff --git a/test/test_builtin_converters.py b/test/test_builtin_converters.py index c3191d9b7b..0f1b4ded75 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -1,9 +1,7 @@ +# -*- 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) -import sys -if (sys.version_info.major >= 3): - from past.builtins import long r""" >>> from builtin_converters_ext import * @@ -17,7 +15,7 @@ # 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])) >>> def test_overflow(method, values): @@ -77,7 +75,7 @@ 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 @@ -283,6 +281,10 @@ >>> assert return_null_handle() is None """ +import sys +if (sys.version_info.major >= 3): + long = int + def run(args = None): import sys import doctest 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 2127b7cdb6..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 diff --git a/test/tuple.py b/test/tuple.py index 1aec5fded4..e2cd5eb179 100644 --- a/test/tuple.py +++ b/test/tuple.py @@ -1,7 +1,6 @@ # 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 __future__ import print_function """ >>> from tuple_ext import * >>> def printer(*args): @@ -22,6 +21,8 @@ ('hello', 42) """ +from __future__ import print_function + def run(args = None): import sys import doctest @@ -29,7 +30,7 @@ def run(args = None): if args is not None: sys.argv = args return doctest.testmod(sys.modules.get(__name__)) - + if __name__ == '__main__': print("running...") import sys 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/voidptr.cpp b/test/voidptr.cpp old mode 100755 new mode 100644 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/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 - - - - - - -