Merge branch 'master' into list_caster_pass_generator

This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-07-31 05:48:00 -07:00
commit d1ffe4f81b
166 changed files with 3456 additions and 1139 deletions

View File

@ -9,7 +9,7 @@ platform:
- x86
environment:
matrix:
- PYTHON: 36
- PYTHON: 38
CONFIG: Debug
install:
- ps: |

View File

@ -57,10 +57,12 @@ Checks: |
readability-string-compare,
readability-suspicious-call-argument,
readability-uniqueptr-delete-release,
-bugprone-chained-comparison,
-bugprone-easily-swappable-parameters,
-bugprone-exception-escape,
-bugprone-reserved-identifier,
-bugprone-unused-raii,
-performance-enum-size,
CheckOptions:
- key: modernize-use-equals-default.IgnoreMacros

View File

@ -4,4 +4,12 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
groups:
actions:
patterns:
- "*"
ignore:
- dependency-name: actions/checkout
versions:
- "<5"

15
.github/labeler.yml vendored
View File

@ -1,8 +1,13 @@
docs:
- any:
- 'docs/**/*.rst'
- '!docs/changelog.rst'
- '!docs/upgrade.rst'
all:
- changed-files:
- all-globs-to-all-files:
- '!docs/changelog.rst'
- '!docs/upgrade.rst'
- base-branch: "^(?!dependabot).*"
- base-branch: "^(?!pre-commit-ci).*"
ci:
- '.github/workflows/*.yml'
- changed-files:
- any-glob-to-any-file:
- '.github/workflows/*.yml'

View File

@ -1,3 +1,8 @@
# Add 'needs changelog` label to any change to code files as long as the `CHANGELOG` hasn't changed
# Skip dependabot and pre-commit-ci PRs
needs changelog:
- all:
- '!docs/changelog.rst'
- all:
- changed-files:
- all-globs-to-all-files: "!docs/changelog.rst"
- base-branch: "^(?!dependabot).*"
- base-branch: "^(?!pre-commit-ci).*"

View File

@ -30,13 +30,12 @@ jobs:
strategy:
fail-fast: false
matrix:
runs-on: [ubuntu-20.04, windows-2022, macos-latest]
runs-on: [ubuntu-20.04, windows-2022, macos-13]
python:
- '3.6'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- 'pypy-3.8'
- 'pypy-3.9'
- 'pypy-3.10'
@ -49,21 +48,26 @@ jobs:
include:
# Just add a key
- runs-on: ubuntu-20.04
python: '3.6'
python: '3.8'
args: >
-DPYBIND11_FINDPYTHON=ON
-DCMAKE_CXX_FLAGS="-D_=1"
exercise_D_: 1
- runs-on: ubuntu-20.04
python: 'pypy-3.8'
args: >
-DPYBIND11_FINDPYTHON=ON
- runs-on: windows-2019
python: '3.6'
python: '3.8'
args: >
-DPYBIND11_FINDPYTHON=ON
# Inject a couple Windows 2019 runs
- runs-on: windows-2019
python: '3.9'
# Extra ubuntu latest job
- runs-on: ubuntu-latest
python: '3.11'
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
runs-on: ${{ matrix.runs-on }}
@ -72,14 +76,14 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
allow-prereleases: true
- name: Setup Boost (Linux)
# Can't use boost + define _
if: runner.os == 'Linux' && matrix.python != '3.6'
if: runner.os == 'Linux' && matrix.exercise_D_ != 1
run: sudo apt-get install libboost-dev
- name: Setup Boost (macOS)
@ -87,11 +91,11 @@ jobs:
run: brew install boost
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Cache wheels
if: runner.os == 'macOS'
uses: actions/cache@v3
uses: actions/cache@v4
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
@ -109,12 +113,15 @@ jobs:
run: python -m pip install pytest-github-actions-annotate-failures
# First build - C++11 mode and inplace
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here.
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here
# (same for PYBIND11_NUMPY_1_ONLY, but requires a NumPy 1.x at runtime).
- name: Configure C++11 ${{ matrix.args }}
run: >
cmake -S . -B .
-DPYBIND11_WERROR=ON
-DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
-DPYBIND11_NUMPY_1_ONLY=ON
-DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=11
@ -127,9 +134,7 @@ jobs:
run: cmake --build . --target pytest -j 2
- name: C++11 tests
# TODO: Figure out how to load the DLL on Python 3.8+
if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11' || matrix.python == 'pypy-3.8'))"
run: cmake --build . --target cpptest -j 2
run: cmake --build . --target cpptest -j 2
- name: Interface test C++11
run: cmake --build . --target test_cmake_build
@ -139,11 +144,13 @@ jobs:
# Second build - C++17 mode and in a build directory
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here.
# (same for PYBIND11_NUMPY_1_ONLY, but requires a NumPy 1.x at runtime).
- name: Configure C++17
run: >
cmake -S . -B build2
-DPYBIND11_WERROR=ON
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
-DPYBIND11_NUMPY_1_ONLY=ON
-DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=17
@ -156,8 +163,6 @@ jobs:
run: cmake --build build2 --target pytest
- name: C++ tests
# TODO: Figure out how to load the DLL on Python 3.8+
if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11' || matrix.python == 'pypy-3.8'))"
run: cmake --build build2 --target cpptest
# Third build - C++17 mode with unstable ABI
@ -188,6 +193,35 @@ jobs:
pytest tests/extra_setuptools
if: "!(matrix.runs-on == 'windows-2022')"
manylinux:
name: Manylinux on 🐍 3.13t • GIL
runs-on: ubuntu-latest
timeout-minutes: 40
container: quay.io/pypa/musllinux_1_2_x86_64:latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare venv
run: python3.13t -m venv .venv
- name: Install Python deps
run: .venv/bin/pip install -r tests/requirements.txt
- name: Configure C++11
run: >
cmake -S. -Bbuild
-DPYBIND11_WERROR=ON
-DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON
-DPython_ROOT_DIR=.venv
- name: Build C++11
run: cmake --build build -j2
- name: Python tests C++11
run: cmake --build build --target pytest -j2
deadsnakes:
strategy:
@ -209,17 +243,17 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
uses: deadsnakes/action@v3.0.1
uses: deadsnakes/action@v3.1.0
with:
python-version: ${{ matrix.python-version }}
debug: ${{ matrix.python-debug }}
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Valgrind cache
if: matrix.valgrind
uses: actions/cache@v3
uses: actions/cache@v4
id: cache-valgrind
with:
path: valgrind
@ -277,11 +311,6 @@ jobs:
fail-fast: false
matrix:
clang:
- 3.6
- 3.7
- 3.9
- 7
- 9
- dev
std:
- 11
@ -290,8 +319,6 @@ jobs:
include:
- clang: 5
std: 14
- clang: 10
std: 17
- clang: 11
std: 20
- clang: 12
@ -306,6 +333,12 @@ jobs:
- clang: 16
std: 20
container_suffix: "-bullseye"
- clang: 17
std: 20
container_suffix: "-bookworm"
- clang: 18
std: 20
container_suffix: "-bookworm"
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
@ -463,11 +496,9 @@ jobs:
fail-fast: false
matrix:
include:
- { gcc: 7, std: 11 }
- { gcc: 7, std: 17 }
- { gcc: 8, std: 14 }
- { gcc: 8, std: 17 }
- { gcc: 9, std: 20 }
- { gcc: 10, std: 17 }
- { gcc: 10, std: 20 }
- { gcc: 11, std: 20 }
- { gcc: 12, std: 20 }
- { gcc: 13, std: 20 }
@ -485,7 +516,7 @@ jobs:
run: python3 -m pip install --upgrade pip
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Configure
shell: bash
@ -530,8 +561,6 @@ jobs:
# Testing on ICC using the oneAPI apt repo
icc:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
name: "🐍 3 • ICC latest • x64"
@ -624,15 +653,13 @@ jobs:
cmake --build build-17 --target test_cmake_build
# Testing on CentOS (manylinux uses a centos base, and this is an easy way
# to get GCC 4.8, which is the manylinux1 compiler).
# Testing on CentOS (manylinux uses a centos base).
centos:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
container:
- "centos:7" # GCC 4.8
- "almalinux:8"
- "almalinux:9"
@ -642,18 +669,13 @@ jobs:
steps:
- name: Latest actions/checkout
uses: actions/checkout@v4
if: matrix.container != 'centos:7'
- name: Pin actions/checkout as required for centos:7
uses: actions/checkout@v3
if: matrix.container == 'centos:7'
- name: Add Python 3.8
if: matrix.container == 'almalinux:8'
run: dnf update -y && dnf install -y python38-devel gcc-c++ make git
- 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'
- name: Add Python 3 (default)
if: matrix.container != 'almalinux:8'
run: dnf update -y && dnf install -y python3-devel gcc-c++ make git
- name: Update pip
@ -663,6 +685,11 @@ jobs:
run: |
python3 -m pip install cmake -r tests/requirements.txt
- name: Ensure NumPy 2 is used (required Python >= 3.9)
if: matrix.container == 'almalinux:9'
run: |
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
- name: Configure
shell: bash
run: >
@ -689,9 +716,9 @@ jobs:
# This tests an "install" with the CMake tools
install-classic:
name: "🐍 3.7 • Debian • x86 • Install"
name: "🐍 3.9 • Debian • x86 • Install"
runs-on: ubuntu-latest
container: i386/debian:buster
container: i386/debian:bullseye
steps:
- uses: actions/checkout@v1 # v1 is required to run inside docker
@ -739,7 +766,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
@ -771,18 +798,23 @@ jobs:
fail-fast: false
matrix:
python:
- 3.6
- 3.7
- 3.8
- 3.9
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
include:
- python: 3.9
- python: '3.12'
args: -DCMAKE_CXX_STANDARD=20
- python: 3.8
- python: '3.11'
args: -DCMAKE_CXX_STANDARD=20
- python: '3.10'
args: -DCMAKE_CXX_STANDARD=20
- python: '3.9'
args: -DCMAKE_CXX_STANDARD=20
- python: '3.8'
args: -DCMAKE_CXX_STANDARD=17
- python: 3.7
args: -DCMAKE_CXX_STANDARD=14
name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}"
@ -792,16 +824,16 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
architecture: x86
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.12.1
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: x86
@ -845,16 +877,16 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
architecture: x86
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.12.1
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: x86
@ -893,16 +925,18 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Prepare env
# Ensure use of NumPy 2 (via NumPy nightlies but can be changed soon)
run: |
python3 -m pip install -r tests/requirements.txt
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Configure C++20
run: >
@ -960,20 +994,30 @@ jobs:
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-python-pip
mingw-w64-${{matrix.env}}-python-numpy
mingw-w64-${{matrix.env}}-python-scipy
mingw-w64-${{matrix.env}}-cmake
mingw-w64-${{matrix.env}}-make
mingw-w64-${{matrix.env}}-python-pytest
mingw-w64-${{matrix.env}}-eigen3
mingw-w64-${{matrix.env}}-boost
mingw-w64-${{matrix.env}}-catch
- uses: msys2/setup-msys2@v2
if: matrix.sys == 'mingw64'
with:
msystem: ${{matrix.sys}}
install: >-
git
mingw-w64-${{matrix.env}}-python-scipy
mingw-w64-${{matrix.env}}-eigen3
- uses: actions/checkout@v4
- name: Configure C++11
# LTO leads to many undefined reference like
# `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&)
run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build
run: >-
cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
-S . -B build
- name: Build C++11
run: cmake --build build -j 2
@ -991,7 +1035,10 @@ jobs:
run: git clean -fdx
- name: Configure C++14
run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build2
run: >-
cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
-S . -B build2
- name: Build C++14
run: cmake --build build2 -j 2
@ -1009,7 +1056,10 @@ jobs:
run: git clean -fdx
- name: Configure C++17
run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build3
run: >-
cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
-S . -B build3
- name: Build C++17
run: cmake --build build3 -j 2
@ -1045,15 +1095,15 @@ jobs:
uses: egor-tensin/setup-clang@v1
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Install ninja-build tool
uses: seanmiddleditch/gha-setup-ninja@v4
uses: seanmiddleditch/gha-setup-ninja@v5
- name: Run pip installs
run: |
@ -1093,8 +1143,8 @@ jobs:
run: git clean -fdx
macos_brew_install_llvm:
name: "macos-latest • brew install llvm"
runs-on: macos-latest
name: "macos-13 • brew install llvm"
runs-on: macos-13
env:
# https://apple.stackexchange.com/questions/227026/how-to-install-recent-clang-with-homebrew
@ -1120,7 +1170,7 @@ jobs:
run: clang++ --version
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Run pip installs
run: |

View File

@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false
matrix:
runs-on: [ubuntu-20.04, macos-latest, windows-latest]
runs-on: [ubuntu-20.04, macos-13, windows-latest]
arch: [x64]
cmake: ["3.26"]
@ -35,26 +35,26 @@ jobs:
- runs-on: ubuntu-20.04
arch: x64
cmake: "3.27"
cmake: "3.29"
- runs-on: macos-latest
- runs-on: macos-13
arch: x64
cmake: "3.7"
cmake: "3.8"
- 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 }}
name: 🐍 3.8 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- name: Setup Python 3.7
uses: actions/setup-python@v4
- name: Setup Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.7
python-version: 3.8
architecture: ${{ matrix.arch }}
- name: Prepare env
@ -63,7 +63,7 @@ jobs:
# An action for adding a specific version of CMake:
# https://github.com/jwlawson/actions-setup-cmake
- name: Setup CMake ${{ matrix.cmake }}
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
with:
cmake-version: ${{ matrix.cmake }}

30
.github/workflows/emscripten.yaml vendored Normal file
View File

@ -0,0 +1,30 @@
name: WASM
on:
workflow_dispatch:
pull_request:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-wasm-emscripten:
name: Pyodide wheel
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- uses: pypa/cibuildwheel@v2.19
env:
PYODIDE_BUILD_EXPORTS: whole_archive
CFLAGS: -fexceptions
LDFLAGS: -fexceptions
with:
package-dir: tests
only: cp312-pyodide_wasm32

View File

@ -26,12 +26,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
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
- uses: pre-commit/action@v3.0.1
with:
# Slow hooks are marked with manual - slow is okay here, run them too
extra_args: --hook-stage manual --all-files
@ -41,7 +41,7 @@ jobs:
# in .github/CONTRIBUTING.md and update as needed.
name: Clang-Tidy
runs-on: ubuntu-latest
container: silkeh/clang:15-bullseye
container: silkeh/clang:18-bookworm
steps:
- uses: actions/checkout@v4

View File

@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- uses: actions/labeler@main
- uses: actions/labeler@v5
if: >
github.event.pull_request.merged == true &&
!startsWith(github.event.pull_request.title, 'chore(deps):') &&

View File

@ -21,19 +21,18 @@ env:
jobs:
# This builds the sdists and wheels and makes sure the files are exactly as
# expected. Using Windows and Python 3.6, since that is often the most
# challenging matrix element.
# expected.
test-packaging:
name: 🐍 3.6 • 📦 tests • windows-latest
name: 🐍 3.8 • 📦 tests • windows-latest
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup 🐍 3.6
uses: actions/setup-python@v4
- name: Setup 🐍 3.8
uses: actions/setup-python@v5
with:
python-version: 3.6
python-version: 3.8
- name: Prepare env
run: |
@ -53,7 +52,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup 🐍 3.8
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: 3.8
@ -73,13 +72,13 @@ jobs:
run: twine check dist/*
- name: Save standard package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: standard
path: dist/pybind11-*
- name: Save global package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: global
path: dist/pybind11_global-*
@ -92,23 +91,27 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
needs: [packaging]
environment: pypi
permissions:
id-token: write
attestations: write
contents: read
steps:
- uses: actions/setup-python@v4
with:
python-version: "3.x"
# Downloads all to directories matching the artifact names
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
- name: Generate artifact attestation for sdist and wheel
uses: actions/attest-build-provenance@5e9cb68e95676991667494a6a4e59b8a2f13e1d0 # v1.3.3
with:
subject-path: "*/pybind11*"
- name: Publish standard package
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.pypi_password }}
packages-dir: standard/
- name: Publish global package
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.pypi_password_global }}
packages-dir: global/

View File

@ -13,13 +13,12 @@ concurrency:
env:
PIP_BREAK_SYSTEM_PACKAGES: 1
PIP_ONLY_BINARY: ":all:"
# For cmake:
VERBOSE: 1
jobs:
standard:
name: "🐍 3.12 latest • ubuntu-latest • x64"
name: "🐍 3.13 latest • ubuntu-latest • x64"
runs-on: ubuntu-latest
# Only runs when the 'python dev' label is selected
if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
@ -27,16 +26,17 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup Python 3.12
uses: actions/setup-python@v4
- name: Setup Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.12-dev"
python-version: "3.13"
allow-prereleases: true
- name: Setup Boost
run: sudo apt-get install libboost-dev
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.14
uses: jwlawson/actions-setup-cmake@v2.0
- name: Run pip installs
run: |

View File

@ -25,14 +25,14 @@ repos:
# Clang format the codebase automatically
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v17.0.4"
rev: "v18.1.8"
hooks:
- id: clang-format
types_or: [c++, c, cuda]
# Ruff, the Python auto-correcting linter/formatter written in Rust
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.4
rev: v0.5.0
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
@ -40,13 +40,13 @@ repos:
# Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.6.1"
rev: "v1.10.1"
hooks:
- id: mypy
args: []
exclude: ^(tests|docs)/
additional_dependencies:
- markdown-it-py<3 # Drop this together with dropping Python 3.7 support.
- markdown-it-py
- nox
- rich
- types-setuptools
@ -62,7 +62,7 @@ repos:
# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v4.5.0"
rev: "v4.6.0"
hooks:
- id: check-added-large-files
- id: check-case-conflict
@ -78,8 +78,8 @@ repos:
- id: trailing-whitespace
# Also code format the docs
- repo: https://github.com/asottile/blacken-docs
rev: "1.16.0"
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.18.0"
hooks:
- id: blacken-docs
additional_dependencies:
@ -87,13 +87,13 @@ repos:
# Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: "v1.5.4"
rev: "v1.5.5"
hooks:
- id: remove-tabs
# Avoid directional quotes
- repo: https://github.com/sirosen/texthooks
rev: "0.6.2"
rev: "0.6.6"
hooks:
- id: fix-ligatures
- id: fix-smartquotes
@ -119,15 +119,15 @@ repos:
# Use tools/codespell_ignore_lines_from_errors.py
# to rebuild .codespell-ignore-lines
- repo: https://github.com/codespell-project/codespell
rev: "v2.2.6"
rev: "v2.3.0"
hooks:
- id: codespell
exclude: ".supp$"
args: ["-x.codespell-ignore-lines", "-Lccompiler"]
args: ["-x.codespell-ignore-lines", "-Lccompiler,intstruct"]
# Check for common shell mistakes
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: "v0.9.0.6"
rev: "v0.10.0.1"
hooks:
- id: shellcheck
@ -142,7 +142,15 @@ repos:
# PyLint has native support - not always usable, but works for us
- repo: https://github.com/PyCQA/pylint
rev: "v3.0.1"
rev: "v3.2.4"
hooks:
- id: pylint
files: ^pybind11
# Check schemas on some of our YAML files
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.28.6
hooks:
- id: check-readthedocs
- id: check-github-workflows
- id: check-dependabot

View File

