mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Merge branch 'master' into list_caster_pass_generator
This commit is contained in:
commit
d1ffe4f81b
@ -9,7 +9,7 @@ platform:
|
||||
- x86
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: 36
|
||||
- PYTHON: 38
|
||||
CONFIG: Debug
|
||||
install:
|
||||
- ps: |
|
||||
|
@ -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
|
||||
|
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@ -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
15
.github/labeler.yml
vendored
@ -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'
|
||||
|
9
.github/labeler_merged.yml
vendored
9
.github/labeler_merged.yml
vendored
@ -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).*"
|
||||
|
202
.github/workflows/ci.yml
vendored
202
.github/workflows/ci.yml
vendored
@ -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: |
|
||||
|
18
.github/workflows/configure.yml
vendored
18
.github/workflows/configure.yml
vendored
@ -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
30
.github/workflows/emscripten.yaml
vendored
Normal 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
|
6
.github/workflows/format.yml
vendored
6
.github/workflows/format.yml
vendored
@ -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
|
||||
|
||||
|
2
.github/workflows/labeler.yml
vendored
2
.github/workflows/labeler.yml
vendored
@ -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):') &&
|
||||
|
35
.github/workflows/pip.yml
vendored
35
.github/workflows/pip.yml
vendored
@ -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/
|
||||
|
12
.github/workflows/upstream.yml
vendored
12
.github/workflows/upstream.yml
vendored
@ -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: |
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
13
README.rst
13
README.rst
@ -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
|
||||
|
@ -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::
|
||||
|
||||
|
@ -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)`
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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).
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as dt
|
||||
import os
|
||||
import random
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -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
6
docs/requirements.in
Normal file
@ -0,0 +1,6 @@
|
||||
breathe
|
||||
furo
|
||||
sphinx
|
||||
sphinx-copybutton
|
||||
sphinxcontrib-moderncmakedomain
|
||||
sphinxcontrib-svg2pdfconverter
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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{}); }
|
||||
|
||||
|
@ -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 ®istered_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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
77
include/pybind11/detail/value_and_holder.h
Normal file
77
include/pybind11/detail/value_and_holder.h
Normal 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)
|
@ -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 "
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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("]"));
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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{
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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("]"));
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 ↦
|
||||
};
|
||||
|
||||
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 ↦
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
62
noxfile.py
62
noxfile.py
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# pylint: disable=missing-function-docstring
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
@ -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("."))
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
DIR = os.path.abspath(os.path.dirname(__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]
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
15
setup.py
15
setup.py
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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}"
|
||||
)
|
||||
|
@ -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()");
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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():
|
||||
|
@ -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",
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
17
tests/pyproject.toml
Normal 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"
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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():
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
import io
|
||||
import struct
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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 = []() {
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
@ -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()
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
@ -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(); });
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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; });
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
import test_cmake_build
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import const_name as m
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
||||
|
@ -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()); });
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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"
|
||||
|
@ -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 &) {});
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user