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/.ci/install.ps1 b/.ci/install.ps1 deleted file mode 100644 index 94d6f01813..0000000000 --- a/.ci/install.ps1 +++ /dev/null @@ -1,229 +0,0 @@ -# Sample script to install Python and pip under Windows -# Authors: Olivier Grisel, Jonathan Helmus, Kyle Kastner, and Alex Willmer -# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ - -$MINICONDA_URL = "http://repo.continuum.io/miniconda/" -$BASE_URL = "https://www.python.org/ftp/python/" -$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" -$GET_PIP_PATH = "C:\get-pip.py" - -$PYTHON_PRERELEASE_REGEX = @" -(?x) -(?\d+) -\. -(?\d+) -\. -(?\d+) -(?[a-z]{1,2}\d+) -"@ - - -function Download ($filename, $url) { - $webclient = New-Object System.Net.WebClient - - $basedir = $pwd.Path + "\" - $filepath = $basedir + $filename - if (Test-Path $filename) { - Write-Host "Reusing" $filepath - return $filepath - } - - # Download and retry up to 3 times in case of network transient errors. - Write-Host "Downloading" $filename "from" $url - $retry_attempts = 2 - for ($i = 0; $i -lt $retry_attempts; $i++) { - try { - $webclient.DownloadFile($url, $filepath) - break - } - Catch [Exception]{ - Start-Sleep 1 - } - } - if (Test-Path $filepath) { - Write-Host "File saved at" $filepath - } else { - # Retry once to get the error message if any at the last try - $webclient.DownloadFile($url, $filepath) - } - return $filepath -} - - -function ParsePythonVersion ($python_version) { - if ($python_version -match $PYTHON_PRERELEASE_REGEX) { - return ([int]$matches.major, [int]$matches.minor, [int]$matches.micro, - $matches.prerelease) - } - $version_obj = [version]$python_version - return ($version_obj.major, $version_obj.minor, $version_obj.build, "") -} - - -function DownloadPython ($python_version, $platform_suffix) { - $major, $minor, $micro, $prerelease = ParsePythonVersion $python_version - - if (($major -le 2 -and $micro -eq 0) ` - -or ($major -eq 3 -and $minor -le 2 -and $micro -eq 0) ` - ) { - $dir = "$major.$minor" - $python_version = "$major.$minor$prerelease" - } else { - $dir = "$major.$minor.$micro" - } - - if ($prerelease) { - if (($major -le 2) ` - -or ($major -eq 3 -and $minor -eq 1) ` - -or ($major -eq 3 -and $minor -eq 2) ` - -or ($major -eq 3 -and $minor -eq 3) ` - ) { - $dir = "$dir/prev" - } - } - - if (($major -le 2) -or ($major -le 3 -and $minor -le 4)) { - $ext = "msi" - if ($platform_suffix) { - $platform_suffix = ".$platform_suffix" - } - } else { - $ext = "exe" - if ($platform_suffix) { - $platform_suffix = "-$platform_suffix" - } - } - - $filename = "python-$python_version$platform_suffix.$ext" - $url = "$BASE_URL$dir/$filename" - $filepath = Download $filename $url - return $filepath -} - - -function InstallPython ($python_version, $architecture, $python_home) { - Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home - if (Test-Path $python_home) { - Write-Host $python_home "already exists, skipping." - return $false - } - if ($architecture -eq "32") { - $platform_suffix = "" - } else { - $platform_suffix = "amd64" - } - $installer_path = DownloadPython $python_version $platform_suffix - $installer_ext = [System.IO.Path]::GetExtension($installer_path) - Write-Host "Installing $installer_path to $python_home" - $install_log = $python_home + ".log" - if ($installer_ext -eq '.msi') { - InstallPythonMSI $installer_path $python_home $install_log - } else { - InstallPythonEXE $installer_path $python_home $install_log - } - if (Test-Path $python_home) { - Write-Host "Python $python_version ($architecture) installation complete" - } else { - Write-Host "Failed to install Python in $python_home" - Get-Content -Path $install_log - Exit 1 - } -} - - -function InstallPythonEXE ($exepath, $python_home, $install_log) { - $install_args = "/quiet InstallAllUsers=1 TargetDir=$python_home" - RunCommand $exepath $install_args -} - - -function InstallPythonMSI ($msipath, $python_home, $install_log) { - $install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home" - $uninstall_args = "/qn /x $msipath" - RunCommand "msiexec.exe" $install_args - if (-not(Test-Path $python_home)) { - Write-Host "Python seems to be installed else-where, reinstalling." - RunCommand "msiexec.exe" $uninstall_args - RunCommand "msiexec.exe" $install_args - } -} - -function RunCommand ($command, $command_args) { - Write-Host $command $command_args - Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru -} - - -function InstallPip ($python_home) { - $pip_path = $python_home + "\Scripts\pip.exe" - $python_path = $python_home + "\python.exe" - if (-not(Test-Path $pip_path)) { - Write-Host "Installing pip..." - $webclient = New-Object System.Net.WebClient - $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) - Write-Host "Executing:" $python_path $GET_PIP_PATH - & $python_path $GET_PIP_PATH - } else { - Write-Host "pip already installed." - } -} - - -function DownloadMiniconda ($python_version, $platform_suffix) { - if ($python_version -eq "3.4") { - $filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe" - } else { - $filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe" - } - $url = $MINICONDA_URL + $filename - $filepath = Download $filename $url - return $filepath -} - - -function InstallMiniconda ($python_version, $architecture, $python_home) { - Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home - if (Test-Path $python_home) { - Write-Host $python_home "already exists, skipping." - return $false - } - if ($architecture -eq "32") { - $platform_suffix = "x86" - } else { - $platform_suffix = "x86_64" - } - $filepath = DownloadMiniconda $python_version $platform_suffix - Write-Host "Installing" $filepath "to" $python_home - $install_log = $python_home + ".log" - $args = "/S /D=$python_home" - Write-Host $filepath $args - Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru - if (Test-Path $python_home) { - Write-Host "Python $python_version ($architecture) installation complete" - } else { - Write-Host "Failed to install Python in $python_home" - Get-Content -Path $install_log - Exit 1 - } -} - - -function InstallMinicondaPip ($python_home) { - $pip_path = $python_home + "\Scripts\pip.exe" - $conda_path = $python_home + "\Scripts\conda.exe" - if (-not(Test-Path $pip_path)) { - Write-Host "Installing pip..." - $args = "install --yes pip" - Write-Host $conda_path $args - Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru - } else { - Write-Host "pip already installed." - } -} - -function main () { - InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON - InstallPip $env:PYTHON -} - -main \ No newline at end of file diff --git a/.ci/run_with_env.cmd b/.ci/run_with_env.cmd deleted file mode 100644 index 5da547c499..0000000000 --- a/.ci/run_with_env.cmd +++ /dev/null @@ -1,88 +0,0 @@ -:: To build extensions for 64 bit Python 3, we need to configure environment -:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) -:: -:: To build extensions for 64 bit Python 2, we need to configure environment -:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) -:: -:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific -:: environment configurations. -:: -:: Note: this script needs to be run with the /E:ON and /V:ON flags for the -:: cmd interpreter, at least for (SDK v7.0) -:: -:: More details at: -:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows -:: http://stackoverflow.com/a/13751649/163740 -:: -:: Author: Olivier Grisel -:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ -:: -:: Notes about batch files for Python people: -:: -:: Quotes in values are literally part of the values: -:: SET FOO="bar" -:: FOO is now five characters long: " b a r " -:: If you don't want quotes, don't include them on the right-hand side. -:: -:: The CALL lines at the end of this file look redundant, but if you move them -:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y -:: case, I don't know why. -@ECHO OFF - -SET COMMAND_TO_RUN=%* -SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows -SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf - -:: Extract the major and minor versions, and allow for the minor version to be -:: more than 9. This requires the version number to have two dots in it. -SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1% -IF "%PYTHON_VERSION:~3,1%" == "." ( - SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1% -) ELSE ( - SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2% -) - -:: Based on the Python version, determine what SDK version to use, and whether -:: to set the SDK for 64-bit. -IF %MAJOR_PYTHON_VERSION% == 2 ( - SET WINDOWS_SDK_VERSION="v7.0" - SET SET_SDK_64=Y -) ELSE ( - IF %MAJOR_PYTHON_VERSION% == 3 ( - SET WINDOWS_SDK_VERSION="v7.1" - IF %MINOR_PYTHON_VERSION% LEQ 4 ( - SET SET_SDK_64=Y - ) ELSE ( - SET SET_SDK_64=N - IF EXIST "%WIN_WDK%" ( - :: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ - REN "%WIN_WDK%" 0wdf - ) - ) - ) ELSE ( - ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" - EXIT 1 - ) -) - -IF %PYTHON_ARCH% == 64 ( - IF %SET_SDK_64% == Y ( - ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture - SET DISTUTILS_USE_SDK=1 - SET MSSdk=1 - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 - ) ELSE ( - ECHO Using default MSVC build environment for 64 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 - ) -) ELSE ( - ECHO Using default MSVC build environment for 32 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 -) diff --git a/.ci/upload_docs.sh b/.ci/upload_docs.sh deleted file mode 100755 index aa20838d5c..0000000000 --- a/.ci/upload_docs.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -set -e # Exit with nonzero exit code if anything fails - -SOURCE_BRANCH="master" -TARGET_BRANCH="gh-pages" - -# Pull requests and commits to other branches shouldn't try to deploy, just build to verify -if [ "$TRAVIS_PULL_REQUEST" != "false" ] || \ - [ "$TRAVIS_BRANCH" != master -a \ - "$TRAVIS_BRANCH" != develop -a \ - "$TRAVIS_BRANCH" != travis ]; then - echo "No docs to upload." - exit 0 -fi - -if [ -z "$GH_TOKEN" ]; then - echo "Error: GH_TOKEN is undefined" - exit 1 -fi - -# Save some useful information -REPO=`git config remote.origin.url` -SHA=`git rev-parse --verify HEAD` - -# bin.SCons happens to contain the "doc/html" tree that we want to push -# into the gh-pages branch. So we step into that directory, create a new repo, -# set the remote appropriately, then commit and push. -cd bin.SCons -git init -git config user.name "Travis CI" -git config user.email "travis-ci" - -# Make sure 'GH_TOKEN' is set (as 'secure' variable) in .travis.yml -git remote add upstream "https://$GH_TOKEN@github.com/boostorg/python.git" -git fetch upstream -git reset upstream/gh-pages - -# Prepare version. -if [ "$TRAVIS_BRANCH" = develop -o "$TRAVIS_BRANCH" = travis ]; then - mkdir -p develop/doc/ - cp ../index.html develop/ - cp ../doc/index.html develop/doc/ - cp -a doc/html develop/doc/ - git add develop/index.html - git add develop/doc/index.html - git add -A develop/doc/html -else - cp ../index.html . - cp ../doc/index.html doc/ - git add index.html - git add doc/index.html - git add -A doc/html -fi -# Commit the new version. -git commit -m "Deploy to GitHub Pages: ${SHA}" - -# Now that we're all set up, we can push. -git push -q upstream HEAD:gh-pages 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/.travis.yml b/.travis.yml deleted file mode 100644 index 97a4fc8a18..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,99 +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) - -sudo: required -dist: trusty - -language: cpp - -env: - global: - - secure: BRNUkxN3p8f+uYKWC3Hr0VPqZA0PxbWr1DJlcI4hbiZtzKhMCWjDmd9UW9CzzexqeOxpd+9s0G87qvOur+wMSVxugDxtTesZrh1czXHeSVxgQrYD783XJtQJ9aYypbChkiboRD6Xpmbq7itwMuHBJMFtCuDxMynpU1jWwkyTf2Y= - -matrix: - include: - - compiler: gcc - env: CXX=g++ PYTHON=python CXXFLAGS=-std=c++98 - - compiler: gcc - env: CXX=g++ PYTHON=python CXXFLAGS=-std=c++11 - - compiler: gcc - env: CXX=g++ PYTHON=python3 CXXFLAGS=-std=c++98 - - compiler: gcc - env: CXX=g++ PYTHON=python3 CXXFLAGS=-std=c++11 - - compiler: clang - # clang generates an 'illegal instruction' error in the NumPy check. - # Perhaps we need to upgrade clang to a newer version ? - env: CXX=clang++ PYTHON=python3 CXXFLAGS=-std=c++98 OPTIONS=--no-numpy - - compiler: clang - env: CXX=clang++ PYTHON=python3 CXXFLAGS=-std=c++11 OPTIONS=--no-numpy - - env: PYTHON=python DOC=1 - - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - scons - - gcc-4.8 - - g++-4.8 - - clang - - python-numpy - - python-sphinx - - python3-dev - - python3-numpy - - libboost-all-dev - - xsltproc - - docbook-xsl - - python-docutils - - -cache: - directories: - - $HOME/Boost - -before_install: - # The Trusty image has several Python versions pre-installed compiled with - # conflicting UCS2 and UCS4 unicode. Modify the PATH to skip the TravisCI python. - # See https://github.com/travis-ci/travis-ci/issues/4948 for details. - - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") - -install: - # Install our own version of Boost (the subset we need) as the system version is - # too old (for C++11 support). - - rm -rf $HOME/Boost - - | - set -e - if [ ! -d $HOME/Boost ]; then - echo "rebuilding Boost prerequisites" - wget https://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.gz/download - tar xf download - pushd boost_1_61_0 - ./bootstrap.sh - ./b2 tools/bcp - mkdir -p $HOME/Boost - dist/bin/bcp python tools/boostbook tools/quickbook $HOME/Boost &> /dev/null - popd - fi - -before_script: -- scons --version - -script: -- scons config --python=$PYTHON --boost-include=$HOME/Boost $OPTIONS -- if [ "$DOC" ]; then scons doc; else scons && scons test; fi - -after_success: -# Upload docs only when building upstream. -- | - if [ "$DOC" -a \ - "$TRAVIS_REPO_SLUG" = "boostorg/python" -a \ - "$TRAVIS_PULL_REQUEST" = "false" ]; then - export GH_TOKEN - .ci/upload_docs.sh - fi 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/README.md b/README.md index 373d4e874a..f57b97505a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ # 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 @@ -19,7 +21,7 @@ See the [Boost.Python](http://boostorg.github.io/python) documentation for detai **Hint :** Check out the [development version](http://boostorg.github.io/python/develop) of the documentation to see work in progress. -# Building ![Build Status](https://travis-ci.org/boostorg/python.svg?branch=develop) +# 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. @@ -27,27 +29,14 @@ While Boost.Python is part of the Boost C++ Libraries super-project, and thus ca * [Python](http://www.python.org) * [Boost](http://www.boost.org) -* [SCons](http://www.scons.org) - -## Configure - -Simply run - -``` -scons config [options] -``` -to prepare a build. See `scons -h` for a description of the available options. For example -``` -scons config --boost=/path/to/boost --python=/path/to/python -``` -will configure Boost.Python to be built against the two specific versions of Boost and Python. +* [Faber](https://stefanseefeld.github.io/faber) ## Build Run ``` -scons +faber ``` to build the library. @@ -56,7 +45,7 @@ to build the library. Run ``` -scons test +faber test.report ``` to run the tests. @@ -65,6 +54,6 @@ to run the tests. Run ``` -scons doc +faber doc.html ``` to build the documentation. diff --git a/SConstruct b/SConstruct deleted file mode 100644 index 3f3dbfd402..0000000000 --- a/SConstruct +++ /dev/null @@ -1,100 +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 -import subprocess -import re - -# -# 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_vars = {} -if 'CXX' in os.environ: env_vars['CXX'] = os.environ['CXX'] -if 'CXXFLAGS' in os.environ: env_vars['CXXFLAGS'] = os.environ['CXXFLAGS'].split() -env = Environment(toolpath=['config/tools'], - tools=['default', 'libs', 'tests', 'doc', 'sphinx4scons'], - variables=vars, - TARGET_ARCH=arch, - **env_vars) -if 'gcc' in env['TOOLS']: - # Earlier SCons versions (~ 2.3.0) can't handle CXX=clang++. - version = subprocess.check_output([env['CXX'], '--version']) - match = re.search(r'[0-9]+(\.[0-9]+)+', version) - if match: - version = match.group(0) - else: - version = 'unknown' - env['CXXVERSION'] = version - -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(env) -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.62' -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 }) - -if 'doc' in COMMAND_LINE_TARGETS: - env.SConscript('doc/SConscript', variant_dir='bin.SCons/doc', - exports = { 'env' : e.Clone(BOOST_LIB = 'python') }) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 4dbaffd734..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,98 +0,0 @@ -environment: - global: - # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the - # /E:ON and /V:ON options are not enabled in the batch script intepreter - # See: http://stackoverflow.com/a/13751649/163740 - CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci\\run_with_env.cmd" - BOOST_PREFIX: C:\Libraries\boost_1_60_0 - - matrix: - - # Pre-installed Python versions, which Appveyor may upgrade to - # a later point release. - # See: http://www.appveyor.com/docs/installed-software#python - - - PYTHON: "C:\\Python27" - PYTHON_VERSION: "2.7.x" # currently 2.7.9 - PYTHON_ARCH: "32" - ARCH: "x86" - - #- PYTHON: "C:\\Python27-x64" - # PYTHON_VERSION: "2.7.x" # currently 2.7.9 - # PYTHON_ARCH: "64" - # ARCH: "x86_64" - - #- PYTHON: "C:\\Python35" - # PYTHON_VERSION: "3.5.x" # currently 3.4.3 - # PYTHON_ARCH: "32" - - #- PYTHON: "C:\\Python35-x64" - # PYTHON_VERSION: "3.5.x" # currently 3.4.3 - # PYTHON_ARCH: "64" - -install: - # If there is a newer build queued for the same PR, cancel this one. - # The AppVeyor 'rollout builds' option is supposed to serve the same - # purpose but it is problematic because it tends to cancel builds pushed - # directly to master instead of just PR builds (or the converse). - # credits: JuliaLang developers. - - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` - https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` - Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` - throw "There are newer queued builds for this pull request, failing early." } - - ECHO "Filesystem root:" - - ps: "ls \"C:/\"" - - ECHO "Installed libraries:" - - ps: "ls \"C:/Libraries/\"" - - ECHO "Installed SDKs:" - - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\"" - - # Install Python (from the official .msi of http://python.org) and pip when - # not already installed. - - ps: if (-not(Test-Path($env:PYTHON))) { & .ci\install.ps1 } - - # Prepend newly installed Python to the PATH of this build (this cannot be - # done from inside the powershell script as it would require to restart - # the parent CMD process). - - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - - # Check that we have the expected version and architecture for Python - - "python --version" - - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - # Upgrade to the latest version of pip to avoid it displaying warnings - # about it being out of date. - - "pip install --disable-pip-version-check --user --upgrade pip" - - # Install the build dependencies of the project. If some dependencies contain - # compiled extensions and are not provided as pre-built wheel packages, - # pip will build them from source using the MSVC compiler matching the - # target Python version and architecture - - easy_install scons - #- "%CMD_IN_ENV% pip install -r dev-requirements.txt" - -build_script: - # Build the compiled extension - #- "%CMD_IN_ENV% python setup.py build" - - scons config arch=%ARCH% --boost-include=%BOOST_PREFIX% - - scons arch=%ARCH% - -test_script: - # Run the project tests - #- "%CMD_IN_ENV% python setup.py nosetests" - - scons test arch=%ARCH% --verbose - -after_test: - # If tests are successful, create binary packages for the project. - #- "%CMD_IN_ENV% python setup.py bdist_wheel" - #- "%CMD_IN_ENV% python setup.py bdist_wininst" - #- "%CMD_IN_ENV% python setup.py bdist_msi" - #- ps: "ls dist" - -#artifacts: - # Archive the generated packages in the ci.appveyor.com build report. - #- path: dist\* - -#on_success: -# - TODO: upload the content of dist/*.whl to a public wheelhouse -# \ No newline at end of file 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 index 235c519015..c8f9859c64 100644 --- a/build/Jamfile +++ b/build/Jamfile @@ -6,7 +6,7 @@ import os ; import indirect ; import modules ; import feature ; - +import property ; import python ; if ! [ python.configured ] && ! ( --without-python in [ modules.peek : ARGV ] ) @@ -30,146 +30,146 @@ else ; } -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 ] ; +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 boost/python +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 lib_boost_python ( is-py3 ? ) +rule tag ( name : type ? : property-set ) { - - 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) ] - - -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag - @$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).python-tag - - : # default build - shared - : # usage requirements - static:BOOST_PYTHON_STATIC_LIB - on:BOOST_DEBUG_PYTHON - ; + if python-tag in [ RULENAMES $(__name__) ] + { + return [ $(__name__).python-tag $(name) : $(type) : $(property-set) ] ; + } } -rule lib_boost_numpy ( is-py3 ? ) +if [ python.configured ] { - numpy-include = [ python.numpy-include ] ; - lib [ cond $(is-py3) : boost_numpy3 : boost_numpy ] - : # sources - numpy/dtype.cpp - numpy/matrix.cpp - numpy/ndarray.cpp - numpy/numpy.cpp - numpy/scalars.cpp - numpy/ufunc.cpp - : # requirements - [ cond [ python.numpy ] : /python//python_for_extensions ] - [ unless [ python.numpy ] : no ] - $(numpy-include) - [ cond $(is-py3) : boost_python3 : boost_python ] - on:BOOST_DEBUG_PYTHON - [ cond $(is-py3) : $(py3-version) ] - - -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag - @$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).python-tag - - : # default build - shared - : # usage requirements - on:BOOST_DEBUG_PYTHON - ; -} -libraries = boost_python ; -libraries3 = boost_python3 ; -if [ python.numpy ] -{ - libraries += boost_numpy ; - libraries3 += boost_numpy3 ; +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 ; -lib_boost_python ; -lib_boost_numpy ; +} -if $(py3-version) +if [ python.configured ] && [ python.numpy ] { - lib_boost_python yes ; - lib_boost_numpy yes ; - libraries += $(libraries3) ; + +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 ; -boost-install $(libraries) ; +} diff --git a/config/__init__.py b/config/__init__.py deleted file mode 100644 index 704124b6b8..0000000000 --- a/config/__init__.py +++ /dev/null @@ -1,140 +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 cxx -from . import python -from . import numpy -from . import boost - -def add_options(vars): - ui.add_option('-V', '--verbose', dest='verbose', action='store_true', help='verbose mode: print full commands.') - ui.add_option('--no-numpy', dest='numpy', action='store_false', help='do not attempt to build NumPy bindings.') - python.add_options(vars) - numpy.add_options(vars) - boost.add_options(vars) - - vars.Add('CXX') - vars.Add('CPPPATH', converter=lambda v:v.split()) - vars.Add('CCFLAGS', converter=lambda v:v.split()) - vars.Add('CXXFLAGS', 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') - vars.Add('prefix') - vars.Add('boostbook_prefix') - vars.Add('CXX11') - vars.Add('NUMPY') - vars.Add('NUMPY_CPPPATH', converter=lambda v:v.split()) - - 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(env): - checks = OrderedDict() - checks['cxx'] = cxx.check - checks['python'] = python.check - if env.GetOption('numpy') is not False: - checks['numpy'] = numpy.check - else: - env['NUMPY'] = False - 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"]: - if env['CXX'] in ('clang', 'clang++'): - suffix += "-clang" + "".join(env["CXXVERSION"].split(".")[0:2]) - else: # assume g++ - suffix += "-gcc" + "".join(env["CXXVERSION"].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" - # FIXME: Support 'toolchain' variable properly. - # For now, we simply check whether $CXX refers to clang or gcc. - if "gcc" in env["TOOLS"]: - if env['CXX'] in ('clang', 'clang++'): - build_dir+="/clang-%s"%env["CXXVERSION"] - else: # assume g++ - build_dir+="/gcc-%s"%env["CXXVERSION"] - default_cxxflags = ['-ftemplate-depth-128', '-Wall', '-g', '-O2'] - vars['CXXFLAGS'] = env.get('CXXFLAGS', default_cxxflags) - 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 a7cde93e66..0000000000 --- a/config/boost.py +++ /dev/null @@ -1,45 +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") - ui.add_option("--boostbook-prefix", dest="boostbook_prefix", type="string", - nargs=1, action="store", - metavar="DIR", default="/usr/share/boostbook", - help="prefix for BoostBook stylesheets") - -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') - boostbook_prefix = context.env.GetOption('boostbook_prefix') - 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.env.AppendUnique(boostbook_prefix=boostbook_prefix) - context.Result(1) - return True diff --git a/config/cxx.py b/config/cxx.py deleted file mode 100644 index ae34beb09c..0000000000 --- a/config/cxx.py +++ /dev/null @@ -1,30 +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): - - pass - -def check(context): - - source = r"""#if __cplusplus < 201103L -#error no C++11 -#endif""" - - context.Message('Checking for C++11 support...') - - if not context.TryCompile(source, '.cpp'): - context.env['CXX11'] = False - context.Result(0) - else: - context.env['CXX11'] = True - context.Result(1) - return True diff --git a/config/numpy.py b/config/numpy.py deleted file mode 100644 index 3380ae565d..0000000000 --- a/config/numpy.py +++ /dev/null @@ -1,86 +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 -from contextlib import contextmanager - -@contextmanager -def saved(context): - save_cpppath = context.env.get('CPPPATH', []) - save_libs = context.env.get('LIBS', []) - yield context - context.env.Replace(LIBS=save_libs) - context.env.Replace(CPPPATH=save_cpppath) - - -def add_options(vars): - - pass - - -def check(context): - - numpy_source_file = r""" -// If defined, enforces linking againg PythonXXd.lib, which -// is usually not included in Python environments. -#undef _DEBUG -#include "Python.h" -#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; -} -""" - - import platform - import subprocess - import re, os - - def check_python(cmd): - try: - return True, subprocess.check_output([python, '-c', cmd]).strip() - except subprocess.CalledProcessError as e: - return False, e - - context.Message('Checking for NumPy...') - with saved(context): - python = context.env['PYTHON'] - result, numpy_incpath = check_python('import numpy; print(numpy.get_include())') - if result: - context.env.AppendUnique(CPPPATH=numpy_incpath) - context.env.AppendUnique(LIBS=context.env['PYTHONLIBS']) - result, output = context.TryRun(numpy_source_file,'.cpp') - if not result: - context.Result(0) - return False - context.env['NUMPY'] = True - context.env['NUMPY_CPPPATH'] = numpy_incpath - 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/doc.py b/config/tools/doc.py deleted file mode 100644 index 5e81f37906..0000000000 --- a/config/tools/doc.py +++ /dev/null @@ -1,75 +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 SCons.Defaults import Copy -from SCons.Script import * -from subprocess import check_output, STDOUT, CalledProcessError -import sys -import os - -def QuickBook(env, target, source, dependencies=[]): - """Compile a QuickBook document to BoostBook.""" - - for d in dependencies: - env.Depends(target, d) - env.Command(target, source, 'quickbook --input-file=$SOURCE --output-file=$TARGET') - - -def BoostBook(env, target, source, resources=[], args=[]): - """Compile a BoostBook document to DocBook.""" - - bb_prefix = env.GetOption('boostbook_prefix') - stylesheet = bb_prefix + '/xsl/docbook.xsl' - env.Command(target, source, - 'xsltproc {} -o $TARGET {} $SOURCE'.format(' '.join(args), stylesheet)) - - -def BoostHTML(env, target, source, resources=[], args=[]): - """Compile a DocBook document to HTML.""" - - bb_prefix = env.GetOption('boostbook_prefix') - stylesheet = bb_prefix + '/xsl/html.xsl' - env.Command(target, source, - 'xsltproc {} -o $TARGET/ {} $SOURCE'.format(' '.join(args), stylesheet)) - prefix=Dir('.').path - for r in resources: - r = File(r).path[len(prefix)+1:] - env.Depends(target, target + r) - env.Command(target + r, r, Copy('$TARGET', '$SOURCE')) - - -def BoostRST(env, target, source, resources=[]): - """Compile an RST document to HTML.""" - - prefix=Dir('.').path - for r in resources: - r = File(r).path[len(prefix)+1:] - env.Depends('html/' + r, r) - env.Command('html/' + r, r, Copy('$TARGET', '$SOURCE')) - env.Command(target, source, - 'rst2html --link-stylesheet --traceback --trim-footnote-reference-space --footnote-references=superscript --stylesheet=rst.css $SOURCE $TARGET') - - -def BoostSphinx(env, target, source): - env.Sphinx(target, source) - - -def exists(env): - return True - - -def generate(env): - - env.AddMethod(QuickBook) - env.AddMethod(BoostBook) - env.AddMethod(BoostHTML) - env.AddMethod(BoostRST) - env.AddMethod(BoostSphinx) diff --git a/config/tools/libs.py b/config/tools/libs.py deleted file mode 100644 index da8119d042..0000000000 --- a/config/tools/libs.py +++ /dev/null @@ -1,85 +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)) - env.Alias(lib, env.Install('$prefix/include/boost', '#/include/boost/python')) - env.Alias(lib, env.Install('$prefix/include/boost', '#/include/boost/python.hpp')) - 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/sphinx4scons.py b/config/tools/sphinx4scons.py deleted file mode 100644 index dda88d23f3..0000000000 --- a/config/tools/sphinx4scons.py +++ /dev/null @@ -1,592 +0,0 @@ -"""SCons.Tool.spinx4scons - -Tool-specific initialization for the Sphinx document build system. - -There normally shouldn't be any need to import this module directly. -It will usually be imported through the generic SCons.Tool.Tool() -selection method. - -It should be placed in e.g. ~/site_scons/site_tools/sphinx4scons/ -directory. Then it may be loaded by placing - - sphinx = Tool('sphinx4scons') - sphinx(env) - -in your SConstruct file. - -For further details, please see the SCons documentation on how to -install and enable custom tools. -""" - -# -# This package is provided under the Expat license -# -# Copyright (c) 2012 Orlando Wingbrant -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# 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 AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__author__ = "Orlando Wingbrant" -__email__ = "orlando@widesite.org" -__url__ = "https://bitbucket.org/wingbrant/sphinx4scons" -__license__ = "Expat license" - -import SCons.Action -import SCons.Builder -import SCons.Defaults -import SCons.Util -import SCons.Node.FS -import os - -from sphinx.util.matching import patfilter, compile_matchers -from sphinx.util.osutil import make_filename - - -class ToolSphinxWarning(SCons.Warnings.Warning): - pass - - -class SphinxBuilderNotFound(ToolSphinxWarning): - pass - -SCons.Warnings.enableWarningClass(ToolSphinxWarning) - - -def exists(env): - return _detect(env) - - -def _detect(env): - """Try to detect the sphinx-build script.""" - try: - return env['SPHINXBUILD'] - except KeyError: - pass - - sphinx = env.WhereIs('sphinx-build') - if sphinx: - return sphinx - - raise SCons.Errors.StopError( - SphinxBuilderNotFound, - "Could not detect sphinx-build script") - return None - - -def generate(env): - """Add Builders and construction variables to the Environment.""" - - env['SPHINXBUILD'] = _detect(env) - sphinx = _create_sphinx_builder(env) - - env.SetDefault( - # Additional command-line flags - SPHINXFLAGS = '', - - # Tag definitions, each entry will appear on the command line preceded by -t - SPHINXTAGS = [], - - # Directory for doctrees - SPHINXDOCTREE = '', - - # Path to sphinx configuration file - SPHINXCONFIG = '', - - # Config file override settings, each entry will be preceded by -D - SPHINXSETTINGS = {}, - - # Default sphinx builder, - SPHINXBUILDER = 'html', - - # Sphinx command - SPHINXCOM = "$SPHINXBUILD $_SPHINXOPTIONS ${SOURCE.attributes.root} ${TARGET.attributes.root}", - - # Alternate console output when building sphinx documents - SPHINXCOMSTR = "" - ) - - try: - env.AddMethod(Sphinx, "Sphinx") - except AttributeError: - # Looks like we use a pre-0.98 version of SCons... - from SCons.Script.SConscript import SConsEnvironment - SConsEnvironment.Sphinx = Sphinx - - -def Sphinx(env, target, source, **kw): - """A pseudo-builder wrapper for the sphinx builder.""" - builder = env['BUILDERS']['Sphinx4Scons'] - env_kw = env.Override(kw) - options = _get_sphinxoptions(env_kw, target, source) - output = builder(env, target, source, _SPHINXOPTIONS=options, **kw) - return output - - -def _get_sphinxoptions(env, target, source): - """Concatenates all the options for the sphinx command line.""" - options = [] - - builder = _get_sphinxbuilder(env) - options.append("-b %s" % env.subst(builder, target=target, source=source)) - - flags = env.get('options', env.get('SPHINXFLAGS', '')) - options.append(env.subst(flags, target=target, source=source)) - - tags = env.get('tags', env.get('SPHINXTAGS', None)) - if tags is not None: - if not SCons.SCons.Util.is_List(tags): - tags = [tags] - for tag in tags: - if tag != '': - tag = env.subst(tag, target=target, source=source) - options.append("-t %s" % tag) - - settings = env.get('settings', env.get('SPHINXSETTINGS', None)) - if settings is not None: - if not SCons.SCons.Util.is_Dict(settings): - raise TypeError('SPHINXSETTINGS and/or settings argument must be a dictionary') - for key, value in settings.iteritems(): - if value != '': - value = env.subst(value, target=target, source=source) - options.append('-D "%s=%s"' % (key, value)) - - doctree = env.get('doctree', env.get("SPHINXDOCTREE", None)) - if isinstance(doctree, SCons.Node.FS.Dir): - options.append("-d %s" % doctree.get_abspath()) - elif doctree is not None and doctree != '': - doctree = env.subst(doctree, target=target, source=source) - options.append("-d %s" % env.Dir(doctree).get_abspath()) - - config = _get_sphinxconfig_path(env, None) - if config is not None and config != '': - config = env.subst(config, target=target, source=source) - options.append("-c %s" % env.Dir(config).File('conf.py').rfile().dir.get_abspath()) - return " ".join(options) - - -def _create_sphinx_builder(env): - try: - sphinx = env['BUILDERS']['Sphinx4Scons'] - except KeyError: - fs = SCons.Node.FS.get_default_fs() - sphinx_com = SCons.Action.Action('$SPHINXCOM', '$SPHINXCOMSTR') - sphinx = SCons.Builder.Builder(action=sphinx_com, - emitter=sphinx_emitter, - target_factory=fs.Dir, - source_factory=fs.Dir - ) - env['BUILDERS']['Sphinx4Scons'] = sphinx - return sphinx - - -def sphinx_emitter(target, source, env): - target[0].must_be_same(SCons.Node.FS.Dir) - targetnode = target[0] - - source[0].must_be_same(SCons.Node.FS.Dir) - srcnode = source[0] - - configdir = _get_sphinxconfig_path(env, None) - if not configdir: - confignode = srcnode - else: - confignode = env.Dir(configdir) - - srcinfo = SourceInfo(srcnode, confignode, env) - targets, sources = _get_emissions(env, target, srcinfo) - env.Clean(targets, target[0]) - - return targets, sources - - -def sphinx_path(os_path): - """Create sphinx-style path from os-style path.""" - return os_path.replace(os.sep, "/") - - -def os_path(sphinx_path): - """Create os-style path from sphinx-style path.""" - return sphinx_path.replace("/", os.sep) - - -class SourceInfo(object): - """ - Data container for all different kinds of source files used in - a sphinx project. - """ - def __init__(self, srcnode, confignode, env): - self.confignode = confignode - self.config = self._get_config(self.confignode, env) - self.templates = self._get_templates(self.confignode, self.config) - self.statics = self._get_statics(self.confignode, self.config) - self.srcnode = srcnode - self.sources = self._get_sources(self.srcnode, self.config) - - self.srcroot = srcnode - if not srcnode.duplicate: - self.srcroot = srcnode.srcnode().rdir() - - - def _get_config(self, confignode, env): - config = {} - execfile(confignode.File('conf.py').rfile().get_abspath(), config) - return config - - - def _get_templates(self, confignode, config): - """Returns template files defined in the project.""" - templates = [] - for path in config.get('templates_path', []): - # Check if path is dir or file. - # We can't use FS.Entry since that will create nodes, and - # these nodes don't know about the source tree and will - # get disambiguated to files even if they are directories in the - # source tree. - p = confignode.File('conf.py').rfile().dir.srcnode().get_abspath() - p = os.path.join(p, os_path(path)) - if os.path.isfile(p): - templates.append(confignode.File(path)) - elif os.path.isdir(p): - node = confignode.Dir(path) - for root, dirs, files in os.walk(p): - mydir = node.Dir(os.path.relpath(root, p)) - templates += [mydir.File(f) for f in files] - return templates - - - def _get_statics(self, confignode, config): - """Returns static files, filtered through exclude_patterns.""" - statics = [] - matchers = compile_matchers(config.get('exclude_patterns', [])) - - for path in config.get('html_static_path', []): - # Check _get_templates() why we use this construction. - p = confignode.File('conf.py').rfile().dir.srcnode().get_abspath() - p = os.path.join(p, os_path(path)) - if os.path.isfile(p): - statics.append(confignode.File(path)) - elif os.path.isdir(p): - node = confignode.Dir(path) - for root, dirs, files in os.walk(p): - relpath = os.path.relpath(root, p) - for entry in [d for d in dirs if - self._anymatch(matchers, - sphinx_path(os.path.join(relpath, d)))]: - dirs.remove(entry) - statics += [node.File(os_path(f)) for f in - self._exclude(matchers, - [sphinx_path(os.path.join(relpath, name)) - for name in files])] - return statics - - - def _get_sources(self, srcnode, config): - """Returns all source files in the project filtered through exclude_patterns.""" - suffix = config.get('source_suffix', '.rst') - matchers = compile_matchers(config.get('exclude_patterns', [])) - - srcfiles = [] - scannode = srcnode.srcnode().rdir() - - for root, dirs, files in os.walk(scannode.get_abspath()): - relpath = os.path.relpath(root, scannode.get_abspath()) - for entry in [d for d in dirs if - self._anymatch(matchers, - sphinx_path(os.path.join(relpath, d)))]: - dirs.remove(entry) - srcfiles += [srcnode.File(os_path(f)) for f in - self._exclude(matchers, - [sphinx_path(os.path.join(relpath, name)) - for name in files if name.endswith(suffix)])] - return srcfiles - - - def _exclude(self, matchers, items): - result = items - for matcher in matchers: - result = filter(lambda x: not matcher(x), result) - return result - - - def _anymatch(self, matchers, item): - for matcher in matchers: - if matcher(item): - return True - return False - - -def _get_sphinxconfig_path(env, default): - path = env.get('config', env.get('SPHINXCONFIG', None)) - if path is None or path == '': - path = default - return path - - -def _get_emissions(env, target, srcinfo): - targets = [] - sources = [] - builder = _get_sphinxbuilder(env) - if builder == 'changes': - targets, sources = _get_changes_emissions(env, target, srcinfo) - if builder == 'devhelp': - targets, sources = _get_help_emissions(env, target, srcinfo, - ['.devhelp.gz']) - elif builder == 'dirhtml': - targets, sources = _get_dirhtml_emissions(env, target, srcinfo) - elif builder == 'doctest': - targets, sources = _get_doctest_emissions(env, target, srcinfo) - elif builder == 'epub': - targets, sources = _get_epub_emissions(env, target, srcinfo) - elif builder == 'html': - targets, sources = _get_serialize_emissions(env, target, srcinfo) - elif builder == 'htmlhelp': - targets, sources = _get_help_emissions(env, target, srcinfo, - ['.hhp'], 'htmlhelp_basename') - elif builder == 'gettext': - targets, sources = _get_gettext_emissions(env, target, srcinfo) - elif builder == 'json': - targets, sources = _get_serialize_emissions(env, target, srcinfo, - '.fjson', - ['globalcontext.json', - 'searchindex.json', - 'self.environment.pickle']) - elif builder == 'latex': - targets, sources = _get_latex_emissions(env, target, srcinfo) - elif builder == 'linkcheck': - targets, sources = _get_linkcheck_emissions(env, target, srcinfo) - elif builder == 'man': - targets, sources = _get_man_emissions(env, target, srcinfo) - elif builder == 'pickle': - targets, sources = _get_serialize_emissions(env, target, srcinfo, - '.fpickle', - ['globalcontext.pickle', - 'searchindex.pickle', - 'environment.pickle']) - elif builder == 'qthelp': - targets, sources = _get_help_emissions(env, target, srcinfo, - ['.qhp', '.qhcp']) - elif builder == 'singlehtml': - targets, sources = _get_singlehtml_emissions(env, target, srcinfo) - elif builder == 'texinfo': - targets, sources = _get_texinfo_emissions(env, target, srcinfo) - elif builder == 'text': - targets, sources = _get_text_emissions(env, target, srcinfo) - - sources.append(srcinfo.confignode.File('conf.py')) - - for s in sources: - s.attributes.root = srcinfo.srcroot - - for t in targets: - t.attributes.root = target[0] - - return targets, sources - - -def _get_sphinxbuilder(env): - builder = env.get('builder', env["SPHINXBUILDER"]) - if builder is None or builder == '': - raise SCons.Errors.UserError(("Missing construction variable " + - "SPHINXBUILDER or variable is empty.")) - return builder - - -def _get_changes_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - targets = [target[0].File("changes.html")] - return targets, sources - - -def _get_dirhtml_emissions(env, target, srcinfo): - suffix = srcinfo.config.get('html_file_suffix', ".html") - - def get_outfilename(pagename): - pagename = os.path.splitext(pagename)[0] - - #Special treatment of files named "index". Don't create directory. - if pagename == 'index' or pagename.endswith(os.sep + 'index'): - outfilename = pagename + suffix - else: - outfilename = os.path.join(pagename, 'index' + suffix) - return outfilename - - sources = [] - sources.extend(srcinfo.sources) - sources.extend(srcinfo.templates) - sources.extend(srcinfo.statics) - - targets = [] - for s in srcinfo.sources: - t = os.path.relpath(str(s), str(srcinfo.srcroot)) - targets.append(target[0].File(get_outfilename(t))) - - for key in srcinfo.config.get('html_additional_pages', {}): - t = target[0].File(get_outfilename(key)) - targets.append(t) - - return targets, sources - - -def _get_doctest_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - targets = [target[0].File("output.txt")] - return targets, sources - - -def _get_epub_emissions(env, target, srcinfo): - epubPreFiles = srcinfo.config.get('epub_pre_files', []) - epubPostFiles = srcinfo.config.get('epub_post_files', []) - epubCover = srcinfo.config.get('epub_cover', (None, None)) - - sources = [] - sources.extend(srcinfo.sources) - sources.extend([srcinfo.srcroot.File(os_path(f[0])) for f in epubPreFiles]) - sources.extend([srcinfo.srcroot.File(os_path(f[0])) for f in epubPostFiles]) - if not (epubCover[0] is None or epubCover[0] == ''): - sources.append(srcinfo.srcroot.File(os_path(epubCover[0]))) - if not (epubCover[1] is None or epubCover[1] == ''): - sources.append(srcinfo.srcroot.File(os_path(epubCover[1]))) - - t = srcinfo.config.get('epub_basename', - srcinfo.config.get('project', - 'Python')) - - targets = [target[0].File("%s.epub" % make_filename(t))] - - return targets, sources - - -def _get_gettext_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - - targets = [os.path.relpath(str(s), str(srcinfo.srcroot)) for s in sources] - targets = [os.path.splitext(t)[0] for t in targets] - targets = set([t.split(os.sep)[0] for t in targets]) - targets = [target[0].File(t + ".pot") for t in targets] - - return targets, sources - - -def _get_help_emissions(env, target, srcinfo, suffixes, basenameConfigKey='project'): - basename = make_filename( - srcinfo.config.get(basenameConfigKey, srcinfo.config['project'])) - - sources = [] - sources.extend(srcinfo.sources) - sources.extend(srcinfo.templates) - sources.extend(srcinfo.statics) - - targets = [target[0].File(basename + s) for s in suffixes] - - return targets, sources - - -def _get_latex_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - - targets = map(lambda x: target[0].File(os_path(x[1])), - srcinfo.config.get('latex_documents')) - - return targets, sources - - -def _get_linkcheck_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - targets = [target[0].File("output.txt")] - return targets, sources - - -def _get_man_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - targets = map(lambda x: target[0].File(os_path("%s.%s" % (x[1], x[4]))), - srcinfo.config.get('man_pages')) - return targets, sources - - -def _get_serialize_emissions(env, target, srcinfo, suffix=None, extrafiles=[]): - if suffix is None: - suffix = srcinfo.config.get('html_file_suffix', '.html') - - sources = [] - sources.extend(srcinfo.sources) - sources.extend(srcinfo.templates) - sources.extend(srcinfo.statics) - - targets = [] - for s in srcinfo.sources: - t = os.path.splitext(str(s))[0] + suffix - t = os.path.relpath(t, str(srcinfo.srcroot)) - targets.append(t) - - for key in srcinfo.config.get('html_additional_pages', {}): - targets.append(os_path("%s%s" % (key, suffix))) - - targets.extend(extrafiles) - targets = [target[0].File(t) for t in targets] - - return targets, sources - - -def _get_singlehtml_emissions(env, target, srcinfo): - suffix = srcinfo.config.get('html_file_suffix', ".html") - - sources = [] - sources.extend(srcinfo.sources) - sources.extend(srcinfo.templates) - sources.extend(srcinfo.statics) - - t = os.path.relpath(srcinfo.config['master_doc'] + suffix, - str(srcinfo.srcroot)) - targets = [target[0].File(t)] - - return targets, sources - - -def _get_texinfo_emissions(env, target, srcinfo): - suffix = srcinfo.config.get('source_suffix', '.rst') - - sources = [] - sources.extend(srcinfo.sources) - sources.extend(map(lambda x: source[0].File(os_path(x + suffix)), - srcinfo.config.get('texinfo_appendices', []))) - - targets = map(lambda x: target[0].File(os_path("%s.texi" % x[1])), - srcinfo.config.get('texinfo_documents')) - - return targets, sources - - -def _get_text_emissions(env, target, srcinfo): - sources = [] - sources.extend(srcinfo.sources) - - targets = [] - for s in sources: - t = os.path.relpath(str(s), str(srcinfo.srcroot)) - t = os.path.splitext(t)[0] + ".txt" - targets.append(target[0].File(t)) - - return targets, sources 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/SConscript b/doc/SConscript deleted file mode 100644 index 8eb0fb9340..0000000000 --- a/doc/SConscript +++ /dev/null @@ -1,52 +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.QuickBook('python.bbk', 'python.qbk', - ['building.qbk', - 'configuration.qbk', - 'support.qbk', - 'faq.qbk', - 'glossary.qbk']) - -env.QuickBook('tutorial.bbk', 'tutorial.qbk') -env.QuickBook('reference.bbk', 'reference.qbk', - Glob('reference/*.qbk')) - - -env.BoostBook('python.dbk', 'python.bbk') -env.BoostBook('tutorial.dbk', 'tutorial.bbk') -env.BoostBook('reference.dbk', 'reference.bbk') - -images = Glob('images/*.*') + Glob('images/callouts/*.*') - -env.BoostHTML('html/', 'python.dbk', - resources=['boostbook.css'] + images, - args=['--stringparam', 'generate.toc', '"library nop; chapter 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']) -env.BoostHTML('html/tutorial/', 'tutorial.dbk', - args=['--stringparam', 'html.stylesheet', '../boostbook.css', - '--stringparam', 'boost.image.src', '../images/bpl.png', - '--stringparam', 'boost.graphics.root', '../images/']) -env.BoostHTML('html/reference/', 'reference.dbk', - args=['--stringparam', 'html.stylesheet', '../boostbook.css', - '--stringparam', 'boost.image.src', '../images/bpl.png', - '--stringparam', 'boost.graphics.root', '../images/']) - -env.BoostRST('html/article.html', 'article.rst', resources=['rst.css']) - -if env['NUMPY']: - env.BoostSphinx('html/numpy', 'numpy/') 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/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/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/_static/boost.css b/doc/numpy/_static/boost.css index 28f8935991..36c1efd082 100644 --- a/doc/numpy/_static/boost.css +++ b/doc/numpy/_static/boost.css @@ -714,3 +714,23 @@ 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/_templates/layout.html b/doc/numpy/_templates/layout.html index 1aa68f0ea1..69e1a868c0 100644 --- a/doc/numpy/_templates/layout.html +++ b/doc/numpy/_templates/layout.html @@ -49,6 +49,9 @@ {%- for scriptfile in script_files %} {%- endfor %} + + + {%- if use_opensearch %}