@ -12,13 +12,13 @@ endif()
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
if(_pybind11_cmp0148)
@ -92,33 +92,59 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(pybind11_system "")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if(CMAKE_VERSION VERSION_LESS "3.18")
set(_pybind11_findpython_default OFF)
else()
set(_pybind11_findpython_default ON)
endif()
else()
set(PYBIND11_MASTER_PROJECT OFF)
set(pybind11_system SYSTEM)
set(_pybind11_findpython_default OFF)
endif()
# Options
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
option(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION
"To enforce that a handle_type_name<> specialization exists" OFF)
option(PYBIND11_SIMPLE_GIL_MANAGEMENT
"Use simpler GIL management logic that does not support disassociation" OFF)
option(PYBIND11_NUMPY_1_ONLY
"Disable NumPy 2 support to avoid changes to previous pybind11 versions." OFF)
set(PYBIND11_INTERNALS_VERSION
""
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
option(PYBIND11_USE_CROSSCOMPILING "Respect CMAKE_CROSSCOMPILING" OFF)
if(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
add_compile_definitions(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
endif()
if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
endif()
if(PYBIND11_NUMPY_1_ONLY)
add_compile_definitions(PYBIND11_NUMPY_1_ONLY)
endif()
cmake_dependent_option(
USE_PYTHON_INCLUDE_DIR
"Install pybind11 headers in Python include directory instead of default installation prefix"
OFF "PYBIND11_INSTALL" OFF)
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" OFF
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default}
"NOT CMAKE_VERSION VERSION_LESS 3.12" OFF)
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
# (makes transition easier while we support both modes).
if(PYBIND11_MASTER_PROJECT
AND PYBIND11_FINDPYTHON
AND DEFINED PYTHON_EXECUTABLE
AND NOT DEFINED Python_EXECUTABLE)
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()
# NB: when adding a header don't forget to also add it to setup.py
set(PYBIND11_HEADERS
include/pybind11/detail/class.h
@ -128,6 +154,7 @@ set(PYBIND11_HEADERS
include/pybind11/detail/internals.h
include/pybind11/detail/type_caster_base.h
include/pybind11/detail/typeid.h
include/pybind11/detail/value_and_holder.h
include/pybind11/attr.h
include/pybind11/buffer_info.h
include/pybind11/cast.h
@ -274,6 +301,7 @@ if(PYBIND11_INSTALL)
tools/pybind11Common.cmake
tools/pybind11Tools.cmake
tools/pybind11NewTools.cmake
tools/pybind11GuessPythonExtSuffix.cmake
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
if(NOT PYBIND11_EXPORT_NAME)

View File

@ -34,12 +34,12 @@ dependency.
Think of this library as a tiny self-contained version of Boost.Python
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 (3.6+, or PyPy) and the C++
lines of code and depend on Python (3.8+, 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
grown beyond Boost.Python in many ways, leading to dramatically simpler
binding code in many common situations.
some C++11 language features (specifically: tuples, lambda functions and
variadic templates). Since its creation, this library has grown beyond
Boost.Python in many ways, leading to dramatically simpler binding code in many
common situations.
Tutorial and reference documentation is provided at
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
@ -71,6 +71,7 @@ pybind11 can map the following core C++ features to Python:
- Internal references with correct reference counting
- C++ classes with virtual (and pure virtual) methods can be extended
in Python
- Integrated NumPy support (NumPy 2 requires pybind11 2.12+)
Goodies
-------
@ -78,7 +79,7 @@ Goodies
In addition to the core functionality, pybind11 provides some extra
goodies:
- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic
- Python 3.8+, 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

View File

@ -826,8 +826,7 @@ An instance can now be pickled as follows:
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+.
and/or segmentation faults.
.. seealso::

View File

@ -18,7 +18,7 @@ information, see :doc:`/compiling`.
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.26)
cmake_minimum_required(VERSION 3.5...3.29)
project(example)
find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)`

View File

@ -368,8 +368,7 @@ Should they throw or fail to catch any exceptions in their call graph,
the C++ runtime calls ``std::terminate()`` to abort immediately.
Similarly, Python exceptions raised in a class's ``__del__`` method do not
propagate, but are logged by Python as an unraisable error. In Python 3.8+, a
`system hook is triggered
propagate, but ``sys.unraisablehook()`` `is triggered
<https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_
and an auditing event is logged.

View File

@ -378,8 +378,6 @@ uses of ``py::array``:
- ``.itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
- ``.ndim()`` returns the number of dimensions.
- ``.shape(n)`` returns the size of dimension ``n``
- ``.size()`` returns the total number of elements (i.e. the product of the shapes).

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import datetime as dt
import os
import random

View File

@ -15,9 +15,298 @@ IN DEVELOPMENT
Changes will be summarized here periodically.
Version 2.13.1 (June 26, 2024)
------------------------------
New Features:
* Add support for ``Typing.Callable[..., T]``.
`#5202 <https://github.com/pybind/pybind11/pull/5202>`_
Bug fixes:
* Avoid aligned allocation in free-threaded build in order to support macOS
versions before 10.14.
`#5200 <https://github.com/pybind/pybind11/pull/5200>`_
Version 2.13.0 (June 25, 2024)
------------------------------
New Features:
* Support free-threaded CPython (3.13t). Add ``py::mod_gil_not_used()`` tag to
indicate if a module supports running with the GIL disabled.
`#5148 <https://github.com/pybind/pybind11/pull/5148>`_
* Support for Python 3.6 was removed. (Official end-of-life: 2021-12-23).
`#5177 <https://github.com/pybind/pybind11/pull/5177>`_
* ``py::list`` gained a ``.clear()`` method.
`#5153 <https://github.com/pybind/pybind11/pull/5153>`_
.. feat(types)
* Support for ``Union``, ``Optional``, ``type[T]``, ``typing.TypeGuard``,
``typing.TypeIs``, ``typing.Never``, ``typing.NoReturn`` and
``typing.Literal`` was added to ``pybind11/typing.h``.
`#5166 <https://github.com/pybind/pybind11/pull/5166>`_
`#5165 <https://github.com/pybind/pybind11/pull/5165>`_
`#5194 <https://github.com/pybind/pybind11/pull/5194>`_
`#5193 <https://github.com/pybind/pybind11/pull/5193>`_
`#5192 <https://github.com/pybind/pybind11/pull/5192>`_
.. feat(cmake)
* In CMake, if ``PYBIND11_USE_CROSSCOMPILING`` is enabled, then
``CMAKE_CROSSCOMPILING`` will be respected and will keep pybind11 from
accessing the interpreter during configuration. Several CMake variables will
be required in this case, but can be deduced from the environment variable
``SETUPTOOLS_EXT_SUFFIX``. The default (currently ``OFF``) may be changed in
the future.
`#5083 <https://github.com/pybind/pybind11/pull/5083>`_
Bug fixes:
* A refcount bug (leading to heap-use-after-free) involving trampoline
functions with ``PyObject *`` return type was fixed.
`#5156 <https://github.com/pybind/pybind11/pull/5156>`_
* Return ``py::ssize_t`` from ``.ref_count()`` instead of ``int``.
`#5139 <https://github.com/pybind/pybind11/pull/5139>`_
* A subtle bug involving C++ types with unusual ``operator&`` overrides
was fixed.
`#5189 <https://github.com/pybind/pybind11/pull/5189>`_
* Support Python 3.13 with minor fix, add to CI.
`#5127 <https://github.com/pybind/pybind11/pull/5127>`_
.. fix(cmake)
* Fix mistake affecting old cmake and old boost.
`#5149 <https://github.com/pybind/pybind11/pull/5149>`_
Documentation:
* Build docs updated to feature scikit-build-core and meson-python, and updated
setuptools instructions.
`#5168 <https://github.com/pybind/pybind11/pull/5168>`_
Tests:
* Avoid immortal objects in tests.
`#5150 <https://github.com/pybind/pybind11/pull/5150>`_
CI:
* Compile against Python 3.13t in CI.
* Use ``macos-13`` (Intel) for CI jobs for now (will drop Python 3.7 soon).
`#5109 <https://github.com/pybind/pybind11/pull/5109>`_
* Releases now have artifact attestations, visible at
https://github.com/pybind/pybind11/attestations.
`#5196 <https://github.com/pybind/pybind11/pull/5196>`_
Other:
* Some cleanup in preparation for 3.13 support.
`#5137 <https://github.com/pybind/pybind11/pull/5137>`_
* Avoid a warning by ensuring an iterator end check is included in release mode.
`#5129 <https://github.com/pybind/pybind11/pull/5129>`_
* Bump max cmake to 3.29.
`#5075 <https://github.com/pybind/pybind11/pull/5075>`_
* Update docs and noxfile.
`#5071 <https://github.com/pybind/pybind11/pull/5071>`_
Version 2.12.0 (March 27, 2024)
-------------------------------
New Features:
* ``pybind11`` now supports compiling for
`NumPy 2 <https://numpy.org/devdocs/numpy_2_0_migration_guide.html>`_. Most
code shouldn't change (see :ref:`upgrade-guide-2.12` for details). However,
if you experience issues you can define ``PYBIND11_NUMPY_1_ONLY`` to disable
the new support for now, but this will be removed in the future.
`#5050 <https://github.com/pybind/pybind11/pull/5050>`_
* ``pybind11/gil_safe_call_once.h`` was added (it needs to be included
explicitly). The primary use case is GIL-safe initialization of C++
``static`` variables.
`#4877 <https://github.com/pybind/pybind11/pull/4877>`_
* Support move-only iterators in ``py::make_iterator``,
``py::make_key_iterator``, ``py::make_value_iterator``.
`#4834 <https://github.com/pybind/pybind11/pull/4834>`_
* Two simple ``py::set_error()`` functions were added and the documentation was
updated accordingly. In particular, ``py::exception<>::operator()`` was
deprecated (use one of the new functions instead). The documentation for
``py::exception<>`` was further updated to not suggest code that may result
in undefined behavior.
`#4772 <https://github.com/pybind/pybind11/pull/4772>`_
Bug fixes:
* Removes potential for Undefined Behavior during process teardown.
`#4897 <https://github.com/pybind/pybind11/pull/4897>`_
* Improve compatibility with the nvcc compiler (especially CUDA 12.1/12.2).
`#4893 <https://github.com/pybind/pybind11/pull/4893>`_
* ``pybind11/numpy.h`` now imports NumPy's ``multiarray`` and ``_internal``
submodules with paths depending on the installed version of NumPy (for
compatibility with NumPy 2).
`#4857 <https://github.com/pybind/pybind11/pull/4857>`_
* Builtins collections names in docstrings are now consistently rendered in
lowercase (list, set, dict, tuple), in accordance with PEP 585.
`#4833 <https://github.com/pybind/pybind11/pull/4833>`_
* Added ``py::typing::Iterator<T>``, ``py::typing::Iterable<T>``.
`#4832 <https://github.com/pybind/pybind11/pull/4832>`_
* Render ``py::function`` as ``Callable`` in docstring.
`#4829 <https://github.com/pybind/pybind11/pull/4829>`_
* Also bump ``PYBIND11_INTERNALS_VERSION`` for MSVC, which unlocks two new
features without creating additional incompatibilities.
`#4819 <https://github.com/pybind/pybind11/pull/4819>`_
* Guard against crashes/corruptions caused by modules built with different MSVC
versions.
`#4779 <https://github.com/pybind/pybind11/pull/4779>`_
* A long-standing bug in the handling of Python multiple inheritance was fixed.
See PR #4762 for the rather complex details.
`#4762 <https://github.com/pybind/pybind11/pull/4762>`_
* Fix ``bind_map`` with ``using`` declarations.
`#4952 <https://github.com/pybind/pybind11/pull/4952>`_
* Qualify ``py::detail::concat`` usage to avoid ADL selecting one from
somewhere else, such as modernjson's concat.
`#4955 <https://github.com/pybind/pybind11/pull/4955>`_
* Use new PyCode API on Python 3.12+.
`#4916 <https://github.com/pybind/pybind11/pull/4916>`_
* Minor cleanup from warnings reported by Clazy.
`#4988 <https://github.com/pybind/pybind11/pull/4988>`_
* Remove typing and duplicate ``class_`` for ``KeysView``/``ValuesView``/``ItemsView``.
`#4985 <https://github.com/pybind/pybind11/pull/4985>`_
* Use ``PyObject_VisitManagedDict()`` and ``PyObject_ClearManagedDict()`` on Python 3.13 and newer.
`#4973 <https://github.com/pybind/pybind11/pull/4973>`_
* Update ``make_static_property_type()`` to make it compatible with Python 3.13.
`#4971 <https://github.com/pybind/pybind11/pull/4971>`_
.. fix(types)
* Render typed iterators for ``make_iterator``, ``make_key_iterator``,
``make_value_iterator``.
`#4876 <https://github.com/pybind/pybind11/pull/4876>`_
* Add several missing type name specializations.
`#5073 <https://github.com/pybind/pybind11/pull/5073>`_
* Change docstring render for ``py::buffer``, ``py::sequence`` and
``py::handle`` (to ``Buffer``, ``Sequence``, ``Any``).
`#4831 <https://github.com/pybind/pybind11/pull/4831>`_
* Fixed ``base_enum.__str__`` docstring.
`#4827 <https://github.com/pybind/pybind11/pull/4827>`_
* Enforce single line docstring signatures.
`#4735 <https://github.com/pybind/pybind11/pull/4735>`_
* Special 'typed' wrappers now available in ``typing.h`` to annotate tuple, dict,
list, set, and function.
`#4259 <https://github.com/pybind/pybind11/pull/4259>`_
* Create ``handle_type_name`` specialization to type-hint variable length tuples.
`#5051 <https://github.com/pybind/pybind11/pull/5051>`_
.. fix(build)
* Setting ``PYBIND11_FINDPYTHON`` to OFF will force the old FindPythonLibs mechanism to be used.
`#5042 <https://github.com/pybind/pybind11/pull/5042>`_
* Skip empty ``PYBIND11_PYTHON_EXECUTABLE_LAST`` for the first cmake run.
`#4856 <https://github.com/pybind/pybind11/pull/4856>`_
* Fix FindPython mode exports & avoid ``pkg_resources`` if
``importlib.metadata`` available.
`#4941 <https://github.com/pybind/pybind11/pull/4941>`_
* ``Python_ADDITIONAL_VERSIONS`` (classic search) now includes 3.12.
`#4909 <https://github.com/pybind/pybind11/pull/4909>`_
* ``pybind11.pc`` is now relocatable by default as long as install destinations
are not absolute paths.
`#4830 <https://github.com/pybind/pybind11/pull/4830>`_
* Correctly detect CMake FindPython removal when used as a subdirectory.
`#4806 <https://github.com/pybind/pybind11/pull/4806>`_
* Don't require the libs component on CMake 3.18+ when using
PYBIND11_FINDPYTHON (fixes manylinux builds).
`#4805 <https://github.com/pybind/pybind11/pull/4805>`_
* ``pybind11_strip`` is no longer automatically applied when
``CMAKE_BUILD_TYPE`` is unset.
`#4780 <https://github.com/pybind/pybind11/pull/4780>`_
* Support ``DEBUG_POSFIX`` correctly for debug builds.
`#4761 <https://github.com/pybind/pybind11/pull/4761>`_
* Hardcode lto/thin lto for Emscripten cross-compiles.
`#4642 <https://github.com/pybind/pybind11/pull/4642>`_
* Upgrade maximum supported CMake version to 3.27 to fix CMP0148 warnings.
`#4786 <https://github.com/pybind/pybind11/pull/4786>`_
Documentation:
* Small fix to grammar in ``functions.rst``.
`#4791 <https://github.com/pybind/pybind11/pull/4791>`_
* Remove upper bound in example pyproject.toml for setuptools.
`#4774 <https://github.com/pybind/pybind11/pull/4774>`_
CI:
* CI: Update NVHPC to 23.5 and Ubuntu 20.04.
`#4764 <https://github.com/pybind/pybind11/pull/4764>`_
* Test on PyPy 3.10.
`#4714 <https://github.com/pybind/pybind11/pull/4714>`_
Other:
* Use Ruff formatter instead of Black.
`#4912 <https://github.com/pybind/pybind11/pull/4912>`_
* An ``assert()`` was added to help Coverty avoid generating a false positive.
`#4817 <https://github.com/pybind/pybind11/pull/4817>`_
Version 2.11.1 (July 17, 2023)
-----------------------------
------------------------------
Changes:
@ -32,7 +321,7 @@ Changes:
Version 2.11.0 (July 14, 2023)
-----------------------------
------------------------------
New features:

View File

@ -3,15 +3,123 @@
Build systems
#############
For an overview of Python packaging including compiled packaging with a pybind11
example, along with a cookiecutter that includes several pybind11 options, see
the `Scientific Python Development Guide`_.
.. _Scientific Python Development Guide: https://learn.scientific-python.org/development/guides/packaging-compiled/
.. scikit-build-core:
Modules with CMake
==================
A Python extension module can be created with just a few lines of code:
.. code-block:: cmake
cmake_minimum_required(VERSION 3.15...3.29)
project(example LANGUAGES CXX)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(example example.cpp)
install(TARGET example DESTINATION .)
(You use the ``add_subdirectory`` instead, see the example in :ref:`cmake`.) In
this example, the code is located in a file named :file:`example.cpp`. Either
method will import the pybind11 project which provides the
``pybind11_add_module`` function. It will take care of all the details needed
to build a Python extension module on any platform.
To build with pip, build, cibuildwheel, uv, or other Python tools, you can
add a ``pyproject.toml`` file like this:
.. code-block:: toml
[build-system]
requires = ["scikit-build-core", "pybind11"]
build-backend = "scikit_build_core.build"
[project]
name = "example"
version = "0.1.0"
You don't need setuptools files like ``MANIFEST.in``, ``setup.py``, or
``setup.cfg``, as this is not setuptools. See `scikit-build-core`_ for details.
For projects you plan to upload to PyPI, be sure to fill out the ``[project]``
table with other important metadata as well (see `Writing pyproject.toml`_).
A working sample project can be found in the [scikit_build_example]_
repository. An older and harder-to-maintain method is in [cmake_example]_. More
details about our cmake support can be found below in :ref:`cmake`.
.. _scikit-build-core: https://scikit-build-core.readthedocs.io
.. [scikit_build_example] https://github.com/pybind/scikit_build_example
.. [cmake_example] https://github.com/pybind/cmake_example
.. _modules-meson-python:
Modules with meson-python
=========================
You can also build a package with `Meson`_ using `meson-python`_, if you prefer
that. Your ``meson.build`` file would look something like this:
.. _meson-example:
.. code-block:: meson
project(
'example',
'cpp',
version: '0.1.0',
default_options: [
'cpp_std=c++11',
],
)
py = import('python').find_installation(pure: false)
pybind11_dep = dependency('pybind11')
py.extension_module('example',
'example.cpp',
install: true,
dependencies : [pybind11_dep],
)
And you would need a ``pyproject.toml`` file like this:
.. code-block:: toml
[build-system]
requires = ["meson-python", "pybind11"]
build-backend = "mesonpy"
Meson-python *requires* your project to be in git (or mercurial) as it uses it
for the SDist creation. For projects you plan to upload to PyPI, be sure to fill out the
``[project]`` table as well (see `Writing pyproject.toml`_).
.. _Writing pyproject.toml: https://packaging.python.org/en/latest/guides/writing-pyproject-toml
.. _meson: https://mesonbuild.com
.. _meson-python: https://meson-python.readthedocs.io/en/latest
.. _build-setuptools:
Building with setuptools
========================
Modules with setuptools
=======================
For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay
has kindly provided an example project which shows how to set up everything,
including automatic generation of documentation using Sphinx. Please refer to
the [python_example]_ repository.
For projects on PyPI, a historically popular option is setuptools. Sylvain
Corlay has kindly provided an example project which shows how to set up
everything, including automatic generation of documentation using Sphinx.
Please refer to the [python_example]_ repository.
.. [python_example] https://github.com/pybind/python_example
@ -21,11 +129,11 @@ To use pybind11 inside your ``setup.py``, you have to have some system to
ensure that ``pybind11`` is installed when you build your package. There are
four possible ways to do this, and pybind11 supports all four: You can ask all
users to install pybind11 beforehand (bad), you can use
:ref:`setup_helpers-pep518` (good, but very new and requires Pip 10),
:ref:`setup_helpers-setup_requires` (discouraged by Python packagers now that
PEP 518 is available, but it still works everywhere), or you can
:ref:`setup_helpers-copy-manually` (always works but you have to manually sync
your copy to get updates).
:ref:`setup_helpers-pep518` (good), ``setup_requires=`` (discouraged), or you
can :ref:`setup_helpers-copy-manually` (works but you have to manually sync
your copy to get updates). Third party packagers like conda-forge generally
strongly prefer the ``pyproject.toml`` method, as it gives them control over
the ``pybind11`` version, and they may apply patches, etc.
An example of a ``setup.py`` using pybind11's helpers:
@ -122,70 +230,41 @@ version number that includes the number of commits since your last tag and a
hash for a dirty directory. Another way to force a rebuild is purge your cache
or use Pip's ``--no-cache-dir`` option.
You also need a ``MANIFEST.in`` file to include all relevant files so that you
can make an SDist. If you use `pypa-build`_, that will build an SDist then a
wheel from that SDist by default, so you can look inside those files (wheels
are just zip files with a ``.whl`` extension) to make sure you aren't missing
files. `check-manifest`_ (setuptools specific) or `check-sdist`_ (general) are
CLI tools that can compare the SDist contents with your source control.
.. [Ccache] https://ccache.dev
.. [setuptools_scm] https://github.com/pypa/setuptools_scm
.. _setup_helpers-pep518:
PEP 518 requirements (Pip 10+ required)
---------------------------------------
Build requirements
------------------
If you use `PEP 518's <https://www.python.org/dev/peps/pep-0518/>`_
``pyproject.toml`` file, you can ensure that ``pybind11`` is available during
the compilation of your project. When this file exists, Pip will make a new
virtual environment, download just the packages listed here in ``requires=``,
and build a wheel (binary Python package). It will then throw away the
environment, and install your wheel.
With a ``pyproject.toml`` file, you can ensure that ``pybind11`` is available
during the compilation of your project. When this file exists, Pip will make a
new virtual environment, download just the packages listed here in
``requires=``, and build a wheel (binary Python package). It will then throw
away the environment, and install your wheel.
Your ``pyproject.toml`` file will likely look something like this:
.. code-block:: toml
[build-system]
requires = ["setuptools>=42", "pybind11>=2.6.1"]
requires = ["setuptools", "pybind11"]
build-backend = "setuptools.build_meta"
.. note::
The main drawback to this method is that a `PEP 517`_ compliant build tool,
such as Pip 10+, is required for this approach to work; older versions of
Pip completely ignore this file. If you distribute binaries (called wheels
in Python) using something like `cibuildwheel`_, remember that ``setup.py``
and ``pyproject.toml`` are not even contained in the wheel, so this high
Pip requirement is only for source builds, and will not affect users of
your binary wheels. If you are building SDists and wheels, then
`pypa-build`_ is the recommended official tool.
.. _PEP 517: https://www.python.org/dev/peps/pep-0517/
.. _cibuildwheel: https://cibuildwheel.readthedocs.io
.. _pypa-build: https://pypa-build.readthedocs.io/en/latest/
.. _setup_helpers-setup_requires:
Classic ``setup_requires``
--------------------------
If you want to support old versions of Pip with the classic
``setup_requires=["pybind11"]`` keyword argument to setup, which triggers a
two-phase ``setup.py`` run, then you will need to use something like this to
ensure the first pass works (which has not yet installed the ``setup_requires``
packages, since it can't install something it does not know about):
.. code-block:: python
try:
from pybind11.setup_helpers import Pybind11Extension
except ImportError:
from setuptools import Extension as Pybind11Extension
It doesn't matter that the Extension class is not the enhanced subclass for the
first pass run; and the second pass will have the ``setup_requires``
requirements.
This is obviously more of a hack than the PEP 518 method, but it supports
ancient versions of Pip.
.. _cibuildwheel: https://cibuildwheel.pypa.io
.. _pypa-build: https://build.pypa.io/en/latest/
.. _check-manifest: https://pypi.io/project/check-manifest
.. _check-sdist: https://pypi.io/project/check-sdist
.. _setup_helpers-copy-manually:
@ -231,32 +310,22 @@ the C++ source file. Python is then able to find the module and load it.
.. [cppimport] https://github.com/tbenthompson/cppimport
.. _cmake:
Building with CMake
===================
For C++ codebases that have an existing CMake-based build system, a Python
extension module can be created with just a few lines of code:
extension module can be created with just a few lines of code, as seen above in
the module section. Pybind11 currently supports a lower minimum if you don't
use the modern FindPython, though be aware that CMake 3.27 removed the old
mechanism, so pybind11 will automatically switch if the old mechanism is not
available. Please opt into the new mechanism if at all possible. Our default
may change in future versions. This is the minimum required:
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.26)
project(example LANGUAGES CXX)
add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)
This assumes that the pybind11 repository is located in a subdirectory named
:file:`pybind11` and that the code is located in a file named :file:`example.cpp`.
The CMake command ``add_subdirectory`` will import the pybind11 project which
provides the ``pybind11_add_module`` function. It will take care of all the
details needed to build a Python extension module on any platform.
A working sample project, including a way to invoke CMake from :file:`setup.py` for
PyPI integration, can be found in the [cmake_example]_ repository.
.. [cmake_example] https://github.com/pybind/cmake_example
.. versionchanged:: 2.6
CMake 3.4+ is required.
@ -264,6 +333,7 @@ PyPI integration, can be found in the [cmake_example]_ repository.
.. versionchanged:: 2.11
CMake 3.5+ is required.
Further information can be found at :doc:`cmake/index`.
pybind11_add_module
@ -356,7 +426,7 @@ with ``PYTHON_EXECUTABLE``. For example:
.. code-block:: bash
cmake -DPYBIND11_PYTHON_VERSION=3.6 ..
cmake -DPYBIND11_PYTHON_VERSION=3.8 ..
# Another method:
cmake -DPYTHON_EXECUTABLE=/path/to/python ..
@ -423,7 +493,7 @@ existing targets instead:
cmake_minimum_required(VERSION 3.15...3.22)
project(example LANGUAGES CXX)
find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED)
find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED)
find_package(pybind11 CONFIG REQUIRED)
# or add_subdirectory(pybind11)
@ -498,7 +568,7 @@ You can use these targets to build complex applications. For example, the
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.26)
cmake_minimum_required(VERSION 3.5...3.29)
project(example LANGUAGES CXX)
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
@ -556,7 +626,7 @@ information about usage in C++, see :doc:`/advanced/embedding`.
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.26)
cmake_minimum_required(VERSION 3.5...3.29)
project(example LANGUAGES CXX)
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
@ -616,6 +686,13 @@ Building with Bazel
You can build with the Bazel build system using the `pybind11_bazel
<https://github.com/pybind/pybind11_bazel>`_ repository.
Building with Meson
===================
You can use Meson, which has support for ``pybind11`` as a dependency (internally
relying on our ``pkg-config`` support). See the :ref:`module example above <meson-example>`.
Generating binding code automatically
=====================================
@ -639,3 +716,11 @@ cross-project dependency management. Additionally, it is able to autogenerate
customizable pybind11-based wrappers by parsing C++ header files.
.. [robotpy-build] https://robotpy-build.readthedocs.io
[litgen]_ is an automatic python bindings generator with a focus on generating
documented and discoverable bindings: bindings will nicely reproduce the documentation
found in headers. It is is based on srcML (srcml.org), a highly scalable, multi-language
parsing tool with a developer centric approach. The API that you want to expose to python
must be C++14 compatible (but your implementation can use more modern constructs).
.. [litgen] https://pthom.github.io/litgen

