diff --git a/.appveyor.yml b/.appveyor.yml index 85445d41a..360760ac8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,6 @@ version: 1.0.{build} image: -- Visual Studio 2015 +- Visual Studio 2017 test: off skip_branch_with_pr: true build: @@ -11,11 +11,9 @@ environment: matrix: - PYTHON: 36 CONFIG: Debug - - PYTHON: 27 - CONFIG: Debug install: - ps: | - $env:CMAKE_GENERATOR = "Visual Studio 14 2015" + $env:CMAKE_GENERATOR = "Visual Studio 15 2017" if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" } $env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH" python -W ignore -m pip install --upgrade pip wheel diff --git a/.clang-tidy b/.clang-tidy index d01ca352c..d945a4a27 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,72 +1,75 @@ FormatStyle: file -Checks: ' -*bugprone*, -clang-analyzer-optin.performance.Padding, -clang-analyzer-optin.cplusplus.VirtualCall, -cppcoreguidelines-init-variables, -cppcoreguidelines-prefer-member-initializer, -cppcoreguidelines-pro-type-static-cast-downcast, -cppcoreguidelines-slicing, -google-explicit-constructor, -llvm-namespace-comment, -misc-misplaced-const, -misc-non-copyable-objects, -misc-static-assert, -misc-throw-by-value-catch-by-reference, -misc-uniqueptr-reset-release, -misc-unused-parameters, -modernize-avoid-bind, -modernize-make-shared, -modernize-redundant-void-arg, -modernize-replace-auto-ptr, -modernize-replace-disallow-copy-and-assign-macro, -modernize-replace-random-shuffle, -modernize-shrink-to-fit, -modernize-use-auto, -modernize-use-bool-literals, -modernize-use-equals-default, -modernize-use-equals-delete, -modernize-use-default-member-init, -modernize-use-noexcept, -modernize-use-emplace, -modernize-use-override, -modernize-use-using, -*performance*, -readability-avoid-const-params-in-decls, -readability-braces-around-statements, -readability-const-return-type, -readability-container-size-empty, -readability-delete-null-pointer, -readability-else-after-return, -readability-implicit-bool-conversion, -readability-inconsistent-declaration-parameter-name, -readability-make-member-function-const, -readability-misplaced-array-index, -readability-non-const-parameter, -readability-qualified-auto, -readability-redundant-function-ptr-dereference, -readability-redundant-smartptr-get, -readability-redundant-string-cstr, -readability-simplify-subscript-expr, -readability-static-accessed-through-instance, -readability-static-definition-in-anonymous-namespace, -readability-string-compare, -readability-suspicious-call-argument, -readability-uniqueptr-delete-release, --bugprone-exception-escape, --bugprone-reserved-identifier, --bugprone-unused-raii, -' +Checks: | + *bugprone*, + *performance*, + clang-analyzer-optin.cplusplus.VirtualCall, + clang-analyzer-optin.performance.Padding, + cppcoreguidelines-init-variables, + cppcoreguidelines-prefer-member-initializer, + cppcoreguidelines-pro-type-static-cast-downcast, + cppcoreguidelines-slicing, + google-explicit-constructor, + llvm-namespace-comment, + misc-definitions-in-headers, + misc-misplaced-const, + misc-non-copyable-objects, + misc-static-assert, + misc-throw-by-value-catch-by-reference, + misc-uniqueptr-reset-release, + misc-unused-parameters, + modernize-avoid-bind, + modernize-loop-convert, + modernize-make-shared, + modernize-redundant-void-arg, + modernize-replace-auto-ptr, + modernize-replace-disallow-copy-and-assign-macro, + modernize-replace-random-shuffle, + modernize-shrink-to-fit, + modernize-use-auto, + modernize-use-bool-literals, + modernize-use-default-member-init, + modernize-use-emplace, + modernize-use-equals-default, + modernize-use-equals-delete, + modernize-use-noexcept, + modernize-use-nullptr, + modernize-use-override, + modernize-use-using, + readability-avoid-const-params-in-decls, + readability-braces-around-statements, + readability-const-return-type, + readability-container-size-empty, + readability-delete-null-pointer, + readability-else-after-return, + readability-implicit-bool-conversion, + readability-inconsistent-declaration-parameter-name, + readability-make-member-function-const, + readability-misplaced-array-index, + readability-non-const-parameter, + readability-qualified-auto, + readability-redundant-function-ptr-dereference, + readability-redundant-smartptr-get, + readability-redundant-string-cstr, + readability-simplify-subscript-expr, + readability-static-accessed-through-instance, + readability-static-definition-in-anonymous-namespace, + readability-string-compare, + readability-suspicious-call-argument, + readability-uniqueptr-delete-release, + -bugprone-easily-swappable-parameters, + -bugprone-exception-escape, + -bugprone-reserved-identifier, + -bugprone-unused-raii, CheckOptions: - key: performance-for-range-copy.WarnOnAllAutoCopies value: true +- key: performance-inefficient-string-concatenation.StrictMode + value: true - key: performance-unnecessary-value-param.AllowedTypes value: 'exception_ptr$;' - key: readability-implicit-bool-conversion.AllowPointerConditions value: true HeaderFilterRegex: 'pybind11/.*h' - -WarningsAsErrors: '*' diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..d611e1496 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +docs/*.svg binary diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e8294c83c..00b1fea4c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -93,11 +93,10 @@ cmake --build build -j4 Tips: -* You can use `virtualenv` (from PyPI) instead of `venv` (which is Python 3 - only). +* You can use `virtualenv` (faster, from PyPI) instead of `venv`. * You can select any name for your environment folder; if it contains "env" it will be ignored by git. -* If you don’t have CMake 3.14+, just add “cmake” to the pip install command. +* If you don't have CMake 3.14+, just add "cmake" to the pip install command. * You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+ * In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`. FindPython uses `-DPython_ROOT_DIR=/path/to` or @@ -105,7 +104,7 @@ Tips: ### Configuration options -In CMake, configuration options are given with “-D”. Options are stored in the +In CMake, configuration options are given with "-D". Options are stored in the build directory, in the `CMakeCache.txt` file, so they are remembered for each build directory. Two selections are special - the generator, given with `-G`, and the compiler, which is selected based on environment variables `CXX` and @@ -115,7 +114,7 @@ after the initial run. The valid options are: * `-DCMAKE_BUILD_TYPE`: Release, Debug, MinSizeRel, RelWithDebInfo -* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+’s FindPython instead of the +* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+'s FindPython instead of the classic, deprecated, custom FindPythonLibs * `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests) * `-DBUILD_TESTING=ON`: Enable the tests @@ -236,12 +235,14 @@ directory inside your pybind11 git clone. Files will be modified in place, so you can use git to monitor the changes. ```bash -docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:12 +docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:13 apt-get update && apt-get install -y python3-dev python3-pytest -cmake -S /mounted_pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);-fix" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17 -cmake --build build -j 2 -- --keep-going +cmake -S /mounted_pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17 +cmake --build build -j 2 ``` +You can add `--fix` to the options list if you want. + ### Include what you use To run include what you use, install (`brew install include-what-you-use` on @@ -257,7 +258,7 @@ The report is sent to stderr; you can pipe it into a file if you wish. ### Build recipes This builds with the Intel compiler (assuming it is in your path, along with a -recent CMake and Python 3): +recent CMake and Python): ```bash python3 -m venv venv diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 73273365c..2c7d17083 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,12 +5,3 @@ updates: directory: "/" schedule: interval: "daily" - ignore: - # Official actions have moving tags like v1 - # that are used, so they don't need updates here - - dependency-name: "actions/checkout" - - dependency-name: "actions/setup-python" - - dependency-name: "actions/cache" - - dependency-name: "actions/upload-artifact" - - dependency-name: "actions/download-artifact" - - dependency-name: "actions/labeler" diff --git a/.github/matchers/pylint.json b/.github/matchers/pylint.json new file mode 100644 index 000000000..e3a6bd16b --- /dev/null +++ b/.github/matchers/pylint.json @@ -0,0 +1,32 @@ +{ + "problemMatcher": [ + { + "severity": "warning", + "pattern": [ + { + "regexp": "^([^:]+):(\\d+):(\\d+): ([A-DF-Z]\\d+): \\033\\[[\\d;]+m([^\\033]+).*$", + "file": 1, + "line": 2, + "column": 3, + "code": 4, + "message": 5 + } + ], + "owner": "pylint-warning" + }, + { + "severity": "error", + "pattern": [ + { + "regexp": "^([^:]+):(\\d+):(\\d+): (E\\d+): \\033\\[[\\d;]+m([^\\033]+).*$", + "file": 1, + "line": 2, + "column": 3, + "code": 4, + "message": 5 + } + ], + "owner": "pylint-error" + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c244a5e6f..412282a4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ concurrency: env: PIP_ONLY_BINARY: numpy + FORCE_COLOR: 3 + PYTEST_TIMEOUT: 300 jobs: # This is the "main" test suite, which tests a large number of different @@ -25,13 +27,13 @@ jobs: matrix: runs-on: [ubuntu-latest, windows-2022, macos-latest] python: - - '2.7' - - '3.5' - '3.6' - '3.9' - '3.10' + - '3.11-dev' - 'pypy-3.7' - 'pypy-3.8' + - 'pypy-3.9' # Items in here will either be added to the build matrix (if not # present), or add new keys to an existing matrix element if all the @@ -45,26 +47,26 @@ jobs: args: > -DPYBIND11_FINDPYTHON=ON -DCMAKE_CXX_FLAGS="-D_=1" - - runs-on: windows-latest + - runs-on: ubuntu-latest + python: 'pypy-3.8' + args: > + -DPYBIND11_FINDPYTHON=ON + - runs-on: windows-2019 python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON - - runs-on: macos-latest - python: 'pypy-2.7' # Inject a couple Windows 2019 runs - runs-on: windows-2019 python: '3.9' - - runs-on: windows-2019 - python: '2.7' name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}" runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} @@ -82,7 +84,7 @@ jobs: - name: Cache wheels if: runner.os == 'macOS' - uses: actions/cache@v2 + uses: actions/cache@v3 with: # This path is specific to macOS - we really only need it for PyPy NumPy wheels # See https://github.com/actions/cache/blob/master/examples.md#python---pip @@ -168,27 +170,11 @@ jobs: - name: Interface test run: cmake --build build2 --target test_cmake_build - # Eventually Microsoft might have an action for setting up - # MSVC, but for now, this action works: - - name: Prepare compiler environment for Windows 🐍 2.7 - if: matrix.python == 2.7 && runner.os == 'Windows' - uses: ilammy/msvc-dev-cmd@v1.10.0 - with: - arch: x64 - - # This makes two environment variables available in the following step(s) - - name: Set Windows 🐍 2.7 environment variables - if: matrix.python == 2.7 && runner.os == 'Windows' - shell: bash - run: | - echo "DISTUTILS_USE_SDK=1" >> $GITHUB_ENV - echo "MSSdk=1" >> $GITHUB_ENV - # This makes sure the setup_helpers module can build packages using # setuptools - name: Setuptools helpers test run: pytest tests/extra_setuptools - if: "!(matrix.python == '3.5' && matrix.runs-on == 'windows-2022')" + if: "!(matrix.runs-on == 'windows-2022')" deadsnakes: @@ -200,14 +186,14 @@ jobs: - python-version: "3.9" python-debug: true valgrind: true - # - python-version: "3.11-dev" - # python-debug: false + - python-version: "3.11-dev" + python-debug: false name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} (deadsnakes) uses: deadsnakes/action@v2.1.1 @@ -220,7 +206,7 @@ jobs: - name: Valgrind cache if: matrix.valgrind - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-valgrind with: path: valgrind @@ -295,12 +281,14 @@ jobs: std: 20 - clang: 10 std: 17 + - clang: 14 + std: 20 name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64" container: "silkeh/clang:${{ matrix.clang }}" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Add wget and python3 run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev @@ -330,11 +318,11 @@ jobs: # Testing NVCC; forces sources to behave like .cu files cuda: runs-on: ubuntu-latest - name: "🐍 3.8 • CUDA 11 • Ubuntu 20.04" - container: nvidia/cuda:11.0-devel-ubuntu20.04 + name: "🐍 3.8 • CUDA 11.2 • Ubuntu 20.04" + container: nvidia/cuda:11.2.2-devel-ubuntu20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND - name: Install 🐍 3 @@ -358,7 +346,7 @@ jobs: # container: centos:8 # # steps: -# - uses: actions/checkout@v2 +# - uses: actions/checkout@v3 # # - name: Add Python 3 and a few requirements # run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules @@ -397,17 +385,17 @@ jobs: # Testing on CentOS 7 + PGI compilers, which seems to require more workarounds centos-nvhpc7: runs-on: ubuntu-latest - name: "🐍 3 • CentOS7 / PGI 20.9 • x64" + name: "🐍 3 • CentOS7 / PGI 22.3 • x64" container: centos:7 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Add Python 3 and a few requirements - run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 + run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 yum-utils - name: Install NVidia HPC SDK - run: yum -y install https://developer.download.nvidia.com/hpc-sdk/20.9/nvhpc-20-9-20.9-1.x86_64.rpm https://developer.download.nvidia.com/hpc-sdk/20.9/nvhpc-2020-20.9-1.x86_64.rpm + run: yum-config-manager --add-repo https://developer.download.nvidia.com/hpc-sdk/rhel/nvhpc.repo && yum -y install nvhpc-22.3 # On CentOS 7, we have to filter a few tests (compiler internal error) # and allow deeper template recursion (not needed on CentOS 8 with a newer @@ -417,7 +405,7 @@ jobs: shell: bash run: | source /etc/profile.d/modules.sh - module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/20.9 + module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.3 cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \ -DCMAKE_CXX_STANDARD=11 \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \ @@ -462,7 +450,7 @@ jobs: container: "gcc:${{ matrix.gcc }}" steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Add Python 3 run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev @@ -504,7 +492,7 @@ jobs: name: "🐍 3 • ICC latest • x64" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Add apt repo run: | @@ -599,19 +587,25 @@ jobs: strategy: fail-fast: false matrix: - centos: - - centos7 # GCC 4.8 - - stream8 + container: + - "centos:7" # GCC 4.8 + - "almalinux:8" + - "almalinux:9" - name: "🐍 3 • CentOS ${{ matrix.centos }} • x64" - container: "quay.io/centos/centos:${{ matrix.centos }}" + name: "🐍 3 • ${{ matrix.container }} • x64" + container: "${{ matrix.container }}" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Add Python 3 + - name: Add Python 3 (RHEL 7) + if: matrix.container == 'centos:7' run: yum update -y && yum install -y python3-devel gcc-c++ make git + - name: Add Python 3 (RHEL 8+) + if: matrix.container != 'centos:7' + run: dnf update -y && dnf install -y python3-devel gcc-c++ make git + - name: Update pip run: python3 -m pip install --upgrade pip @@ -645,18 +639,18 @@ jobs: # This tests an "install" with the CMake tools install-classic: - name: "🐍 3.5 • Debian • x86 • Install" + name: "🐍 3.7 • Debian • x86 • Install" runs-on: ubuntu-latest - container: i386/debian:stretch + container: i386/debian:buster steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v1 # Required to run inside docker - name: Install requirements run: | apt-get update apt-get install -y git make cmake g++ libeigen3-dev python3-dev python3-pip - pip3 install "pytest==3.1.*" + pip3 install "pytest==6.*" - name: Configure for install run: > @@ -687,15 +681,17 @@ jobs: # This verifies that the documentation is not horribly broken, and does a - # basic sanity check on the SDist. + # basic validation check on the SDist. doxygen: name: "Documentation build test" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 + with: + python-version: "3.x" - name: Install Doxygen run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04 @@ -725,27 +721,25 @@ jobs: fail-fast: false matrix: python: - - 3.5 - 3.6 - 3.7 - 3.8 - 3.9 - - pypy-3.6 include: - python: 3.9 - args: -DCMAKE_CXX_STANDARD=20 -DDOWNLOAD_EIGEN=OFF + args: -DCMAKE_CXX_STANDARD=20 - python: 3.8 args: -DCMAKE_CXX_STANDARD=17 name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}" - runs-on: windows-latest + runs-on: windows-2019 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} architecture: x86 @@ -777,25 +771,31 @@ jobs: - name: Python tests run: cmake --build build -t pytest - win32-msvc2015: - name: "🐍 ${{ matrix.python }} • MSVC 2015 • x64" - runs-on: windows-latest + win32-debug: strategy: fail-fast: false matrix: python: - - 2.7 - - 3.6 - - 3.7 - # todo: check/cpptest does not support 3.8+ yet + - 3.8 + - 3.9 + + include: + - python: 3.9 + args: -DCMAKE_CXX_STANDARD=20 + - python: 3.8 + args: -DCMAKE_CXX_STANDARD=17 + + name: "🐍 ${{ matrix.python }} • MSVC 2019 (Debug) • x86 ${{ matrix.args }}" + runs-on: windows-2019 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Setup 🐍 ${{ matrix.python }} - uses: actions/setup-python@v2 + - name: Setup Python ${{ matrix.python }} + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + architecture: x86 - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.12 @@ -803,82 +803,73 @@ jobs: - name: Prepare MSVC uses: ilammy/msvc-dev-cmd@v1.10.0 with: - toolset: 14.0 + arch: x86 - name: Prepare env run: | python -m pip install -r tests/requirements.txt # First build - C++11 mode and inplace - - name: Configure + - name: Configure ${{ matrix.args }} run: > cmake -S . -B build - -G "Visual Studio 14 2015" -A x64 + -G "Visual Studio 16 2019" -A Win32 + -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON + ${{ matrix.args }} + - name: Build C++11 + run: cmake --build build --config Debug -j 2 - - name: Build C++14 - run: cmake --build build -j 2 - - - name: Run all checks - run: cmake --build build -t check + - name: Python tests + run: cmake --build build --config Debug -t pytest - win32-msvc2017: - name: "🐍 ${{ matrix.python }} • MSVC 2017 • x64" - runs-on: windows-2016 + windows-2022: strategy: fail-fast: false matrix: python: - - 2.7 - - 3.5 - - 3.7 - std: - - 14 + - 3.9 - include: - - python: 2.7 - std: 17 - args: > - -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" - - python: 3.7 - std: 17 - args: > - -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" + name: "🐍 ${{ matrix.python }} • MSVC 2022 C++20 • x64" + runs-on: windows-2022 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Setup 🐍 ${{ matrix.python }} - uses: actions/setup-python@v2 + - name: Setup Python ${{ matrix.python }} + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + - name: Prepare env + run: | + python3 -m pip install -r tests/requirements.txt + - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.12 - - name: Prepare env - run: | - python -m pip install -r tests/requirements.txt - - # First build - C++11 mode and inplace - - name: Configure + - name: Configure C++20 run: > cmake -S . -B build - -G "Visual Studio 15 2017" -A x64 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON - -DCMAKE_CXX_STANDARD=${{ matrix.std }} - ${{ matrix.args }} + -DCMAKE_CXX_STANDARD=20 - - name: Build ${{ matrix.std }} + - name: Build C++20 run: cmake --build build -j 2 - - name: Run all checks - run: cmake --build build -t check + - name: Python tests + run: cmake --build build --target pytest + + - name: C++20 tests + run: cmake --build build --target cpptest -j 2 + + - name: Interface test C++20 + run: cmake --build build --target test_cmake_build mingw: name: "🐍 3 • windows-latest • ${{ matrix.sys }}" @@ -909,7 +900,7 @@ jobs: mingw-w64-${{matrix.env}}-boost mingw-w64-${{matrix.env}}-catch - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Configure C++11 # LTO leads to many undefined reference like diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index 66ab0e3d7..edcad4198 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -18,7 +18,7 @@ jobs: matrix: runs-on: [ubuntu-latest, macos-latest, windows-latest] arch: [x64] - cmake: ["3.21"] + cmake: ["3.23"] include: - runs-on: ubuntu-latest @@ -29,22 +29,18 @@ jobs: arch: x64 cmake: 3.7 - - runs-on: windows-2016 - arch: x86 - cmake: 3.8 - - - runs-on: windows-2016 - arch: x86 + - runs-on: windows-2019 + arch: x64 # x86 compilers seem to be missing on 2019 image cmake: 3.18 name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python 3.7 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.7 architecture: ${{ matrix.arch }} diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index ab7b40503..31d893c47 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -12,14 +12,21 @@ on: - stable - "v*" +env: + FORCE_COLOR: 3 + jobs: pre-commit: name: Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - - uses: pre-commit/action@v2.0.3 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Add matchers + run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json" + - uses: pre-commit/action@v3.0.0 with: # Slow hooks are marked with manual - slow is okay here, run them too extra_args: --hook-stage manual --all-files @@ -29,9 +36,9 @@ jobs: # in .github/CONTRIBUTING.md and update as needed. name: Clang-Tidy runs-on: ubuntu-latest - container: silkeh/clang:12 + container: silkeh/clang:13 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install requirements run: apt-get update && apt-get install -y python3-dev python3-pytest @@ -39,7 +46,7 @@ jobs: - name: Configure run: > cmake -S . -B build - -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy)" + -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color;--warnings-as-errors=*" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17 diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index f74b79f0c..2c16735e1 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -17,19 +17,19 @@ env: jobs: # This builds the sdists and wheels and makes sure the files are exactly as - # expected. Using Windows and Python 2.7, since that is often the most + # expected. Using Windows and Python 3.6, since that is often the most # challenging matrix element. test-packaging: - name: 🐍 2.7 • 📦 tests • windows-latest + name: 🐍 3.6 • 📦 tests • windows-latest runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Setup 🐍 2.7 - uses: actions/setup-python@v2 + - name: Setup 🐍 3.6 + uses: actions/setup-python@v4 with: - python-version: 2.7 + python-version: 3.6 - name: Prepare env run: | @@ -46,10 +46,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup 🐍 3.8 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 @@ -69,13 +69,13 @@ jobs: run: twine check dist/* - name: Save standard package - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: standard path: dist/pybind11-* - name: Save global package - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: global path: dist/pybind11_global-* @@ -90,10 +90,12 @@ jobs: needs: [packaging] steps: - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 + with: + python-version: "3.x" # Downloads all to directories matching the artifact names - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 - name: Publish standard package uses: pypa/gh-action-pypi-publish@v1.5.0 diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 138c9ad29..a40a6c7d7 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -14,15 +14,15 @@ env: jobs: standard: - name: "🐍 3.11 dev • ubuntu-latest • x64" + name: "🐍 3.11 latest internals • ubuntu-latest • x64" runs-on: ubuntu-latest if: "contains(github.event.pull_request.labels.*.name, 'python dev')" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python 3.11 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: "3.11-dev" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c31cab71c..ba9955a31 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: # Standard hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: "v4.3.0" hooks: - id: check-added-large-files - id: check-case-conflict @@ -29,73 +29,92 @@ repos: - id: mixed-line-ending - id: requirements-txt-fixer - id: trailing-whitespace - - id: fix-encoding-pragma - exclude: ^noxfile.py$ +# Upgrade old Python syntax - repo: https://github.com/asottile/pyupgrade - rev: v2.31.0 + rev: "v2.37.1" hooks: - id: pyupgrade + args: [--py36-plus] +# Nicely sort includes - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: "5.10.1" hooks: - id: isort # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: 21.12b0 # Keep in sync with blacken-docs + rev: "22.6.0" # Keep in sync with blacken-docs hooks: - id: black +# Also code format the docs - repo: https://github.com/asottile/blacken-docs - rev: v1.12.0 + rev: "v1.12.1" hooks: - id: blacken-docs additional_dependencies: - - black==21.12b0 # keep in sync with black hook + - black==22.6.0 # keep in sync with black hook # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.1.10 + rev: "v1.3.0" hooks: - id: remove-tabs +- repo: https://github.com/sirosen/texthooks + rev: "0.3.1" + hooks: + - id: fix-ligatures + - id: fix-smartquotes + # Autoremoves unused imports - repo: https://github.com/hadialqattan/pycln - rev: v1.1.0 + rev: "v2.0.1" hooks: - id: pycln + stages: [manual] +# Checking for common mistakes - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 + rev: "v1.9.0" hooks: - id: python-check-blanket-noqa - id: python-check-blanket-type-ignore - id: python-no-log-warn + - id: python-use-type-annotations - id: rst-backticks - id: rst-directive-colons - id: rst-inline-touching-normal -# Flake8 also supports pre-commit natively (same author) -- repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 +# Automatically remove noqa that are not used +- repo: https://github.com/asottile/yesqa + rev: "v1.3.0" hooks: - - id: flake8 + - id: yesqa additional_dependencies: &flake8_dependencies - flake8-bugbear - pep8-naming - exclude: ^(docs/.*|tools/.*)$ -- repo: https://github.com/asottile/yesqa - rev: v1.3.0 +# Flake8 also supports pre-commit natively (same author) +- repo: https://github.com/PyCQA/flake8 + rev: "4.0.1" hooks: - - id: yesqa + - id: flake8 + exclude: ^(docs/.*|tools/.*)$ additional_dependencies: *flake8_dependencies +# PyLint has native support - not always usable, but works for us +- repo: https://github.com/PyCQA/pylint + rev: "v2.14.4" + hooks: + - id: pylint + files: ^pybind11 + # CMake formatting - repo: https://github.com/cheshirekow/cmake-format-precommit - rev: v0.6.13 + rev: "v0.6.13" hooks: - id: cmake-format additional_dependencies: [pyyaml] @@ -104,44 +123,48 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.931 + rev: "v0.961" hooks: - id: mypy - # Running per-file misbehaves a bit, so just run on all files, it's fast - pass_filenames: false - additional_dependencies: [typed_ast] + args: [] + exclude: ^(tests|docs)/ + additional_dependencies: [nox, rich] # Checks the manifest for missing files (native support) - repo: https://github.com/mgedmin/check-manifest - rev: "0.47" + rev: "0.48" hooks: - id: check-manifest # This is a slow hook, so only run this if --hook-stage manual is passed stages: [manual] additional_dependencies: [cmake, ninja] +# Check for spelling - repo: https://github.com/codespell-project/codespell - rev: v2.1.0 + rev: "v2.1.0" hooks: - id: codespell exclude: ".supp$" args: ["-L", "nd,ot,thist"] +# Check for common shell mistakes - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.8.0.3 + rev: "v0.8.0.4" hooks: - id: shellcheck -# The original pybind11 checks for a few C++ style items +# Disallow some common capitalization mistakes - repo: local hooks: - id: disallow-caps name: Disallow improper capitalization language: pygrep entry: PyBind|Numpy|Cmake|CCache|PyTest - exclude: .pre-commit-config.yaml + exclude: ^\.pre-commit-config.yaml$ +# Clang format the codebase automatically - repo: https://github.com/pre-commit/mirrors-clang-format - rev: "v13.0.0" + rev: "v14.0.6" hooks: - id: clang-format + types_or: [c++, c, cuda] diff --git a/MANIFEST.in b/MANIFEST.in index aed183e87..033303a74 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ recursive-include pybind11/include/pybind11 *.h recursive-include pybind11 *.py recursive-include pybind11 py.typed -recursive-include pybind11 *.pyi include pybind11/share/cmake/pybind11/*.cmake include LICENSE README.rst pyproject.toml setup.py setup.cfg diff --git a/README.rst b/README.rst index 45c4af5a6..3c75edb57 100644 --- a/README.rst +++ b/README.rst @@ -32,9 +32,9 @@ this heavy machinery has become an excessively large and unnecessary dependency. Think of this library as a tiny self-contained version of Boost.Python -with everything stripped away that isn’t relevant for binding +with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K -lines of code and depend on Python (2.7 or 3.5+, or PyPy) and the C++ +lines of code and depend on Python (3.6+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to some of the new C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has @@ -78,8 +78,8 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an - implementation-agnostic interface. +- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic + interface (pybind11 2.9 was the last version to support Python 2 and 3.5). - It is possible to bind C++11 lambda functions with captured variables. The lambda capture data is stored inside the resulting @@ -88,8 +88,8 @@ goodies: - pybind11 uses C++11 move constructors and move assignment operators whenever possible to efficiently transfer custom data types. -- It’s easy to expose the internal storage of custom data types through - Pythons’ buffer protocols. This is handy e.g. for fast conversion +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between C++ matrix classes like Eigen and NumPy without expensive copy operations. @@ -119,10 +119,10 @@ goodies: Supported compilers ------------------- -1. Clang/LLVM 3.3 or newer (for Apple Xcode’s clang, this is 5.0.0 or +1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer) 2. GCC 4.8 or newer -3. Microsoft Visual Studio 2015 Update 3 or newer +3. Microsoft Visual Studio 2017 or newer 4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI) 5. Cygwin/GCC (previously tested on 2.5.1) 6. NVCC (CUDA 11.0 tested in CI) diff --git a/docs/Doxyfile b/docs/Doxyfile index 62c267556..09138db36 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -18,5 +18,4 @@ ALIASES += "endrst=\endverbatim" QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = NO -PREDEFINED = PY_MAJOR_VERSION=3 \ - PYBIND11_NOINLINE +PREDEFINED = PYBIND11_NOINLINE diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 000000000..7a49a6ac4 --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,3 @@ +.highlight .go { + color: #707070; +} diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css deleted file mode 100644 index 1071809fa..000000000 --- a/docs/_static/theme_overrides.css +++ /dev/null @@ -1,11 +0,0 @@ -.wy-table-responsive table td, -.wy-table-responsive table th { - white-space: initial !important; -} -.rst-content table.docutils td { - vertical-align: top !important; -} -div[class^='highlight'] pre { - white-space: pre; - white-space: pre-wrap; -} diff --git a/docs/advanced/cast/overview.rst b/docs/advanced/cast/overview.rst index 6a834a3e5..011bd4c7a 100644 --- a/docs/advanced/cast/overview.rst +++ b/docs/advanced/cast/overview.rst @@ -167,5 +167,4 @@ as arguments and return values, refer to the section on binding :ref:`classes`. +------------------------------------+---------------------------+-----------------------------------+ .. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and - ``os.PathLike`` is converted to ``std::filesystem::path``, but this requires - Python 3.6 (for ``__fspath__`` support). + ``os.PathLike`` is converted to ``std::filesystem::path``. diff --git a/docs/advanced/cast/stl.rst b/docs/advanced/cast/stl.rst index b8622ee09..109763f7a 100644 --- a/docs/advanced/cast/stl.rst +++ b/docs/advanced/cast/stl.rst @@ -87,8 +87,6 @@ included to tell pybind11 how to visit the variant. pybind11 only supports the modern implementation of ``boost::variant`` which makes use of variadic templates. This requires Boost 1.56 or newer. - Additionally, on Windows, MSVC 2017 is required because ``boost::variant`` - falls back to the old non-variadic implementation on MSVC 2015. .. _opaque: diff --git a/docs/advanced/cast/strings.rst b/docs/advanced/cast/strings.rst index cfd7e7b7a..e246c5219 100644 --- a/docs/advanced/cast/strings.rst +++ b/docs/advanced/cast/strings.rst @@ -1,14 +1,6 @@ Strings, bytes and Unicode conversions ###################################### -.. note:: - - This section discusses string handling in terms of Python 3 strings. For - Python 2.7, replace all occurrences of ``str`` with ``unicode`` and - ``bytes`` with ``str``. Python 2.7 users may find it best to use ``from - __future__ import unicode_literals`` to avoid unintentionally using ``str`` - instead of ``unicode``. - Passing Python strings to C++ ============================= @@ -58,9 +50,9 @@ Passing bytes to C++ -------------------- A Python ``bytes`` object will be passed to C++ functions that accept -``std::string`` or ``char*`` *without* conversion. On Python 3, in order to -make a function *only* accept ``bytes`` (and not ``str``), declare it as taking -a ``py::bytes`` argument. +``std::string`` or ``char*`` *without* conversion. In order to make a function +*only* accept ``bytes`` (and not ``str``), declare it as taking a ``py::bytes`` +argument. Returning C++ strings to Python @@ -204,11 +196,6 @@ decoded to Python ``str``. } ); -.. warning:: - - Wide character strings may not work as described on Python 2.7 or Python - 3.3 compiled with ``--enable-unicode=ucs2``. - Strings in multibyte encodings such as Shift-JIS must transcoded to a UTF-8/16/32 before being returned to Python. diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst index f3339336d..49ddf5c0b 100644 --- a/docs/advanced/classes.rst +++ b/docs/advanced/classes.rst @@ -133,14 +133,14 @@ a virtual method call. >>> from example import * >>> d = Dog() >>> call_go(d) - u'woof! woof! woof! ' + 'woof! woof! woof! ' >>> class Cat(Animal): ... def go(self, n_times): ... return "meow! " * n_times ... >>> c = Cat() >>> call_go(c) - u'meow! meow! meow! ' + 'meow! meow! meow! ' If you are defining a custom constructor in a derived Python class, you *must* ensure that you explicitly call the bound C++ constructor using ``__init__``, @@ -813,26 +813,21 @@ An instance can now be pickled as follows: .. code-block:: python - try: - import cPickle as pickle # Use cPickle on Python 2.7 - except ImportError: - import pickle + import pickle p = Pickleable("test_value") p.setExtra(15) - data = pickle.dumps(p, 2) + data = pickle.dumps(p) .. note:: - Note that only the cPickle module is supported on Python 2.7. - - The second argument to ``dumps`` is also crucial: it selects the pickle - protocol version 2, since the older version 1 is not supported. Newer - versions are also fine—for instance, specify ``-1`` to always use the - latest available version. Beware: failure to follow these instructions - will cause important pybind11 memory allocation routines to be skipped - during unpickling, which will likely lead to memory corruption and/or - segmentation faults. + If given, the second argument to ``dumps`` must be 2 or larger - 0 and 1 are + not supported. Newer versions are also fine; for instance, specify ``-1`` to + always use the latest available version. Beware: failure to follow these + instructions will cause important pybind11 memory allocation routines to be + skipped during unpickling, which will likely lead to memory corruption + and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and + version 4 for Python 3.8+. .. seealso:: @@ -849,11 +844,9 @@ Python normally uses references in assignments. Sometimes a real copy is needed to prevent changing all copies. The ``copy`` module [#f5]_ provides these capabilities. -On Python 3, a class with pickle support is automatically also (deep)copy +A class with pickle support is automatically also (deep)copy compatible. However, performance can be improved by adding custom -``__copy__`` and ``__deepcopy__`` methods. With Python 2.7, these custom methods -are mandatory for (deep)copy compatibility, because pybind11 only supports -cPickle. +``__copy__`` and ``__deepcopy__`` methods. For simple classes (deep)copy can be enabled by using the copy constructor, which should look as follows: @@ -1125,13 +1118,6 @@ described trampoline: py::class_(m, "A") // <-- `Trampoline` here .def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`! -.. note:: - - MSVC 2015 has a compiler bug (fixed in version 2017) which - requires a more explicit function binding in the form of - ``.def("foo", static_cast(&Publicist::foo));`` - where ``int (A::*)() const`` is the type of ``A::foo``. - Binding final classes ===================== diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index 7cd8447b9..2211caf5d 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -328,8 +328,8 @@ an invalid state. Chaining exceptions ('raise from') ================================== -In Python 3.3 a mechanism for indicating that exceptions were caused by other -exceptions was introduced: +Python has a mechanism for indicating that exceptions were caused by other +exceptions: .. code-block:: py @@ -340,7 +340,7 @@ exceptions was introduced: To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It sets the current python error indicator, so to continue propagating the exception -you should ``throw py::error_already_set()`` (Python 3 only). +you should ``throw py::error_already_set()``. .. code-block:: cpp diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index bf5b5fa00..69e3d8a1d 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -372,7 +372,7 @@ like so: Keyword-only arguments ====================== -Python 3 introduced keyword-only arguments by specifying an unnamed ``*`` +Python implements keyword-only arguments by specifying an unnamed ``*`` argument in a function definition: .. code-block:: python @@ -395,19 +395,18 @@ argument annotations when registering the function: m.def("f", [](int a, int b) { /* ... */ }, py::arg("a"), py::kw_only(), py::arg("b")); -Note that you currently cannot combine this with a ``py::args`` argument. This -feature does *not* require Python 3 to work. - .. versionadded:: 2.6 -As of pybind11 2.9, a ``py::args`` argument implies that any following arguments -are keyword-only, as if ``py::kw_only()`` had been specified in the same -relative location of the argument list as the ``py::args`` argument. The -``py::kw_only()`` may be included to be explicit about this, but is not -required. (Prior to 2.9 ``py::args`` may only occur at the end of the argument -list, or immediately before a ``py::kwargs`` argument at the end). +A ``py::args`` argument implies that any following arguments are keyword-only, +as if ``py::kw_only()`` had been specified in the same relative location of the +argument list as the ``py::args`` argument. The ``py::kw_only()`` may be +included to be explicit about this, but is not required. + +.. versionchanged:: 2.9 + This can now be combined with ``py::args``. Before, ``py::args`` could only + occur at the end of the argument list, or immediately before a ``py::kwargs`` + argument at the end. -.. versionadded:: 2.9 Positional-only arguments ========================= diff --git a/docs/advanced/pycpp/numpy.rst b/docs/advanced/pycpp/numpy.rst index 30daeefff..b6ef019ed 100644 --- a/docs/advanced/pycpp/numpy.rst +++ b/docs/advanced/pycpp/numpy.rst @@ -87,7 +87,7 @@ buffer objects (e.g. a NumPy matrix). /* Request a buffer descriptor from Python */ py::buffer_info info = b.request(); - /* Some sanity checks ... */ + /* Some basic validation checks ... */ if (info.format != py::format_descriptor::format()) throw std::runtime_error("Incompatible format: expected a double array!"); @@ -395,11 +395,9 @@ uses of ``py::array``: Ellipsis ======== -Python 3 provides a convenient ``...`` ellipsis notation that is often used to +Python provides a convenient ``...`` ellipsis notation that is often used to slice multidimensional arrays. For instance, the following snippet extracts the middle dimensions of a tensor with the first and last index set to zero. -In Python 2, the syntactic sugar ``...`` is not available, but the singleton -``Ellipsis`` (of type ``ellipsis``) can still be used directly. .. code-block:: python @@ -414,8 +412,6 @@ operation on the C++ side: py::array a = /* A NumPy array */; py::array b = a[py::make_tuple(0, py::ellipsis(), 0)]; -.. versionchanged:: 2.6 - ``py::ellipsis()`` is now also available in Python 2. Memory view =========== @@ -455,9 +451,5 @@ We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer: ); }) -.. note:: - - ``memoryview::from_memory`` is not available in Python 2. - .. versionchanged:: 2.6 ``memoryview::from_memory`` added. diff --git a/docs/basics.rst b/docs/basics.rst index e0479b298..e9b24c7fa 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -32,8 +32,7 @@ The last line will both compile and run the tests. Windows ------- -On Windows, only **Visual Studio 2015** and newer are supported since pybind11 relies -on various C++11 language features that break older versions of Visual Studio. +On Windows, only **Visual Studio 2017** and newer are supported. .. Note:: @@ -166,12 +165,12 @@ load and execute the example: .. code-block:: pycon $ python - Python 2.7.10 (default, Aug 22 2015, 20:33:39) - [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin + Python 3.9.10 (main, Jan 15 2022, 11:48:04) + [Clang 13.0.0 (clang-1300.0.29.3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> example.add(1, 2) - 3L + 3 >>> .. _keyword_args: diff --git a/docs/benchmark.py b/docs/benchmark.py index f19079367..2150b6ca7 100644 --- a/docs/benchmark.py +++ b/docs/benchmark.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import datetime as dt import os import random @@ -12,20 +11,20 @@ def generate_dummy_code_pybind11(nclasses=10): bindings = "" for cl in range(nclasses): - decl += "class cl%03i;\n" % cl + decl += f"class cl{cl:03};\n" decl += "\n" for cl in range(nclasses): - decl += "class cl%03i {\n" % cl + decl += f"class {cl:03} {{\n" decl += "public:\n" - bindings += ' py::class_(m, "cl%03i")\n' % (cl, cl) + bindings += f' py::class_(m, "cl{cl:03}")\n' for fn in range(nfns): ret = random.randint(0, nclasses - 1) params = [random.randint(0, nclasses - 1) for i in range(nargs)] - decl += " cl%03i *fn_%03i(" % (ret, fn) - decl += ", ".join("cl%03i *" % p for p in params) + decl += f" cl{ret:03} *fn_{fn:03}(" + decl += ", ".join(f"cl{p:03} *" for p in params) decl += ");\n" - bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % (fn, cl, fn) + bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03})\n' decl += "};\n\n" bindings += " ;\n" @@ -43,23 +42,20 @@ def generate_dummy_code_boost(nclasses=10): bindings = "" for cl in range(nclasses): - decl += "class cl%03i;\n" % cl + decl += f"class cl{cl:03};\n" decl += "\n" for cl in range(nclasses): decl += "class cl%03i {\n" % cl decl += "public:\n" - bindings += ' py::class_("cl%03i")\n' % (cl, cl) + bindings += f' py::class_("cl{cl:03}")\n' for fn in range(nfns): ret = random.randint(0, nclasses - 1) params = [random.randint(0, nclasses - 1) for i in range(nargs)] - decl += " cl%03i *fn_%03i(" % (ret, fn) - decl += ", ".join("cl%03i *" % p for p in params) + decl += f" cl{ret:03} *fn_{fn:03}(" + decl += ", ".join(f"cl{p:03} *" for p in params) decl += ");\n" - bindings += ( - ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy())\n' - % (fn, cl, fn) - ) + bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03}, py::return_value_policy())\n' decl += "};\n\n" bindings += " ;\n" @@ -75,7 +71,7 @@ def generate_dummy_code_boost(nclasses=10): for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: print("{") for i in range(0, 10): - nclasses = 2 ** i + nclasses = 2**i with open("test.cpp", "w") as f: f.write(codegen(nclasses)) n1 = dt.datetime.now() diff --git a/docs/changelog.rst b/docs/changelog.rst index e96db74bf..b926b27af 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,49 +9,182 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning Changes will be added here periodically from the "Suggested changelog entry" block in pull request descriptions. -IN DEVELOPMENT --------------- +Version 2.10.0 (Jul 15, 2022) +----------------------------- Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC 2017 is limited due to availability of CI runners; we highly recommend MSVC -2019 or 2022 be used. +2019 or 2022 be used. Initial support added for Python 3.11. New features: +* ``py::anyset`` & ``py::frozenset`` were added, with copying (cast) to + ``std::set`` (similar to ``set``). + `#3901 `_ + +* Support bytearray casting to string. + `#3707 `_ + * ``type_caster`` was added. ``std::monostate`` is a tag type that allows ``std::variant`` to act as an optional, or allows default construction of a ``std::variant`` holding a non-default constructible type. `#3818 `_ -* Support bytearray casting to string. - `#3707 `_ +* ``pybind11::capsule::set_name`` added to mutate the name of the capsule instance. + `#3866 `_ + +* NumPy: dtype constructor from type number added, accessors corresponding to + Python API ``dtype.num``, ``dtype.byteorder``, ``dtype.flags`` and + ``dtype.alignment`` added. + `#3868 `_ + Changes: -* Python 2 support was removed completely. +* Python 3.6 is now the minimum supported version. `#3688 `_ + `#3719 `_ * The minimum version for MSVC is now 2017. `#3722 `_ +* Fix issues with CPython 3.11 betas and add to supported test matrix. + `#3923 `_ + +* ``error_already_set`` is now safer and more performant, especially for + exceptions with long tracebacks, by delaying computation. + `#1895 `_ + * Improve exception handling in python ``str`` bindings. `#3826 `_ * The bindings for capsules now have more consistent exception handling. `#3825 `_ -* Fix exception handling when ``pybind11::weakref()`` fails. - `#3739 `_ +* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can now be + used to define classes in namespaces other than pybind11. + `#3797 `_ + +* Error printing code now uses ``PYBIND11_DETAILED_ERROR_MESSAGES`` instead of + requiring ``NDEBUG``, allowing use with release builds if desired. + `#3913 `_ + +* Implicit conversion of the literal ``0`` to ``pybind11::handle`` is now disabled. + `#4008 `_ Bug fixes: -* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can be used - to define classes in namespaces other than pybind11. - `#3797 `_ +* Fix exception handling when ``pybind11::weakref()`` fails. + `#3739 `_ + +* ``module_::def_submodule`` was missing proper error handling. This is fixed now. + `#3973 `_ + +* The behavior or ``error_already_set`` was made safer and the highly opaque + "Unknown internal error occurred" message was replaced with a more helpful + message. + `#3982 `_ + +* ``error_already_set::what()`` now handles non-normalized exceptions correctly. + `#3971 `_ + +* Support older C++ compilers where filesystem is not yet part of the standard + library and is instead included in ``std::experimental::filesystem``. + `#3840 `_ + +* Fix ``-Wfree-nonheap-object`` warnings produced by GCC by avoiding returning + pointers to static objects with ``return_value_policy::take_ownership``. + `#3946 `_ + +* Fix cast from pytype rvalue to another pytype. + `#3949 `_ + +* Ensure proper behavior when garbage collecting classes with dynamic attributes in Python >=3.9. + `#4051 `_ + +* A couple long-standing ``PYBIND11_NAMESPACE`` + ``__attribute__((visibility("hidden")))`` inconsistencies are now fixed + (affects only unusual environments). + `#4043 `_ + +* ``pybind11::detail::get_internals()`` is now resilient to in-flight Python + exceptions. + `#3981 `_ + +* Arrays with a dimension of size 0 are now properly converted to dynamic Eigen + matrices (more common in NumPy 1.23). + `#4038 `_ + +* Avoid catching unrelated errors when importing NumPy. + `#3974 `_ + +Performance and style: + +* Added an accessor overload of ``(object &&key)`` to reference steal the + object when using python types as keys. This prevents unnecessary reference + count overhead for attr, dictionary, tuple, and sequence look ups. Added + additional regression tests. Fixed a performance bug the caused accessor + assignments to potentially perform unnecessary copies. + `#3970 `_ + +* Perfect forward all args of ``make_iterator``. + `#3980 `_ + +* Avoid potential bug in pycapsule destructor by adding an ``error_guard`` to + one of the dtors. + `#3958 `_ + +* Optimize dictionary access in ``strip_padding`` for numpy. + `#3994 `_ + +* ``stl_bind.h`` bindings now take slice args as a const-ref. + `#3852 `_ + +* Made slice constructor more consistent, and improve performance of some + casters by allowing reference stealing. + `#3845 `_ + +* Change numpy dtype from_args method to use const ref. + `#3878 `_ + +* Follow rule of three to ensure ``PyErr_Restore`` is called only once. + `#3872 `_ + +* Added missing perfect forwarding for ``make_iterator`` functions. + `#3860 `_ + +* Optimize c++ to python function casting by using the rvalue caster. + `#3966 `_ + +* Optimize Eigen sparse matrix casting by removing unnecessary temporary. + `#4064 `_ + +* Avoid potential implicit copy/assignment constructors causing double free in + ``strdup_gaurd``. + `#3905 `_ + +* Enable clang-tidy checks ``misc-definitions-in-headers``, + ``modernize-loop-convert``, and ``modernize-use-nullptr``. + `#3881 `_ + `#3988 `_ + Build system improvements: +* CMake: Fix file extension on Windows with cp36 and cp37 using FindPython. + `#3919 `_ + +* CMake: Support multiple Python targets (such as on vcpkg). + `#3948 `_ + +* CMake: Fix issue with NVCC on Windows. + `#3947 `_ + +* CMake: Drop the bitness check on cross compiles (like targeting WebAssembly + via Emscripten). + `#3959 `_ + * Add MSVC builds in debug mode to CI. `#3784 `_ @@ -59,15 +192,23 @@ Build system improvements: `#3732 `_, `#3741 `_ -* Avoid ``setup.py `` usage in internal tests. - `#3734 `_ - Backend and tidying up: -* Remove idioms in code comments. Use inclusive language. +* New theme for the documentation. + `#3109 `_ + +* Remove idioms in code comments. Use more inclusive language. `#3809 `_ +* ``#include `` was removed from the ``pybind11/stl.h`` header. Your + project may break if it has a transitive dependency on this include. The fix + is to "Include What You Use". + `#3928 `_ + +* Avoid ``setup.py `` usage in internal tests. + `#3734 `_ + Version 2.9.2 (Mar 29, 2022) ---------------------------- @@ -919,7 +1060,7 @@ Packaging / building improvements: `#2338 `_ and `#2370 `_ - * Full integration with CMake’s C++ standard system and compile features + * Full integration with CMake's C++ standard system and compile features replaces ``PYBIND11_CPP_STANDARD``. * Generated config file is now portable to different Python/compiler/CMake diff --git a/docs/classes.rst b/docs/classes.rst index 13fa8b538..c0c53135b 100644 --- a/docs/classes.rst +++ b/docs/classes.rst @@ -48,10 +48,10 @@ interactive Python session demonstrating this example is shown below: >>> print(p) >>> p.getName() - u'Molly' + 'Molly' >>> p.setName("Charly") >>> p.getName() - u'Charly' + 'Charly' .. seealso:: @@ -124,10 +124,10 @@ This makes it possible to write >>> p = example.Pet("Molly") >>> p.name - u'Molly' + 'Molly' >>> p.name = "Charly" >>> p.name - u'Charly' + 'Charly' Now suppose that ``Pet::name`` was a private internal variable that can only be accessed via setters and getters. @@ -282,9 +282,9 @@ expose fields and methods of both types: >>> p = example.Dog("Molly") >>> p.name - u'Molly' + 'Molly' >>> p.bark() - u'woof!' + 'woof!' The C++ classes defined above are regular non-polymorphic types with an inheritance relationship. This is reflected in Python: @@ -332,7 +332,7 @@ will automatically recognize this: >>> type(p) PolymorphicDog # automatically downcast >>> p.bark() - u'woof!' + 'woof!' Given a pointer to a polymorphic base, pybind11 performs automatic downcasting to the actual derived type. Note that this goes beyond the usual situation in @@ -434,8 +434,7 @@ you can use ``py::detail::overload_cast_impl`` with an additional set of parenth .def("set", overload_cast_()(&Pet::set), "Set the pet's age") .def("set", overload_cast_()(&Pet::set), "Set the pet's name"); -.. [#cpp14] A compiler which supports the ``-std=c++14`` flag - or Visual Studio 2015 Update 2 and newer. +.. [#cpp14] A compiler which supports the ``-std=c++14`` flag. .. note:: @@ -483,7 +482,7 @@ The binding code for this example looks as follows: .value("Cat", Pet::Kind::Cat) .export_values(); - py::class_ attributes(pet, "Attributes") + py::class_(pet, "Attributes") .def(py::init<>()) .def_readwrite("age", &Pet::Attributes::age); diff --git a/docs/compiling.rst b/docs/compiling.rst index 25adb9fcf..2b543be0b 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -417,10 +417,10 @@ existing targets instead: .. code-block:: cmake - cmake_minimum_required(VERSION 3.15...3.19) + cmake_minimum_required(VERSION 3.15...3.22) project(example LANGUAGES CXX) - find_package(Python COMPONENTS Interpreter Development REQUIRED) + find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 CONFIG REQUIRED) # or add_subdirectory(pybind11) @@ -433,9 +433,8 @@ algorithms from the CMake invocation, with ``-DPYBIND11_FINDPYTHON=ON``. .. warning:: - If you use FindPython2 and FindPython3 to dual-target Python, use the - individual targets listed below, and avoid targets that directly include - Python parts. + If you use FindPython to multi-target Python versions, use the individual + targets listed below, and avoid targets that directly include Python parts. There are `many ways to hint or force a discovery of a specific Python installation `_), @@ -462,11 +461,8 @@ available in all modes. The targets provided are: ``pybind11::headers`` Just the pybind11 headers and minimum compile requirements - ``pybind11::python2_no_register`` - Quiets the warning/error when mixing C++14 or higher and Python 2 - ``pybind11::pybind11`` - Python headers + ``pybind11::headers`` + ``pybind11::python2_no_register`` (Python 2 only) + Python headers + ``pybind11::headers`` ``pybind11::python_link_helper`` Just the "linking" part of pybind11:module @@ -509,7 +505,10 @@ You can use these targets to build complex applications. For example, the target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras) pybind11_extension(example) - pybind11_strip(example) + if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo) + # Strip unnecessary sections of the binary on Linux/macOS + pybind11_strip(example) + endif() set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden" CUDA_VISIBILITY_PRESET "hidden") @@ -577,21 +576,12 @@ On Linux, you can compile an example such as the one given in $ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix) -The flags given here assume that you're using Python 3. For Python 2, just -change the executable appropriately (to ``python`` or ``python2``). - The ``python3 -m pybind11 --includes`` command fetches the include paths for both pybind11 and Python headers. This assumes that pybind11 has been installed using ``pip`` or ``conda``. If it hasn't, you can also manually specify ``-I /include`` together with the Python includes path ``python3-config --includes``. -Note that Python 2.7 modules don't use a special suffix, so you should simply -use ``example.so`` instead of ``example$(python3-config --extension-suffix)``. -Besides, the ``--extension-suffix`` option may or may not be available, depending -on the distribution; in the latter case, the module extension can be manually -set to ``.so``. - On macOS: the build command is almost the same but it also requires passing the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when building the module: diff --git a/docs/conf.py b/docs/conf.py index 092e274e0..2da6773f4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # pybind11 documentation build configuration file, created by # sphinx-quickstart on Sun Oct 11 19:23:48 2015. @@ -36,6 +35,7 @@ DIR = Path(__file__).parent.resolve() # ones. extensions = [ "breathe", + "sphinx_copybutton", "sphinxcontrib.rsvgconverter", "sphinxcontrib.moderncmakedomain", ] @@ -126,23 +126,7 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -on_rtd = os.environ.get("READTHEDOCS", None) == "True" - -if not on_rtd: # only import and set the theme if we're building docs locally - import sphinx_rtd_theme - - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - - html_context = {"css_files": ["_static/theme_overrides.css"]} -else: - html_context = { - "css_files": [ - "//media.readthedocs.org/css/sphinx_rtd_theme.css", - "//media.readthedocs.org/css/readthedocs-doc-embed.css", - "_static/theme_overrides.css", - ] - } +html_theme = "furo" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -173,6 +157,10 @@ else: # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] +html_css_files = [ + "css/custom.css", +] + # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. @@ -345,9 +333,9 @@ def generate_doxygen_xml(app): subprocess.call(["doxygen", "--version"]) retcode = subprocess.call(["doxygen"], cwd=app.confdir) if retcode < 0: - sys.stderr.write("doxygen error code: {}\n".format(-retcode)) + sys.stderr.write(f"doxygen error code: {-retcode}\n") except OSError as e: - sys.stderr.write("doxygen execution failed: {}\n".format(e)) + sys.stderr.write(f"doxygen execution failed: {e}\n") def prepare(app): diff --git a/docs/faq.rst b/docs/faq.rst index e2f477b1f..28498e7df 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -8,9 +8,7 @@ Frequently asked questions filename of the extension library (without suffixes such as ``.so``). 2. If the above did not fix the issue, you are likely using an incompatible -version of Python (for instance, the extension library was compiled against -Python 2, while the interpreter is running on top of some version of Python -3, or vice versa). +version of Python that does not match what you compiled with. "Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``" ======================================================================== @@ -147,7 +145,7 @@ using C++14 template metaprogramming. .. _`faq:hidden_visibility`: -"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]" +"'SomeClass' declared with greater visibility than the type of its field 'SomeClass::member' [-Wattributes]" ============================================================================================================ This error typically indicates that you are compiling without the required @@ -222,20 +220,6 @@ In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids potential serious issues when loading multiple modules and is required for proper pybind operation. See the previous FAQ entry for more details. -Working with ancient Visual Studio 2008 builds on Windows -========================================================= - -The official Windows distributions of Python are compiled using truly -ancient versions of Visual Studio that lack good C++11 support. Some users -implicitly assume that it would be impossible to load a plugin built with -Visual Studio 2015 into a Python distribution that was compiled using Visual -Studio 2008. However, no such issue exists: it's perfectly legitimate to -interface DLLs that are built with different compilers and/or C libraries. -Common gotchas to watch out for involve not ``free()``-ing memory region -that that were ``malloc()``-ed in another shared library, using data -structures with incompatible ABIs, and so on. pybind11 is very careful not -to make these types of mistakes. - How can I properly handle Ctrl-C in long-running functions? =========================================================== @@ -289,27 +273,7 @@ Conflicts can arise, however, when using pybind11 in a project that *also* uses the CMake Python detection in a system with several Python versions installed. This difference may cause inconsistencies and errors if *both* mechanisms are -used in the same project. Consider the following CMake code executed in a -system with Python 2.7 and 3.x installed: - -.. code-block:: cmake - - find_package(PythonInterp) - find_package(PythonLibs) - find_package(pybind11) - -It will detect Python 2.7 and pybind11 will pick it as well. - -In contrast this code: - -.. code-block:: cmake - - find_package(pybind11) - find_package(PythonInterp) - find_package(PythonLibs) - -will detect Python 3.x for pybind11 and may crash on -``find_package(PythonLibs)`` afterwards. +used in the same project. There are three possible solutions: diff --git a/docs/pybind11-logo.png b/docs/pybind11-logo.png index 4cbad54f7..2d633a4d0 100644 Binary files a/docs/pybind11-logo.png and b/docs/pybind11-logo.png differ diff --git a/docs/requirements.txt b/docs/requirements.txt index b2801b1f0..d2a9ae164 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,6 @@ -breathe==4.31.0 -sphinx==3.5.4 -sphinx_rtd_theme==1.0.0 -sphinxcontrib-moderncmakedomain==3.19 -sphinxcontrib-svg2pdfconverter==1.1.1 +breathe==4.34.0 +furo==2022.6.21 +sphinx==5.0.2 +sphinx-copybutton==0.5.0 +sphinxcontrib-moderncmakedomain==3.21.4 +sphinxcontrib-svg2pdfconverter==1.2.0 diff --git a/docs/upgrade.rst b/docs/upgrade.rst index d91d51e6f..6a9db2d08 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -524,7 +524,7 @@ include a declaration of the form: PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) -Continuing to do so won’t cause an error or even a deprecation warning, +Continuing to do so won't cause an error or even a deprecation warning, but it's completely redundant. diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index de95f89d0..db7cd8eff 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -10,6 +10,7 @@ #pragma once +#include "detail/common.h" #include "cast.h" #include @@ -61,7 +62,7 @@ struct base { PYBIND11_DEPRECATED( "base() was deprecated in favor of specifying 'T' as a template argument to class_") - base() {} // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + base() = default; }; /// Keep patient alive while nurse lives @@ -82,8 +83,7 @@ struct metaclass { handle value; PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") - // NOLINTNEXTLINE(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute - metaclass() {} + metaclass() = default; /// Override pybind11's default metaclass explicit metaclass(handle value) : value(value) {} @@ -345,9 +345,11 @@ struct type_record { bases.append((PyObject *) base_info->type); - if (base_info->type->tp_dictoffset != 0) { - dynamic_attr = true; - } +#if PY_VERSION_HEX < 0x030B0000 + dynamic_attr |= base_info->type->tp_dictoffset != 0; +#else + dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0; +#endif if (caster) { base_info->implicit_casts.emplace_back(type, caster); @@ -478,7 +480,7 @@ struct process_attribute : process_attribute_default { } if (!a.value) { -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string descr("'"); if (a.name) { descr += std::string(a.name) + ": "; @@ -499,7 +501,8 @@ struct process_attribute : process_attribute_default { #else pybind11_fail("arg(): could not convert default argument " "into a Python object (type not registered yet?). " - "Compile in debug mode for more information."); + "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " + "more information."); #endif } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 5b7fb24f0..a0e32281b 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -329,7 +329,7 @@ public: res = 0; // None is implicitly converted to False } #if defined(PYPY_VERSION) - // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists + // On PyPy, check that "__bool__" attr exists else if (hasattr(src, PYBIND11_BOOL_ATTR)) { res = PyObject_IsTrue(src.ptr()); } @@ -379,37 +379,16 @@ struct string_caster { static constexpr size_t UTF_N = 8 * sizeof(CharT); bool load(handle src, bool) { -#if PY_MAJOR_VERSION < 3 - object temp; -#endif handle load_src = src; if (!src) { return false; } if (!PyUnicode_Check(load_src.ptr())) { -#if PY_MAJOR_VERSION >= 3 - return load_bytes(load_src); -#else - if (std::is_same::value) { - return load_bytes(load_src); - } - - // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false - if (!PYBIND11_BYTES_CHECK(load_src.ptr())) - return false; - - temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); - if (!temp) { - PyErr_Clear(); - return false; - } - load_src = temp; -#endif + return load_raw(load_src); } -#if PY_VERSION_HEX >= 0x03030000 - // On Python >= 3.3, for UTF-8 we avoid the need for a temporary `bytes` - // object by using `PyUnicode_AsUTF8AndSize`. + // For UTF-8 we avoid the need for a temporary `bytes` object by using + // `PyUnicode_AsUTF8AndSize`. if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) { Py_ssize_t size = -1; const auto *buffer @@ -421,7 +400,6 @@ struct string_caster { value = StringType(buffer, static_cast(size)); return true; } -#endif auto utfNbytes = reinterpret_steal(PyUnicode_AsEncodedString(load_src.ptr(), @@ -484,26 +462,37 @@ private: #endif } - // When loading into a std::string or char*, accept a bytes object as-is (i.e. + // When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e. // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. // which supports loading a unicode from a str, doesn't take this path. template - bool load_bytes(enable_if_t::value, handle> src) { + bool load_raw(enable_if_t::value, handle> src) { if (PYBIND11_BYTES_CHECK(src.ptr())) { - // We were passed a Python 3 raw bytes; accept it into a std::string or char* + // We were passed raw bytes; accept it into a std::string or char* // without any encoding attempt. const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); - if (bytes) { - value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); - return true; + if (!bytes) { + pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure."); } + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + if (PyByteArray_Check(src.ptr())) { + // We were passed a bytearray; accept it into a std::string or char* + // without any encoding attempt. + const char *bytearray = PyByteArray_AsString(src.ptr()); + if (!bytearray) { + pybind11_fail("Unexpected PyByteArray_AsString() failure."); + } + value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr())); + return true; } return false; } template - bool load_bytes(enable_if_t::value, handle>) { + bool load_raw(enable_if_t::value, handle>) { return false; } }; @@ -525,7 +514,7 @@ struct type_caster, template struct type_caster::value>> { using StringType = std::basic_string; - using StringCaster = type_caster; + using StringCaster = make_caster; StringCaster str_caster; bool none = false; CharT one_char = 0; @@ -788,8 +777,9 @@ protected: return true; } throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " -#if defined(NDEBUG) - "(compile in debug mode for type information)"); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " + "type information)"); #else "of type '" + type_id() + "''"); @@ -856,7 +846,7 @@ struct always_construct_holder { /// Create a specialization for custom holder types (silently ignores std::shared_ptr) #define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \ - namespace pybind11 { \ + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \ namespace detail { \ template \ struct always_construct_holder : always_construct_holder { \ @@ -865,7 +855,7 @@ struct always_construct_holder { class type_caster::value>> \ : public type_caster_holder {}; \ } \ - } + PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) // PYBIND11_DECLARE_HOLDER_TYPE holder types: template @@ -918,6 +908,14 @@ struct handle_type_name { template struct pyobject_caster { + template ::value, int> = 0> + pyobject_caster() : value() {} + + // `type` may not be default constructible (e.g. frozenset, anyset). Initializing `value` + // to a nil handle is safe since it will only be accessed if `load` succeeds. + template ::value, int> = 0> + pyobject_caster() : value(reinterpret_steal(handle())) {} + template ::value, int> = 0> bool load(handle src, bool /* convert */) { value = src; @@ -926,18 +924,6 @@ struct pyobject_caster { template ::value, int> = 0> bool load(handle src, bool /* convert */) { -#if PY_MAJOR_VERSION < 3 && !defined(PYBIND11_STR_LEGACY_PERMISSIVE) - // For Python 2, without this implicit conversion, Python code would - // need to be cluttered with six.ensure_text() or similar, only to be - // un-cluttered later after Python 2 support is dropped. - if (PYBIND11_SILENCE_MSVC_C4127(std::is_same::value) && isinstance(src)) { - PyObject *str_from_bytes = PyUnicode_FromEncodedObject(src.ptr(), "utf-8", nullptr); - if (!str_from_bytes) - throw error_already_set(); - value = reinterpret_steal(str_from_bytes); - return true; - } -#endif if (!isinstance(src)) { return false; } @@ -1023,10 +1009,12 @@ struct return_value_policy_override< // Basic python -> C++ casting; throws if casting fails template type_caster &load_type(type_caster &conv, const handle &handle) { + static_assert(!detail::is_pyobject::value, + "Internal error: type_caster should only be used for C++ types"); if (!conv.load(handle, true)) { -#if defined(NDEBUG) - throw cast_error( - "Unable to cast Python instance to C++ type (compile in debug mode for details)"); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + throw cast_error("Unable to cast Python instance to C++ type (#define " + "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); #else throw cast_error("Unable to cast Python instance of type " + (std::string) str(type::handle_of(handle)) + " to C++ type '" @@ -1091,10 +1079,10 @@ inline void handle::cast() const { template detail::enable_if_t::value, T> move(object &&obj) { if (obj.ref_count() > 1) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error( "Unable to cast Python instance to C++ rvalue: instance has multiple references" - " (compile in debug mode for details)"); + " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); #else throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) + " instance to C++ " + type_id() @@ -1113,21 +1101,30 @@ detail::enable_if_t::value, T> move(object &&obj) { // - If both movable and copyable, check ref count: if 1, move; otherwise copy // - Otherwise (not movable), copy. template -detail::enable_if_t::value, T> cast(object &&object) { +detail::enable_if_t::value && detail::move_always::value, T> +cast(object &&object) { return move(std::move(object)); } template -detail::enable_if_t::value, T> cast(object &&object) { +detail::enable_if_t::value && detail::move_if_unreferenced::value, T> +cast(object &&object) { if (object.ref_count() > 1) { return cast(object); } return move(std::move(object)); } template -detail::enable_if_t::value, T> cast(object &&object) { +detail::enable_if_t::value && detail::move_never::value, T> +cast(object &&object) { return cast(object); } +// pytype rvalue -> pytype (calls converting constructor) +template +detail::enable_if_t::value, T> cast(object &&object) { + return T(std::move(object)); +} + template T object::cast() const & { return pybind11::cast(*this); @@ -1178,24 +1175,27 @@ enable_if_t::value, T> cast_ref(object &&, // static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast // that only does anything in cases where pybind11::cast is valid. template -enable_if_t::value, T> cast_safe(object &&o) { - return pybind11::cast(std::move(o)); -} -template enable_if_t::value, T> cast_safe(object &&) { pybind11_fail("Internal error: cast_safe fallback invoked"); } -template <> -inline void cast_safe(object &&) {} +template +enable_if_t>::value, void> cast_safe(object &&) {} +template +enable_if_t, + std::is_same>>::value, + T> +cast_safe(object &&o) { + return pybind11::cast(std::move(o)); +} PYBIND11_NAMESPACE_END(detail) // The overloads could coexist, i.e. the #if is not strictly speaking needed, // but it is an easy minor optimization. -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) inline cast_error cast_error_unable_to_convert_call_arg() { - return cast_error( - "Unable to convert call argument to Python object (compile in debug mode for details)"); + return cast_error("Unable to convert call argument to Python object (#define " + "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } #else inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name, @@ -1217,7 +1217,7 @@ tuple make_tuple(Args &&...args_) { detail::make_caster::cast(std::forward(args_), policy, nullptr))...}}; for (size_t i = 0; i < args.size(); i++) { if (!args[i]) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error_unable_to_convert_call_arg(); #else std::array argtypes{{type_id()...}}; @@ -1266,10 +1266,10 @@ struct arg_v : arg { private: template arg_v(arg &&base, T &&x, const char *descr = nullptr) - : arg(base), value(reinterpret_steal( - detail::make_caster::cast(x, return_value_policy::automatic, {}))), + : arg(base), value(reinterpret_steal(detail::make_caster::cast( + std::forward(x), return_value_policy::automatic, {}))), descr(descr) -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) , type(type_id()) #endif @@ -1309,7 +1309,7 @@ public: object value; /// The (optional) description of the default value const char *descr; -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) /// The C++ type name of the default value (only available when compiled in debug mode) std::string type; #endif @@ -1317,7 +1317,7 @@ public: /// \ingroup annotations /// Annotation indicating that all following arguments are keyword-only; the is the equivalent of -/// an unnamed '*' argument (in Python 3) +/// an unnamed '*' argument struct kw_only {}; /// \ingroup annotations @@ -1507,14 +1507,14 @@ private: auto o = reinterpret_steal( detail::make_caster::cast(std::forward(x), policy, {})); if (!o) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error_unable_to_convert_call_arg(); #else throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()), type_id()); #endif } - args_list.append(o); + args_list.append(std::move(o)); } void process(list &args_list, detail::args_proxy ap) { @@ -1525,21 +1525,21 @@ private: void process(list & /*args_list*/, arg_v a) { if (!a.name) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) nameless_argument_error(); #else nameless_argument_error(a.type); #endif } if (m_kwargs.contains(a.name)) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) multiple_values_error(); #else multiple_values_error(a.name); #endif } if (!a.value) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error_unable_to_convert_call_arg(); #else throw cast_error_unable_to_convert_call_arg(a.name, a.type); @@ -1554,7 +1554,7 @@ private: } for (auto k : reinterpret_borrow(kp)) { if (m_kwargs.contains(k.first)) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) multiple_values_error(); #else multiple_values_error(str(k.first)); @@ -1565,9 +1565,10 @@ private: } [[noreturn]] static void nameless_argument_error() { - throw type_error("Got kwargs without a name; only named arguments " - "may be passed via py::arg() to a python function call. " - "(compile in debug mode for details)"); + throw type_error( + "Got kwargs without a name; only named arguments " + "may be passed via py::arg() to a python function call. " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } [[noreturn]] static void nameless_argument_error(const std::string &type) { throw type_error("Got kwargs without a name of type '" + type @@ -1575,8 +1576,9 @@ private: "arguments may be passed via py::arg() to a python function call. "); } [[noreturn]] static void multiple_values_error() { - throw type_error("Got multiple values for keyword argument " - "(compile in debug mode for details)"); + throw type_error( + "Got multiple values for keyword argument " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } [[noreturn]] static void multiple_values_error(const std::string &name) { @@ -1623,7 +1625,7 @@ unpacking_collector collect_arguments(Args &&...args) { template template object object_api::operator()(Args &&...args) const { -#if !defined(NDEBUG) && PY_VERSION_HEX >= 0x03060000 +#ifndef NDEBUG if (!PyGILState_Check()) { pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure."); } @@ -1648,12 +1650,12 @@ handle type::handle_of() { } #define PYBIND11_MAKE_OPAQUE(...) \ - namespace pybind11 { \ + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \ namespace detail { \ template <> \ class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \ } \ - } + PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) /// Lets you pass a type containing a `,` through a macro parameter without needing a separate /// typedef, e.g.: diff --git a/include/pybind11/chrono.h b/include/pybind11/chrono.h index ad5e97b02..167ea0e3d 100644 --- a/include/pybind11/chrono.h +++ b/include/pybind11/chrono.h @@ -18,17 +18,6 @@ #include #include -// Backport the PyDateTime_DELTA functions from Python3.3 if required -#ifndef PyDateTime_DELTA_GET_DAYS -# define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta *) o)->days) -#endif -#ifndef PyDateTime_DELTA_GET_SECONDS -# define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta *) o)->seconds) -#endif -#ifndef PyDateTime_DELTA_GET_MICROSECONDS -# define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta *) o)->microseconds) -#endif - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 0e06b94f1..42720f844 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -15,12 +15,12 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) -#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION) +#if !defined(PYPY_VERSION) # define PYBIND11_BUILTIN_QUALNAME # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) #else -// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type -// signatures; in 3.3+ this macro expands to nothing: +// In PyPy, we still set __qualname__ so that we can produce reliable function type +// signatures; in CPython this macro expands to nothing: # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \ setattr((PyObject *) obj, "__qualname__", nameobj) #endif @@ -155,7 +155,6 @@ extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyOb } } -#if PY_MAJOR_VERSION >= 3 /** * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing * methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function, @@ -170,7 +169,6 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name } return PyType_Type.tp_getattro(obj, name); } -#endif /// metaclass `__call__` function that is used to create all pybind11 objects. extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) { @@ -266,9 +264,7 @@ inline PyTypeObject *make_default_metaclass() { type->tp_call = pybind11_meta_call; type->tp_setattro = pybind11_meta_setattro; -#if PY_MAJOR_VERSION >= 3 type->tp_getattro = pybind11_meta_getattro; -#endif type->tp_dealloc = pybind11_meta_dealloc; @@ -459,6 +455,8 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) { #endif } +std::string error_string(); + /** Create the type which can be used as a common base for all classes. This is needed in order to satisfy Python's requirements for multiple inheritance. Return value: New reference. */ @@ -494,7 +492,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { type->tp_weaklistoffset = offsetof(instance, weakrefs); if (PyType_Ready(type) < 0) { - pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); + pybind11_fail("PyType_Ready failed in make_object_base_type(): " + error_string()); } setattr((PyObject *) type, "__module__", str("pybind11_builtins")); @@ -533,6 +531,10 @@ extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { PyObject *&dict = *_PyObject_GetDictPtr(self); Py_VISIT(dict); +// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse +#if PY_VERSION_HEX >= 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif return 0; } @@ -547,8 +549,12 @@ extern "C" inline int pybind11_clear(PyObject *self) { inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { auto *type = &heap_type->ht_type; type->tp_flags |= Py_TPFLAGS_HAVE_GC; +#if PY_VERSION_HEX < 0x030B0000 type->tp_dictoffset = type->tp_basicsize; // place dict at the end type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it +#else + type->tp_flags |= Py_TPFLAGS_MANAGED_DICT; +#endif type->tp_traverse = pybind11_traverse; type->tp_clear = pybind11_clear; @@ -613,9 +619,6 @@ extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) { /// Give this type a buffer interface. inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer; -#if PY_MAJOR_VERSION < 3 - heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; -#endif heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer; heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer; @@ -628,12 +631,8 @@ inline PyObject *make_new_python_type(const type_record &rec) { auto qualname = name; if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) { -#if PY_MAJOR_VERSION >= 3 qualname = reinterpret_steal( PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr())); -#else - qualname = str(rec.scope.attr("__qualname__").cast() + "." + rec.name); -#endif } object module_; @@ -697,15 +696,10 @@ inline PyObject *make_new_python_type(const type_record &rec) { type->tp_as_number = &heap_type->as_number; type->tp_as_sequence = &heap_type->as_sequence; type->tp_as_mapping = &heap_type->as_mapping; -#if PY_VERSION_HEX >= 0x03050000 type->tp_as_async = &heap_type->as_async; -#endif /* Flags */ type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE; -#if PY_MAJOR_VERSION < 3 - type->tp_flags |= Py_TPFLAGS_CHECKTYPES; -#endif if (!rec.is_final) { type->tp_flags |= Py_TPFLAGS_BASETYPE; } @@ -723,7 +717,7 @@ inline PyObject *make_new_python_type(const type_record &rec) { } if (PyType_Ready(type) < 0) { - pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); + pybind11_fail(std::string(rec.name) + ": PyType_Ready failed: " + error_string()); } assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 6e8cfd492..1da323f31 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -10,12 +10,12 @@ #pragma once #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 9 -#define PYBIND11_VERSION_PATCH 2 +#define PYBIND11_VERSION_MINOR 10 +#define PYBIND11_VERSION_PATCH 0 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x02090200 +#define PYBIND11_VERSION_HEX 0x020A0000 #define PYBIND11_NAMESPACE_BEGIN(name) namespace name { #define PYBIND11_NAMESPACE_END(name) } @@ -38,6 +38,7 @@ # define PYBIND11_CPP17 # if __cplusplus >= 202002L # define PYBIND11_CPP20 +// Please update tests/pybind11_tests.cpp `cpp_std()` when adding a macro here. # endif # endif # endif @@ -47,7 +48,7 @@ // or newer. # if _MSVC_LANG >= 201402L # define PYBIND11_CPP14 -# if _MSVC_LANG > 201402L && _MSC_VER >= 1910 +# if _MSVC_LANG > 201402L # define PYBIND11_CPP17 # if _MSVC_LANG >= 202002L # define PYBIND11_CPP20 @@ -81,10 +82,8 @@ # error pybind11 requires gcc 4.8 or newer # endif #elif defined(_MSC_VER) -// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features -// (e.g. std::negation) added in 2015u3: -# if _MSC_FULL_VER < 190024210 -# error pybind11 requires MSVC 2015 update 3 or newer +# if _MSC_VER < 1910 +# error pybind11 2.10+ requires MSVC 2017 or newer # endif #endif @@ -149,7 +148,7 @@ /* Don't let Python.h #define (v)snprintf as macro because they are implemented properly in Visual Studio since 2015. */ -#if defined(_MSC_VER) && _MSC_VER >= 1900 +#if defined(_MSC_VER) # define HAVE_SNPRINTF 1 #endif @@ -211,6 +210,9 @@ #endif #include +#if PY_VERSION_HEX < 0x03060000 +# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5." +#endif #include #include @@ -266,78 +268,37 @@ // If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and // pybind11::isinstance() is true only for pybind11::str. // However, for Python 2 only (!), the pybind11::str caster -// implicitly decodes bytes to PyUnicodeObject. This is to ease +// implicitly decoded bytes to PyUnicodeObject. This was to ease // the transition from the legacy behavior to the non-permissive // behavior. -#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions -# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) -# define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check -# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION -# define PYBIND11_BYTES_CHECK PyBytes_Check -# define PYBIND11_BYTES_FROM_STRING PyBytes_FromString -# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize -# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize -# define PYBIND11_BYTES_AS_STRING PyBytes_AsString -# define PYBIND11_BYTES_SIZE PyBytes_Size -# define PYBIND11_LONG_CHECK(o) PyLong_Check(o) -# define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) -# define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o)) -# define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o)) -# define PYBIND11_BYTES_NAME "bytes" -# define PYBIND11_STRING_NAME "str" -# define PYBIND11_SLICE_OBJECT PyObject -# define PYBIND11_FROM_STRING PyUnicode_FromString -# define PYBIND11_STR_TYPE ::pybind11::str -# define PYBIND11_BOOL_ATTR "__bool__" -# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) -# define PYBIND11_BUILTINS_MODULE "builtins" +/// Compatibility macros for Python 2 / Python 3 versions TODO: remove +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) +#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION +#define PYBIND11_BYTES_CHECK PyBytes_Check +#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_BYTES_SIZE PyBytes_Size +#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) +#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) +#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o)) +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o)) +#define PYBIND11_BYTES_NAME "bytes" +#define PYBIND11_STRING_NAME "str" +#define PYBIND11_SLICE_OBJECT PyObject +#define PYBIND11_FROM_STRING PyUnicode_FromString +#define PYBIND11_STR_TYPE ::pybind11::str +#define PYBIND11_BOOL_ATTR "__bool__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) +#define PYBIND11_BUILTINS_MODULE "builtins" // Providing a separate declaration to make Clang's -Wmissing-prototypes happy. // See comment for PYBIND11_MODULE below for why this is marked "maybe unused". -# define PYBIND11_PLUGIN_IMPL(name) \ - extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \ - extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() - -#else -# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_) -# define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check -# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION -# define PYBIND11_BYTES_CHECK PyString_Check -# define PYBIND11_BYTES_FROM_STRING PyString_FromString -# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize -# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize -# define PYBIND11_BYTES_AS_STRING PyString_AsString -# define PYBIND11_BYTES_SIZE PyString_Size -# define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) -# define PYBIND11_LONG_AS_LONGLONG(o) \ - (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) -# define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed. -# define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed. -# define PYBIND11_BYTES_NAME "str" -# define PYBIND11_STRING_NAME "unicode" -# define PYBIND11_SLICE_OBJECT PySliceObject -# define PYBIND11_FROM_STRING PyString_FromString -# define PYBIND11_STR_TYPE ::pybind11::bytes -# define PYBIND11_BOOL_ATTR "__nonzero__" -# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero) -# define PYBIND11_BUILTINS_MODULE "__builtin__" -// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy. -// See comment for PYBIND11_MODULE below for why this is marked "maybe unused". -# define PYBIND11_PLUGIN_IMPL(name) \ - static PyObject *pybind11_init_wrapper(); \ - extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT void init##name(); \ - extern "C" PYBIND11_EXPORT void init##name() { (void) pybind11_init_wrapper(); } \ - PyObject *pybind11_init_wrapper() -#endif - -#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 -extern "C" { -struct _Py_atomic_address { - void *value; -}; -PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; -} -#endif +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() #define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code #define PYBIND11_STRINGIFY(x) #x @@ -362,31 +323,15 @@ PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; } \ } -#if PY_VERSION_HEX >= 0x03030000 - -# define PYBIND11_CATCH_INIT_EXCEPTIONS \ - catch (pybind11::error_already_set & e) { \ - pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \ - return nullptr; \ - } \ - catch (const std::exception &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } - -#else - -# define PYBIND11_CATCH_INIT_EXCEPTIONS \ - catch (pybind11::error_already_set & e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } \ - catch (const std::exception &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } - -#endif +#define PYBIND11_CATCH_INIT_EXCEPTIONS \ + catch (pybind11::error_already_set & e) { \ + pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \ + return nullptr; \ + } \ + catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } /** \rst ***Deprecated in favor of PYBIND11_MODULE*** @@ -483,7 +428,7 @@ enum class return_value_policy : uint8_t { /** Reference an existing object (i.e. do not create a new copy) and take ownership. Python will call the destructor and delete operator when the - object’s reference count reaches zero. Undefined behavior ensues when + object's reference count reaches zero. Undefined behavior ensues when the C++ side does the same.. */ take_ownership, @@ -499,7 +444,7 @@ enum class return_value_policy : uint8_t { move, /** Reference an existing object, but do not take ownership. The C++ side - is responsible for managing the object’s lifetime and deallocating it + is responsible for managing the object's lifetime and deallocating it when it is no longer used. Warning: undefined behavior will ensue when the C++ side deletes an object that is still referenced and used by Python. */ @@ -508,7 +453,7 @@ enum class return_value_policy : uint8_t { /** This policy only applies to methods and properties. It references the object without taking ownership similar to the above return_value_policy::reference policy. In contrast to that policy, the - function or property’s implicit this argument (called the parent) is + function or property's implicit this argument (called the parent) is considered to be the the owner of the return value (the child). pybind11 then couples the lifetime of the parent to the child via a reference relationship that ensures that the parent cannot be garbage @@ -615,7 +560,7 @@ static_assert(std::is_standard_layout::value, "Internal error: `pybind11::detail::instance` is not standard layout!"); /// from __cpp_future__ import (convenient aliases from C++14/17) -#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +#if defined(PYBIND11_CPP14) using std::conditional_t; using std::enable_if_t; using std::remove_cv_t; @@ -878,10 +823,12 @@ struct is_template_base_of_impl { /// Check if a template is the base of a type. For example: /// `is_template_base_of` is true if `struct T : Base {}` where U can be anything template