C++ Boost

+ alt="C++ Boost" src="{{ pathto('_static/bpl.png', 1) }}" border="0"> diff --git a/doc/numpy/conf.py b/doc/numpy/conf.py index 2f5d5e8146..23ab678d3a 100644 --- a/doc/numpy/conf.py +++ b/doc/numpy/conf.py @@ -40,8 +40,8 @@ master_doc = 'index' # General information about the project. -project = u'Boost.Python NumPy extension' -copyright = u'2011, Stefan Seefeld' +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 @@ -181,8 +181,8 @@ # 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', u'Boost.Python NumPy Documentation', - u'Stefan Seefeld', 'manual'), + ('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 @@ -214,6 +214,6 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'boostnumpy', u'Boost.Python NumPy Documentation', - [u'Stefan Seefeld'], 1) + ('index', 'boostnumpy', 'Boost.Python NumPy Documentation', + ['Stefan Seefeld'], 1) ] diff --git a/doc/numpy/tutorial/dtype.rst b/doc/numpy/tutorial/dtype.rst index 557e72ba2d..9bea646a65 100644 --- a/doc/numpy/tutorial/dtype.rst +++ b/doc/numpy/tutorial/dtype.rst @@ -48,7 +48,7 @@ Next, create a list, and add this tuple to the list. Then use the list to create 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 dtpye :: +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/python.qbk b/doc/python.qbk index ffd2d0ddb5..b8b0926def 100644 --- a/doc/python.qbk +++ b/doc/python.qbk @@ -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_ @@ -58,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/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/tutorial.qbk b/doc/tutorial.qbk index 74126476c1..197470013e 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -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 @@ -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/README.md b/example/README.md index b090cbe1e3..af03f20ba8 100644 --- a/example/README.md +++ b/example/README.md @@ -3,7 +3,7 @@ # Examples This directory contains various examples using Boost.Python. -You may compile these using the `bjam` command either in this directory +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. diff --git a/example/numpy/demo_gaussian.py b/example/numpy/demo_gaussian.py index 0b1c78995e..08bb58b82a 100644 --- a/example/numpy/demo_gaussian.py +++ b/example/numpy/demo_gaussian.py @@ -3,6 +3,7 @@ # (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 @@ -19,19 +20,19 @@ z = g(x, y) s = z.sum() * (r[1] - r[0])**2 -print "sum (should be ~ 1):", s +print("sum (should be ~ 1):", s) xc = (z * x).sum() / z.sum() -print "x centroid (should be ~ %f): %f" % (mu[0], xc) +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) +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) +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) +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) +print("xy moment (should be ~ %f): %f" % (sigma[0,1], xy)) diff --git a/example/quickstart/script.py b/example/quickstart/script.py index c3e034ba84..f360cef2d2 100644 --- a/example/quickstart/script.py +++ b/example/quickstart/script.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/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) diff --git a/example/quickstart/test_extending.py b/example/quickstart/test_extending.py index 938c7b9047..035ca96134 100644 --- a/example/quickstart/test_extending.py +++ b/example/quickstart/test_extending.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/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/tutorial/hello.py b/example/tutorial/hello.py index 31f75565df..7888b2e0fd 100755 --- a/example/tutorial/hello.py +++ b/example/tutorial/hello.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/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) 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 a622250dca..98013052ec 100644 --- a/include/boost/python/converter/registered.hpp +++ b/include/boost/python/converter/registered.hpp @@ -10,9 +10,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include @@ -44,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 > { @@ -78,7 +76,7 @@ namespace detail registry::lookup_shared_ptr(type_id >()); } -#if __cplusplus >= 201103L +#if !defined(BOOST_NO_CXX11_SMART_PTR) template inline void register_shared_ptr0(std::shared_ptr*) 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 bb2ae863ff..b5c62ba940 100644 --- a/include/boost/python/converter/shared_ptr_from_python.hpp +++ b/include/boost/python/converter/shared_ptr_from_python.hpp @@ -49,13 +49,17 @@ struct shared_ptr_from_python 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)); + 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; } }; diff --git a/include/boost/python/converter/shared_ptr_to_python.hpp b/include/boost/python/converter/shared_ptr_to_python.hpp index cc68646109..02649d406e 100644 --- a/include/boost/python/converter/shared_ptr_to_python.hpp +++ b/include/boost/python/converter/shared_ptr_to_python.hpp @@ -25,7 +25,7 @@ PyObject* shared_ptr_to_python(shared_ptr const& x) return converter::registered const&>::converters.to_python(&x); } -#if __cplusplus >= 201103L +#if !defined(BOOST_NO_CXX11_SMART_PTR) template PyObject* shared_ptr_to_python(std::shared_ptr const& x) { 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 bef0e05afb..383383bc12 --- a/include/boost/python/detail/is_shared_ptr.hpp +++ b/include/boost/python/detail/is_shared_ptr.hpp @@ -13,7 +13,7 @@ namespace boost { namespace python { namespace detail { BOOST_PYTHON_IS_XXX_DEF(shared_ptr, shared_ptr, 1) -#if __cplusplus >= 201103L +#if !defined(BOOST_NO_CXX11_SMART_PTR) template struct is_shared_ptr > : std::true_type {}; #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_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 92a7951d35..3769970cad 100644 --- a/include/boost/python/make_constructor.hpp +++ b/include/boost/python/make_constructor.hpp @@ -43,27 +43,28 @@ namespace detail private: template - void dispatch(U* x, mpl::true_) const + void dispatch(U* x, detail::true_) const { -#if __cplusplus < 201103L +#if defined(BOOST_NO_CXX11_SMART_PTR) std::auto_ptr owner(x); - dispatch(owner, mpl::false_()); + dispatch(owner, detail::false_()); #else std::unique_ptr owner(x); - dispatch(std::move(owner), mpl::false_()); + 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 __cplusplus < 201103L +#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); 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 index cd5876a8e4..18a6389d51 100644 --- a/include/boost/python/numpy.hpp +++ b/include/boost/python/numpy.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace boost { namespace python { namespace numpy { @@ -26,7 +27,7 @@ namespace boost { namespace python { namespace numpy { * and "import_ufunc()", and then calls * dtype::register_scalar_converters(). */ -void initialize(bool register_scalar_converters=true); +BOOST_NUMPY_DECL void initialize(bool register_scalar_converters=true); }}} // namespace boost::python::numpy 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 index 1284f9e5d8..9438d79fdc 100644 --- a/include/boost/python/numpy/dtype.hpp +++ b/include/boost/python/numpy/dtype.hpp @@ -13,10 +13,11 @@ */ #include +#include #include - #include -#include +#include +#include namespace boost { namespace python { namespace numpy { @@ -25,7 +26,7 @@ namespace boost { namespace python { namespace numpy { * * @todo This could have a lot more interesting accessors. */ -class dtype : public object { +class BOOST_NUMPY_DECL dtype : public object { static python::detail::new_reference convert(object::object_cref arg, bool align); public: @@ -55,7 +56,7 @@ class dtype : public object { * 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 bool equivalent(dtype const & a, dtype const & b); + 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. @@ -69,7 +70,7 @@ class dtype : public object { }; -bool equivalent(dtype const & a, dtype const & b); +BOOST_NUMPY_DECL bool equivalent(dtype const & a, dtype const & b); namespace detail { @@ -89,7 +90,7 @@ struct builtin_dtype { }; template <> -struct builtin_dtype { +struct BOOST_NUMPY_DECL builtin_dtype { static dtype get(); }; diff --git a/include/boost/python/numpy/internal.hpp b/include/boost/python/numpy/internal.hpp index fed31cbb08..c24718f0ae 100644 --- a/include/boost/python/numpy/internal.hpp +++ b/include/boost/python/numpy/internal.hpp @@ -15,6 +15,7 @@ */ #include +#include #ifdef BOOST_PYTHON_NUMPY_INTERNAL #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC diff --git a/include/boost/python/numpy/invoke_matching.hpp b/include/boost/python/numpy/invoke_matching.hpp index 90ec8ae2cb..095ca3a8db 100644 --- a/include/boost/python/numpy/invoke_matching.hpp +++ b/include/boost/python/numpy/invoke_matching.hpp @@ -19,7 +19,7 @@ namespace boost { namespace python { namespace numpy { namespace detail { -struct add_pointer_meta +struct BOOST_NUMPY_DECL add_pointer_meta { template struct apply @@ -29,8 +29,8 @@ struct add_pointer_meta }; -struct dtype_template_match_found {}; -struct nd_template_match_found {}; +struct BOOST_NUMPY_DECL dtype_template_match_found {}; +struct BOOST_NUMPY_DECL nd_template_match_found {}; template struct dtype_template_invoker diff --git a/include/boost/python/numpy/matrix.hpp b/include/boost/python/numpy/matrix.hpp index af20e8f9be..829f544af5 100644 --- a/include/boost/python/numpy/matrix.hpp +++ b/include/boost/python/numpy/matrix.hpp @@ -14,6 +14,8 @@ #include #include #include +#include + namespace boost { namespace python { namespace numpy { @@ -27,7 +29,7 @@ namespace boost { namespace python { namespace numpy { * bad things happen when Python shuts down. I think this solution is safe, but I'd * love to get that confirmed. */ -class matrix : public ndarray +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); diff --git a/include/boost/python/numpy/ndarray.hpp b/include/boost/python/numpy/ndarray.hpp index 2985907b5b..2cb3b509f8 100644 --- a/include/boost/python/numpy/ndarray.hpp +++ b/include/boost/python/numpy/ndarray.hpp @@ -13,9 +13,11 @@ #include #include -#include +#include #include #include +#include + #include namespace boost { namespace python { namespace numpy { @@ -26,7 +28,8 @@ namespace boost { namespace python { namespace numpy { * @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 ndarray : public object + +class BOOST_NUMPY_DECL ndarray : public object { /** @@ -83,11 +86,11 @@ class ndarray : public object /// @brief Copy the scalar (deep for all non-object fields). ndarray copy() const; - /// @brief Return the size of the nth dimension. - Py_intptr_t shape(int n) const { return get_shape()[n]; } + /// @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. - Py_intptr_t strides(int n) const { return get_strides()[n]; } + /// @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. @@ -139,32 +142,32 @@ class ndarray : public object /** * @brief Construct a new array with the given shape and data type, with data initialized to zero. */ -ndarray zeros(python::tuple const & shape, dtype const & dt); -ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); +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. */ -ndarray empty(python::tuple const & shape, dtype const & dt); -ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); +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. */ -ndarray array(object const & obj); -ndarray array(object const & obj, dtype const & dt); +BOOST_NUMPY_DECL ndarray array(object const & obj); +BOOST_NUMPY_DECL ndarray array(object const & obj, dtype const & dt); namespace detail { -ndarray from_data_impl(void * data, - dtype const & dt, - std::vector const & shape, - std::vector const & strides, - object const & owner, - bool writeable); +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, @@ -173,19 +176,19 @@ ndarray from_data_impl(void * data, Container strides, object const & owner, bool writeable, - typename boost::enable_if< boost::is_integral >::type * enabled = NULL) + 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); } -ndarray from_data_impl(void * data, - dtype const & dt, - object const & shape, - object const & strides, - object const & owner, - bool 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 @@ -247,39 +250,53 @@ inline ndarray from_data(void const * data, * @param[in] nd_max Maximum number of dimensions. * @param[in] flags Bitwise OR of flags specifying additional requirements. */ -ndarray from_object(object const & obj, dtype const & dt, - int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); - -inline ndarray from_object(object const & obj, dtype const & dt, - int nd, ndarray::bitflag flags=ndarray::NONE) +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); } -inline ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE) +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); } -ndarray from_object(object const & obj, int nd_min, int nd_max, - ndarray::bitflag flags=ndarray::NONE); +BOOST_NUMPY_DECL ndarray from_object(object const & obj, + int nd_min, + int nd_max, + ndarray::bitflag flags=ndarray::NONE); -inline ndarray from_object(object const & obj, int nd, 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); } -inline ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE) +BOOST_NUMPY_DECL inline ndarray from_object(object const & obj, + ndarray::bitflag flags=ndarray::NONE) { return from_object(obj, 0, 0, flags); } -inline ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) +BOOST_NUMPY_DECL inline ndarray::bitflag operator|(ndarray::bitflag a, + ndarray::bitflag b) { return ndarray::bitflag(int(a) | int(b)); } -inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b) +BOOST_NUMPY_DECL inline ndarray::bitflag operator&(ndarray::bitflag a, + ndarray::bitflag b) { return ndarray::bitflag(int(a) & int(b)); } diff --git a/include/boost/python/numpy/numpy_object_mgr_traits.hpp b/include/boost/python/numpy/numpy_object_mgr_traits.hpp index 8f9f444074..a138f4cd52 100644 --- a/include/boost/python/numpy/numpy_object_mgr_traits.hpp +++ b/include/boost/python/numpy/numpy_object_mgr_traits.hpp @@ -7,6 +7,8 @@ #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(). @@ -14,7 +16,7 @@ #define NUMPY_OBJECT_MANAGER_TRAITS(manager) \ template <> \ -struct object_manager_traits \ +struct BOOST_NUMPY_DECL object_manager_traits \ { \ BOOST_STATIC_CONSTANT(bool, is_specialized = true); \ static inline python::detail::new_reference adopt(PyObject* x) \ diff --git a/include/boost/python/numpy/scalars.hpp b/include/boost/python/numpy/scalars.hpp index 0ba23c41ac..c2a83d8253 100644 --- a/include/boost/python/numpy/scalars.hpp +++ b/include/boost/python/numpy/scalars.hpp @@ -22,7 +22,7 @@ namespace boost { namespace python { namespace numpy { * * @todo This could have a lot more functionality. */ -class void_ : public object +class BOOST_NUMPY_DECL void_ : public object { static python::detail::new_reference convert(object_cref arg, bool align); public: diff --git a/include/boost/python/numpy/ufunc.hpp b/include/boost/python/numpy/ufunc.hpp index 9262b37840..79d7d262b8 100644 --- a/include/boost/python/numpy/ufunc.hpp +++ b/include/boost/python/numpy/ufunc.hpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace boost { namespace python { namespace numpy { @@ -34,7 +35,7 @@ namespace boost { namespace python { namespace numpy { * It's more dangerous than most object managers, however - maybe it actually belongs in * a detail namespace? */ -class multi_iter : public object +class BOOST_NUMPY_DECL multi_iter : public object { public: @@ -61,13 +62,13 @@ class multi_iter : public object }; /// @brief Construct a multi_iter over a single sequence or scalar object. -multi_iter make_multi_iter(object const & a1); +BOOST_NUMPY_DECL multi_iter make_multi_iter(object const & a1); /// @brief Construct a multi_iter by broadcasting two objects. -multi_iter make_multi_iter(object const & a1, object const & a2); +BOOST_NUMPY_DECL multi_iter make_multi_iter(object const & a1, object const & a2); /// @brief Construct a multi_iter by broadcasting three objects. -multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3); +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 @@ -105,7 +106,7 @@ struct unary_ufunc 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 != object()) ? + 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); @@ -170,7 +171,7 @@ struct binary_ufunc 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 != object()) + 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); 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 8e750b85cf..06d3f8efa7 100644 --- a/include/boost/python/object/class_metadata.hpp +++ b/include/boost/python/object/class_metadata.hpp @@ -17,14 +17,11 @@ #include #include +#include #include #include -#include -#include -#include - #include #include #include @@ -35,9 +32,6 @@ #include #include -#include - -#include #include #include @@ -56,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(); @@ -65,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); } @@ -89,7 +83,7 @@ inline void register_shared_ptr_from_python_and_casts(T*, Bases) { // Constructor performs registration python::detail::force_instantiate(converter::shared_ptr_from_python()); -#if __cplusplus >= 201103L +#if !defined(BOOST_NO_CXX11_SMART_PTR) python::detail::force_instantiate(converter::shared_ptr_from_python()); #endif @@ -98,7 +92,7 @@ inline void register_shared_ptr_from_python_and_casts(T*, Bases) // 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); + mpl::for_each(register_base_of(), (Bases*)0, (boost::python::detail::add_pointer*)0); } // @@ -109,7 +103,7 @@ struct select_held_type : mpl::if_< mpl::or_< python::detail::specifies_bases - , is_same + , boost::python::detail::is_same > , Prev , T @@ -156,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; // @@ -167,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. @@ -185,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; @@ -214,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()); } @@ -243,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 >()); 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 3a28190293..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,7 @@ struct make_ptr_instance template static inline Holder* construct(void* storage, PyObject*, Arg& x) { -#if __cplusplus < 201103L +#if defined(BOOST_NO_CXX11_SMART_PTR) return new (storage) Holder(x); #else return new (storage) Holder(std::move(x)); @@ -47,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; @@ -55,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 b28cbd83c8..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,7 +106,7 @@ struct pointer_holder_back_reference : instance_holder template inline pointer_holder::pointer_holder(Pointer p) -#if __cplusplus < 201103L +#if defined(BOOST_NO_CXX11_SMART_PTR) : m_p(p) #else : m_p(std::move(p)) @@ -117,7 +116,7 @@ inline pointer_holder::pointer_holder(Pointer p) template inline pointer_holder_back_reference::pointer_holder_back_reference(Pointer p) -#if __cplusplus < 201103L +#if defined(BOOST_NO_CXX11_SMART_PTR) : m_p(p) #else : m_p(std::move(p)) @@ -128,7 +127,7 @@ inline pointer_holder_back_reference::pointer_holder_back_referen 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 05cedfa00a..df2fb44a4f 100644 --- a/include/boost/python/object/py_function.hpp +++ b/include/boost/python/object/py_function.hpp @@ -135,7 +135,7 @@ struct py_function {} py_function(py_function const& rhs) -#if __cplusplus < 201103L +#if defined(BOOST_NO_CXX11_SMART_PTR) : m_impl(rhs.m_impl) #else : m_impl(std::move(rhs.m_impl)) @@ -168,7 +168,7 @@ struct py_function } private: -#if __cplusplus < 201103L +#if defined(BOOST_NO_CXX11_SMART_PTR) mutable std::auto_ptr m_impl; #else mutable std::unique_ptr m_impl; 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 209310ffd7..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,16 @@ 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 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/stl_iterator.hpp b/include/boost/python/stl_iterator.hpp old mode 100755 new mode 100644 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 af6ed33b9b..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,7 +83,7 @@ namespace detail // copy constructor. # if defined(__ICL) && __ICL < 600 typedef boost::shared_ptr smart_pointer; -# elif __cplusplus < 201103L +# elif defined(BOOST_NO_CXX11_SMART_PTR) typedef std::auto_ptr smart_pointer; # else typedef std::unique_ptr smart_pointer; diff --git a/include/boost/python/to_python_value.hpp b/include/boost/python/to_python_value.hpp index 2681f8a39c..b6ec0135ba 100644 --- a/include/boost/python/to_python_value.hpp +++ b/include/boost/python/to_python_value.hpp @@ -19,14 +19,12 @@ #include #include +#include #include #include -#include - #include #include -#include namespace boost { namespace python { @@ -120,7 +118,7 @@ struct object_manager_get_pytype 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 __cplusplus >= 201103L +# if !defined(BOOST_NO_CXX11_SMART_PTR) template PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} template 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/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/src/SConscript b/src/SConscript deleted file mode 100644 index 6d81a9dc02..0000000000 --- a/src/SConscript +++ /dev/null @@ -1,54 +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']) - -if env['NUMPY']: - env.BoostLibrary( - 'numpy', - ['numpy/dtype.cpp', - 'numpy/matrix.cpp', - 'numpy/ndarray.cpp', - 'numpy/numpy.cpp', - 'numpy/scalars.cpp', - 'numpy/ufunc.cpp']) diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index 1c28af7fc9..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 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 index 13904ddde3..1ce8c6ec32 100644 --- a/src/numpy/dtype.cpp +++ b/src/numpy/dtype.cpp @@ -11,29 +11,33 @@ #include #define DTYPE_FROM_CODE(code) \ - dtype(python::detail::new_reference(reinterpret_cast(PyArray_DescrFromType(code)))) + dtype(python::detail::new_reference(reinterpret_cast(PyArray_DescrFromType(code)))) #define BUILTIN_INT_DTYPE(bits) \ - template <> struct builtin_int_dtype< bits, false > { \ - static dtype get() { return DTYPE_FROM_CODE(NPY_INT ## bits); } \ - }; \ - template <> struct builtin_int_dtype< bits, true > { \ - static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits); } \ - }; \ - template dtype get_int_dtype< bits, false >(); \ - template dtype get_int_dtype< bits, true >() + 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< bits > { \ - static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits); } \ - }; \ - template dtype get_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< bits > { \ - static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits); } \ - }; \ - template dtype get_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) @@ -58,7 +62,9 @@ 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); @@ -92,37 +98,18 @@ python::detail::new_reference dtype::convert(object const & arg, bool align) return python::detail::new_reference(reinterpret_cast(obj)); } -int dtype::get_itemsize() const { return reinterpret_cast(ptr())->elsize;} - -bool equivalent(dtype const & a, dtype const & b) { - // On Windows x64, the behaviour described on - // http://docs.scipy.org/doc/numpy/reference/c-api.array.html for - // PyArray_EquivTypes unfortunately does not extend as expected: - // "For example, on 32-bit platforms, NPY_LONG and NPY_INT are equivalent". - // This should also hold for 64-bit platforms (and does on Linux), but not - // on Windows. Implement an alternative: -#ifdef _MSC_VER - if (sizeof(long) == sizeof(int) && - // Manually take care of the type equivalence. - ((a == dtype::get_builtin() || a == dtype::get_builtin()) && - (b == dtype::get_builtin() || b == dtype::get_builtin()) || - (a == dtype::get_builtin() || a == dtype::get_builtin()) && - (b == dtype::get_builtin() || b == dtype::get_builtin()))) { - return true; - } else { - return PyArray_EquivTypes( - reinterpret_cast(a.ptr()), - reinterpret_cast(b.ptr()) - ); - } +int dtype::get_itemsize() const { +#if NPY_ABI_VERSION < 0x02000000 + return reinterpret_cast(ptr())->elsize; #else - return PyArray_EquivTypes( - reinterpret_cast(a.ptr()), - reinterpret_cast(b.ptr()) - ); + return PyDataType_ELSIZE(reinterpret_cast(ptr())); #endif } +bool equivalent(dtype const & a, dtype const & b) { + return a == b; +} + namespace { diff --git a/src/numpy/ndarray.cpp b/src/numpy/ndarray.cpp index 710e3d4993..af09ecc338 100644 --- a/src/numpy/ndarray.cpp +++ b/src/numpy/ndarray.cpp @@ -22,20 +22,20 @@ namespace detail ndarray::bitflag numpy_to_bitflag(int const f) { ndarray::bitflag r = ndarray::NONE; - if (f & NPY_C_CONTIGUOUS) r = (r | ndarray::C_CONTIGUOUS); - if (f & NPY_F_CONTIGUOUS) r = (r | ndarray::F_CONTIGUOUS); - if (f & NPY_ALIGNED) r = (r | ndarray::ALIGNED); - if (f & NPY_WRITEABLE) r = (r | ndarray::WRITEABLE); + 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_C_CONTIGUOUS; - if (f & ndarray::F_CONTIGUOUS) r |= NPY_F_CONTIGUOUS; - if (f & ndarray::ALIGNED) r |= NPY_ALIGNED; - if (f & ndarray::WRITEABLE) r |= NPY_WRITEABLE; + 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; } @@ -119,10 +119,10 @@ ndarray from_data_impl(void * data, } int itemsize = dt.get_itemsize(); int flags = 0; - if (writeable) flags |= NPY_WRITEABLE; - if (is_c_contiguous(shape, strides, itemsize)) flags |= NPY_C_CONTIGUOUS; - if (is_f_contiguous(shape, strides, itemsize)) flags |= NPY_F_CONTIGUOUS; - if (is_aligned(strides, itemsize)) flags |= NPY_ALIGNED; + 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), @@ -138,6 +138,30 @@ ndarray from_data_impl(void * data, } // 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 @@ -170,7 +194,7 @@ python::object ndarray::get_base() const void ndarray::set_base(object const & base) { Py_XDECREF(get_struct()->base); - if (base != object()) + if (base.ptr()) { Py_INCREF(base.ptr()); get_struct()->base = base.ptr(); @@ -243,13 +267,13 @@ ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt) ndarray array(python::object const & obj) { return ndarray(python::detail::new_reference - (PyArray_FromAny(obj.ptr(), NULL, 0, 0, NPY_ENSUREARRAY, NULL))); + (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_ENSUREARRAY, NULL))); + (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) diff --git a/src/numpy/numpy.cpp b/src/numpy/numpy.cpp index 8e259bc755..3ae2295e39 100644 --- a/src/numpy/numpy.cpp +++ b/src/numpy/numpy.cpp @@ -19,6 +19,7 @@ static void wrap_import_array() static void * wrap_import_array() { import_array(); + return NULL; } #endif 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/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 b/test/Jamfile index 72d60d379a..40115d86cb 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -2,14 +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/checks/config : requires ; +import config : requires ; lib socket ; -use-project /boost/python : ../build ; -project /boost/python/test +project : requirements gcc:-Wextra qnxnto:socket @@ -28,7 +30,7 @@ rule py-run ( sources * : input-file ? ) : $(input-file) : #requirements BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION - + ] ; } @@ -50,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 : @@ -95,14 +111,18 @@ bpl-test crossmod_exception [ 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 ] @@ -113,9 +133,9 @@ bpl-test crossmod_exception [ 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 ] @@ -126,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 ] @@ -185,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) @@ -205,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 ] @@ -248,3 +270,4 @@ bpl-test crossmod_opaque ; +} diff --git a/test/SConscript b/test/SConscript deleted file mode 100644 index ee41547f41..0000000000 --- a/test/SConscript +++ /dev/null @@ -1,160 +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',), - ('boost_shared_ptr',), - ('enable_shared_from_this',), - ('andreas_beyer',), - ('polymorphism',), - ('polymorphism2',), - ('wrapper_held_type',), - ('minimal',), - ('args',), - ('raw_ctor',), - ('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) - -if env['CXX11']: - for test in [ - ('shared_ptr',), - ]: - tests+=env.BPLTest(*test) -else: - for test in [ - ('polymorphism2_auto_ptr',), - ('auto_ptr',), - ]: - 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') - -if env['NUMPY']: - numpy_env = env.Clone() - numpy_env.BoostUseLib('numpy') - for test in [('numpy/dtype',), - ('numpy/ufunc',), - ('numpy/templates',), - ('numpy/ndarray',), - ('numpy/indexing',), - ('numpy/shapes',),]: - tests+=numpy_env.BPLTest(*test) - - -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/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/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 f63923632e..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): - long = int ''' >>> 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/numpy/dtype.py b/test/numpy/dtype.py index a27ee0f55d..a2eabb58e2 100644 --- a/test/numpy/dtype.py +++ b/test/numpy/dtype.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright Jim Bosch & Ankit Daftery 2010-2012. # Distributed under the Boost Software License, Version 1.0. @@ -15,7 +15,7 @@ class DtypeTestCase(unittest.TestCase): def assertEquivalent(self, a, b): - return self.assert_(dtype_ext.equivalent(a, b), "%r is not equivalent to %r") + return self.assertTrue(dtype_ext.equivalent(a, b), "%r is not equivalent to %r") def testIntegers(self): for bits in (8, 16, 32, 64): diff --git a/test/numpy/indexing.py b/test/numpy/indexing.py index ebd9dcbabb..3fb9adb4c0 100644 --- a/test/numpy/indexing.py +++ b/test/numpy/indexing.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright Jim Bosch & Ankit Daftery 2010-2012. # Distributed under the Boost Software License, Version 1.0. diff --git a/test/numpy/ndarray.cpp b/test/numpy/ndarray.cpp index 808872e855..75a1010435 100644 --- a/test/numpy/ndarray.cpp +++ b/test/numpy/ndarray.cpp @@ -31,6 +31,9 @@ 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(); @@ -43,4 +46,6 @@ BOOST_PYTHON_MODULE(ndarray_ext) 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 index fb92a2a23e..13f3c73e42 100644 --- a/test/numpy/ndarray.py +++ b/test/numpy/ndarray.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright Jim Bosch & Ankit Daftery 2010-2012. # Distributed under the Boost Software License, Version 1.0. @@ -19,7 +19,7 @@ def testNdzeros(self): a1 = ndarray_ext.zeros(shape,dt) a2 = v.reshape(a1.shape) self.assertEqual(shape,a1.shape) - self.assert_((a1 == a2).all()) + self.assertTrue((a1 == a2).all()) def testNdzeros_matrix(self): for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): @@ -28,7 +28,7 @@ def testNdzeros_matrix(self): a1 = ndarray_ext.zeros_matrix(shape, dt) a2 = numpy.matrix(numpy.zeros(shape, dtype=dtp)) self.assertEqual(shape,a1.shape) - self.assert_((a1 == a2).all()) + self.assertTrue((a1 == a2).all()) self.assertEqual(type(a1), type(a2)) def testNdarray(self): @@ -38,8 +38,8 @@ def testNdarray(self): dt = numpy.dtype(dtp) a1 = ndarray_ext.array(a) a2 = ndarray_ext.array(a,dt) - self.assert_((a1 == v).all()) - self.assert_((a2 == v).all()) + 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) @@ -75,5 +75,38 @@ def testReshape(self): 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.py b/test/numpy/shapes.py index d0a0099ca6..28c74b7b18 100644 --- a/test/numpy/shapes.py +++ b/test/numpy/shapes.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright Jim Bosch & Ankit Daftery 2010-2012. # Distributed under the Boost Software License, Version 1.0. diff --git a/test/numpy/templates.py b/test/numpy/templates.py index 8290b13a07..9c21622881 100755 --- a/test/numpy/templates.py +++ b/test/numpy/templates.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright Jim Bosch & Ankit Daftery 2010-2012. # Distributed under the Boost Software License, Version 1.0. @@ -18,7 +18,7 @@ def testTemplates(self): a1 = numpy.zeros(shape, dtype=dtype) a2 = v.reshape(a1.shape) templates_ext.fill(a1) - self.assert_((a1 == a2).all()) + 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) diff --git a/test/numpy/ufunc.py b/test/numpy/ufunc.py index e820121ee1..1fa3090b3e 100755 --- a/test/numpy/ufunc.py +++ b/test/numpy/ufunc.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright Jim Bosch & Ankit Daftery 2010-2012. # Distributed under the Boost Software License, Version 1.0. @@ -8,7 +8,10 @@ import ufunc_ext import unittest import numpy -from numpy.testing.utils import assert_array_almost_equal +try: + from numpy.testing import assert_array_almost_equal +except ImportError: + from numpy.testing.utils import assert_array_almost_equal class TestUnary(unittest.TestCase): @@ -24,7 +27,7 @@ def testArray(self): assert_array_almost_equal(b, a*2.0) c = numpy.zeros(5, dtype=float) d = f(a,output=c) - self.assert_(c is d) + self.assertTrue((c == d).all()) assert_array_almost_equal(d, a*2.0) def testList(self): @@ -47,7 +50,7 @@ def testArray(self): assert_array_almost_equal(f(a,b), (a*2+b*3)) c = numpy.zeros(5, dtype=float) d = f(a,b,output=c) - self.assert_(c is d) + 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) 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/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.py b/test/shared_ptr.py index d250ae7eca..4ef88f78d8 100644 --- a/test/shared_ptr.py +++ b/test/shared_ptr.py @@ -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) 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 adc397e1e5..0f1b4ded75 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,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): @@ -74,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 @@ -133,9 +134,6 @@ >>> print(rewrap_value_wstring(u'yo, wassup?')) yo, wassup? ->>> print(rewrap_value_wstring(u'\U0001f4a9')) -\U0001f4a9 - test that overloading on unicode works: >>> print(rewrap_value_string(u'yo, wassup?')) 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 );