View File

@ -11,6 +11,7 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
from __future__ import annotations
import os
import re
@ -81,7 +82,7 @@ version = loc["__version__"]
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = "en"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:

View File

@ -50,10 +50,6 @@ clean, well written patch would likely be accepted to solve them.
One consequence is that containers of ``char *`` are currently not supported.
`#2245 <https://github.com/pybind/pybind11/issues/2245>`_
- The ``cpptest`` does not run on Windows with Python 3.8 or newer, due to DLL
loader changes. User code that is correctly installed should not be affected.
`#2560 <https://github.com/pybind/pybind11/issue/2560>`_
Python 3.9.0 warning
^^^^^^^^^^^^^^^^^^^^

View File

@ -36,19 +36,19 @@ If you don't have nox, you should either use ``pipx run nox`` instead, or use
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
- Ensure that all the information in ``setup.cfg`` is up-to-date, like
- Ensure that all the information in ``setup.cfg`` is up-to-date, like
supported Python versions.
- Add release date in ``docs/changelog.rst`` and integrate the output of
``nox -s make_changelog``.
- Add release date in ``docs/changelog.rst`` and integrate the output of
``nox -s make_changelog``.
- Note that the ``make_changelog`` command inspects
`needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_.
- Note that the ``nox -s make_changelog`` command inspects
`needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_.
- Manually clear the ``needs changelog`` labels using the GitHub web
interface (very easy: start by clicking the link above).
- Manually clear the ``needs changelog`` labels using the GitHub web
interface (very easy: start by clicking the link above).
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
fails due to a known flake issue, either ignore or restart CI.)
- Add a release branch if this is a new MINOR version, or update the existing

6
docs/requirements.in Normal file
View File

@ -0,0 +1,6 @@
breathe
furo
sphinx
sphinx-copybutton
sphinxcontrib-moderncmakedomain
sphinxcontrib-svg2pdfconverter

View File

@ -1,6 +1,275 @@
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
# This file was autogenerated by uv via the following command:
# uv pip compile --generate-hashes docs/requirements.in -o docs/requirements.txt
alabaster==0.7.16 \
--hash=sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65 \
--hash=sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92
# via sphinx
babel==2.14.0 \
--hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
--hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
# via sphinx
beautifulsoup4==4.12.3 \
--hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \
--hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed
# via furo
breathe==4.35.0 \
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
# via -r requirements.in
certifi==2024.7.4 \
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
# via requests
charset-normalizer==3.3.2 \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via requests
docutils==0.20.1 \
--hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
--hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
# via
# breathe
# sphinx
furo==2024.1.29 \
--hash=sha256:3548be2cef45a32f8cdc0272d415fcb3e5fa6a0eb4ddfe21df3ecf1fe45a13cf \
--hash=sha256:4d6b2fe3f10a6e36eb9cc24c1e7beb38d7a23fc7b3c382867503b7fcac8a1e02
# via -r requirements.in
idna==3.7 \
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
# via requests
imagesize==1.4.1 \
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
# via sphinx
jinja2==3.1.4 \
--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
# via sphinx
markupsafe==2.1.5 \
--hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \
--hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \
--hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \
--hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \
--hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \
--hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \
--hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \
--hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \
--hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \
--hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \
--hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \
--hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \
--hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \
--hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \
--hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \
--hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \
--hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \
--hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \
--hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \
--hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \
--hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \
--hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \
--hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \
--hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \
--hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \
--hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \
--hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \
--hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \
--hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \
--hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \
--hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \
--hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \
--hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \
--hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \
--hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \
--hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \
--hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \
--hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \
--hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \
--hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \
--hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \
--hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \
--hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \
--hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \
--hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \
--hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \
--hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \
--hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \
--hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \
--hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \
--hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \
--hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \
--hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \
--hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \
--hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \
--hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \
--hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \
--hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \
--hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \
--hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68
# via jinja2
packaging==24.0 \
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
# via sphinx
pygments==2.17.2 \
--hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
--hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
# via
# furo
# sphinx
requests==2.32.0 \
--hash=sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5 \
--hash=sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8
# via sphinx
snowballstemmer==2.2.0 \
--hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
--hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
# via sphinx
soupsieve==2.5 \
--hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \
--hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7
# via beautifulsoup4
sphinx==7.2.6 \
--hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
--hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
# via
# -r requirements.in
# breathe
# furo
# sphinx-basic-ng
# sphinx-copybutton
# sphinxcontrib-moderncmakedomain
# sphinxcontrib-svg2pdfconverter
sphinx-basic-ng==1.0.0b2 \
--hash=sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9 \
--hash=sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b
# via furo
sphinx-copybutton==0.5.2 \
--hash=sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd \
--hash=sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e
# via -r requirements.in
sphinxcontrib-applehelp==1.0.8 \
--hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \
--hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4
# via sphinx
sphinxcontrib-devhelp==1.0.6 \
--hash=sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f \
--hash=sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3
# via sphinx
sphinxcontrib-htmlhelp==2.0.5 \
--hash=sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015 \
--hash=sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04
# via sphinx
sphinxcontrib-jsmath==1.0.1 \
--hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
--hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
# via sphinx
sphinxcontrib-moderncmakedomain==3.27.0 \
--hash=sha256:51e259e91f58d17cc0fac9307fd40106aa59d5acaa741887903fc3660361d1a1 \
--hash=sha256:70a73e0e7cff1b117074e968ccb7f72383ed0f572414df0e216cea06914de988
# via -r requirements.in
sphinxcontrib-qthelp==1.0.7 \
--hash=sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6 \
--hash=sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182
# via sphinx
sphinxcontrib-serializinghtml==1.1.10 \
--hash=sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7 \
--hash=sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f
# via sphinx
sphinxcontrib-svg2pdfconverter==1.2.2 \
--hash=sha256:04ec767b55780a6b18d89cc1a8ada6d900c6efde9d1683abdb98a49b144465ca \
--hash=sha256:80a55ca61f70eae93efc65f3814f2f177c86ba55934a9f6c5022f1778b62146b
# via -r requirements.in
urllib3==2.2.2 \
--hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
--hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
# via requests

View File

@ -8,6 +8,34 @@ to a new version. But it goes into more detail. This includes things like
deprecated APIs and their replacements, build system changes, general code
modernization and other useful information.
.. _upgrade-guide-2.12:
v2.12
=====
NumPy support has been upgraded to support the 2.x series too. The two relevant
changes are that:
* ``dtype.flags()`` is now a ``uint64`` and ``dtype.alignment()`` an
``ssize_t`` (and NumPy may return an larger than integer value for
``itemsize()`` in NumPy 2.x).
* The long deprecated NumPy function ``PyArray_GetArrayParamsFromObject``
function is not available anymore.
Due to NumPy changes, you may experience difficulties updating to NumPy 2.
Please see the [NumPy 2 migration guide](https://numpy.org/devdocs/numpy_2_0_migration_guide.html) for details.
For example, a more direct change could be that the default integer ``"int_"``
(and ``"uint"``) is now ``ssize_t`` and not ``long`` (affects 64bit windows).
If you want to only support NumPy 1.x for now and are having problems due to
the two internal changes listed above, you can define
``PYBIND11_NUMPY_1_ONLY`` to disable the new support for now. Make sure you
define this on all pybind11 compile units, since it could be a source of ODR
violations if used inconsistently. This option will be removed in the future,
so adapting your code is highly recommended.
.. _upgrade-guide-2.11:
v2.11

View File

@ -102,22 +102,22 @@ struct buffer_info {
template <typename T>
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
: buffer_info(
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
explicit buffer_info(Py_buffer *view, bool ownview = true)
: buffer_info(
view->buf,
view->itemsize,
view->format,
view->ndim,
{view->shape, view->shape + view->ndim},
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
* ignore this flag and return a view with NULL strides.
* When strides are NULL, build them manually. */
view->strides
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
(view->readonly != 0)) {
view->buf,
view->itemsize,
view->format,
view->ndim,
{view->shape, view->shape + view->ndim},
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
* ignore this flag and return a view with NULL strides.
* When strides are NULL, build them manually. */
view->strides
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
(view->readonly != 0)) {
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
this->m_view = view;
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
@ -176,7 +176,7 @@ private:
detail::any_container<ssize_t> &&strides_in,
bool readonly)
: buffer_info(
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
Py_buffer *m_view = nullptr;
bool ownview = false;

View File

@ -158,7 +158,7 @@ public:
} else {
handle src_or_index = src;
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
#if defined(PYPY_VERSION)
object index;
if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
@ -327,8 +327,9 @@ public:
value = false;
return true;
}
if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) {
// (allow non-implicit conversion for numpy booleans)
if (convert || is_numpy_bool(src)) {
// (allow non-implicit conversion for numpy booleans), use strncmp
// since NumPy 1.x had an additional trailing underscore.
Py_ssize_t res = -1;
if (src.is_none()) {
@ -360,6 +361,15 @@ public:
return handle(src ? Py_True : Py_False).inc_ref();
}
PYBIND11_TYPE_CASTER(bool, const_name("bool"));
private:
// Test if an object is a NumPy boolean (without fetching the type).
static inline bool is_numpy_bool(handle object) {
const char *type_name = Py_TYPE(object.ptr())->tp_name;
// Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support
return std::strcmp("numpy.bool", type_name) == 0
|| std::strcmp("numpy.bool_", type_name) == 0;
}
};
// Helper class for UTF-{8,16,32} C++ stl strings:
@ -662,8 +672,9 @@ public:
return cast(*src, policy, parent);
}
static constexpr auto name
= const_name("tuple[") + concat(make_caster<Ts>::name...) + const_name("]");
static constexpr auto name = const_name("tuple[")
+ ::pybind11::detail::concat(make_caster<Ts>::name...)
+ const_name("]");
template <typename T>
using cast_op_type = type;
@ -729,6 +740,13 @@ class type_caster<std::pair<T1, T2>> : public tuple_caster<std::pair, T1, T2> {}
template <typename... Ts>
class type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, Ts...> {};
template <>
class type_caster<std::tuple<>> : public tuple_caster<std::tuple> {
public:
// PEP 484 specifies this syntax for an empty tuple
static constexpr auto name = const_name("tuple[()]");
};
/// Helper class which abstracts away certain actions. Users can provide specializations for
/// custom holders, but it's only necessary if the type has a non-standard interface.
template <typename T>
@ -776,11 +794,11 @@ protected:
}
}
bool load_value(value_and_holder &&v_h) {
void load_value(value_and_holder &&v_h) {
if (v_h.holder_constructed()) {
value = v_h.value_ptr();
holder = v_h.template holder<holder_type>();
return true;
return;
}
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
@ -871,10 +889,53 @@ struct is_holder_type
template <typename base, typename deleter>
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888
// This leads to compilation errors if a specialization is missing.
template <typename T>
struct handle_type_name;
#else
template <typename T>
struct handle_type_name {
static constexpr auto name = const_name<T>();
};
#endif
template <>
struct handle_type_name<object> {
static constexpr auto name = const_name("object");
};
template <>
struct handle_type_name<list> {
static constexpr auto name = const_name("list");
};
template <>
struct handle_type_name<dict> {
static constexpr auto name = const_name("dict");
};
template <>
struct handle_type_name<anyset> {
static constexpr auto name = const_name("Union[set, frozenset]");
};
template <>
struct handle_type_name<set> {
static constexpr auto name = const_name("set");
};
template <>
struct handle_type_name<frozenset> {
static constexpr auto name = const_name("frozenset");
};
template <>
struct handle_type_name<str> {
static constexpr auto name = const_name("str");
};
template <>
struct handle_type_name<tuple> {
static constexpr auto name = const_name("tuple");
};
template <>
struct handle_type_name<bool_> {
static constexpr auto name = const_name("bool");
@ -920,6 +981,34 @@ struct handle_type_name<sequence> {
static constexpr auto name = const_name("Sequence");
};
template <>
struct handle_type_name<bytearray> {
static constexpr auto name = const_name("bytearray");
};
template <>
struct handle_type_name<memoryview> {
static constexpr auto name = const_name("memoryview");
};
template <>
struct handle_type_name<slice> {
static constexpr auto name = const_name("slice");
};
template <>
struct handle_type_name<type> {
static constexpr auto name = const_name("type");
};
template <>
struct handle_type_name<capsule> {
static constexpr auto name = const_name("capsule");
};
template <>
struct handle_type_name<ellipsis> {
static constexpr auto name = const_name("ellipsis");
};
template <>
struct handle_type_name<weakref> {
static constexpr auto name = const_name("weakref");
};
template <>
struct handle_type_name<args> {
static constexpr auto name = const_name("*args");
};
@ -927,6 +1016,30 @@ template <>
struct handle_type_name<kwargs> {
static constexpr auto name = const_name("**kwargs");
};
template <>
struct handle_type_name<obj_attr_accessor> {
static constexpr auto name = const_name<obj_attr_accessor>();
};
template <>
struct handle_type_name<str_attr_accessor> {
static constexpr auto name = const_name<str_attr_accessor>();
};
template <>
struct handle_type_name<item_accessor> {
static constexpr auto name = const_name<item_accessor>();
};
template <>
struct handle_type_name<sequence_accessor> {
static constexpr auto name = const_name<sequence_accessor>();
};
template <>
struct handle_type_name<list_accessor> {
static constexpr auto name = const_name<list_accessor>();
};
template <>
struct handle_type_name<tuple_accessor> {
static constexpr auto name = const_name<tuple_accessor>();
};
template <typename type>
struct pyobject_caster {
@ -1233,13 +1346,24 @@ enable_if_t<!cast_is_temporary_value_reference<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 <typename T>
enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
enable_if_t<cast_is_temporary_value_reference<T>::value
&& !detail::is_same_ignoring_cvref<T, PyObject *>::value,
T>
cast_safe(object &&) {
pybind11_fail("Internal error: cast_safe fallback invoked");
}
template <typename T>
enable_if_t<std::is_void<T>::value, void> cast_safe(object &&) {}
template <typename T>
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>, std::is_void<T>>::value, T>
enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value, PyObject *>
cast_safe(object &&o) {
return o.release().ptr();
}
template <typename T>
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>,
detail::is_same_ignoring_cvref<T, PyObject *>,
std::is_void<T>>::value,
T>
cast_safe(object &&o) {
return pybind11::cast<T>(std::move(o));
}
@ -1379,7 +1503,7 @@ struct kw_only {};
/// \ingroup annotations
/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of
/// an unnamed '/' argument (in Python 3.8)
/// an unnamed '/' argument
struct pos_only {};
template <typename T>
@ -1464,7 +1588,8 @@ public:
static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(),
"py::args cannot be specified more than once");
static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...);
static constexpr auto arg_names
= ::pybind11::detail::concat(type_descr(make_caster<Args>::name)...);
bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }

View File

@ -86,17 +86,16 @@ inline PyTypeObject *make_static_property_type() {
type->tp_descr_get = pybind11_static_get;
type->tp_descr_set = pybind11_static_set;
if (PyType_Ready(type) < 0) {
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
}
# if PY_VERSION_HEX >= 0x030C0000
// PRE 3.12 FEATURE FREEZE. PLEASE REVIEW AFTER FREEZE.
// Since Python-3.12 property-derived types are required to
// have dynamic attributes (to set `__doc__`)
enable_dynamic_attributes(heap_type);
# endif
if (PyType_Ready(type) < 0) {
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
}
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
@ -206,39 +205,40 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
/// Cleanup the type-info for a pybind11-registered type.
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
auto *type = (PyTypeObject *) obj;
auto &internals = get_internals();
with_internals([obj](internals &internals) {
auto *type = (PyTypeObject *) obj;
// A pybind11-registered type will:
// 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
&& found_type->second[0]->type == type) {
// A pybind11-registered type will:
// 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
&& found_type->second[0]->type == type) {
auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype);
internals.direct_conversions.erase(tindex);
auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype);
internals.direct_conversions.erase(tindex);
if (tinfo->module_local) {
get_local_internals().registered_types_cpp.erase(tindex);
} else {
internals.registered_types_cpp.erase(tindex);
}
internals.registered_types_py.erase(tinfo->type);
// Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it);
if (tinfo->module_local) {
get_local_internals().registered_types_cpp.erase(tindex);
} else {
++it;
internals.registered_types_cpp.erase(tindex);
}
}
internals.registered_types_py.erase(tinfo->type);
delete tinfo;
}
// Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it);
} else {
++it;
}
}
delete tinfo;
}
});
PyType_Type.tp_dealloc(obj);
}
@ -311,19 +311,20 @@ inline void traverse_offset_bases(void *valueptr,
}
inline bool register_instance_impl(void *ptr, instance *self) {
get_internals().registered_instances.emplace(ptr, self);
with_instance_map(ptr, [&](instance_map &instances) { instances.emplace(ptr, self); });
return true; // unused, but gives the same signature as the deregister func
}
inline bool deregister_instance_impl(void *ptr, instance *self) {
auto &registered_instances = get_internals().registered_instances;
auto range = registered_instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) {
if (self == it->second) {
registered_instances.erase(it);
return true;
return with_instance_map(ptr, [&](instance_map &instances) {
auto range = instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) {
if (self == it->second) {
instances.erase(it);
return true;
}
}
}
return false;
return false;
});
}
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
@ -378,23 +379,32 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject
}
inline void add_patient(PyObject *nurse, PyObject *patient) {
auto &internals = get_internals();
auto *instance = reinterpret_cast<detail::instance *>(nurse);
instance->has_patients = true;
Py_INCREF(patient);
internals.patients[nurse].push_back(patient);
with_internals([&](internals &internals) { internals.patients[nurse].push_back(patient); });
}
inline void clear_patients(PyObject *self) {
auto *instance = reinterpret_cast<detail::instance *>(self);
auto &internals = get_internals();
auto pos = internals.patients.find(self);
assert(pos != internals.patients.end());
// Clearing the patients can cause more Python code to run, which
// can invalidate the iterator. Extract the vector of patients
// from the unordered_map first.
auto patients = std::move(pos->second);
internals.patients.erase(pos);
std::vector<PyObject *> patients;
with_internals([&](internals &internals) {
auto pos = internals.patients.find(self);
if (pos == internals.patients.end()) {
pybind11_fail(
"FATAL: Internal consistency check failed: Invalid clear_patients() call.");
}
// Clearing the patients can cause more Python code to run, which
// can invalidate the iterator. Extract the vector of patients
// from the unordered_map first.
patients = std::move(pos->second);
internals.patients.erase(pos);
});
instance->has_patients = false;
for (PyObject *&patient : patients) {
Py_CLEAR(patient);
@ -456,19 +466,9 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) {
type->tp_free(self);
#if PY_VERSION_HEX < 0x03080000
// `type->tp_dealloc != pybind11_object_dealloc` means that we're being called
// as part of a derived type's dealloc, in which case we're not allowed to decref
// the type here. For cross-module compatibility, we shouldn't compare directly
// with `pybind11_object_dealloc`, but with the common one stashed in internals.
auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base;
if (type->tp_dealloc == pybind11_object_type->tp_dealloc)
Py_DECREF(type);
#else
// This was not needed before Python 3.8 (Python issue 35810)
// https://github.com/pybind/pybind11/issues/1946
Py_DECREF(type);
#endif
}
std::string error_string();
@ -520,8 +520,12 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject_VisitManagedDict(self, visit, arg);
#else
PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_VISIT(dict);
#endif
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
#if PY_VERSION_HEX >= 0x03090000
Py_VISIT(Py_TYPE(self));
@ -531,8 +535,12 @@ extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *a
/// dynamic_attr: Allow the GC to clear the dictionary.
extern "C" inline int pybind11_clear(PyObject *self) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject_ClearManagedDict(self);
#else
PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_CLEAR(dict);
#endif
return 0;
}
@ -549,17 +557,9 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
type->tp_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear;
static PyGetSetDef getset[] = {{
#if PY_VERSION_HEX < 0x03070000
const_cast<char *>("__dict__"),
#else
"__dict__",
#endif
PyObject_GenericGetDict,
PyObject_GenericSetDict,
nullptr,
nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}};
static PyGetSetDef getset[]
= {{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}};
type->tp_getset = getset;
}
@ -651,10 +651,13 @@ inline PyObject *make_new_python_type(const type_record &rec) {
char *tp_doc = nullptr;
if (rec.doc && options::show_user_defined_docstrings()) {
/* Allocate memory for docstring (using PyObject_MALLOC, since
Python will free this later on) */
/* Allocate memory for docstring (Python will free this later on) */
size_t size = std::strlen(rec.doc) + 1;
#if PY_VERSION_HEX >= 0x030D0000
tp_doc = (char *) PyMem_MALLOC(size);
#else
tp_doc = (char *) PyObject_MALLOC(size);
#endif
std::memcpy((void *) tp_doc, rec.doc, size);
}

View File

@ -10,12 +10,12 @@
#pragma once
#define PYBIND11_VERSION_MAJOR 2
#define PYBIND11_VERSION_MINOR 12
#define PYBIND11_VERSION_MINOR 14
#define PYBIND11_VERSION_PATCH 0.dev1
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
// Additional convention: 0xD = dev
#define PYBIND11_VERSION_HEX 0x020C00D1
#define PYBIND11_VERSION_HEX 0x020E00D1
// Define some generic pybind11 helper macros for warning management.
//
@ -272,9 +272,8 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
#endif
#include <Python.h>
// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000
#if PY_VERSION_HEX < 0x03060000
# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5."
#if PY_VERSION_HEX < 0x03080000
# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7."
#endif
#include <frameobject.h>
#include <pythread.h>
@ -296,6 +295,10 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
# undef copysign
#endif
#if defined(PYBIND11_NUMPY_1_ONLY)
# define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED
#endif
#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# define PYBIND11_SIMPLE_GIL_MANAGEMENT
#endif
@ -459,8 +462,24 @@ PYBIND11_WARNING_POP
return "Hello, World!";
});
}
The third macro argument is optional (available since 2.13.0), and can be used to
mark the extension module as safe to run without the GIL under a free-threaded CPython
interpreter. Passing this argument has no effect on other interpreters.
.. code-block:: cpp
PYBIND11_MODULE(example, m, py::mod_gil_not_used()) {
m.doc() = "pybind11 example module safe to run without the GIL";
// Add bindings here
m.def("foo", []() {
return "Hello, Free-threaded World!";
});
}
\endrst */
#define PYBIND11_MODULE(name, variable) \
#define PYBIND11_MODULE(name, variable, ...) \
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
PYBIND11_MAYBE_UNUSED; \
PYBIND11_MAYBE_UNUSED \
@ -469,7 +488,10 @@ PYBIND11_WARNING_POP
PYBIND11_CHECK_PYTHON_VERSION \
PYBIND11_ENSURE_INTERNALS_READY \
auto m = ::pybind11::module_::create_extension_module( \
PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
PYBIND11_TOSTRING(name), \
nullptr, \
&PYBIND11_CONCAT(pybind11_module_def_, name), \
##__VA_ARGS__); \
try { \
PYBIND11_CONCAT(pybind11_init_, name)(m); \
return m.ptr(); \
@ -921,8 +943,7 @@ using is_template_base_of
= decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr));
#else
struct is_template_base_of
: decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)) {
};
: decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)){};
#endif
/// Check if T is an instantiation of the template `Class`. For example:
@ -1104,14 +1125,14 @@ struct overload_cast_impl {
}
template <typename Return, typename Class>
constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
-> decltype(pmf) {
constexpr auto operator()(Return (Class::*pmf)(Args...),
std::false_type = {}) const noexcept -> decltype(pmf) {
return pmf;
}
template <typename Return, typename Class>
constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
-> decltype(pmf) {
constexpr auto operator()(Return (Class::*pmf)(Args...) const,
std::true_type) const noexcept -> decltype(pmf) {
return pmf;
}
};

View File

@ -156,8 +156,9 @@ constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {
}
#else
template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
constexpr auto concat(const descr<N, Ts...> &d,
const Args &...args) -> decltype(std::declval<descr<N + 2, Ts...>>()
+ concat(args...)) {
return d + const_name(", ") + concat(args...);
}
#endif

View File

@ -128,11 +128,13 @@ void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
// the holder and destruction happens when we leave the C++ scope, and the holder
// class gets to handle the destruction however it likes.
v_h.value_ptr() = ptr;
v_h.set_instance_registered(true); // To prevent init_instance from registering it
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
// DANGER ZONE BEGIN: exceptions will leave v_h in an invalid state.
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
v_h.set_instance_registered(false);
// DANGER ZONE END.
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
} else {

View File

@ -11,13 +11,15 @@
#include "common.h"
#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "../gil.h"
#endif
#include "../pytypes.h"
#include <exception>
#include <mutex>
#include <thread>
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
///
@ -62,60 +64,41 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
// Thread Specific Storage (TSS) API.
#if PY_VERSION_HEX >= 0x03070000
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
// `Py_LIMITED_API` anyway.
# if PYBIND11_INTERNALS_VERSION > 4
# define PYBIND11_TLS_KEY_REF Py_tss_t &
# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
// for every field.
# define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("GCC diagnostic push") /**/ \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("GCC diagnostic pop")
# else
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
# endif
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
#if PYBIND11_INTERNALS_VERSION > 4
# define PYBIND11_TLS_KEY_REF Py_tss_t &
# if defined(__clang__)
# define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("clang diagnostic push") /**/ \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("clang diagnostic pop")
# elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
# define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("GCC diagnostic push") /**/ \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("GCC diagnostic pop")
# else
# define PYBIND11_TLS_KEY_REF Py_tss_t *
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
# define PYBIND11_TLS_KEY_CREATE(var) \
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
# endif
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
#else
// Usually an int but a long on Cygwin64 with Python 3.x
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
# if defined(PYPY_VERSION)
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
// the value if it has already been set. Instead, it must first be deleted and
// then set again.
inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {
PyThread_delete_key_value(key);
PyThread_set_key_value(key, value);
}
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
::pybind11::detail::tls_replace_value((key), (value))
# else
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
# endif
# define PYBIND11_TLS_FREE(key) (void) key
# define PYBIND11_TLS_KEY_REF Py_tss_t *
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
# define PYBIND11_TLS_KEY_CREATE(var) \
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
#endif
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
@ -163,15 +146,48 @@ struct override_hash {
}
};
using instance_map = std::unordered_multimap<const void *, instance *>;
#ifdef Py_GIL_DISABLED
// Wrapper around PyMutex to provide BasicLockable semantics
class pymutex {
PyMutex mutex;
public:
pymutex() : mutex({}) {}
void lock() { PyMutex_Lock(&mutex); }
void unlock() { PyMutex_Unlock(&mutex); }
};
// Instance map shards are used to reduce mutex contention in free-threaded Python.
struct instance_map_shard {
instance_map registered_instances;
pymutex mutex;
// alignas(64) would be better, but causes compile errors in macOS before 10.14 (see #5200)
char padding[64 - (sizeof(instance_map) + sizeof(pymutex)) % 64];
};
static_assert(sizeof(instance_map_shard) % 64 == 0,
"instance_map_shard size is not a multiple of 64 bytes");
#endif
/// Internal data structure used to track registered instances and types.
/// Whenever binary incompatible changes are made to this structure,
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
struct internals {
#ifdef Py_GIL_DISABLED
pymutex mutex;
#endif
// std::type_index -> pybind11's type information
type_map<type_info *> registered_types_cpp;
// PyTypeObject* -> base type_info(s)
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
#ifdef Py_GIL_DISABLED
std::unique_ptr<instance_map_shard[]> instance_shards; // void * -> instance*
size_t instance_shards_mask;
#else
instance_map registered_instances; // void * -> instance*
#endif
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
@ -187,28 +203,27 @@ struct internals {
PyTypeObject *static_property_type;
PyTypeObject *default_metaclass;
PyObject *instance_base;
#if defined(WITH_THREAD)
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
PYBIND11_TLS_KEY_INIT(tstate)
# if PYBIND11_INTERNALS_VERSION > 4
#if PYBIND11_INTERNALS_VERSION > 4
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
# endif // PYBIND11_INTERNALS_VERSION > 4
#endif // PYBIND11_INTERNALS_VERSION > 4
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
PyInterpreterState *istate = nullptr;
# if PYBIND11_INTERNALS_VERSION > 4
#if PYBIND11_INTERNALS_VERSION > 4
// Note that we have to use a std::string to allocate memory to ensure a unique address
// We want unique addresses since we use pointer equality to compare function records
std::string function_record_capsule_name = internals_function_record_capsule_name;
# endif
#endif
internals() = default;
internals(const internals &other) = delete;
internals &operator=(const internals &other) = delete;
~internals() {
# if PYBIND11_INTERNALS_VERSION > 4
#if PYBIND11_INTERNALS_VERSION > 4
PYBIND11_TLS_FREE(loader_life_support_tls_key);
# endif // PYBIND11_INTERNALS_VERSION > 4
#endif // PYBIND11_INTERNALS_VERSION > 4
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
@ -219,7 +234,6 @@ struct internals {
// that the `tstate` be allocated with the CPython allocator.
PYBIND11_TLS_FREE(tstate);
}
#endif
};
/// Additional type information which does not fit into the PyTypeObject.
@ -304,22 +318,18 @@ struct type_info {
#endif
#ifndef PYBIND11_INTERNALS_KIND
# if defined(WITH_THREAD)
# define PYBIND11_INTERNALS_KIND ""
# else
# define PYBIND11_INTERNALS_KIND "_without_thread"
# endif
# define PYBIND11_INTERNALS_KIND ""
#endif
#define PYBIND11_INTERNALS_ID \
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE "__"
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
#define PYBIND11_MODULE_LOCAL_ID \
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE "__"
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
/// Each module locally stores a pointer to the `internals` data. The data
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
@ -437,7 +447,7 @@ inline void translate_local_exception(std::exception_ptr p) {
inline object get_python_state_dict() {
object state_dict;
#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
#if PYBIND11_INTERNALS_VERSION <= 4 || defined(PYPY_VERSION)
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
#else
# if PY_VERSION_HEX < 0x03090000
@ -457,7 +467,8 @@ inline object get_python_state_dict() {
}
inline object get_internals_obj_from_state_dict(handle state_dict) {
return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));
return reinterpret_steal<object>(
dict_getitemstringref(state_dict.ptr(), PYBIND11_INTERNALS_ID));
}
inline internals **get_internals_pp_from_capsule(handle obj) {
@ -469,6 +480,20 @@ inline internals **get_internals_pp_from_capsule(handle obj) {
return static_cast<internals **>(raw_ptr);
}
inline uint64_t round_up_to_next_pow2(uint64_t x) {
// Round-up to the next power of two.
// See https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
x--;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
x++;
return x;
}
/// Return a reference to the current `internals` data
PYBIND11_NOINLINE internals &get_internals() {
auto **&internals_pp = get_internals_pp();
@ -476,10 +501,9 @@ PYBIND11_NOINLINE internals &get_internals() {
return **internals_pp;
}
#if defined(WITH_THREAD)
# if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
gil_scoped_acquire gil;
# else
#else
// Ensure that the GIL is held since we will need to make Python calls.
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
struct gil_scoped_acquire_local {
@ -489,7 +513,6 @@ PYBIND11_NOINLINE internals &get_internals() {
~gil_scoped_acquire_local() { PyGILState_Release(state); }
const PyGILState_STATE state;
} gil;
# endif
#endif
error_scope err_scope;
@ -514,7 +537,6 @@ PYBIND11_NOINLINE internals &get_internals() {
}
auto *&internals_ptr = *internals_pp;
internals_ptr = new internals();
#if defined(WITH_THREAD)
PyThreadState *tstate = PyThreadState_Get();
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
@ -523,20 +545,29 @@ PYBIND11_NOINLINE internals &get_internals() {
}
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
# if PYBIND11_INTERNALS_VERSION > 4
#if PYBIND11_INTERNALS_VERSION > 4
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
pybind11_fail("get_internals: could not successfully initialize the "
"loader_life_support TSS key!");
}
# endif
internals_ptr->istate = tstate->interp;
#endif
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
internals_ptr->istate = tstate->interp;
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
internals_ptr->registered_exception_translators.push_front(&translate_exception);
internals_ptr->static_property_type = make_static_property_type();
internals_ptr->default_metaclass = make_default_metaclass();
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
#ifdef Py_GIL_DISABLED
// Scale proportional to the number of cores. 2x is a heuristic to reduce contention.
auto num_shards
= static_cast<size_t>(round_up_to_next_pow2(2 * std::thread::hardware_concurrency()));
if (num_shards == 0) {
num_shards = 1;
}
internals_ptr->instance_shards.reset(new instance_map_shard[num_shards]);
internals_ptr->instance_shards_mask = num_shards - 1;
#endif // Py_GIL_DISABLED
}
return **internals_pp;
}
@ -550,7 +581,7 @@ PYBIND11_NOINLINE internals &get_internals() {
struct local_internals {
type_map<type_info *> registered_types_cpp;
std::forward_list<ExceptionTranslator> registered_exception_translators;
#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
#if PYBIND11_INTERNALS_VERSION == 4
// For ABI compatibility, we can't store the loader_life_support TLS key in
// the `internals` struct directly. Instead, we store it in `shared_data` and
@ -583,7 +614,7 @@ struct local_internals {
loader_life_support_tls_key
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
}
#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
#endif // PYBIND11_INTERNALS_VERSION == 4
};
/// Works like `get_internals`, but for things which are locally registered.
@ -597,13 +628,80 @@ inline local_internals &get_local_internals() {
return *locals;
}
#ifdef Py_GIL_DISABLED
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<pymutex> lock((internals).mutex)
#else
# define PYBIND11_LOCK_INTERNALS(internals)
#endif
template <typename F>
inline auto with_internals(const F &cb) -> decltype(cb(get_internals())) {
auto &internals = get_internals();
PYBIND11_LOCK_INTERNALS(internals);
return cb(internals);
}
inline std::uint64_t mix64(std::uint64_t z) {
// David Stafford's variant 13 of the MurmurHash3 finalizer popularized
// by the SplitMix PRNG.
// https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
template <typename F>
inline auto with_instance_map(const void *ptr,
const F &cb) -> decltype(cb(std::declval<instance_map &>())) {
auto &internals = get_internals();
#ifdef Py_GIL_DISABLED
// Hash address to compute shard, but ignore low bits. We'd like allocations
// from the same thread/core to map to the same shard and allocations from
// other threads/cores to map to other shards. Using the high bits is a good
// heuristic because memory allocators often have a per-thread
// arena/superblock/segment from which smaller allocations are served.
auto addr = reinterpret_cast<std::uintptr_t>(ptr);
auto hash = mix64(static_cast<std::uint64_t>(addr >> 20));
auto idx = static_cast<size_t>(hash & internals.instance_shards_mask);
auto &shard = internals.instance_shards[idx];
std::unique_lock<pymutex> lock(shard.mutex);
return cb(shard.registered_instances);
#else
(void) ptr;
return cb(internals.registered_instances);
#endif
}
// Returns the number of registered instances for testing purposes. The result may not be
// consistent if other threads are registering or unregistering instances concurrently.
inline size_t num_registered_instances() {
auto &internals = get_internals();
#ifdef Py_GIL_DISABLED
size_t count = 0;
for (size_t i = 0; i <= internals.instance_shards_mask; ++i) {
auto &shard = internals.instance_shards[i];
std::unique_lock<pymutex> lock(shard.mutex);
count += shard.registered_instances.size();
}
return count;
#else
return internals.registered_instances.size();
#endif
}
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
template <typename... Args>
const char *c_str(Args &&...args) {
auto &strings = get_internals().static_strings;
// GCC 4.8 doesn't like parameter unpack within lambda capture, so use
// PYBIND11_LOCK_INTERNALS.
auto &internals = get_internals();
PYBIND11_LOCK_INTERNALS(internals);
auto &strings = internals.static_strings;
strings.emplace_front(std::forward<Args>(args)...);
return strings.front().c_str();
}
@ -633,15 +731,18 @@ PYBIND11_NAMESPACE_END(detail)
/// pybind11 version) running in the current interpreter. Names starting with underscores
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
auto &internals = detail::get_internals();
auto it = internals.shared_data.find(name);
return it != internals.shared_data.end() ? it->second : nullptr;
return detail::with_internals([&](detail::internals &internals) {
auto it = internals.shared_data.find(name);
return it != internals.shared_data.end() ? it->second : nullptr;
});
}
/// Set the shared data that can be later recovered by `get_shared_data()`.
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
detail::get_internals().shared_data[name] = data;
return data;
return detail::with_internals([&](detail::internals &internals) {
internals.shared_data[name] = data;
return data;
});
}
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
@ -649,14 +750,15 @@ PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
/// added to the shared data under the given name and a reference to it is returned.
template <typename T>
T &get_or_create_shared_data(const std::string &name) {
auto &internals = detail::get_internals();
auto it = internals.shared_data.find(name);
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
if (!ptr) {
ptr = new T();
internals.shared_data[name] = ptr;
}
return *ptr;
return *detail::with_internals([&](detail::internals &internals) {
auto it = internals.shared_data.find(name);
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
if (!ptr) {
ptr = new T();
internals.shared_data[name] = ptr;
}
return ptr;
});
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -14,6 +14,7 @@
#include "descr.h"
#include "internals.h"
#include "typeid.h"
#include "value_and_holder.h"
#include <cstdint>
#include <iterator>
@ -36,14 +37,13 @@ private:
loader_life_support *parent = nullptr;
std::unordered_set<PyObject *> keep_alive;
#if defined(WITH_THREAD)
// Store stack pointer in thread-local storage.
static PYBIND11_TLS_KEY_REF get_stack_tls_key() {
# if PYBIND11_INTERNALS_VERSION == 4
#if PYBIND11_INTERNALS_VERSION == 4
return get_local_internals().loader_life_support_tls_key;
# else
#else
return get_internals().loader_life_support_tls_key;
# endif
#endif
}
static loader_life_support *get_stack_top() {
return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));
@ -51,15 +51,6 @@ private:
static void set_stack_top(loader_life_support *value) {
PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), value);
}
#else
// Use single global variable for stack.
static loader_life_support **get_stack_pp() {
static loader_life_support *global_stack = nullptr;
return global_stack;
}
static loader_life_support *get_stack_top() { return *get_stack_pp(); }
static void set_stack_top(loader_life_support *value) { *get_stack_pp() = value; }
#endif
public:
/// A new patient frame is created when a function is entered
@ -217,12 +208,15 @@ inline detail::type_info *get_local_type_info(const std::type_index &tp) {
}
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
auto &types = get_internals().registered_types_cpp;
auto it = types.find(tp);
if (it != types.end()) {
return it->second;
}
return nullptr;
return with_internals([&](internals &internals) {
detail::type_info *type_info = nullptr;
auto &types = internals.registered_types_cpp;
auto it = types.find(tp);
if (it != types.end()) {
type_info = it->second;
}
return type_info;
});
}
/// Return the type info for a given C++ type; on lookup failure can either throw or return
@ -253,78 +247,19 @@ PYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if
// Searches the inheritance graph for a registered Python instance, using all_type_info().
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
const detail::type_info *tinfo) {
auto it_instances = get_internals().registered_instances.equal_range(src);
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
return handle((PyObject *) it_i->second).inc_ref();
return with_instance_map(src, [&](instance_map &instances) {
auto it_instances = instances.equal_range(src);
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
return handle((PyObject *) it_i->second).inc_ref();
}
}
}
}
return handle();
return handle();
});
}
struct value_and_holder {
instance *inst = nullptr;
size_t index = 0u;
const detail::type_info *type = nullptr;
void **vh = nullptr;
// Main constructor for a found value/holder:
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
: inst{i}, index{index}, type{type},
vh{inst->simple_layout ? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[vpos]} {}
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
value_and_holder() = default;
// Used for past-the-end iterator
explicit value_and_holder(size_t index) : index{index} {}
template <typename V = void>
V *&value_ptr() const {
return reinterpret_cast<V *&>(vh[0]);
}
// True if this `value_and_holder` has a non-null value pointer
explicit operator bool() const { return value_ptr() != nullptr; }
template <typename H>
H &holder() const {
return reinterpret_cast<H &>(vh[1]);
}
bool holder_constructed() const {
return inst->simple_layout
? inst->simple_holder_constructed
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_holder_constructed(bool v = true) {
if (inst->simple_layout) {
inst->simple_holder_constructed = v;
} else if (v) {
inst->nonsimple.status[index] |= instance::status_holder_constructed;
} else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
}
}
bool instance_registered() const {
return inst->simple_layout
? inst->simple_instance_registered
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_instance_registered(bool v = true) {
if (inst->simple_layout) {
inst->simple_instance_registered = v;
} else if (v) {
inst->nonsimple.status[index] |= instance::status_instance_registered;
} else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
}
}
};
// Container for accessing and iterating over an instance's values/holders
struct values_and_holders {
private:
@ -493,7 +428,7 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
// NOLINTNEXTLINE(readability-make-member-function-const)
PYBIND11_NOINLINE void instance::deallocate_layout() {
if (!simple_layout) {
PyMem_Free(nonsimple.values_and_holders);
PyMem_Free(reinterpret_cast<void *>(nonsimple.values_and_holders));
}
}
@ -506,16 +441,17 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp)
}
PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) {
auto &instances = get_internals().registered_instances;
auto range = instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) {
for (const auto &vh : values_and_holders(it->second)) {
if (vh.type == type) {
return handle((PyObject *) it->second);
return with_instance_map(ptr, [&](instance_map &instances) {
auto range = instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) {
for (const auto &vh : values_and_holders(it->second)) {
if (vh.type == type) {
return handle((PyObject *) it->second);
}
}
}
}
return handle();
return handle();
});
}
inline PyThreadState *get_thread_state_unchecked() {
@ -1111,11 +1047,11 @@ public:
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast(&src, policy, parent);
return cast(std::addressof(src), policy, parent);
}
static handle cast(itype &&src, return_value_policy, handle parent) {
return cast(&src, return_value_policy::move, parent);
return cast(std::addressof(src), return_value_policy::move, parent);
}
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
@ -1184,14 +1120,14 @@ protected:
does not have a private operator new implementation. A comma operator is used in the
decltype argument to apply SFINAE to the public copy/move constructors.*/
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
static auto make_copy_constructor(const T *)
-> decltype(new T(std::declval<const T>()), Constructor{}) {
static auto make_copy_constructor(const T *) -> decltype(new T(std::declval<const T>()),
Constructor{}) {
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
}
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
static auto make_move_constructor(const T *)
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
static auto make_move_constructor(const T *) -> decltype(new T(std::declval<T &&>()),
Constructor{}) {
return [](const void *arg) -> void * {
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
};
@ -1201,13 +1137,17 @@ protected:
static Constructor make_move_constructor(...) { return nullptr; }
};
inline std::string quote_cpp_type_name(const std::string &cpp_type_name) {
return cpp_type_name; // No-op for now. See PR #4888
}
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
if (auto *type_data = get_type_info(ti)) {
handle th((PyObject *) type_data->type);
return th.attr("__module__").cast<std::string>() + '.'
+ th.attr("__qualname__").cast<std::string>();
}
return clean_type_id(ti.name());
return quote_cpp_type_name(clean_type_id(ti.name()));
}
PYBIND11_NAMESPACE_END(detail)

View File

@ -0,0 +1,77 @@
// Copyright (c) 2016-2024 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "common.h"
#include <cstddef>
#include <typeinfo>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
struct value_and_holder {
instance *inst = nullptr;
size_t index = 0u;
const detail::type_info *type = nullptr;
void **vh = nullptr;
// Main constructor for a found value/holder:
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
: inst{i}, index{index}, type{type},
vh{inst->simple_layout ? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[vpos]} {}
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
value_and_holder() = default;
// Used for past-the-end iterator
explicit value_and_holder(size_t index) : index{index} {}
template <typename V = void>
V *&value_ptr() const {
return reinterpret_cast<V *&>(vh[0]);
}
// True if this `value_and_holder` has a non-null value pointer
explicit operator bool() const { return value_ptr() != nullptr; }
template <typename H>
H &holder() const {
return reinterpret_cast<H &>(vh[1]);
}
bool holder_constructed() const {
return inst->simple_layout
? inst->simple_holder_constructed
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_holder_constructed(bool v = true) {
if (inst->simple_layout) {
inst->simple_holder_constructed = v;
} else if (v) {
inst->nonsimple.status[index] |= instance::status_holder_constructed;
} else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
}
}
bool instance_registered() const {
return inst->simple_layout
? inst->simple_instance_registered
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_instance_registered(bool v = true) {
if (inst->simple_layout) {
inst->simple_instance_registered = v;
} else if (v) {
inst->nonsimple.status[index] |= instance::status_instance_registered;
} else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
}
}
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -70,7 +70,7 @@ struct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexTy
template <size_t... Is>
struct helper<index_sequence<Is...>> {
static constexpr auto value = concat(const_name(((void) Is, "?"))...);
static constexpr auto value = ::pybind11::detail::concat(const_name(((void) Is, "?"))...);
};
static constexpr auto dimensions_descriptor
@ -104,7 +104,8 @@ struct eigen_tensor_helper<
return get_shape() == shape;
}
static constexpr auto dimensions_descriptor = concat(const_name<Indices>()...);
static constexpr auto dimensions_descriptor
= ::pybind11::detail::concat(const_name<Indices>()...);
template <typename... Args>
static Type *alloc(Args &&...args) {
@ -468,9 +469,6 @@ struct type_caster<Eigen::TensorMap<Type, Options>,
parent_object = reinterpret_borrow<object>(parent);
break;
case return_value_policy::take_ownership:
delete src;
// fallthrough
default:
// move, take_ownership don't make any sense for a ref/map:
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "

View File

@ -103,19 +103,6 @@ inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
bool add_program_dir_to_path) {
detail::precheck_interpreter();
Py_InitializeEx(init_signal_handlers ? 1 : 0);
# if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
PyEval_InitThreads();
# endif
// Before it was special-cased in python 3.8, passing an empty or null argv
// caused a segfault, so we have to reimplement the special case ourselves.
bool special_case = (argv == nullptr || argc <= 0);
const char *const empty_argv[]{"\0"};
const char *const *safe_argv = special_case ? empty_argv : argv;
if (special_case) {
argc = 1;
}
auto argv_size = static_cast<size_t>(argc);
// SetArgv* on python 3 takes wchar_t, so we have to convert.
@ -123,7 +110,7 @@ inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
widened_argv_entries.reserve(argv_size);
for (size_t ii = 0; ii < argv_size; ++ii) {
widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));
widened_argv_entries.emplace_back(detail::widen_chars(argv[ii]));
if (!widened_argv_entries.back()) {
// A null here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.

View File

@ -19,7 +19,7 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline void ensure_builtins_in_globals(object &global) {
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
#if defined(PYPY_VERSION)
// Running exec and eval adds `builtins` module under `__builtins__` key to
// globals if not yet present. Python 3.8 made PyRun_String behave
// similarly. Let's also do that for older versions, for consistency. This

View File

@ -128,7 +128,8 @@ public:
}
PYBIND11_TYPE_CASTER(type,
const_name("Callable[[") + concat(make_caster<Args>::name...)
const_name("Callable[[")
+ ::pybind11::detail::concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name
+ const_name("]"));
};

View File

@ -13,7 +13,7 @@
#include <cassert>
#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "detail/internals.h"
#endif
@ -26,9 +26,7 @@ PyThreadState *get_thread_state_unchecked();
PYBIND11_NAMESPACE_END(detail)
#if defined(WITH_THREAD)
# if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
/* The functions below essentially reproduce the PyGILState_* API using a RAII
* pattern, but there are a few important differences:
@ -69,11 +67,11 @@ public:
if (!tstate) {
tstate = PyThreadState_New(internals.istate);
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!tstate) {
pybind11_fail("scoped_acquire: could not create thread state!");
}
# endif
# endif
tstate->gilstate_counter = 0;
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
} else {
@ -94,20 +92,20 @@ public:
PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter;
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (detail::get_thread_state_unchecked() != tstate) {
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
}
if (tstate->gilstate_counter < 0) {
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
}
# endif
# endif
if (tstate->gilstate_counter == 0) {
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!release) {
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
}
# endif
# endif
PyThreadState_Clear(tstate);
if (active) {
PyThreadState_DeleteCurrent();
@ -149,9 +147,7 @@ public:
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
tstate = PyEval_SaveThread();
if (disassoc) {
// Python >= 3.7 can remove this, it's an int before 3.7
// NOLINTNEXTLINE(readability-qualified-auto)
auto key = internals.tstate;
auto key = internals.tstate; // NOLINT(readability-qualified-auto)
PYBIND11_TLS_DELETE_VALUE(key);
}
}
@ -175,9 +171,7 @@ public:
PyEval_RestoreThread(tstate);
}
if (disassoc) {
// Python >= 3.7 can remove this, it's an int before 3.7
// NOLINTNEXTLINE(readability-qualified-auto)
auto key = detail::get_internals().tstate;
auto key = detail::get_internals().tstate; // NOLINT(readability-qualified-auto)
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
}
}
@ -188,7 +182,7 @@ private:
bool active = true;
};
# else // PYBIND11_SIMPLE_GIL_MANAGEMENT
#else // PYBIND11_SIMPLE_GIL_MANAGEMENT
class gil_scoped_acquire {
PyGILState_STATE state;
@ -216,32 +210,6 @@ public:
void disarm() {}
};
# endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
#else // WITH_THREAD
class gil_scoped_acquire {
public:
gil_scoped_acquire() {
// Trick to suppress `unused variable` error messages (at call sites).
(void) (this != (this + 1));
}
gil_scoped_acquire(const gil_scoped_acquire &) = delete;
gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
void disarm() {}
};
class gil_scoped_release {
public:
gil_scoped_release() {
// Trick to suppress `unused variable` error messages (at call sites).
(void) (this != (this + 1));
}
gil_scoped_release(const gil_scoped_release &) = delete;
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
void disarm() {}
};
#endif // WITH_THREAD
#endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -8,6 +8,10 @@
#include <cassert>
#include <mutex>
#ifdef Py_GIL_DISABLED
# include <atomic>
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
// Use the `gil_safe_call_once_and_store` class below instead of the naive
@ -82,7 +86,12 @@ public:
private:
alignas(T) char storage_[sizeof(T)] = {};
std::once_flag once_flag_ = {};
bool is_initialized_ = false;
#ifdef Py_GIL_DISABLED
std::atomic_bool
#else
bool
#endif
is_initialized_{false};
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
// but the latter does not have the triviality properties of former,
// therefore `std::optional` is not a viable alternative here.

View File

@ -29,10 +29,15 @@
#include <utility>
#include <vector>
#if defined(PYBIND11_NUMPY_1_ONLY) && !defined(PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED)
# error PYBIND11_NUMPY_1_ONLY must be defined before any pybind11 header is included.
#endif
/* This will be true on all flat address space platforms and allows us to reduce the
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
upon the library user. */
upon the library user.
Note that NumPy 2 now uses ssize_t for `npy_intp` to simplify this. */
static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
@ -41,10 +46,16 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127)
class dtype; // Forward declaration
class array; // Forward declaration
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<dtype> {
static constexpr auto name = const_name("numpy.dtype");
};
template <>
struct handle_type_name<array> {
static constexpr auto name = const_name("numpy.ndarray");
@ -53,7 +64,8 @@ struct handle_type_name<array> {
template <typename type, typename SFINAE = void>
struct npy_format_descriptor;
struct PyArrayDescr_Proxy {
/* NumPy 1 proxy (always includes legacy fields) */
struct PyArrayDescr1_Proxy {
PyObject_HEAD
PyObject *typeobj;
char kind;
@ -68,6 +80,43 @@ struct PyArrayDescr_Proxy {
PyObject *names;
};
#ifndef PYBIND11_NUMPY_1_ONLY
struct PyArrayDescr_Proxy {
PyObject_HEAD
PyObject *typeobj;
char kind;
char type;
char byteorder;
char _former_flags;
int type_num;
/* Additional fields are NumPy version specific. */
};
#else
/* NumPy 1.x only, we can expose all fields */
using PyArrayDescr_Proxy = PyArrayDescr1_Proxy;
#endif
/* NumPy 2 proxy, including legacy fields */
struct PyArrayDescr2_Proxy {
PyObject_HEAD
PyObject *typeobj;
char kind;
char type;
char byteorder;
char _former_flags;
int type_num;
std::uint64_t flags;
ssize_t elsize;
ssize_t alignment;
PyObject *metadata;
Py_hash_t hash;
void *reserved_null[2];
/* The following fields only exist if 0 <= type_num < 2056 */
char *subarray;
PyObject *fields;
PyObject *names;
};
struct PyArray_Proxy {
PyObject_HEAD
char *data;
@ -131,6 +180,14 @@ PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name
object numpy_version = numpy_lib.attr("NumpyVersion")(version_string);
int major_version = numpy_version.attr("major").cast<int>();
#ifdef PYBIND11_NUMPY_1_ONLY
if (major_version >= 2) {
throw std::runtime_error(
"This extension was built with PYBIND11_NUMPY_1_ONLY defined, "
"but NumPy 2 is used in this process. For NumPy2 compatibility, "
"this extension needs to be rebuilt without the PYBIND11_NUMPY_1_ONLY define.");
}
#endif
/* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially
became a private module. */
std::string numpy_core_path = major_version >= 2 ? "numpy._core" : "numpy.core";
@ -203,6 +260,8 @@ struct npy_api {
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
};
unsigned int PyArray_RUNTIME_VERSION_;
struct PyArray_Dims {
Py_intptr_t *ptr;
int len;
@ -241,6 +300,7 @@ struct npy_api {
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
#ifdef PYBIND11_NUMPY_1_ONLY
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
PyObject *,
unsigned char,
@ -249,6 +309,7 @@ struct npy_api {
Py_intptr_t *,
PyObject **,
PyObject *);
#endif
PyObject *(*PyArray_Squeeze_)(PyObject *);
// Unused. Not removed because that affects ABI of the class.
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
@ -266,7 +327,8 @@ private:
API_PyArray_DescrFromScalar = 57,
API_PyArray_FromAny = 69,
API_PyArray_Resize = 80,
API_PyArray_CopyInto = 82,
// CopyInto was slot 82 and 50 was effectively an alias. NumPy 2 removed 82.
API_PyArray_CopyInto = 50,
API_PyArray_NewCopy = 85,
API_PyArray_NewFromDescr = 94,
API_PyArray_DescrNewFromType = 96,
@ -275,7 +337,9 @@ private:
API_PyArray_View = 137,
API_PyArray_DescrConverter = 174,
API_PyArray_EquivTypes = 182,
#ifdef PYBIND11_NUMPY_1_ONLY
API_PyArray_GetArrayParamsFromObject = 278,
#endif
API_PyArray_SetBaseObject = 282
};
@ -290,7 +354,8 @@ private:
npy_api api;
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) {
api.PyArray_RUNTIME_VERSION_ = api.PyArray_GetNDArrayCFeatureVersion_();
if (api.PyArray_RUNTIME_VERSION_ < 0x7) {
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
}
DECL_NPY_API(PyArray_Type);
@ -309,7 +374,9 @@ private:
DECL_NPY_API(PyArray_View);
DECL_NPY_API(PyArray_DescrConverter);
DECL_NPY_API(PyArray_EquivTypes);
#ifdef PYBIND11_NUMPY_1_ONLY
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
#endif
DECL_NPY_API(PyArray_SetBaseObject);
#undef DECL_NPY_API
@ -331,6 +398,14 @@ inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);
}
inline const PyArrayDescr1_Proxy *array_descriptor1_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr1_Proxy *>(ptr);
}
inline const PyArrayDescr2_Proxy *array_descriptor2_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr2_Proxy *>(ptr);
}
inline bool check_flags(const void *ptr, int flag) {
return (flag == (array_proxy(ptr)->flags & flag));
}
@ -371,7 +446,7 @@ struct array_info<std::array<T, N>> {
}
static constexpr auto extents = const_name<array_info<T>::is_array>(
concat(const_name<N>(), array_info<T>::extents), const_name<N>());
::pybind11::detail::concat(const_name<N>(), array_info<T>::extents), const_name<N>());
};
// For numpy we have special handling for arrays of characters, so we don't include
// the size in the array extents.
@ -610,10 +685,32 @@ public:
}
/// Size of the data type in bytes.
#ifdef PYBIND11_NUMPY_1_ONLY
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
#else
ssize_t itemsize() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return detail::array_descriptor1_proxy(m_ptr)->elsize;
}
return detail::array_descriptor2_proxy(m_ptr)->elsize;
}
#endif
/// Returns true for structured data types.
#ifdef PYBIND11_NUMPY_1_ONLY
bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }
#else
bool has_fields() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return detail::array_descriptor1_proxy(m_ptr)->names != nullptr;
}
const auto *proxy = detail::array_descriptor2_proxy(m_ptr);
if (proxy->type_num < 0 || proxy->type_num >= 2056) {
return false;
}
return proxy->names != nullptr;
}
#endif
/// Single-character code for dtype's kind.
/// For example, floating point types are 'f' and integral types are 'i'.
@ -639,11 +736,29 @@ public:
/// Single character for byteorder
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
/// Alignment of the data type
/// Alignment of the data type
#ifdef PYBIND11_NUMPY_1_ONLY
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
#else
ssize_t alignment() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return detail::array_descriptor1_proxy(m_ptr)->alignment;
}
return detail::array_descriptor2_proxy(m_ptr)->alignment;
}
#endif
/// Flags for the array descriptor
/// Flags for the array descriptor
#ifdef PYBIND11_NUMPY_1_ONLY
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
#else
std::uint64_t flags() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return (unsigned char) detail::array_descriptor1_proxy(m_ptr)->flags;
}
return detail::array_descriptor2_proxy(m_ptr)->flags;
}
#endif
private:
static object &_dtype_from_pep3118() {
@ -786,7 +901,11 @@ public:
template <typename T>
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
: array(pybind11::dtype::of<T>(),
std::move(shape),
std::move(strides),
reinterpret_cast<const void *>(ptr),
base) {}
template <typename T>
array(ShapeContainer shape, const T *ptr, handle base = handle())
@ -810,9 +929,7 @@ public:
}
/// Byte size of a single element
ssize_t itemsize() const {
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
}
ssize_t itemsize() const { return dtype().itemsize(); }
/// Total number of bytes
ssize_t nbytes() const { return size() * itemsize(); }
@ -1440,7 +1557,9 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor>
auto tindex = std::type_index(tinfo);
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)};
get_internals().direct_conversions[tindex].push_back(direct_converter);
with_internals([tindex, &direct_converter](internals &internals) {
internals.direct_conversions[tindex].push_back(direct_converter);
});
}
template <typename T, typename SFINAE>
@ -1871,7 +1990,7 @@ private:
// Pointers to values the function was called with; the vectorized ones set here will start
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
// call the wrapped function. Non-vectorized pointers are left as-is.
std::array<void *, N> params{{&args...}};
std::array<void *, N> params{{reinterpret_cast<void *>(&args)...}};
// The array of `buffer_info`s of vectorized arguments:
std::array<buffer_info, NVectorized> buffers{

View File

@ -492,9 +492,7 @@ protected:
signature += rec->scope.attr("__module__").cast<std::string>() + "."
+ rec->scope.attr("__qualname__").cast<std::string>();
} else {
std::string tname(t->name());
detail::clean_type_id(tname);
signature += tname;
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
}
} else {
signature += c;
@ -1056,13 +1054,20 @@ protected:
- delegate translation to the next translator by throwing a new type of exception.
*/
auto &local_exception_translators
= get_local_internals().registered_exception_translators;
if (detail::apply_exception_translators(local_exception_translators)) {
return nullptr;
}
auto &exception_translators = get_internals().registered_exception_translators;
if (detail::apply_exception_translators(exception_translators)) {
bool handled = with_internals([&](internals &internals) {
auto &local_exception_translators
= get_local_internals().registered_exception_translators;
if (detail::apply_exception_translators(local_exception_translators)) {
return true;
}
auto &exception_translators = internals.registered_exception_translators;
if (detail::apply_exception_translators(exception_translators)) {
return true;
}
return false;
});
if (handled) {
return nullptr;
}
@ -1192,6 +1197,25 @@ protected:
}
};
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<cpp_function> {
static constexpr auto name = const_name("Callable");
};
PYBIND11_NAMESPACE_END(detail)
// Use to activate Py_MOD_GIL_NOT_USED.
class mod_gil_not_used {
public:
explicit mod_gil_not_used(bool flag = true) : flag_(flag) {}
bool flag() const { return flag_; }
private:
bool flag_;
};
/// Wrapper for Python extension modules
class module_ : public object {
public:
@ -1292,7 +1316,11 @@ public:
``def`` should point to a statically allocated module_def.
\endrst */
static module_ create_extension_module(const char *name, const char *doc, module_def *def) {
static module_ create_extension_module(const char *name,
const char *doc,
module_def *def,
mod_gil_not_used gil_not_used
= mod_gil_not_used(false)) {
// module_def is PyModuleDef
// Placement new (not an allocation).
def = new (def)
@ -1312,6 +1340,11 @@ public:
}
pybind11_fail("Internal error in module_::create_extension_module()");
}
if (gil_not_used.flag()) {
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
}
// TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when
// returned from PyInit_...
// For Python 2, reinterpret_borrow was correct.
@ -1319,6 +1352,15 @@ public:
}
};
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<module_> {
static constexpr auto name = const_name("module");
};
PYBIND11_NAMESPACE_END(detail)
// When inside a namespace (or anywhere as long as it's not the first item on a line),
// C++20 allows "module" to be used. This is provided for backward compatibility, and for
// simplicity, if someone wants to use py::module for example, that is perfectly safe.
@ -1328,8 +1370,14 @@ using module = module_;
/// Return a dictionary representing the global variables in the current execution frame,
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
inline dict globals() {
#if PY_VERSION_HEX >= 0x030d0000
PyObject *p = PyEval_GetFrameGlobals();
return p ? reinterpret_steal<dict>(p)
: reinterpret_borrow<dict>(module_::import("__main__").attr("__dict__").ptr());
#else
PyObject *p = PyEval_GetGlobals();
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
#endif
}
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
@ -1375,15 +1423,16 @@ protected:
tinfo->default_holder = rec.default_holder;
tinfo->module_local = rec.module_local;
auto &internals = get_internals();
auto tindex = std::type_index(*rec.type);
tinfo->direct_conversions = &internals.direct_conversions[tindex];
if (rec.module_local) {
get_local_internals().registered_types_cpp[tindex] = tinfo;
} else {
internals.registered_types_cpp[tindex] = tinfo;
}
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
with_internals([&](internals &internals) {
auto tindex = std::type_index(*rec.type);
tinfo->direct_conversions = &internals.direct_conversions[tindex];
if (rec.module_local) {
get_local_internals().registered_types_cpp[tindex] = tinfo;
} else {
internals.registered_types_cpp[tindex] = tinfo;
}
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
});
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
mark_parents_nonsimple(tinfo->type);
@ -1596,10 +1645,12 @@ public:
generic_type::initialize(record);
if (has_alias) {
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
: get_internals().registered_types_cpp;
instances[std::type_index(typeid(type_alias))]
= instances[std::type_index(typeid(type))];
with_internals([&](internals &internals) {
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
: internals.registered_types_cpp;
instances[std::type_index(typeid(type_alias))]
= instances[std::type_index(typeid(type))];
});
}
}
@ -2314,28 +2365,32 @@ keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
all_type_info_get_cache(PyTypeObject *type) {
auto res = get_internals()
.registered_types_py
auto res = with_internals([type](internals &internals) {
return internals
.registered_types_py
#ifdef __cpp_lib_unordered_map_try_emplace
.try_emplace(type);
.try_emplace(type);
#else
.emplace(type, std::vector<detail::type_info *>());
.emplace(type, std::vector<detail::type_info *>());
#endif
});
if (res.second) {
// New cache entry created; set up a weak reference to automatically remove it if the type
// gets destroyed:
weakref((PyObject *) type, cpp_function([type](handle wr) {
get_internals().registered_types_py.erase(type);
with_internals([type](internals &internals) {
internals.registered_types_py.erase(type);
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
auto &cache = get_internals().inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == reinterpret_cast<PyObject *>(type)) {
it = cache.erase(it);
} else {
++it;
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == reinterpret_cast<PyObject *>(type)) {
it = cache.erase(it);
} else {
++it;
}
}
}
});
wr.dec_ref();
}))
@ -2540,7 +2595,11 @@ void implicitly_convertible() {
~set_flag() { flag = false; }
};
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
#ifdef Py_GIL_DISABLED
thread_local bool currently_used = false;
#else
static bool currently_used = false;
#endif
if (currently_used) { // implicit conversions are non-reentrant
return nullptr;
}
@ -2565,8 +2624,10 @@ void implicitly_convertible() {
}
inline void register_exception_translator(ExceptionTranslator &&translator) {
detail::get_internals().registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
detail::with_internals([&](detail::internals &internals) {
internals.registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
});
}
/**
@ -2576,8 +2637,11 @@ inline void register_exception_translator(ExceptionTranslator &&translator) {
* the exception.
*/
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
detail::get_local_internals().registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
detail::with_internals([&](detail::internals &internals) {
(void) internals;
detail::get_local_internals().registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
});
}
/**
@ -2611,6 +2675,11 @@ public:
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<exception<void>> {
static constexpr auto name = const_name("Exception");
};
// Helper function for register_exception and register_local_exception
template <typename CppException>
exception<CppException> &
@ -2729,14 +2798,19 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
/* Cache functions that aren't overridden in Python to avoid
many costly Python dictionary lookups below */
auto &cache = get_internals().inactive_override_cache;
if (cache.find(key) != cache.end()) {
bool not_overridden = with_internals([&key](internals &internals) {
auto &cache = internals.inactive_override_cache;
return cache.find(key) != cache.end();
});
if (not_overridden) {
return function();
}
function override = getattr(self, name, function());
if (override.is_cpp_function()) {
cache.insert(std::move(key));
with_internals([&](internals &internals) {
internals.inactive_override_cache.insert(std::move(key));
});
return function();
}
@ -2749,7 +2823,12 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
PyCodeObject *f_code = PyFrame_GetCode(frame);
// f_code is guaranteed to not be NULL
if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) {
# if PY_VERSION_HEX >= 0x030d0000
PyObject *locals = PyEval_GetFrameLocals();
# else
PyObject *locals = PyEval_GetLocals();
Py_XINCREF(locals);
# endif
if (locals != nullptr) {
# if PY_VERSION_HEX >= 0x030b0000
PyObject *co_varnames = PyCode_GetVarnames(f_code);
@ -2759,6 +2838,7 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
PyObject *self_arg = PyTuple_GET_ITEM(co_varnames, 0);
Py_DECREF(co_varnames);
PyObject *self_caller = dict_getitem(locals, self_arg);
Py_DECREF(locals);
if (self_caller == self.ptr()) {
Py_DECREF(f_code);
Py_DECREF(frame);
@ -2835,10 +2915,14 @@ function get_override(const T *this_ptr, const char *name) {
= pybind11::get_override(static_cast<const cname *>(this), name); \
if (override) { \
auto o = override(__VA_ARGS__); \
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
PYBIND11_WARNING_PUSH \
PYBIND11_WARNING_DISABLE_MSVC(4127) \
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value \
&& !pybind11::detail::is_same_ignoring_cvref<ret_type, PyObject *>::value) { \
static pybind11::detail::override_caster_t<ret_type> caster; \
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
} \
PYBIND11_WARNING_POP \
return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
} \
} while (false)

View File

@ -59,6 +59,7 @@ struct sequence_item;
struct list_item;
struct tuple_item;
} // namespace accessor_policies
// PLEASE KEEP handle_type_name SPECIALIZATIONS IN SYNC.
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
using str_attr_accessor = accessor<accessor_policies::str_attr>;
using item_accessor = accessor<accessor_policies::generic_item>;
@ -182,7 +183,15 @@ public:
str_attr_accessor doc() const;
/// Return the object's current reference count
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
ssize_t ref_count() const {
#ifdef PYPY_VERSION
// PyPy uses the top few bits for REFCNT_FROM_PYPY & REFCNT_FROM_PYPY_LIGHT
// Following pybind11 2.12.1 and older behavior and removing this part
return static_cast<ssize_t>(static_cast<int>(Py_REFCNT(derived().ptr())));
#else
return Py_REFCNT(derived().ptr());
#endif
}
// TODO PYBIND11_DEPRECATED(
// "Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()")
@ -971,6 +980,23 @@ inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
return rv;
}
inline PyObject *dict_getitemstringref(PyObject *v, const char *key) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject *rv;
if (PyDict_GetItemStringRef(v, key, &rv) < 0) {
throw error_already_set();
}
return rv;
#else
PyObject *rv = dict_getitemstring(v, key);
if (rv == nullptr && PyErr_Occurred()) {
throw error_already_set();
}
Py_XINCREF(rv);
return rv;
#endif
}
// Helper aliases/functions to support implicit casting of values given to python
// accessors/methods. When given a pyobject, this simply returns the pyobject as-is; for other C++
// type, the value goes through pybind11::cast(obj) to convert it to an `object`.
@ -2174,6 +2200,11 @@ public:
throw error_already_set();
}
}
void clear() /* py-non-const */ {
if (PyList_SetSlice(m_ptr, 0, PyList_Size(m_ptr), nullptr) == -1) {
throw error_already_set();
}
}
};
class args : public tuple {

View File

@ -151,7 +151,7 @@ private:
void reserve_maybe(const anyset &, void *) {}
bool convert_iterable(const iterable &itbl, bool convert) {
for (auto it : itbl) {
for (const auto &it : itbl) {
key_conv conv;
if (!conv.load(it, convert)) {
return false;
@ -218,7 +218,7 @@ private:
bool convert_elements(const dict &d, bool convert) {
value.clear();
reserve_maybe(d, &value);
for (auto it : d) {
for (const auto &it : d) {
key_conv kconv;
value_conv vconv;
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
@ -308,7 +308,7 @@ private:
auto s = reinterpret_borrow<sequence>(seq);
value.clear();
reserve_maybe(s, &value);
for (auto it : seq) {
for (const auto &it : seq) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
@ -372,7 +372,7 @@ private:
return false;
}
size_t ctr = 0;
for (auto it : l) {
for (const auto &it : l) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
@ -565,7 +565,8 @@ struct variant_caster<V<Ts...>> {
using Type = V<Ts...>;
PYBIND11_TYPE_CASTER(Type,
const_name("Union[") + detail::concat(make_caster<Ts>::name...)
const_name("Union[")
+ ::pybind11::detail::concat(make_caster<Ts>::name...)
+ const_name("]"));
};

View File

@ -14,8 +14,7 @@
#ifdef __has_include
# if defined(PYBIND11_CPP17)
# if __has_include(<filesystem>) && \
PY_VERSION_HEX >= 0x03060000
# if __has_include(<filesystem>)
# include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1
# elif __has_include(<experimental/filesystem>)
@ -34,6 +33,13 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#ifdef PYPY_VERSION
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) (__VA_ARGS__)
#else
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) \
(reinterpret_cast<void *>(__VA_ARGS__))
#endif
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <typename T>
struct path_caster {
@ -73,7 +79,8 @@ public:
}
PyObject *native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) {
if (PyUnicode_FSConverter(buf, &native) != 0) {
if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
!= 0) {
if (auto *c_str = PyBytes_AsString(native)) {
// AsString returns a pointer to the internal buffer, which
// must not be free'd.
@ -81,7 +88,8 @@ public:
}
}
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
if (PyUnicode_FSDecoder(buf, &native) != 0) {
if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
!= 0) {
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
// AsWideCharString returns a new string that must be free'd.
value = c_str; // Copies the string.

View File

@ -158,8 +158,7 @@ void vector_modifiers(
return v.release();
}));
cl.def(
"clear", [](Vector &v) { v.clear(); }, "Clear the contents");
cl.def("clear", [](Vector &v) { v.clear(); }, "Clear the contents");
cl.def(
"extend",
@ -181,7 +180,7 @@ void vector_modifiers(
v.end());
try {
v.shrink_to_fit();
} catch (const std::exception &) {
} catch (const std::exception &) { // NOLINT(bugprone-empty-catch)
// Do nothing
}
throw;
@ -525,7 +524,7 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
[](const Vector &v) -> bool { return !v.empty(); },
"Check whether the list is nonempty");
cl.def("__len__", &Vector::size);
cl.def("__len__", [](const Vector &vec) { return vec.size(); });
#if 0
// C++ style functions deprecated, leaving it here as an example
@ -645,49 +644,50 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
"Return the canonical string representation of this map.");
}
template <typename KeyType>
struct keys_view {
virtual size_t len() = 0;
virtual iterator iter() = 0;
virtual bool contains(const KeyType &k) = 0;
virtual bool contains(const object &k) = 0;
virtual bool contains(const handle &k) = 0;
virtual ~keys_view() = default;
};
template <typename MappedType>
struct values_view {
virtual size_t len() = 0;
virtual iterator iter() = 0;
virtual ~values_view() = default;
};
template <typename KeyType, typename MappedType>
struct items_view {
virtual size_t len() = 0;
virtual iterator iter() = 0;
virtual ~items_view() = default;
};
template <typename Map, typename KeysView>
struct KeysViewImpl : public KeysView {
template <typename Map>
struct KeysViewImpl : public detail::keys_view {
explicit KeysViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); }
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); }
bool contains(const object &) override { return false; }
bool contains(const handle &k) override {
try {
return map.find(k.template cast<typename Map::key_type>()) != map.end();
} catch (const cast_error &) {
return false;
}
}
Map &map;
};
template <typename Map, typename ValuesView>
struct ValuesViewImpl : public ValuesView {
template <typename Map>
struct ValuesViewImpl : public detail::values_view {
explicit ValuesViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); }
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
Map &map;
};
template <typename Map, typename ItemsView>
struct ItemsViewImpl : public ItemsView {
template <typename Map>
struct ItemsViewImpl : public detail::items_view {
explicit ItemsViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); }
iterator iter() override { return make_iterator(map.begin(), map.end()); }
@ -700,11 +700,9 @@ template <typename Map, typename holder_type = std::unique_ptr<Map>, typename...
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
using StrippedKeyType = detail::remove_cvref_t<KeyType>;
using StrippedMappedType = detail::remove_cvref_t<MappedType>;
using KeysView = detail::keys_view<StrippedKeyType>;
using ValuesView = detail::values_view<StrippedMappedType>;
using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
using KeysView = detail::keys_view;
using ValuesView = detail::values_view;
using ItemsView = detail::items_view;
using Class_ = class_<Map, holder_type>;
// If either type is a non-module-local bound type then make the map binding non-local as well;
@ -718,39 +716,20 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
}
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
// If key type isn't properly wrapped, fall back to C++ names
if (key_type_name == "%") {
key_type_name = detail::type_info_description(typeid(KeyType));
}
// Similarly for value type:
if (mapped_type_name == "%") {
mapped_type_name = detail::type_info_description(typeid(MappedType));
}
// Wrap KeysView[KeyType] if it wasn't already wrapped
// Wrap KeysView if it wasn't already wrapped
if (!detail::get_type_info(typeid(KeysView))) {
class_<KeysView> keys_view(
scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
class_<KeysView> keys_view(scope, "KeysView", pybind11::module_local(local));
keys_view.def("__len__", &KeysView::len);
keys_view.def("__iter__",
&KeysView::iter,
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
keys_view.def("__contains__",
static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
// Fallback for when the object is not of the key type
keys_view.def("__contains__",
static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
keys_view.def("__contains__", &KeysView::contains);
}
// Similarly for ValuesView:
if (!detail::get_type_info(typeid(ValuesView))) {
class_<ValuesView> values_view(scope,
("ValuesView[" + mapped_type_name + "]").c_str(),
pybind11::module_local(local));
class_<ValuesView> values_view(scope, "ValuesView", pybind11::module_local(local));
values_view.def("__len__", &ValuesView::len);
values_view.def("__iter__",
&ValuesView::iter,
@ -759,10 +738,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
}
// Similarly for ItemsView:
if (!detail::get_type_info(typeid(ItemsView))) {
class_<ItemsView> items_view(
scope,
("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
pybind11::module_local(local));
class_<ItemsView> items_view(scope, "ItemsView", pybind11::module_local(local));
items_view.def("__len__", &ItemsView::len);
items_view.def("__iter__",
&ItemsView::iter,
@ -788,25 +764,19 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
cl.def(
"keys",
[](Map &m) {
return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
},
[](Map &m) { return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map>(m)); },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def(
"values",
[](Map &m) {
return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
},
[](Map &m) { return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map>(m)); },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def(
"items",
[](Map &m) {
return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
},
[](Map &m) { return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map>(m)); },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
@ -843,7 +813,8 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
m.erase(it);
});
cl.def("__len__", &Map::size);
// Always use a lambda in case of `using` declaration
cl.def("__len__", [](const Map &m) { return m.size(); });
return cl;
}

View File

@ -14,6 +14,8 @@
#include "cast.h"
#include "pytypes.h"
#include <algorithm>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(typing)
@ -63,14 +65,74 @@ class Callable<Return(Args...)> : public function {
using function::function;
};
template <typename T>
class Type : public type {
using type::type;
};
template <typename... Types>
class Union : public object {
PYBIND11_OBJECT_DEFAULT(Union, object, PyObject_Type)
using object::object;
};
template <typename T>
class Optional : public object {
PYBIND11_OBJECT_DEFAULT(Optional, object, PyObject_Type)
using object::object;
};
template <typename T>
class TypeGuard : public bool_ {
using bool_::bool_;
};
template <typename T>
class TypeIs : public bool_ {
using bool_::bool_;
};
class NoReturn : public none {
using none::none;
};
class Never : public none {
using none::none;
};
#if defined(__cpp_nontype_template_parameter_class) \
&& (/* See #5201 */ !defined(__GNUC__) \
|| (__GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 3)))
# define PYBIND11_TYPING_H_HAS_STRING_LITERAL
template <size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, name); }
char name[N];
};
template <StringLiteral... StrLits>
class Literal : public object {
PYBIND11_OBJECT_DEFAULT(Literal, object, PyObject_Type)
};
// Example syntax for creating a TypeVar.
// typedef typing::TypeVar<"T"> TypeVarT;
template <StringLiteral>
class TypeVar : public object {
PYBIND11_OBJECT_DEFAULT(TypeVar, object, PyObject_Type)
using object::object;
};
#endif
PYBIND11_NAMESPACE_END(typing)
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename... Types>
struct handle_type_name<typing::Tuple<Types...>> {
static constexpr auto name
= const_name("tuple[") + concat(make_caster<Types>::name...) + const_name("]");
static constexpr auto name = const_name("tuple[")
+ ::pybind11::detail::concat(make_caster<Types>::name...)
+ const_name("]");
};
template <>
@ -79,6 +141,13 @@ struct handle_type_name<typing::Tuple<>> {
static constexpr auto name = const_name("tuple[()]");
};
template <typename T>
struct handle_type_name<typing::Tuple<T, ellipsis>> {
// PEP 484 specifies this syntax for a variable-length tuple
static constexpr auto name
= const_name("tuple[") + make_caster<T>::name + const_name(", ...]");
};
template <typename K, typename V>
struct handle_type_name<typing::Dict<K, V>> {
static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ")
@ -108,10 +177,68 @@ struct handle_type_name<typing::Iterator<T>> {
template <typename Return, typename... Args>
struct handle_type_name<typing::Callable<Return(Args...)>> {
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
static constexpr auto name = const_name("Callable[[") + concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name
static constexpr auto name
= const_name("Callable[[") + ::pybind11::detail::concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name + const_name("]");
};
template <typename Return>
struct handle_type_name<typing::Callable<Return(ellipsis)>> {
// PEP 484 specifies this syntax for defining only return types of callables
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
static constexpr auto name
= const_name("Callable[..., ") + make_caster<retval_type>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::Type<T>> {
static constexpr auto name = const_name("type[") + make_caster<T>::name + const_name("]");
};
template <typename... Types>
struct handle_type_name<typing::Union<Types...>> {
static constexpr auto name = const_name("Union[")
+ ::pybind11::detail::concat(make_caster<Types>::name...)
+ const_name("]");
};
template <typename T>
struct handle_type_name<typing::Optional<T>> {
static constexpr auto name = const_name("Optional[") + make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::TypeGuard<T>> {
static constexpr auto name = const_name("TypeGuard[") + make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::TypeIs<T>> {
static constexpr auto name = const_name("TypeIs[") + make_caster<T>::name + const_name("]");
};
template <>
struct handle_type_name<typing::NoReturn> {
static constexpr auto name = const_name("NoReturn");
};
template <>
struct handle_type_name<typing::Never> {
static constexpr auto name = const_name("Never");
};
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
template <typing::StringLiteral... Literals>
struct handle_type_name<typing::Literal<Literals...>> {
static constexpr auto name = const_name("Literal[")
+ pybind11::detail::concat(const_name(Literals.name)...)
+ const_name("]");
};
template <typing::StringLiteral StrLit>
struct handle_type_name<typing::TypeVar<StrLit>> {
static constexpr auto name = const_name(StrLit.name);
};
#endif
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -1,24 +1,12 @@
import os
from __future__ import annotations
import argparse
import nox
nox.needs_version = ">=2022.1.7"
nox.needs_version = ">=2024.3.2"
nox.options.sessions = ["lint", "tests", "tests_packaging"]
PYTHON_VERSIONS = [
"3.6",
"3.7",
"3.8",
"3.9",
"3.10",
"3.11",
"pypy3.7",
"pypy3.8",
"pypy3.9",
]
if os.environ.get("CI", None):
nox.options.error_on_missing_interpreters = True
nox.options.default_venv_backend = "uv|virtualenv"
@nox.session(reuse_venv=True)
@ -30,7 +18,7 @@ def lint(session: nox.Session) -> None:
session.run("pre-commit", "run", "-a", *session.posargs)
@nox.session(python=PYTHON_VERSIONS)
@nox.session
def tests(session: nox.Session) -> None:
"""
Run the tests (requires a compiler).
@ -57,30 +45,42 @@ def tests_packaging(session: nox.Session) -> None:
Run the packaging tests.
"""
session.install("-r", "tests/requirements.txt")
session.install("-r", "tests/requirements.txt", "pip")
session.run("pytest", "tests/extra_python_package", *session.posargs)
@nox.session(reuse_venv=True)
def docs(session: nox.Session) -> None:
"""
Build the docs. Pass "serve" to serve.
Build the docs. Pass --non-interactive to avoid serving.
"""
session.install("-r", "docs/requirements.txt")
parser = argparse.ArgumentParser()
parser.add_argument(
"-b", dest="builder", default="html", help="Build target (default: html)"
)
args, posargs = parser.parse_known_args(session.posargs)
serve = args.builder == "html" and session.interactive
extra_installs = ["sphinx-autobuild"] if serve else []
session.install("-r", "docs/requirements.txt", *extra_installs)
session.chdir("docs")
if "pdf" in session.posargs:
session.run("sphinx-build", "-M", "latexpdf", ".", "_build")
return
shared_args = (
"-n", # nitpicky mode
"-T", # full tracebacks
f"-b={args.builder}",
".",
f"_build/{args.builder}",
*posargs,
)
session.run("sphinx-build", "-M", "html", ".", "_build")
if "serve" in session.posargs:
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
session.run("python", "-m", "http.server", "8000", "-d", "_build/html")
elif session.posargs:
session.error("Unsupported argument to docs")
if serve:
session.run(
"sphinx-autobuild", "--open-browser", "--ignore=.build", *shared_args
)
else:
session.run("sphinx-build", "--keep-going", *shared_args)
@nox.session(reuse_venv=True)

View File

@ -1,7 +1,9 @@
from __future__ import annotations
import sys
if sys.version_info < (3, 6): # noqa: UP036
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
if sys.version_info < (3, 8): # noqa: UP036
msg = "pybind11 does not support Python < 3.8. v2.13 was the last release supporting Python 3.7."
raise ImportError(msg)

View File

@ -1,4 +1,5 @@
# pylint: disable=missing-function-docstring
from __future__ import annotations
import argparse
import sys

View File

@ -1,12 +1,12 @@
from typing import Union
from __future__ import annotations
def _to_int(s: str) -> Union[int, str]:
def _to_int(s: str) -> int | str:
try:
return int(s)
except ValueError:
return s
__version__ = "2.12.0.dev1"
__version__ = "2.14.0.dev1"
version_info = tuple(_to_int(s) for s in __version__.split("."))

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os
DIR = os.path.abspath(os.path.dirname(__file__))

View File

@ -36,6 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# If you copy this file in, you don't
# need the .pyi file; it's just an interface file for static type checkers.
from __future__ import annotations
import contextlib
import os
@ -52,7 +53,6 @@ from pathlib import Path
from typing import (
Any,
Callable,
Dict,
Iterable,
Iterator,
List,
@ -113,10 +113,10 @@ class Pybind11Extension(_Extension):
# flags are prepended, so that they can be further overridden, e.g. by
# ``extra_compile_args=["-g"]``.
def _add_cflags(self, flags: List[str]) -> None:
def _add_cflags(self, flags: list[str]) -> None:
self.extra_compile_args[:0] = flags
def _add_ldflags(self, flags: List[str]) -> None:
def _add_ldflags(self, flags: list[str]) -> None:
self.extra_link_args[:0] = flags
def __init__(self, *args: Any, **kwargs: Any) -> None:
@ -249,8 +249,8 @@ def has_flag(compiler: Any, flag: str) -> bool:
cpp_flag_cache = None
@lru_cache()
def auto_cpp_level(compiler: Any) -> Union[str, int]:
@lru_cache
def auto_cpp_level(compiler: Any) -> str | int:
"""
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
"""
@ -288,8 +288,8 @@ class build_ext(_build_ext): # noqa: N801
def intree_extensions(
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None
) -> List[Pybind11Extension]:
paths: Iterable[str], package_dir: dict[str, str] | None = None
) -> list[Pybind11Extension]:
"""
Generate Pybind11Extensions from source files directly located in a Python
source tree.
@ -353,7 +353,7 @@ CCompilerMethod = Callable[
distutils.ccompiler.CCompiler,
List[str],
Optional[str],
Optional[Union[Tuple[str], Tuple[str, Optional[str]]]],
Optional[List[Union[Tuple[str], Tuple[str, Optional[str]]]]],
Optional[List[str]],
bool,
Optional[List[str]],
@ -409,7 +409,7 @@ class ParallelCompile:
def __init__(
self,
envvar: Optional[str] = None,
envvar: str | None = None,
default: int = 0,
max: int = 0, # pylint: disable=redefined-builtin
needs_recompile: Callable[[str, str], bool] = no_recompile,
@ -418,7 +418,7 @@ class ParallelCompile:
self.default = default
self.max = max
self.needs_recompile = needs_recompile
self._old: List[CCompilerMethod] = []
self._old: list[CCompilerMethod] = []
def function(self) -> CCompilerMethod:
"""
@ -427,14 +427,14 @@ class ParallelCompile:
def compile_function(
compiler: distutils.ccompiler.CCompiler,
sources: List[str],
output_dir: Optional[str] = None,
macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None,
include_dirs: Optional[List[str]] = None,
sources: list[str],
output_dir: str | None = None,
macros: list[tuple[str] | tuple[str, str | None]] | None = None,
include_dirs: list[str] | None = None,
debug: bool = False,
extra_preargs: Optional[List[str]] = None,
extra_postargs: Optional[List[str]] = None,
depends: Optional[List[str]] = None,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
depends: list[str] | None = None,
) -> Any:
# These lines are directly from distutils.ccompiler.CCompiler
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]

View File

@ -19,9 +19,8 @@ ignore = [
[tool.mypy]
files = ["pybind11"]
python_version = "3.7"
python_version = "3.8"
strict = true
show_error_codes = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true
@ -30,20 +29,8 @@ module = ["ghapi.*"]
ignore_missing_imports = true
[tool.pytest.ini_options]
minversion = "6.0"
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
xfail_strict = true
filterwarnings = ["error"]
log_cli_level = "info"
testpaths = [
"tests",
]
timeout=300
[tool.pylint]
master.py-version = "3.6"
master.py-version = "3.8"
reports.output-format = "colorized"
messages_control.disable = [
"design",
@ -58,7 +45,7 @@ messages_control.disable = [
]
[tool.ruff]
target-version = "py37"
target-version = "py38"
src = ["src"]
[tool.ruff.lint]
@ -89,7 +76,12 @@ ignore = [
]
unfixable = ["T20"]
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
isort.required-imports = ["from __future__ import annotations"]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["EM", "N", "E721"]
"tests/test_call_policies.py" = ["PLC1901"]
[tool.repo-review]
ignore = ["PP"]

View File

@ -14,13 +14,12 @@ classifiers =
Topic :: Utilities
Programming Language :: C++
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
Programming Language :: Python :: 3.13
License :: OSI Approved :: BSD License
Programming Language :: Python :: Implementation :: PyPy
Programming Language :: Python :: Implementation :: CPython
@ -39,5 +38,5 @@ project_urls =
Chat = https://gitter.im/pybind/Lobby
[options]
python_requires = >=3.6
python_requires = >=3.8
zip_safe = False

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python3
# Setup script for PyPI; use CMakeFile.txt to build extension modules
from __future__ import annotations
import contextlib
import os
@ -9,9 +10,9 @@ import shutil
import string
import subprocess
import sys
from collections.abc import Generator
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Dict, Iterator, List, Union
import setuptools.command.sdist
@ -23,7 +24,7 @@ VERSION_FILE = Path("pybind11/_version.py")
COMMON_FILE = Path("include/pybind11/detail/common.h")
def build_expected_version_hex(matches: Dict[str, str]) -> str:
def build_expected_version_hex(matches: dict[str, str]) -> str:
patch_level_serial = matches["PATCH"]
serial = None
major = int(matches["MAJOR"])
@ -64,7 +65,7 @@ to_src = (
# Read the listed version
loc: Dict[str, str] = {}
loc: dict[str, str] = {}
code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
exec(code, loc)
version = loc["__version__"]
@ -84,9 +85,7 @@ if version_hex != exp_version_hex:
# TODO: use literals & overload (typing extensions or Python 3.8)
def get_and_replace(
filename: Path, binary: bool = False, **opts: str
) -> Union[bytes, str]:
def get_and_replace(filename: Path, binary: bool = False, **opts: str) -> bytes | str:
if binary:
contents = filename.read_bytes()
return string.Template(contents.decode()).substitute(opts).encode()
@ -97,7 +96,7 @@ def get_and_replace(
# Use our input files instead when making the SDist (and anything that depends
# on it, like a wheel)
class SDist(setuptools.command.sdist.sdist):
def make_release_tree(self, base_dir: str, files: List[str]) -> None:
def make_release_tree(self, base_dir: str, files: list[str]) -> None:
super().make_release_tree(base_dir, files)
for to, src in to_src:
@ -112,7 +111,7 @@ class SDist(setuptools.command.sdist.sdist):
# Remove the CMake install directory when done
@contextlib.contextmanager
def remove_output(*sources: str) -> Iterator[None]:
def remove_output(*sources: str) -> Generator[None, None, None]:
try:
yield
finally:

View File

@ -7,13 +7,13 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
# Filter out items; print an optional message if any items filtered. This ignores extensions.
@ -88,7 +88,12 @@ set(PYBIND11_TEST_FILTER
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
# We're being loaded directly, i.e. not via add_subdirectory, so make this
# work as its own project and load the pybind11Config to get the tools we need
find_package(pybind11 REQUIRED CONFIG)
if(SKBUILD)
add_subdirectory(.. pybind11_src)
else()
find_package(pybind11 REQUIRED CONFIG)
endif()
endif()
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
@ -330,7 +335,7 @@ if(Boost_FOUND)
add_library(Boost::headers IMPORTED INTERFACE)
if(TARGET Boost::boost)
# Classic FindBoost
set_property(TARGET Boost::boost PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost)
set_property(TARGET Boost::headers PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost)
else()
# Very old FindBoost, or newer Boost than CMake in older CMakes
set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
@ -489,6 +494,9 @@ foreach(target ${test_targets})
endforeach()
endif()
endif()
if(SKBUILD)
install(TARGETS ${target} LIBRARY DESTINATION .)
endif()
endforeach()
# Provide nice organisation in IDEs
@ -520,11 +528,15 @@ set(PYBIND11_TEST_PREFIX_COMMAND
""
CACHE STRING "Put this before pytest, use for checkers and such")
set(PYBIND11_PYTEST_ARGS
""
CACHE STRING "Extra arguments for pytest")
# A single command to compile and run the tests
add_custom_target(
pytest
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
${PYBIND11_ABS_PYTEST_FILES}
${PYBIND11_ABS_PYTEST_FILES} ${PYBIND11_PYTEST_ARGS}
DEPENDS ${test_targets}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
USES_TERMINAL)

View File

@ -4,6 +4,8 @@ Extends output capture as needed by pybind11: ignore constructors, optional unor
Adds docstring and exceptions message sanitizers.
"""
from __future__ import annotations
import contextlib
import difflib
import gc
@ -218,4 +220,5 @@ def pytest_report_header(config):
f" {pybind11_tests.cpp_std}"
f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
f" PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}"
)

View File

@ -190,7 +190,7 @@ public:
t1 = &p.first;
}
}
} catch (const std::out_of_range &) {
} catch (const std::out_of_range &) { // NOLINT(bugprone-empty-catch)
}
if (!t1) {
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");

View File

@ -92,6 +92,9 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
if (m != nullptr) {
static_assert(sizeof(&gil_acquire) == sizeof(void *),
"Function pointer must have the same size as void*");
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
ADD_FUNCTION("gil_acquire_funcaddr", gil_acquire)
ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release)
ADD_FUNCTION("gil_acquire_inner_custom_funcaddr",

View File

@ -42,6 +42,9 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_interleaved_error_alrea
if (m != nullptr) {
static_assert(sizeof(&interleaved_error_already_set) == sizeof(void *),
"Function pointer must have the same size as void *");
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
PyModule_AddObject(
m,
"funcaddr",

View File

@ -11,4 +11,6 @@
#include "test_eigen_tensor.inl"
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m) { eigen_tensor_test::test_module(m); }
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m, pybind11::mod_gil_not_used()) {
eigen_tensor_test::test_module(m);
}

View File

@ -1,5 +1,8 @@
from __future__ import annotations
import platform
import sys
import sysconfig
import pytest
@ -9,6 +12,7 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
CPYTHON = platform.python_implementation() == "CPython"
PYPY = platform.python_implementation() == "PyPy"
PY_GIL_DISABLED = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
def deprecated_call():

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import contextlib
import os
import string
@ -56,6 +58,7 @@ detail_headers = {
"include/pybind11/detail/internals.h",
"include/pybind11/detail/type_caster_base.h",
"include/pybind11/detail/typeid.h",
"include/pybind11/detail/value_and_holder.h",
}
eigen_headers = {
@ -73,6 +76,7 @@ cmake_files = {
"share/cmake/pybind11/pybind11Common.cmake",
"share/cmake/pybind11/pybind11Config.cmake",
"share/cmake/pybind11/pybind11ConfigVersion.cmake",
"share/cmake/pybind11/pybind11GuessPythonExtSuffix.cmake",
"share/cmake/pybind11/pybind11NewTools.cmake",
"share/cmake/pybind11/pybind11Targets.cmake",
"share/cmake/pybind11/pybind11Tools.cmake",

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os
import subprocess
import sys

View File

@ -16,7 +16,7 @@
#include <numeric>
#include <utility>
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
PYBIND11_MODULE(pybind11_cross_module_tests, m, py::mod_gil_not_used()) {
m.doc() = "pybind11 cross-module test module";
// test_local_bindings.py tests:

View File

@ -58,7 +58,7 @@ void bind_ConstructorStats(py::module_ &m) {
// registered instances to allow instance cleanup checks (invokes a GC first)
.def_static("detail_reg_inst", []() {
ConstructorStats::gc();
return py::detail::get_internals().registered_instances.size();
return py::detail::num_registered_instances();
});
}
@ -75,26 +75,34 @@ const char *cpp_std() {
#endif
}
PYBIND11_MODULE(pybind11_tests, m) {
PYBIND11_MODULE(pybind11_tests, m, py::mod_gil_not_used()) {
m.doc() = "pybind11 test module";
// Intentionally kept minimal to not create a maintenance chore
// ("just enough" to be conclusive).
#if defined(_MSC_FULL_VER)
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
#elif defined(__VERSION__)
#if defined(__VERSION__)
m.attr("compiler_info") = __VERSION__;
#elif defined(_MSC_FULL_VER)
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
#else
m.attr("compiler_info") = py::none();
#endif
m.attr("cpp_std") = cpp_std();
m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
// Free threaded Python uses UINT32_MAX for immortal objects.
m.attr("PYBIND11_REFCNT_IMMORTAL") = UINT32_MAX;
m.attr("PYBIND11_SIMPLE_GIL_MANAGEMENT") =
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
true;
#else
false;
#endif
m.attr("PYBIND11_NUMPY_1_ONLY") =
#if defined(PYBIND11_NUMPY_1_ONLY)
true;
#else
false;
#endif
bind_ConstructorStats(m);

View File

@ -3,6 +3,8 @@
#include <pybind11/eval.h>
#include <pybind11/pybind11.h>
#include <memory>
namespace py = pybind11;
using namespace pybind11::literals;
@ -52,6 +54,17 @@ union IntFloat {
float f;
};
class UnusualOpRef {
public:
using NonTrivialType = std::shared_ptr<int>; // Almost any non-trivial type will do.
// Overriding operator& should not break pybind11.
NonTrivialType operator&() { return non_trivial_member; }
NonTrivialType operator&() const { return non_trivial_member; }
private:
NonTrivialType non_trivial_member;
};
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast
/// context. Used to test recursive casters (e.g. std::tuple, stl containers).
struct RValueCaster {};

17
tests/pyproject.toml Normal file
View File

@ -0,0 +1,17 @@
# Warning: this is currently used for pyodide, and is not a general out-of-tree
# builder for the tests (yet). Specifically, wheels can't be built from SDists.
[build-system]
requires = ["scikit-build-core"]
build-backend = "scikit_build_core.build"
[project]
name = "pybind11_tests"
version = "0.0.1"
dependencies = ["pytest", "pytest-timeout", "numpy", "scipy"]
[tool.scikit-build.cmake.define]
PYBIND11_FINDPYTHON = true
[tool.cibuildwheel]
test-command = "pytest -o timeout=0 -p no:cacheprovider {project}/tests/test_*.py"

View File

@ -20,3 +20,4 @@ filterwarnings =
# bogus numpy ABI warning (see numpy/#432)
ignore:.*numpy.dtype size changed.*:RuntimeWarning
ignore:.*numpy.ufunc size changed.*:RuntimeWarning
default:The global interpreter lock:RuntimeWarning

View File

@ -1,15 +1,12 @@
--only-binary=:all:
build~=0.9; python_version=="3.6"
build~=1.0; python_version>="3.7"
numpy~=1.20.0; python_version=="3.7" and platform_python_implementation=="PyPy"
build~=1.0; python_version>="3.8"
numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy"
numpy~=1.25.0; python_version=="3.9" and platform_python_implementation=='PyPy'
numpy~=1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"
numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.8" and python_version<"3.10"
numpy~=1.22.2; platform_python_implementation!="PyPy" and python_version=="3.10"
numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11"
numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13"
pytest~=7.0
pytest-timeout
scipy~=1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10"
scipy~=1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10"
scipy~=1.11.1; platform_python_implementation!="PyPy" and python_version>="3.11"
scipy~=1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10" and sys_platform!='win32'
scipy~=1.11.1; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13" and sys_platform!='win32'

View File

@ -1,8 +1,15 @@
from __future__ import annotations
import sys
import pytest
asyncio = pytest.importorskip("asyncio")
m = pytest.importorskip("pybind11_tests.async_module")
if sys.platform.startswith("emscripten"):
pytest.skip("Can't run a new event_loop in pyodide", allow_module_level=True)
@pytest.fixture()
def event_loop():

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import ctypes
import io
import struct

View File

@ -95,7 +95,7 @@ TEST_SUBMODULE(builtin_casters, m) {
} // 𝐀, utf16
else {
wstr.push_back((wchar_t) mathbfA32);
} // 𝐀, utf32
} // 𝐀, utf32
wstr.push_back(0x7a); // z
m.def("good_utf8_string", []() {
@ -104,10 +104,9 @@ TEST_SUBMODULE(builtin_casters, m) {
m.def("good_utf16_string", [=]() {
return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16});
}); // b‽🎂𝐀z
m.def("good_utf32_string", [=]() {
return std::u32string({a32, mathbfA32, cake32, ib32, z32});
}); // a𝐀🎂‽z
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
m.def("good_utf32_string",
[=]() { return std::u32string({a32, mathbfA32, cake32, ib32, z32}); }); // a𝐀🎂‽z
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
m.def("bad_utf8_string", []() {
return std::string("abc\xd0"
"def");
@ -117,9 +116,8 @@ TEST_SUBMODULE(builtin_casters, m) {
// UnicodeDecodeError
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
if (sizeof(wchar_t) == 2) {
m.def("bad_wchar_string", [=]() {
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
});
m.def("bad_wchar_string",
[=]() { return std::wstring({wchar_t(0x61), wchar_t(0xd800)}); });
}
m.def("u8_Z", []() -> char { return 'Z'; });
m.def("u8_eacute", []() -> char { return '\xe9'; });
@ -236,8 +234,7 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_int_convert
m.def("int_passthrough", [](int arg) { return arg; });
m.def(
"int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
// test_tuple
m.def(
@ -302,8 +299,7 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_bool_caster
m.def("bool_passthrough", [](bool arg) { return arg; });
m.def(
"bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
// TODO: This should be disabled and fixed in future Intel compilers
#if !defined(__INTEL_COMPILER)
@ -311,8 +307,7 @@ TEST_SUBMODULE(builtin_casters, m) {
// When compiled with the Intel compiler, this results in segmentation faults when importing
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
// a newer version of icc is available.
m.def(
"bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
m.def("bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
#endif
// test_reference_wrapper

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys
import pytest
@ -295,7 +297,7 @@ def test_int_convert():
cant_convert(3.14159)
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
if sys.version_info < (3, 10) and env.CPYTHON:
with env.deprecated_call():
assert convert(Int()) == 42
else:
@ -366,6 +368,8 @@ def test_tuple(doc):
"""
)
assert doc(m.empty_tuple) == """empty_tuple() -> tuple[()]"""
assert m.rvalue_pair() == ("rvalue", "rvalue")
assert m.lvalue_pair() == ("lvalue", "lvalue")
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")

View File

@ -63,10 +63,8 @@ TEST_SUBMODULE(call_policies, m) {
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
.def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
m.def(
"free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
m.def(
"invalid_arg_index", [] {}, py::keep_alive<0, 1>());
m.def("free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
m.def("invalid_arg_index", [] {}, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION)
// test_alive_gc
@ -97,7 +95,7 @@ TEST_SUBMODULE(call_policies, m) {
},
py::call_guard<DependentGuard, CustomGuard>());
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
#if !defined(PYPY_VERSION)
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
auto report_gil_status = []() {

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
import env # noqa: F401

View File

@ -1,3 +1,6 @@
from __future__ import annotations
import sys
import time
from threading import Thread
@ -151,6 +154,7 @@ def test_python_builtins():
assert m.test_sum_builtin(sum, []) == 0
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
def test_async_callbacks():
# serves as state for async callback
class Item:
@ -174,6 +178,7 @@ def test_async_callbacks():
assert sum(res) == sum(x + 3 for x in work)
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
def test_async_async_callbacks():
t = Thread(target=test_async_callbacks)
t.start()

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import datetime
import pytest

View File

@ -403,7 +403,7 @@ TEST_SUBMODULE(class_, m) {
// [workaround(intel)] = default does not work here
// Removing or defaulting this destructor results in linking errors with the Intel compiler
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
~PublicistB() override {}; // NOLINT(modernize-use-equals-default)
using ProtectedB::foo;
using ProtectedB::get_self;
using ProtectedB::void_foo;
@ -461,8 +461,7 @@ TEST_SUBMODULE(class_, m) {
py::class_<Nested>(base, "Nested")
.def(py::init<>())
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
.def(
"fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
.def("fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
base.def("g", [](NestBase &, Nested &) {});
base.def("h", []() { return NestBase(); });

View File

@ -1,9 +1,11 @@
from __future__ import annotations
from unittest import mock
import pytest
import env
from pybind11_tests import ConstructorStats, UserType
from pybind11_tests import PYBIND11_REFCNT_IMMORTAL, ConstructorStats, UserType
from pybind11_tests import class_ as m
@ -377,7 +379,9 @@ def test_class_refcount():
refcount_3 = getrefcount(cls)
assert refcount_1 == refcount_3
assert refcount_2 > refcount_1
assert (refcount_2 > refcount_1) or (
refcount_2 == refcount_1 == PYBIND11_REFCNT_IMMORTAL
)
def test_reentrant_implicit_conversion_failure(msg):

View File

@ -5,9 +5,8 @@ function(pybind11_add_build_test name)
set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}")
if(PYBIND11_FINDPYTHON)
list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}")
if(DEFINED Python_ROOT_DIR)
list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}")
endif()

View File

@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
project(test_installed_embed CXX)

View File

@ -1,13 +1,13 @@
cmake_minimum_required(VERSION 3.5)
project(test_installed_module CXX)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
project(test_installed_function CXX)

View File

@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
project(test_installed_target CXX)

View File

@ -1,6 +1,6 @@
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(test_cmake_build, m) {
PYBIND11_MODULE(test_cmake_build, m, py::mod_gil_not_used()) {
m.def("add", [](int i, int j) { return i + j; });
}

View File

@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
project(test_subdirectory_embed CXX)
@ -16,6 +16,12 @@ set(PYBIND11_INSTALL
CACHE BOOL "")
set(PYBIND11_EXPORT_NAME test_export)
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
# (makes transition easier while we support both modes).
if(DEFINED PYTHON_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE)
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
# Test basic target functionality

View File

@ -1,16 +1,22 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
project(test_subdirectory_function CXX)
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
# (makes transition easier while we support both modes).
if(DEFINED PYTHON_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE)
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
pybind11_add_module(test_subdirectory_function ../main.cpp)
set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build)

View File

@ -1,16 +1,22 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.26)
cmake_policy(VERSION 3.29)
endif()
project(test_subdirectory_target CXX)
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
# (makes transition easier while we support both modes).
if(DEFINED PYTHON_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE)
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
add_library(test_subdirectory_target MODULE ../main.cpp)

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys
import test_cmake_build

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pybind11_tests import const_name as m

View File

@ -54,7 +54,11 @@ int f2(int x) noexcept(true) { return x + 2; }
int f3(int x) noexcept(false) { return x + 3; }
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
#if defined(__clang_major__) && __clang_major__ >= 5
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-dynamic-exception-spec")
#else
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
#endif
// NOLINTNEXTLINE(modernize-use-noexcept)
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
PYBIND11_WARNING_POP

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
m = pytest.importorskip("pybind11_tests.constants_and_functions")

View File

@ -157,6 +157,13 @@ public:
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11)
namespace {
py::object CastUnusualOpRefConstRef(const UnusualOpRef &cref) { return py::cast(cref); }
py::object CastUnusualOpRefMovable(UnusualOpRef &&mvbl) { return py::cast(std::move(mvbl)); }
} // namespace
TEST_SUBMODULE(copy_move_policies, m) {
// test_lacking_copy_ctor
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
@ -289,11 +296,15 @@ TEST_SUBMODULE(copy_move_policies, m) {
"get_moveissue1",
[](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
py::return_value_policy::move);
m.def(
"get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
// Make sure that cast from pytype rvalue to other pytype works
m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
py::class_<UnusualOpRef>(m, "UnusualOpRef");
m.def("CallCastUnusualOpRefConstRef",
[]() { return CastUnusualOpRefConstRef(UnusualOpRef()); });
m.def("CallCastUnusualOpRefMovable", []() { return CastUnusualOpRefMovable(UnusualOpRef()); });
}
/*

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pybind11_tests import copy_move_policies as m
@ -130,3 +132,9 @@ def test_pytype_rvalue_cast():
value = m.get_pytype_rvalue_castissue(1.0)
assert value == 1
def test_unusual_op_ref():
# Merely to test that this still exists and built successfully.
assert m.CallCastUnusualOpRefConstRef().__class__.__name__ == "UnusualOpRef"
assert m.CallCastUnusualOpRefMovable().__class__.__name__ == "UnusualOpRef"

View File

@ -134,6 +134,16 @@ struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
} // namespace detail
} // namespace PYBIND11_NAMESPACE
// This simply is required to compile
namespace ADL_issue {
template <typename OutStringType = std::string, typename... Args>
OutStringType concat(Args &&...) {
return OutStringType();
}
struct test {};
} // namespace ADL_issue
TEST_SUBMODULE(custom_type_casters, m) {
// test_custom_type_casters
@ -175,14 +185,10 @@ TEST_SUBMODULE(custom_type_casters, m) {
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
py::arg() = ArgAlwaysConverts());
m.def(
"floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
m.def(
"floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
m.def(
"ints_preferred", [](int i) { return i / 2; }, "i"_a);
m.def(
"ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
m.def("ints_preferred", [](int i) { return i / 2; }, "i"_a);
m.def("ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
// test_custom_caster_destruction
// Test that `take_ownership` works on types with a custom type caster when given a pointer
@ -206,4 +212,6 @@ TEST_SUBMODULE(custom_type_casters, m) {
py::return_value_policy::reference);
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
m.def("_adl_issue", [](const ADL_issue::test &) {});
}

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pybind11_tests import custom_type_casters as m

Some files were not shown because too many files have changed in this diff Show More