mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Compare commits
1 Commits
b6a9b6e3ab
...
0d4a2777d3
Author | SHA1 | Date | |
---|---|---|---|
|
0d4a2777d3 |
@ -9,7 +9,7 @@ platform:
|
|||||||
- x86
|
- x86
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- PYTHON: 38
|
- PYTHON: 36
|
||||||
CONFIG: Debug
|
CONFIG: Debug
|
||||||
install:
|
install:
|
||||||
- ps: |
|
- ps: |
|
||||||
|
@ -57,12 +57,10 @@ Checks: |
|
|||||||
readability-string-compare,
|
readability-string-compare,
|
||||||
readability-suspicious-call-argument,
|
readability-suspicious-call-argument,
|
||||||
readability-uniqueptr-delete-release,
|
readability-uniqueptr-delete-release,
|
||||||
-bugprone-chained-comparison,
|
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
-bugprone-exception-escape,
|
-bugprone-exception-escape,
|
||||||
-bugprone-reserved-identifier,
|
-bugprone-reserved-identifier,
|
||||||
-bugprone-unused-raii,
|
-bugprone-unused-raii,
|
||||||
-performance-enum-size,
|
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: modernize-use-equals-default.IgnoreMacros
|
- key: modernize-use-equals-default.IgnoreMacros
|
||||||
|
10
.github/CONTRIBUTING.md
vendored
10
.github/CONTRIBUTING.md
vendored
@ -81,7 +81,7 @@ nox -s build
|
|||||||
### Full setup
|
### Full setup
|
||||||
|
|
||||||
To setup an ideal development environment, run the following commands on a
|
To setup an ideal development environment, run the following commands on a
|
||||||
system with CMake 3.15+:
|
system with CMake 3.14+:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
@ -96,8 +96,8 @@ Tips:
|
|||||||
* You can use `virtualenv` (faster, from PyPI) instead of `venv`.
|
* You can use `virtualenv` (faster, from PyPI) instead of `venv`.
|
||||||
* You can select any name for your environment folder; if it contains "env" it
|
* You can select any name for your environment folder; if it contains "env" it
|
||||||
will be ignored by git.
|
will be ignored by git.
|
||||||
* If you don't have CMake 3.15+, just add "cmake" to the pip install command.
|
* If you don't have CMake 3.14+, just add "cmake" to the pip install command.
|
||||||
* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython.
|
* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+
|
||||||
* In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`.
|
* In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`.
|
||||||
FindPython uses `-DPython_ROOT_DIR=/path/to` or
|
FindPython uses `-DPython_ROOT_DIR=/path/to` or
|
||||||
`-DPython_EXECUTABLE=/path/to/python`.
|
`-DPython_EXECUTABLE=/path/to/python`.
|
||||||
@ -149,8 +149,8 @@ To run the tests, you can "build" the check target:
|
|||||||
cmake --build build --target check
|
cmake --build build --target check
|
||||||
```
|
```
|
||||||
|
|
||||||
`--target` can be spelled `-t`. You can also run individual tests with these
|
`--target` can be spelled `-t` in CMake 3.15+. You can also run individual
|
||||||
targets:
|
tests with these targets:
|
||||||
|
|
||||||
* `pytest`: Python tests only, using the
|
* `pytest`: Python tests only, using the
|
||||||
[pytest](https://docs.pytest.org/en/stable/) framework
|
[pytest](https://docs.pytest.org/en/stable/) framework
|
||||||
|
82
.github/workflows/ci.yml
vendored
82
.github/workflows/ci.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-20.04, windows-2022, macos-13]
|
runs-on: [ubuntu-20.04, windows-2022, macos-13]
|
||||||
python:
|
python:
|
||||||
- '3.8'
|
- '3.6'
|
||||||
- '3.9'
|
- '3.9'
|
||||||
- '3.12'
|
- '3.12'
|
||||||
- '3.13'
|
- '3.13'
|
||||||
@ -48,17 +48,16 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
# Just add a key
|
# Just add a key
|
||||||
- runs-on: ubuntu-20.04
|
- runs-on: ubuntu-20.04
|
||||||
python: '3.8'
|
python: '3.6'
|
||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
-DCMAKE_CXX_FLAGS="-D_=1"
|
-DCMAKE_CXX_FLAGS="-D_=1"
|
||||||
exercise_D_: 1
|
|
||||||
- runs-on: ubuntu-20.04
|
- runs-on: ubuntu-20.04
|
||||||
python: 'pypy-3.8'
|
python: 'pypy-3.8'
|
||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
- runs-on: windows-2019
|
- runs-on: windows-2019
|
||||||
python: '3.8'
|
python: '3.6'
|
||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
# Inject a couple Windows 2019 runs
|
# Inject a couple Windows 2019 runs
|
||||||
@ -83,7 +82,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Boost (Linux)
|
- name: Setup Boost (Linux)
|
||||||
# Can't use boost + define _
|
# Can't use boost + define _
|
||||||
if: runner.os == 'Linux' && matrix.exercise_D_ != 1
|
if: runner.os == 'Linux' && matrix.python != '3.6'
|
||||||
run: sudo apt-get install libboost-dev
|
run: sudo apt-get install libboost-dev
|
||||||
|
|
||||||
- name: Setup Boost (macOS)
|
- name: Setup Boost (macOS)
|
||||||
@ -134,7 +133,9 @@ jobs:
|
|||||||
run: cmake --build . --target pytest -j 2
|
run: cmake --build . --target pytest -j 2
|
||||||
|
|
||||||
- name: C++11 tests
|
- name: C++11 tests
|
||||||
run: cmake --build . --target cpptest -j 2
|
# 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
|
||||||
|
|
||||||
- name: Interface test C++11
|
- name: Interface test C++11
|
||||||
run: cmake --build . --target test_cmake_build
|
run: cmake --build . --target test_cmake_build
|
||||||
@ -163,6 +164,8 @@ jobs:
|
|||||||
run: cmake --build build2 --target pytest
|
run: cmake --build build2 --target pytest
|
||||||
|
|
||||||
- name: C++ tests
|
- 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
|
run: cmake --build build2 --target cpptest
|
||||||
|
|
||||||
# Third build - C++17 mode with unstable ABI
|
# Third build - C++17 mode with unstable ABI
|
||||||
@ -243,7 +246,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
|
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
|
||||||
uses: deadsnakes/action@v3.2.0
|
uses: deadsnakes/action@v3.1.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
debug: ${{ matrix.python-debug }}
|
debug: ${{ matrix.python-debug }}
|
||||||
@ -311,6 +314,11 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
clang:
|
clang:
|
||||||
|
- 3.6
|
||||||
|
- 3.7
|
||||||
|
- 3.9
|
||||||
|
- 7
|
||||||
|
- 9
|
||||||
- dev
|
- dev
|
||||||
std:
|
std:
|
||||||
- 11
|
- 11
|
||||||
@ -319,6 +327,8 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- clang: 5
|
- clang: 5
|
||||||
std: 14
|
std: 14
|
||||||
|
- clang: 10
|
||||||
|
std: 17
|
||||||
- clang: 11
|
- clang: 11
|
||||||
std: 20
|
std: 20
|
||||||
- clang: 12
|
- clang: 12
|
||||||
@ -333,12 +343,6 @@ jobs:
|
|||||||
- clang: 16
|
- clang: 16
|
||||||
std: 20
|
std: 20
|
||||||
container_suffix: "-bullseye"
|
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"
|
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
|
||||||
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
|
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
|
||||||
@ -496,9 +500,11 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { gcc: 9, std: 20 }
|
- { gcc: 7, std: 11 }
|
||||||
|
- { gcc: 7, std: 17 }
|
||||||
|
- { gcc: 8, std: 14 }
|
||||||
|
- { gcc: 8, std: 17 }
|
||||||
- { gcc: 10, std: 17 }
|
- { gcc: 10, std: 17 }
|
||||||
- { gcc: 10, std: 20 }
|
|
||||||
- { gcc: 11, std: 20 }
|
- { gcc: 11, std: 20 }
|
||||||
- { gcc: 12, std: 20 }
|
- { gcc: 12, std: 20 }
|
||||||
- { gcc: 13, std: 20 }
|
- { gcc: 13, std: 20 }
|
||||||
@ -653,13 +659,15 @@ jobs:
|
|||||||
cmake --build build-17 --target test_cmake_build
|
cmake --build build-17 --target test_cmake_build
|
||||||
|
|
||||||
|
|
||||||
# Testing on CentOS (manylinux uses a centos base).
|
# Testing on CentOS (manylinux uses a centos base, and this is an easy way
|
||||||
|
# to get GCC 4.8, which is the manylinux1 compiler).
|
||||||
centos:
|
centos:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
container:
|
container:
|
||||||
|
- "centos:7" # GCC 4.8
|
||||||
- "almalinux:8"
|
- "almalinux:8"
|
||||||
- "almalinux:9"
|
- "almalinux:9"
|
||||||
|
|
||||||
@ -669,13 +677,18 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Latest actions/checkout
|
- name: Latest actions/checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
if: matrix.container != 'centos:7'
|
||||||
|
|
||||||
- name: Add Python 3.8
|
- name: Pin actions/checkout as required for centos:7
|
||||||
if: matrix.container == 'almalinux:8'
|
uses: actions/checkout@v3
|
||||||
run: dnf update -y && dnf install -y python38-devel gcc-c++ make git
|
if: matrix.container == 'centos:7'
|
||||||
|
|
||||||
- name: Add Python 3 (default)
|
- name: Add Python 3 (RHEL 7)
|
||||||
if: matrix.container != 'almalinux:8'
|
if: matrix.container == 'centos:7'
|
||||||
|
run: yum update -y && yum install -y python3-devel gcc-c++ make git
|
||||||
|
|
||||||
|
- name: Add Python 3 (RHEL 8+)
|
||||||
|
if: matrix.container != 'centos:7'
|
||||||
run: dnf update -y && dnf install -y python3-devel gcc-c++ make git
|
run: dnf update -y && dnf install -y python3-devel gcc-c++ make git
|
||||||
|
|
||||||
- name: Update pip
|
- name: Update pip
|
||||||
@ -716,9 +729,9 @@ jobs:
|
|||||||
|
|
||||||
# This tests an "install" with the CMake tools
|
# This tests an "install" with the CMake tools
|
||||||
install-classic:
|
install-classic:
|
||||||
name: "🐍 3.9 • Debian • x86 • Install"
|
name: "🐍 3.7 • Debian • x86 • Install"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: i386/debian:bullseye
|
container: i386/debian:buster
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1 # v1 is required to run inside docker
|
- uses: actions/checkout@v1 # v1 is required to run inside docker
|
||||||
@ -798,23 +811,18 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- '3.8'
|
- 3.6
|
||||||
- '3.9'
|
- 3.7
|
||||||
- '3.10'
|
- 3.8
|
||||||
- '3.11'
|
- 3.9
|
||||||
- '3.12'
|
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- python: '3.12'
|
- python: 3.9
|
||||||
args: -DCMAKE_CXX_STANDARD=20
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
- python: '3.11'
|
- python: 3.8
|
||||||
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
|
args: -DCMAKE_CXX_STANDARD=17
|
||||||
|
- python: 3.7
|
||||||
|
args: -DCMAKE_CXX_STANDARD=14
|
||||||
|
|
||||||
|
|
||||||
name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}"
|
name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}"
|
||||||
@ -1103,7 +1111,7 @@ jobs:
|
|||||||
uses: jwlawson/actions-setup-cmake@v2.0
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Install ninja-build tool
|
- name: Install ninja-build tool
|
||||||
uses: seanmiddleditch/gha-setup-ninja@v5
|
uses: seanmiddleditch/gha-setup-ninja@v4
|
||||||
|
|
||||||
- name: Run pip installs
|
- name: Run pip installs
|
||||||
run: |
|
run: |
|
||||||
|
10
.github/workflows/configure.yml
vendored
10
.github/workflows/configure.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- runs-on: ubuntu-20.04
|
- runs-on: ubuntu-20.04
|
||||||
arch: x64
|
arch: x64
|
||||||
cmake: "3.15"
|
cmake: "3.5"
|
||||||
|
|
||||||
- runs-on: ubuntu-20.04
|
- runs-on: ubuntu-20.04
|
||||||
arch: x64
|
arch: x64
|
||||||
@ -39,22 +39,22 @@ jobs:
|
|||||||
|
|
||||||
- runs-on: macos-13
|
- runs-on: macos-13
|
||||||
arch: x64
|
arch: x64
|
||||||
cmake: "3.15"
|
cmake: "3.7"
|
||||||
|
|
||||||
- runs-on: windows-2019
|
- runs-on: windows-2019
|
||||||
arch: x64 # x86 compilers seem to be missing on 2019 image
|
arch: x64 # x86 compilers seem to be missing on 2019 image
|
||||||
cmake: "3.18"
|
cmake: "3.18"
|
||||||
|
|
||||||
name: 🐍 3.8 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
|
name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python 3.8
|
- name: Setup Python 3.7
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.7
|
||||||
architecture: ${{ matrix.arch }}
|
architecture: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
|
30
.github/workflows/emscripten.yaml
vendored
30
.github/workflows/emscripten.yaml
vendored
@ -1,30 +0,0 @@
|
|||||||
name: WASM
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- stable
|
|
||||||
- v*
|
|
||||||
|
|
||||||
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.21
|
|
||||||
env:
|
|
||||||
PYODIDE_BUILD_EXPORTS: whole_archive
|
|
||||||
with:
|
|
||||||
package-dir: tests
|
|
||||||
only: cp312-pyodide_wasm32
|
|
2
.github/workflows/format.yml
vendored
2
.github/workflows/format.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
|||||||
# in .github/CONTRIBUTING.md and update as needed.
|
# in .github/CONTRIBUTING.md and update as needed.
|
||||||
name: Clang-Tidy
|
name: Clang-Tidy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: silkeh/clang:18-bookworm
|
container: silkeh/clang:15-bullseye
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
28
.github/workflows/pip.yml
vendored
28
.github/workflows/pip.yml
vendored
@ -21,18 +21,19 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# This builds the sdists and wheels and makes sure the files are exactly as
|
# This builds the sdists and wheels and makes sure the files are exactly as
|
||||||
# expected.
|
# expected. Using Windows and Python 3.6, since that is often the most
|
||||||
|
# challenging matrix element.
|
||||||
test-packaging:
|
test-packaging:
|
||||||
name: 🐍 3.8 • 📦 tests • windows-latest
|
name: 🐍 3.6 • 📦 tests • windows-latest
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup 🐍 3.8
|
- name: Setup 🐍 3.6
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.6
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
run: |
|
run: |
|
||||||
@ -91,30 +92,23 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name == 'release' && github.event.action == 'published'
|
if: github.event_name == 'release' && github.event.action == 'published'
|
||||||
needs: [packaging]
|
needs: [packaging]
|
||||||
environment:
|
|
||||||
name: pypi
|
|
||||||
url: https://pypi.org/p/pybind11
|
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
attestations: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
|
||||||
# Downloads all to directories matching the artifact names
|
# Downloads all to directories matching the artifact names
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Generate artifact attestation for sdist and wheel
|
|
||||||
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
|
|
||||||
with:
|
|
||||||
subject-path: "*/pybind11*"
|
|
||||||
|
|
||||||
- name: Publish standard package
|
- name: Publish standard package
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
with:
|
with:
|
||||||
|
password: ${{ secrets.pypi_password }}
|
||||||
packages-dir: standard/
|
packages-dir: standard/
|
||||||
attestations: true
|
|
||||||
|
|
||||||
- name: Publish global package
|
- name: Publish global package
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
with:
|
with:
|
||||||
|
password: ${{ secrets.pypi_password_global }}
|
||||||
packages-dir: global/
|
packages-dir: global/
|
||||||
attestations: true
|
|
||||||
|
@ -25,14 +25,14 @@ repos:
|
|||||||
|
|
||||||
# Clang format the codebase automatically
|
# Clang format the codebase automatically
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: "v18.1.8"
|
rev: "v18.1.5"
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
types_or: [c++, c, cuda]
|
types_or: [c++, c, cuda]
|
||||||
|
|
||||||
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.6.3
|
rev: v0.4.7
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["--fix", "--show-fixes"]
|
args: ["--fix", "--show-fixes"]
|
||||||
@ -40,7 +40,7 @@ repos:
|
|||||||
|
|
||||||
# Check static types with mypy
|
# Check static types with mypy
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: "v1.11.2"
|
rev: "v1.10.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args: []
|
args: []
|
||||||
@ -79,7 +79,7 @@ repos:
|
|||||||
|
|
||||||
# Also code format the docs
|
# Also code format the docs
|
||||||
- repo: https://github.com/adamchainz/blacken-docs
|
- repo: https://github.com/adamchainz/blacken-docs
|
||||||
rev: "1.18.0"
|
rev: "1.16.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
@ -93,7 +93,7 @@ repos:
|
|||||||
|
|
||||||
# Avoid directional quotes
|
# Avoid directional quotes
|
||||||
- repo: https://github.com/sirosen/texthooks
|
- repo: https://github.com/sirosen/texthooks
|
||||||
rev: "0.6.7"
|
rev: "0.6.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: fix-ligatures
|
- id: fix-ligatures
|
||||||
- id: fix-smartquotes
|
- id: fix-smartquotes
|
||||||
@ -142,14 +142,14 @@ repos:
|
|||||||
|
|
||||||
# PyLint has native support - not always usable, but works for us
|
# PyLint has native support - not always usable, but works for us
|
||||||
- repo: https://github.com/PyCQA/pylint
|
- repo: https://github.com/PyCQA/pylint
|
||||||
rev: "v3.2.7"
|
rev: "v3.2.2"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pylint
|
- id: pylint
|
||||||
files: ^pybind11
|
files: ^pybind11
|
||||||
|
|
||||||
# Check schemas on some of our YAML files
|
# Check schemas on some of our YAML files
|
||||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||||
rev: 0.29.2
|
rev: 0.28.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-readthedocs
|
- id: check-readthedocs
|
||||||
- id: check-github-workflows
|
- id: check-github-workflows
|
||||||
|
@ -10,7 +10,16 @@ if(NOT CMAKE_VERSION VERSION_LESS "3.27")
|
|||||||
cmake_policy(GET CMP0148 _pybind11_cmp0148)
|
cmake_policy(GET CMP0148 _pybind11_cmp0148)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(_pybind11_cmp0148)
|
if(_pybind11_cmp0148)
|
||||||
cmake_policy(SET CMP0148 ${_pybind11_cmp0148})
|
cmake_policy(SET CMP0148 ${_pybind11_cmp0148})
|
||||||
@ -18,7 +27,9 @@ if(_pybind11_cmp0148)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Avoid infinite recursion if tests include this as a subdirectory
|
# Avoid infinite recursion if tests include this as a subdirectory
|
||||||
include_guard(GLOBAL)
|
if(DEFINED PYBIND11_MASTER_PROJECT)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Extract project version from source
|
# Extract project version from source
|
||||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h"
|
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h"
|
||||||
@ -63,6 +74,14 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
|||||||
|
|
||||||
set(PYBIND11_MASTER_PROJECT ON)
|
set(PYBIND11_MASTER_PROJECT ON)
|
||||||
|
|
||||||
|
if(OSX AND CMAKE_VERSION VERSION_LESS 3.7)
|
||||||
|
# Bug in macOS CMake < 3.7 is unable to download catch
|
||||||
|
message(WARNING "CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended")
|
||||||
|
elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8)
|
||||||
|
# Only tested with 3.8+ in CI.
|
||||||
|
message(WARNING "CMAKE 3.8+ tested on Windows, previous versions untested")
|
||||||
|
endif()
|
||||||
|
|
||||||
message(STATUS "CMake ${CMAKE_VERSION}")
|
message(STATUS "CMake ${CMAKE_VERSION}")
|
||||||
|
|
||||||
if(CMAKE_CXX_STANDARD)
|
if(CMAKE_CXX_STANDARD)
|
||||||
@ -114,7 +133,8 @@ cmake_dependent_option(
|
|||||||
"Install pybind11 headers in Python include directory instead of default installation prefix"
|
"Install pybind11 headers in Python include directory instead of default installation prefix"
|
||||||
OFF "PYBIND11_INSTALL" OFF)
|
OFF "PYBIND11_INSTALL" OFF)
|
||||||
|
|
||||||
option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default})
|
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
|
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
|
||||||
# (makes transition easier while we support both modes).
|
# (makes transition easier while we support both modes).
|
||||||
@ -129,14 +149,11 @@ endif()
|
|||||||
set(PYBIND11_HEADERS
|
set(PYBIND11_HEADERS
|
||||||
include/pybind11/detail/class.h
|
include/pybind11/detail/class.h
|
||||||
include/pybind11/detail/common.h
|
include/pybind11/detail/common.h
|
||||||
include/pybind11/detail/cpp_conduit.h
|
|
||||||
include/pybind11/detail/descr.h
|
include/pybind11/detail/descr.h
|
||||||
include/pybind11/detail/init.h
|
include/pybind11/detail/init.h
|
||||||
include/pybind11/detail/internals.h
|
include/pybind11/detail/internals.h
|
||||||
include/pybind11/detail/type_caster_base.h
|
include/pybind11/detail/type_caster_base.h
|
||||||
include/pybind11/detail/typeid.h
|
include/pybind11/detail/typeid.h
|
||||||
include/pybind11/detail/value_and_holder.h
|
|
||||||
include/pybind11/detail/exception_translation.h
|
|
||||||
include/pybind11/attr.h
|
include/pybind11/attr.h
|
||||||
include/pybind11/buffer_info.h
|
include/pybind11/buffer_info.h
|
||||||
include/pybind11/cast.h
|
include/pybind11/cast.h
|
||||||
@ -162,11 +179,10 @@ set(PYBIND11_HEADERS
|
|||||||
include/pybind11/stl_bind.h
|
include/pybind11/stl_bind.h
|
||||||
include/pybind11/stl/filesystem.h
|
include/pybind11/stl/filesystem.h
|
||||||
include/pybind11/type_caster_pyobject_ptr.h
|
include/pybind11/type_caster_pyobject_ptr.h
|
||||||
include/pybind11/typing.h
|
include/pybind11/typing.h)
|
||||||
include/pybind11/warnings.h)
|
|
||||||
|
|
||||||
# Compare with grep and warn if mismatched
|
# Compare with grep and warn if mismatched
|
||||||
if(PYBIND11_MASTER_PROJECT)
|
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||||
file(
|
file(
|
||||||
GLOB_RECURSE _pybind11_header_check
|
GLOB_RECURSE _pybind11_header_check
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
@ -184,7 +200,10 @@ if(PYBIND11_MASTER_PROJECT)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(TRANSFORM PYBIND11_HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
# CMake 3.12 added list(TRANSFORM <list> PREPEND
|
||||||
|
# But we can't use it yet
|
||||||
|
string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" PYBIND11_HEADERS
|
||||||
|
"${PYBIND11_HEADERS}")
|
||||||
|
|
||||||
# Cache variable so this can be used in parent projects
|
# Cache variable so this can be used in parent projects
|
||||||
set(pybind11_INCLUDE_DIR
|
set(pybind11_INCLUDE_DIR
|
||||||
@ -254,11 +273,25 @@ if(PYBIND11_INSTALL)
|
|||||||
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||||
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
|
|
||||||
# CMake natively supports header-only libraries
|
if(CMAKE_VERSION VERSION_LESS 3.14)
|
||||||
write_basic_package_version_file(
|
# Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
# not depend on architecture specific settings or libraries.
|
||||||
VERSION ${PROJECT_VERSION}
|
set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||||
COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT)
|
unset(CMAKE_SIZEOF_VOID_P)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion)
|
||||||
|
|
||||||
|
set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P})
|
||||||
|
else()
|
||||||
|
# CMake 3.14+ natively supports header-only libraries
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||||
|
@ -34,7 +34,7 @@ dependency.
|
|||||||
Think of this library as a tiny self-contained version of Boost.Python
|
Think of this library as a tiny self-contained version of Boost.Python
|
||||||
with everything stripped away that isn't relevant for binding
|
with everything stripped away that isn't relevant for binding
|
||||||
generation. Without comments, the core header files only require ~4K
|
generation. Without comments, the core header files only require ~4K
|
||||||
lines of code and depend on Python (3.8+, or PyPy) and the C++
|
lines of code and depend on Python (3.6+, or PyPy) and the C++
|
||||||
standard library. This compact implementation was possible thanks to
|
standard library. This compact implementation was possible thanks to
|
||||||
some C++11 language features (specifically: tuples, lambda functions and
|
some C++11 language features (specifically: tuples, lambda functions and
|
||||||
variadic templates). Since its creation, this library has grown beyond
|
variadic templates). Since its creation, this library has grown beyond
|
||||||
@ -79,7 +79,7 @@ Goodies
|
|||||||
In addition to the core functionality, pybind11 provides some extra
|
In addition to the core functionality, pybind11 provides some extra
|
||||||
goodies:
|
goodies:
|
||||||
|
|
||||||
- Python 3.8+, and PyPy3 7.3 are supported with an implementation-agnostic
|
- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic
|
||||||
interface (pybind11 2.9 was the last version to support Python 2 and 3.5).
|
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
|
- It is possible to bind C++11 lambda functions with captured
|
||||||
|
@ -259,7 +259,7 @@ copying to take place:
|
|||||||
"small"_a // <- This one can be copied if needed
|
"small"_a // <- This one can be copied if needed
|
||||||
);
|
);
|
||||||
|
|
||||||
With the above binding code, attempting to call the ``some_method(m)``
|
With the above binding code, attempting to call the the ``some_method(m)``
|
||||||
method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)``
|
method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)``
|
||||||
will raise a ``RuntimeError`` rather than making a temporary copy of the array.
|
will raise a ``RuntimeError`` rather than making a temporary copy of the array.
|
||||||
It will, however, allow the ``m2`` argument to be copied into a temporary if
|
It will, however, allow the ``m2`` argument to be copied into a temporary if
|
||||||
|
@ -162,7 +162,7 @@ the declaration
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
PYBIND11_MAKE_OPAQUE(std::vector<int>)
|
PYBIND11_MAKE_OPAQUE(std::vector<int>);
|
||||||
|
|
||||||
before any binding code (e.g. invocations to ``class_::def()``, etc.). This
|
before any binding code (e.g. invocations to ``class_::def()``, etc.). This
|
||||||
macro must be specified at the top level (and outside of any namespaces), since
|
macro must be specified at the top level (and outside of any namespaces), since
|
||||||
@ -207,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`:
|
|||||||
// Don't forget this
|
// Don't forget this
|
||||||
#include <pybind11/stl_bind.h>
|
#include <pybind11/stl_bind.h>
|
||||||
|
|
||||||
PYBIND11_MAKE_OPAQUE(std::vector<int>)
|
PYBIND11_MAKE_OPAQUE(std::vector<int>);
|
||||||
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>)
|
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>);
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
|
@ -826,7 +826,8 @@ An instance can now be pickled as follows:
|
|||||||
always use the latest available version. Beware: failure to follow these
|
always use the latest available version. Beware: failure to follow these
|
||||||
instructions will cause important pybind11 memory allocation routines to be
|
instructions will cause important pybind11 memory allocation routines to be
|
||||||
skipped during unpickling, which will likely lead to memory corruption
|
skipped during unpickling, which will likely lead to memory corruption
|
||||||
and/or segmentation faults.
|
and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and
|
||||||
|
version 4 for Python 3.8+.
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ information, see :doc:`/compiling`.
|
|||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5...3.29)
|
||||||
project(example)
|
project(example)
|
||||||
|
|
||||||
find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)`
|
find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)`
|
||||||
|
@ -368,7 +368,8 @@ Should they throw or fail to catch any exceptions in their call graph,
|
|||||||
the C++ runtime calls ``std::terminate()`` to abort immediately.
|
the C++ runtime calls ``std::terminate()`` to abort immediately.
|
||||||
|
|
||||||
Similarly, Python exceptions raised in a class's ``__del__`` method do not
|
Similarly, Python exceptions raised in a class's ``__del__`` method do not
|
||||||
propagate, but ``sys.unraisablehook()`` `is triggered
|
propagate, but are logged by Python as an unraisable error. In Python 3.8+, a
|
||||||
|
`system hook is triggered
|
||||||
<https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_
|
<https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_
|
||||||
and an auditing event is logged.
|
and an auditing event is logged.
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ top namespace level before any binding code:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
||||||
|
|
||||||
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
|
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
|
||||||
placeholder name that is used as a template parameter of the second argument.
|
placeholder name that is used as a template parameter of the second argument.
|
||||||
@ -136,7 +136,7 @@ by default. Specify
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true)
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true);
|
||||||
|
|
||||||
if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the
|
if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the
|
||||||
risk of inconsistencies (such as multiple independent ``SmartPtr`` instances
|
risk of inconsistencies (such as multiple independent ``SmartPtr`` instances
|
||||||
@ -154,7 +154,7 @@ specialized:
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
// Always needed for custom holder types
|
// Always needed for custom holder types
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
||||||
|
|
||||||
// Only needed if the type's `.get()` goes by another name
|
// Only needed if the type's `.get()` goes by another name
|
||||||
namespace PYBIND11_NAMESPACE { namespace detail {
|
namespace PYBIND11_NAMESPACE { namespace detail {
|
||||||
|
@ -78,13 +78,6 @@ For brevity, all code examples assume that the following two lines are present:
|
|||||||
|
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
``pybind11/pybind11.h`` includes ``Python.h``, as such it must be the first file
|
|
||||||
included in any source file or header for `the same reasons as Python.h`_.
|
|
||||||
|
|
||||||
.. _`the same reasons as Python.h`: https://docs.python.org/3/extending/extending.html#a-simple-example
|
|
||||||
|
|
||||||
Some features may require additional headers, but those will be specified as needed.
|
Some features may require additional headers, but those will be specified as needed.
|
||||||
|
|
||||||
.. _simple_example:
|
.. _simple_example:
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
@ -15,273 +15,6 @@ IN DEVELOPMENT
|
|||||||
|
|
||||||
Changes will be summarized here periodically.
|
Changes will be summarized here periodically.
|
||||||
|
|
||||||
New Features:
|
|
||||||
|
|
||||||
* Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27).
|
|
||||||
`#5191 <https://github.com/pybind/pybind11/pull/5191>`_
|
|
||||||
|
|
||||||
* stl.h ``list|set|map_caster`` were made more user friendly: it is no longer
|
|
||||||
necessary to explicitly convert Python iterables to ``tuple()``, ``set()``,
|
|
||||||
or ``map()`` in many common situations.
|
|
||||||
`#4686 <https://github.com/pybind/pybind11/pull/4686>`_
|
|
||||||
|
|
||||||
* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported.
|
|
||||||
`#5304 <https://github.com/pybind/pybind11/pull/5304>`_
|
|
||||||
|
|
||||||
* The ``array_caster`` in pybind11/stl.h was enhanced to support value types that are not default-constructible.
|
|
||||||
`#5305 <https://github.com/pybind/pybind11/pull/5305>`_
|
|
||||||
|
|
||||||
* Added ``py::warnings`` namespace with ``py::warnings::warn`` and ``py::warnings::new_warning_type`` that provides the interface for Python warnings.
|
|
||||||
`#5291 <https://github.com/pybind/pybind11/pull/5291>`_
|
|
||||||
|
|
||||||
Version 2.13.6 (September 13, 2024)
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
New Features:
|
|
||||||
|
|
||||||
* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all
|
|
||||||
``py::class_``-wrapped types, to enable type-safe interoperability between
|
|
||||||
different independent Python/C++ bindings systems, including pybind11
|
|
||||||
versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on
|
|
||||||
pybind11 2.11.2, 2.12.1, and 2.13.6+.
|
|
||||||
`#5296 <https://github.com/pybind/pybind11/pull/5296>`_
|
|
||||||
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
* Using ``__cpp_nontype_template_args`` instead of ``__cpp_nontype_template_parameter_class``.
|
|
||||||
`#5330 <https://github.com/pybind/pybind11/pull/5330>`_
|
|
||||||
|
|
||||||
* Properly translate C++ exception to Python exception when creating Python buffer from wrapped object.
|
|
||||||
`#5324 <https://github.com/pybind/pybind11/pull/5324>`_
|
|
||||||
|
|
||||||
|
|
||||||
Documentation:
|
|
||||||
|
|
||||||
* Adds an answer (FAQ) for "What is a highly conclusive and simple way to find memory leaks?".
|
|
||||||
`#5340 <https://github.com/pybind/pybind11/pull/5340>`_
|
|
||||||
|
|
||||||
|
|
||||||
Version 2.13.5 (August 22, 2024)
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
* Fix includes when using Windows long paths (``\\?\`` prefix).
|
|
||||||
`#5321 <https://github.com/pybind/pybind11/pull/5321>`_
|
|
||||||
|
|
||||||
* Support ``-Wpedantic`` in C++20 mode.
|
|
||||||
`#5322 <https://github.com/pybind/pybind11/pull/5322>`_
|
|
||||||
|
|
||||||
* Fix and test ``<ranges>`` support for ``py::tuple`` and ``py::list``.
|
|
||||||
`#5314 <https://github.com/pybind/pybind11/pull/5314>`_
|
|
||||||
|
|
||||||
Version 2.13.4 (August 14, 2024)
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
* Fix paths with spaces, including on Windows.
|
|
||||||
(Replaces regression from `#5302 <https://github.com/pybind/pybind11/pull/5302>`_)
|
|
||||||
`#4874 <https://github.com/pybind/pybind11/pull/4874>`_
|
|
||||||
|
|
||||||
Documentation:
|
|
||||||
|
|
||||||
* Remove repetitive words.
|
|
||||||
`#5308 <https://github.com/pybind/pybind11/pull/5308>`_
|
|
||||||
|
|
||||||
|
|
||||||
Version 2.13.3 (August 13, 2024)
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
* Quote paths from pybind11-config
|
|
||||||
`#5302 <https://github.com/pybind/pybind11/pull/5302>`_
|
|
||||||
|
|
||||||
|
|
||||||
* Fix typo in Emscripten support when in config mode (CMake)
|
|
||||||
`#5301 <https://github.com/pybind/pybind11/pull/5301>`_
|
|
||||||
|
|
||||||
|
|
||||||
Version 2.13.2 (August 13, 2024)
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
New Features:
|
|
||||||
|
|
||||||
* A ``pybind11::detail::type_caster_std_function_specializations`` feature was added, to support specializations for
|
|
||||||
``std::function``'s with return types that require custom to-Python conversion behavior (to primary use case is to catch and
|
|
||||||
convert exceptions).
|
|
||||||
`#4597 <https://github.com/pybind/pybind11/pull/4597>`_
|
|
||||||
|
|
||||||
|
|
||||||
Changes:
|
|
||||||
|
|
||||||
|
|
||||||
* Use ``PyMutex`` instead of ``std::mutex`` for internal locking in the free-threaded build.
|
|
||||||
`#5219 <https://github.com/pybind/pybind11/pull/5219>`_
|
|
||||||
|
|
||||||
* Add a special type annotation for C++ empty tuple.
|
|
||||||
`#5214 <https://github.com/pybind/pybind11/pull/5214>`_
|
|
||||||
|
|
||||||
* When compiling for WebAssembly, add the required exception flags (CMake 3.13+).
|
|
||||||
`#5298 <https://github.com/pybind/pybind11/pull/5298>`_
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
* Make ``gil_safe_call_once_and_store`` thread-safe in free-threaded CPython.
|
|
||||||
`#5246 <https://github.com/pybind/pybind11/pull/5246>`_
|
|
||||||
|
|
||||||
* A missing ``#include <algorithm>`` in pybind11/typing.h was added to fix build errors (in case user code does not already depend
|
|
||||||
on that include).
|
|
||||||
`#5208 <https://github.com/pybind/pybind11/pull/5208>`_
|
|
||||||
|
|
||||||
* Fix regression introduced in #5201 for GCC<10.3 in C++20 mode.
|
|
||||||
`#5205 <https://github.com/pybind/pybind11/pull/5205>`_
|
|
||||||
|
|
||||||
|
|
||||||
.. fix(cmake)
|
|
||||||
|
|
||||||
* Remove extra = when assigning flto value in the case for Clang in CMake.
|
|
||||||
`#5207 <https://github.com/pybind/pybind11/pull/5207>`_
|
|
||||||
|
|
||||||
|
|
||||||
Tests:
|
|
||||||
|
|
||||||
* Adding WASM testing to our CI (Pyodide / Emscripten via scikit-build-core).
|
|
||||||
`#4745 <https://github.com/pybind/pybind11/pull/4745>`_
|
|
||||||
|
|
||||||
* clang-tidy (in GitHub Actions) was updated from clang 15 to clang 18.
|
|
||||||
`#5272 <https://github.com/pybind/pybind11/pull/5272>`_
|
|
||||||
|
|
||||||
|
|
||||||
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.1 (September 13, 2024)
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
New Features:
|
|
||||||
|
|
||||||
* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all
|
|
||||||
``py::class_``-wrapped types, to enable type-safe interoperability between
|
|
||||||
different independent Python/C++ bindings systems, including pybind11
|
|
||||||
versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on
|
|
||||||
pybind11 2.11.2, 2.12.1, and 2.13.6+.
|
|
||||||
`#5296 <https://github.com/pybind/pybind11/pull/5296>`_
|
|
||||||
|
|
||||||
|
|
||||||
Version 2.12.0 (March 27, 2024)
|
Version 2.12.0 (March 27, 2024)
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
@ -456,18 +189,6 @@ Other:
|
|||||||
* An ``assert()`` was added to help Coverty avoid generating a false positive.
|
* An ``assert()`` was added to help Coverty avoid generating a false positive.
|
||||||
`#4817 <https://github.com/pybind/pybind11/pull/4817>`_
|
`#4817 <https://github.com/pybind/pybind11/pull/4817>`_
|
||||||
|
|
||||||
Version 2.11.2 (September 13, 2024)
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
New Features:
|
|
||||||
|
|
||||||
* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all
|
|
||||||
``py::class_``-wrapped types, to enable type-safe interoperability between
|
|
||||||
different independent Python/C++ bindings systems, including pybind11
|
|
||||||
versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on
|
|
||||||
pybind11 2.11.2, 2.12.1, and 2.13.6+.
|
|
||||||
`#5296 <https://github.com/pybind/pybind11/pull/5296>`_
|
|
||||||
|
|
||||||
|
|
||||||
Version 2.11.1 (July 17, 2023)
|
Version 2.11.1 (July 17, 2023)
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -3,123 +3,15 @@
|
|||||||
Build systems
|
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.30)
|
|
||||||
project(example LANGUAGES CXX)
|
|
||||||
|
|
||||||
set(PYBIND11_FINDPYTHON ON)
|
|
||||||
find_package(pybind11 CONFIG REQUIRED)
|
|
||||||
|
|
||||||
pybind11_add_module(example example.cpp)
|
|
||||||
install(TARGETS 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:
|
.. _build-setuptools:
|
||||||
|
|
||||||
Modules with setuptools
|
Building with setuptools
|
||||||
=======================
|
========================
|
||||||
|
|
||||||
For projects on PyPI, a historically popular option is setuptools. Sylvain
|
For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay
|
||||||
Corlay has kindly provided an example project which shows how to set up
|
has kindly provided an example project which shows how to set up everything,
|
||||||
everything, including automatic generation of documentation using Sphinx.
|
including automatic generation of documentation using Sphinx. Please refer to
|
||||||
Please refer to the [python_example]_ repository.
|
the [python_example]_ repository.
|
||||||
|
|
||||||
.. [python_example] https://github.com/pybind/python_example
|
.. [python_example] https://github.com/pybind/python_example
|
||||||
|
|
||||||
@ -129,11 +21,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
|
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
|
four possible ways to do this, and pybind11 supports all four: You can ask all
|
||||||
users to install pybind11 beforehand (bad), you can use
|
users to install pybind11 beforehand (bad), you can use
|
||||||
:ref:`setup_helpers-pep518` (good), ``setup_requires=`` (discouraged), or you
|
:ref:`setup_helpers-pep518` (good, but very new and requires Pip 10),
|
||||||
can :ref:`setup_helpers-copy-manually` (works but you have to manually sync
|
:ref:`setup_helpers-setup_requires` (discouraged by Python packagers now that
|
||||||
your copy to get updates). Third party packagers like conda-forge generally
|
PEP 518 is available, but it still works everywhere), or you can
|
||||||
strongly prefer the ``pyproject.toml`` method, as it gives them control over
|
:ref:`setup_helpers-copy-manually` (always works but you have to manually sync
|
||||||
the ``pybind11`` version, and they may apply patches, etc.
|
your copy to get updates).
|
||||||
|
|
||||||
An example of a ``setup.py`` using pybind11's helpers:
|
An example of a ``setup.py`` using pybind11's helpers:
|
||||||
|
|
||||||
@ -230,41 +122,70 @@ 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
|
hash for a dirty directory. Another way to force a rebuild is purge your cache
|
||||||
or use Pip's ``--no-cache-dir`` option.
|
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
|
.. [Ccache] https://ccache.dev
|
||||||
|
|
||||||
.. [setuptools_scm] https://github.com/pypa/setuptools_scm
|
.. [setuptools_scm] https://github.com/pypa/setuptools_scm
|
||||||
|
|
||||||
.. _setup_helpers-pep518:
|
.. _setup_helpers-pep518:
|
||||||
|
|
||||||
Build requirements
|
PEP 518 requirements (Pip 10+ required)
|
||||||
------------------
|
---------------------------------------
|
||||||
|
|
||||||
With a ``pyproject.toml`` file, you can ensure that ``pybind11`` is available
|
If you use `PEP 518's <https://www.python.org/dev/peps/pep-0518/>`_
|
||||||
during the compilation of your project. When this file exists, Pip will make a
|
``pyproject.toml`` file, you can ensure that ``pybind11`` is available during
|
||||||
new virtual environment, download just the packages listed here in
|
the compilation of your project. When this file exists, Pip will make a new
|
||||||
``requires=``, and build a wheel (binary Python package). It will then throw
|
virtual environment, download just the packages listed here in ``requires=``,
|
||||||
away the environment, and install your wheel.
|
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:
|
Your ``pyproject.toml`` file will likely look something like this:
|
||||||
|
|
||||||
.. code-block:: toml
|
.. code-block:: toml
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools", "pybind11"]
|
requires = ["setuptools>=42", "pybind11>=2.6.1"]
|
||||||
build-backend = "setuptools.build_meta"
|
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/
|
.. _PEP 517: https://www.python.org/dev/peps/pep-0517/
|
||||||
.. _cibuildwheel: https://cibuildwheel.pypa.io
|
.. _cibuildwheel: https://cibuildwheel.readthedocs.io
|
||||||
.. _pypa-build: https://build.pypa.io/en/latest/
|
.. _pypa-build: https://pypa-build.readthedocs.io/en/latest/
|
||||||
.. _check-manifest: https://pypi.io/project/check-manifest
|
|
||||||
.. _check-sdist: https://pypi.io/project/check-sdist
|
.. _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.
|
||||||
|
|
||||||
.. _setup_helpers-copy-manually:
|
.. _setup_helpers-copy-manually:
|
||||||
|
|
||||||
@ -310,22 +231,32 @@ the C++ source file. Python is then able to find the module and load it.
|
|||||||
|
|
||||||
.. [cppimport] https://github.com/tbenthompson/cppimport
|
.. [cppimport] https://github.com/tbenthompson/cppimport
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _cmake:
|
.. _cmake:
|
||||||
|
|
||||||
Building with CMake
|
Building with CMake
|
||||||
===================
|
===================
|
||||||
|
|
||||||
For C++ codebases that have an existing CMake-based build system, a Python
|
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, as seen above in
|
extension module can be created with just a few lines of code:
|
||||||
the module section. Pybind11 currently defaults to the old mechanism, 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.29)
|
||||||
|
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
|
.. versionchanged:: 2.6
|
||||||
CMake 3.4+ is required.
|
CMake 3.4+ is required.
|
||||||
@ -333,10 +264,6 @@ minimum required:
|
|||||||
.. versionchanged:: 2.11
|
.. versionchanged:: 2.11
|
||||||
CMake 3.5+ is required.
|
CMake 3.5+ is required.
|
||||||
|
|
||||||
.. versionchanged:: 2.14
|
|
||||||
CMake 3.15+ is required.
|
|
||||||
|
|
||||||
|
|
||||||
Further information can be found at :doc:`cmake/index`.
|
Further information can be found at :doc:`cmake/index`.
|
||||||
|
|
||||||
pybind11_add_module
|
pybind11_add_module
|
||||||
@ -391,7 +318,7 @@ that will be respected instead of the built-in flag search.
|
|||||||
|
|
||||||
The ``OPT_SIZE`` flag enables size-based optimization equivalent to the
|
The ``OPT_SIZE`` flag enables size-based optimization equivalent to the
|
||||||
standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type,
|
standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type,
|
||||||
which avoid optimizations that can substantially increase the size of the
|
which avoid optimizations that that can substantially increase the size of the
|
||||||
resulting binary. This flag is particularly useful in projects that are split
|
resulting binary. This flag is particularly useful in projects that are split
|
||||||
into performance-critical parts and associated bindings. In this case, we can
|
into performance-critical parts and associated bindings. In this case, we can
|
||||||
compile the project in release mode (and hence, optimize performance globally),
|
compile the project in release mode (and hence, optimize performance globally),
|
||||||
@ -429,7 +356,7 @@ with ``PYTHON_EXECUTABLE``. For example:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cmake -DPYBIND11_PYTHON_VERSION=3.8 ..
|
cmake -DPYBIND11_PYTHON_VERSION=3.6 ..
|
||||||
|
|
||||||
# Another method:
|
# Another method:
|
||||||
cmake -DPYTHON_EXECUTABLE=/path/to/python ..
|
cmake -DPYTHON_EXECUTABLE=/path/to/python ..
|
||||||
@ -447,7 +374,7 @@ See the `Config file`_ docstring for details of relevant CMake variables.
|
|||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.4...3.18)
|
||||||
project(example LANGUAGES CXX)
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(pybind11 REQUIRED)
|
find_package(pybind11 REQUIRED)
|
||||||
@ -486,16 +413,17 @@ can refer to the same [cmake_example]_ repository for a full sample project
|
|||||||
FindPython mode
|
FindPython mode
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Modern CMake (3.18.2+ ideal) added a new module called FindPython that had a
|
CMake 3.12+ (3.15+ recommended, 3.18.2+ ideal) added a new module called
|
||||||
highly improved search algorithm and modern targets and tools. If you use
|
FindPython that had a highly improved search algorithm and modern targets
|
||||||
FindPython, pybind11 will detect this and use the existing targets instead:
|
and tools. If you use FindPython, pybind11 will detect this and use the
|
||||||
|
existing targets instead:
|
||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.15...3.22)
|
||||||
project(example LANGUAGES CXX)
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED)
|
find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED)
|
||||||
find_package(pybind11 CONFIG REQUIRED)
|
find_package(pybind11 CONFIG REQUIRED)
|
||||||
# or add_subdirectory(pybind11)
|
# or add_subdirectory(pybind11)
|
||||||
|
|
||||||
@ -543,7 +471,7 @@ available in all modes. The targets provided are:
|
|||||||
Just the "linking" part of pybind11:module
|
Just the "linking" part of pybind11:module
|
||||||
|
|
||||||
``pybind11::module``
|
``pybind11::module``
|
||||||
Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython) or ``pybind11::python_link_helper``
|
Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper``
|
||||||
|
|
||||||
``pybind11::embed``
|
``pybind11::embed``
|
||||||
Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs
|
Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs
|
||||||
@ -570,7 +498,7 @@ You can use these targets to build complex applications. For example, the
|
|||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5...3.29)
|
||||||
project(example LANGUAGES CXX)
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
||||||
@ -628,7 +556,7 @@ information about usage in C++, see :doc:`/advanced/embedding`.
|
|||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5...3.29)
|
||||||
project(example LANGUAGES CXX)
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
||||||
@ -688,13 +616,6 @@ Building with Bazel
|
|||||||
You can build with the Bazel build system using the `pybind11_bazel
|
You can build with the Bazel build system using the `pybind11_bazel
|
||||||
<https://github.com/pybind/pybind11_bazel>`_ repository.
|
<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
|
Generating binding code automatically
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
@ -721,7 +642,7 @@ customizable pybind11-based wrappers by parsing C++ header files.
|
|||||||
|
|
||||||
[litgen]_ is an automatic python bindings generator with a focus on generating
|
[litgen]_ is an automatic python bindings generator with a focus on generating
|
||||||
documented and discoverable bindings: bindings will nicely reproduce the documentation
|
documented and discoverable bindings: bindings will nicely reproduce the documentation
|
||||||
found in headers. It is based on srcML (srcml.org), a highly scalable, multi-language
|
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
|
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).
|
must be C++14 compatible (but your implementation can use more modern constructs).
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#
|
#
|
||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
60
docs/faq.rst
60
docs/faq.rst
@ -247,50 +247,6 @@ been received, you must either explicitly interrupt execution by throwing
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
What is a highly conclusive and simple way to find memory leaks (e.g. in pybind11 bindings)?
|
|
||||||
============================================================================================
|
|
||||||
|
|
||||||
Use ``while True`` & ``top`` (Linux, macOS).
|
|
||||||
|
|
||||||
For example, locally change tests/test_type_caster_pyobject_ptr.py like this:
|
|
||||||
|
|
||||||
.. code-block:: diff
|
|
||||||
|
|
||||||
def test_return_list_pyobject_ptr_reference():
|
|
||||||
+ while True:
|
|
||||||
vec_obj = m.return_list_pyobject_ptr_reference(ValueHolder)
|
|
||||||
assert [e.value for e in vec_obj] == [93, 186]
|
|
||||||
# Commenting out the next `assert` will leak the Python references.
|
|
||||||
# An easy way to see evidence of the leaks:
|
|
||||||
# Insert `while True:` as the first line of this function and monitor the
|
|
||||||
# process RES (Resident Memory Size) with the Unix top command.
|
|
||||||
- assert m.dec_ref_each_pyobject_ptr(vec_obj) == 2
|
|
||||||
+ # assert m.dec_ref_each_pyobject_ptr(vec_obj) == 2
|
|
||||||
|
|
||||||
Then run the test as you would normally do, which will go into the infinite loop.
|
|
||||||
|
|
||||||
**In another shell, but on the same machine** run:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
top
|
|
||||||
|
|
||||||
This will show:
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
|
|
||||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
|
||||||
1266095 rwgk 20 0 5207496 611372 45696 R 100.0 0.3 0:08.01 test_type_caste
|
|
||||||
|
|
||||||
Look for the number under ``RES`` there. You'll see it going up very quickly.
|
|
||||||
|
|
||||||
**Don't forget to Ctrl-C the test command** before your machine becomes
|
|
||||||
unresponsive due to swapping.
|
|
||||||
|
|
||||||
This method only takes a couple minutes of effort and is very conclusive.
|
|
||||||
What you want to see is that the ``RES`` number is stable after a couple
|
|
||||||
seconds.
|
|
||||||
|
|
||||||
CMake doesn't detect the right Python version
|
CMake doesn't detect the right Python version
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
@ -302,9 +258,9 @@ CMake configure line. (Replace ``$(which python)`` with a path to python if
|
|||||||
your prefer.)
|
your prefer.)
|
||||||
|
|
||||||
You can alternatively try ``-DPYBIND11_FINDPYTHON=ON``, which will activate the
|
You can alternatively try ``-DPYBIND11_FINDPYTHON=ON``, which will activate the
|
||||||
new CMake FindPython support instead of pybind11's custom search. Newer CMake,
|
new CMake FindPython support instead of pybind11's custom search. Requires
|
||||||
like, 3.18.2+, is recommended. You can set this in your ``CMakeLists.txt``
|
CMake 3.12+, and 3.15+ or 3.18.2+ are even better. You can set this in your
|
||||||
before adding or finding pybind11, as well.
|
``CMakeLists.txt`` before adding or finding pybind11, as well.
|
||||||
|
|
||||||
Inconsistent detection of Python version in CMake and pybind11
|
Inconsistent detection of Python version in CMake and pybind11
|
||||||
==============================================================
|
==============================================================
|
||||||
@ -325,11 +281,11 @@ There are three possible solutions:
|
|||||||
from CMake and rely on pybind11 in detecting Python version. If this is not
|
from CMake and rely on pybind11 in detecting Python version. If this is not
|
||||||
possible, the CMake machinery should be called *before* including pybind11.
|
possible, the CMake machinery should be called *before* including pybind11.
|
||||||
2. Set ``PYBIND11_FINDPYTHON`` to ``True`` or use ``find_package(Python
|
2. Set ``PYBIND11_FINDPYTHON`` to ``True`` or use ``find_package(Python
|
||||||
COMPONENTS Interpreter Development)`` on modern CMake ( 3.18.2+ best).
|
COMPONENTS Interpreter Development)`` on modern CMake (3.12+, 3.15+ better,
|
||||||
Pybind11 in these cases uses the new CMake FindPython instead of the old,
|
3.18.2+ best). Pybind11 in these cases uses the new CMake FindPython instead
|
||||||
deprecated search tools, and these modules are much better at finding the
|
of the old, deprecated search tools, and these modules are much better at
|
||||||
correct Python. If FindPythonLibs/Interp are not available (CMake 3.27+),
|
finding the correct Python. If FindPythonLibs/Interp are not available
|
||||||
then this will be ignored and FindPython will be used.
|
(CMake 3.27+), then this will be ignored and FindPython will be used.
|
||||||
3. Set ``PYBIND11_NOPYTHON`` to ``TRUE``. Pybind11 will not search for Python.
|
3. Set ``PYBIND11_NOPYTHON`` to ``TRUE``. Pybind11 will not search for Python.
|
||||||
However, you will have to use the target-based system, and do more setup
|
However, you will have to use the target-based system, and do more setup
|
||||||
yourself, because it does not know about or include things that depend on
|
yourself, because it does not know about or include things that depend on
|
||||||
|
@ -50,6 +50,10 @@ clean, well written patch would likely be accepted to solve them.
|
|||||||
One consequence is that containers of ``char *`` are currently not supported.
|
One consequence is that containers of ``char *`` are currently not supported.
|
||||||
`#2245 <https://github.com/pybind/pybind11/issues/2245>`_
|
`#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
|
Python 3.9.0 warning
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@ breathe==4.35.0 \
|
|||||||
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
|
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
|
||||||
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
|
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
certifi==2024.7.4 \
|
certifi==2024.2.2 \
|
||||||
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
|
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||||
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
|
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||||
# via requests
|
# via requests
|
||||||
charset-normalizer==3.3.2 \
|
charset-normalizer==3.3.2 \
|
||||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||||
@ -269,7 +269,7 @@ sphinxcontrib-svg2pdfconverter==1.2.2 \
|
|||||||
--hash=sha256:04ec767b55780a6b18d89cc1a8ada6d900c6efde9d1683abdb98a49b144465ca \
|
--hash=sha256:04ec767b55780a6b18d89cc1a8ada6d900c6efde9d1683abdb98a49b144465ca \
|
||||||
--hash=sha256:80a55ca61f70eae93efc65f3814f2f177c86ba55934a9f6c5022f1778b62146b
|
--hash=sha256:80a55ca61f70eae93efc65f3814f2f177c86ba55934a9f6c5022f1778b62146b
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
urllib3==2.2.2 \
|
urllib3==2.2.1 \
|
||||||
--hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
|
--hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
|
||||||
--hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
|
--hash=sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19
|
||||||
# via requests
|
# via requests
|
||||||
|
@ -158,7 +158,7 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
handle src_or_index = src;
|
handle src_or_index = src;
|
||||||
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
|
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
|
||||||
#if defined(PYPY_VERSION)
|
#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
|
||||||
object index;
|
object index;
|
||||||
if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
|
if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
|
||||||
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
|
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
|
||||||
@ -740,13 +740,6 @@ class type_caster<std::pair<T1, T2>> : public tuple_caster<std::pair, T1, T2> {}
|
|||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
class type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, 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
|
/// 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.
|
/// custom holders, but it's only necessary if the type has a non-standard interface.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -794,11 +787,11 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_value(value_and_holder &&v_h) {
|
bool load_value(value_and_holder &&v_h) {
|
||||||
if (v_h.holder_constructed()) {
|
if (v_h.holder_constructed()) {
|
||||||
value = v_h.value_ptr();
|
value = v_h.value_ptr();
|
||||||
holder = v_h.template holder<holder_type>();
|
holder = v_h.template holder<holder_type>();
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
||||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
@ -1503,7 +1496,7 @@ struct kw_only {};
|
|||||||
|
|
||||||
/// \ingroup annotations
|
/// \ingroup annotations
|
||||||
/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of
|
/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of
|
||||||
/// an unnamed '/' argument
|
/// an unnamed '/' argument (in Python 3.8)
|
||||||
struct pos_only {};
|
struct pos_only {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -9,10 +9,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pybind11/attr.h>
|
#include "../attr.h"
|
||||||
#include <pybind11/options.h>
|
#include "../options.h"
|
||||||
|
|
||||||
#include "exception_translation.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
@ -207,40 +205,39 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
|||||||
|
|
||||||
/// Cleanup the type-info for a pybind11-registered type.
|
/// Cleanup the type-info for a pybind11-registered type.
|
||||||
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
|
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
|
||||||
with_internals([obj](internals &internals) {
|
auto *type = (PyTypeObject *) obj;
|
||||||
auto *type = (PyTypeObject *) obj;
|
auto &internals = get_internals();
|
||||||
|
|
||||||
// A pybind11-registered type will:
|
// A pybind11-registered type will:
|
||||||
// 1) be found in internals.registered_types_py
|
// 1) be found in internals.registered_types_py
|
||||||
// 2) have exactly one associated `detail::type_info`
|
// 2) have exactly one associated `detail::type_info`
|
||||||
auto found_type = internals.registered_types_py.find(type);
|
auto found_type = internals.registered_types_py.find(type);
|
||||||
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
|
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
|
||||||
&& found_type->second[0]->type == type) {
|
&& found_type->second[0]->type == type) {
|
||||||
|
|
||||||
auto *tinfo = found_type->second[0];
|
auto *tinfo = found_type->second[0];
|
||||||
auto tindex = std::type_index(*tinfo->cpptype);
|
auto tindex = std::type_index(*tinfo->cpptype);
|
||||||
internals.direct_conversions.erase(tindex);
|
internals.direct_conversions.erase(tindex);
|
||||||
|
|
||||||
if (tinfo->module_local) {
|
if (tinfo->module_local) {
|
||||||
get_local_internals().registered_types_cpp.erase(tindex);
|
get_local_internals().registered_types_cpp.erase(tindex);
|
||||||
} else {
|
} else {
|
||||||
internals.registered_types_cpp.erase(tindex);
|
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);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete tinfo;
|
|
||||||
}
|
}
|
||||||
});
|
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);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete tinfo;
|
||||||
|
}
|
||||||
|
|
||||||
PyType_Type.tp_dealloc(obj);
|
PyType_Type.tp_dealloc(obj);
|
||||||
}
|
}
|
||||||
@ -313,20 +310,19 @@ inline void traverse_offset_bases(void *valueptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool register_instance_impl(void *ptr, instance *self) {
|
inline bool register_instance_impl(void *ptr, instance *self) {
|
||||||
with_instance_map(ptr, [&](instance_map &instances) { instances.emplace(ptr, self); });
|
get_internals().registered_instances.emplace(ptr, self);
|
||||||
return true; // unused, but gives the same signature as the deregister func
|
return true; // unused, but gives the same signature as the deregister func
|
||||||
}
|
}
|
||||||
inline bool deregister_instance_impl(void *ptr, instance *self) {
|
inline bool deregister_instance_impl(void *ptr, instance *self) {
|
||||||
return with_instance_map(ptr, [&](instance_map &instances) {
|
auto ®istered_instances = get_internals().registered_instances;
|
||||||
auto range = instances.equal_range(ptr);
|
auto range = registered_instances.equal_range(ptr);
|
||||||
for (auto it = range.first; it != range.second; ++it) {
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
if (self == it->second) {
|
if (self == it->second) {
|
||||||
instances.erase(it);
|
registered_instances.erase(it);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
});
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
|
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
|
||||||
@ -381,32 +377,27 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void add_patient(PyObject *nurse, PyObject *patient) {
|
inline void add_patient(PyObject *nurse, PyObject *patient) {
|
||||||
|
auto &internals = get_internals();
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(nurse);
|
auto *instance = reinterpret_cast<detail::instance *>(nurse);
|
||||||
instance->has_patients = true;
|
instance->has_patients = true;
|
||||||
Py_INCREF(patient);
|
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) {
|
inline void clear_patients(PyObject *self) {
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
auto *instance = reinterpret_cast<detail::instance *>(self);
|
||||||
std::vector<PyObject *> patients;
|
auto &internals = get_internals();
|
||||||
|
auto pos = internals.patients.find(self);
|
||||||
|
|
||||||
with_internals([&](internals &internals) {
|
if (pos == internals.patients.end()) {
|
||||||
auto pos = internals.patients.find(self);
|
pybind11_fail("FATAL: Internal consistency check failed: Invalid clear_patients() call.");
|
||||||
|
}
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 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);
|
||||||
instance->has_patients = false;
|
instance->has_patients = false;
|
||||||
for (PyObject *&patient : patients) {
|
for (PyObject *&patient : patients) {
|
||||||
Py_CLEAR(patient);
|
Py_CLEAR(patient);
|
||||||
@ -468,9 +459,19 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
|||||||
|
|
||||||
type->tp_free(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)
|
// This was not needed before Python 3.8 (Python issue 35810)
|
||||||
// https://github.com/pybind/pybind11/issues/1946
|
// https://github.com/pybind/pybind11/issues/1946
|
||||||
Py_DECREF(type);
|
Py_DECREF(type);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string error_string();
|
std::string error_string();
|
||||||
@ -559,9 +560,17 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
|||||||
type->tp_traverse = pybind11_traverse;
|
type->tp_traverse = pybind11_traverse;
|
||||||
type->tp_clear = pybind11_clear;
|
type->tp_clear = pybind11_clear;
|
||||||
|
|
||||||
static PyGetSetDef getset[]
|
static PyGetSetDef getset[] = {{
|
||||||
= {{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, nullptr, nullptr},
|
#if PY_VERSION_HEX < 0x03070000
|
||||||
{nullptr, nullptr, nullptr, nullptr, nullptr}};
|
const_cast<char *>("__dict__"),
|
||||||
|
#else
|
||||||
|
"__dict__",
|
||||||
|
#endif
|
||||||
|
PyObject_GenericGetDict,
|
||||||
|
PyObject_GenericSetDict,
|
||||||
|
nullptr,
|
||||||
|
nullptr},
|
||||||
|
{nullptr, nullptr, nullptr, nullptr, nullptr}};
|
||||||
type->tp_getset = getset;
|
type->tp_getset = getset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,18 +592,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
std::memset(view, 0, sizeof(Py_buffer));
|
std::memset(view, 0, sizeof(Py_buffer));
|
||||||
buffer_info *info = nullptr;
|
buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
|
||||||
try {
|
|
||||||
info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
|
|
||||||
} catch (...) {
|
|
||||||
try_translate_exceptions();
|
|
||||||
raise_from(PyExc_BufferError, "Error getting buffer");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (info == nullptr) {
|
|
||||||
pybind11_fail("FATAL UNEXPECTED SITUATION: tinfo->get_buffer() returned nullptr.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
||||||
delete info;
|
delete info;
|
||||||
// view->obj = nullptr; // Was just memset to 0, so not necessary
|
// view->obj = nullptr; // Was just memset to 0, so not necessary
|
||||||
@ -664,13 +662,10 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
|||||||
|
|
||||||
char *tp_doc = nullptr;
|
char *tp_doc = nullptr;
|
||||||
if (rec.doc && options::show_user_defined_docstrings()) {
|
if (rec.doc && options::show_user_defined_docstrings()) {
|
||||||
/* Allocate memory for docstring (Python will free this later on) */
|
/* Allocate memory for docstring (using PyObject_MALLOC, since
|
||||||
|
Python will free this later on) */
|
||||||
size_t size = std::strlen(rec.doc) + 1;
|
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);
|
tp_doc = (char *) PyObject_MALLOC(size);
|
||||||
#endif
|
|
||||||
std::memcpy((void *) tp_doc, rec.doc, size);
|
std::memcpy((void *) tp_doc, rec.doc, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PYBIND11_VERSION_MAJOR 2
|
#define PYBIND11_VERSION_MAJOR 2
|
||||||
#define PYBIND11_VERSION_MINOR 14
|
#define PYBIND11_VERSION_MINOR 13
|
||||||
#define PYBIND11_VERSION_PATCH 0.dev1
|
#define PYBIND11_VERSION_PATCH 0.dev1
|
||||||
|
|
||||||
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
|
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
|
||||||
// Additional convention: 0xD = dev
|
// Additional convention: 0xD = dev
|
||||||
#define PYBIND11_VERSION_HEX 0x020E00D1
|
#define PYBIND11_VERSION_HEX 0x020D00D1
|
||||||
|
|
||||||
// Define some generic pybind11 helper macros for warning management.
|
// Define some generic pybind11 helper macros for warning management.
|
||||||
//
|
//
|
||||||
@ -272,8 +272,9 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#if PY_VERSION_HEX < 0x03080000
|
// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000
|
||||||
# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7."
|
#if PY_VERSION_HEX < 0x03060000
|
||||||
|
# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5."
|
||||||
#endif
|
#endif
|
||||||
#include <frameobject.h>
|
#include <frameobject.h>
|
||||||
#include <pythread.h>
|
#include <pythread.h>
|
||||||
@ -462,26 +463,8 @@ PYBIND11_WARNING_POP
|
|||||||
return "Hello, World!";
|
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 */
|
\endrst */
|
||||||
PYBIND11_WARNING_PUSH
|
#define PYBIND11_MODULE(name, variable) \
|
||||||
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
|
|
||||||
#define PYBIND11_MODULE(name, variable, ...) \
|
|
||||||
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
|
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
|
||||||
PYBIND11_MAYBE_UNUSED; \
|
PYBIND11_MAYBE_UNUSED; \
|
||||||
PYBIND11_MAYBE_UNUSED \
|
PYBIND11_MAYBE_UNUSED \
|
||||||
@ -490,10 +473,7 @@ PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
|
|||||||
PYBIND11_CHECK_PYTHON_VERSION \
|
PYBIND11_CHECK_PYTHON_VERSION \
|
||||||
PYBIND11_ENSURE_INTERNALS_READY \
|
PYBIND11_ENSURE_INTERNALS_READY \
|
||||||
auto m = ::pybind11::module_::create_extension_module( \
|
auto m = ::pybind11::module_::create_extension_module( \
|
||||||
PYBIND11_TOSTRING(name), \
|
PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
||||||
nullptr, \
|
|
||||||
&PYBIND11_CONCAT(pybind11_module_def_, name), \
|
|
||||||
##__VA_ARGS__); \
|
|
||||||
try { \
|
try { \
|
||||||
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||||
return m.ptr(); \
|
return m.ptr(); \
|
||||||
@ -501,7 +481,6 @@ PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
|
|||||||
PYBIND11_CATCH_INIT_EXCEPTIONS \
|
PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
} \
|
} \
|
||||||
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
|
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
|
||||||
PYBIND11_WARNING_POP
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
@ -557,7 +536,7 @@ enum class return_value_policy : uint8_t {
|
|||||||
object without taking ownership similar to the above
|
object without taking ownership similar to the above
|
||||||
return_value_policy::reference policy. In contrast to that policy, the
|
return_value_policy::reference policy. In contrast to that policy, the
|
||||||
function or property's implicit this argument (called the parent) is
|
function or property's implicit this argument (called the parent) is
|
||||||
considered to be the owner of the return value (the child).
|
considered to be the the owner of the return value (the child).
|
||||||
pybind11 then couples the lifetime of the parent to the child via a
|
pybind11 then couples the lifetime of the parent to the child via a
|
||||||
reference relationship that ensures that the parent cannot be garbage
|
reference relationship that ensures that the parent cannot be garbage
|
||||||
collected while Python is still using the child. More advanced
|
collected while Python is still using the child. More advanced
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
// Copyright (c) 2024 The pybind Community.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <pybind11/pytypes.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "internals.h"
|
|
||||||
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
// Forward declaration needed here: Refactoring opportunity.
|
|
||||||
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);
|
|
||||||
|
|
||||||
inline bool type_is_managed_by_our_internals(PyTypeObject *type_obj) {
|
|
||||||
#if defined(PYPY_VERSION)
|
|
||||||
auto &internals = get_internals();
|
|
||||||
return bool(internals.registered_types_py.find(type_obj)
|
|
||||||
!= internals.registered_types_py.end());
|
|
||||||
#else
|
|
||||||
return bool(type_obj->tp_new == pybind11_object_new);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) {
|
|
||||||
PyObject *descr = _PyType_Lookup(type_obj, attr_name);
|
|
||||||
return bool((descr != nullptr) && PyInstanceMethod_Check(descr));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object try_get_cpp_conduit_method(PyObject *obj) {
|
|
||||||
if (PyType_Check(obj)) {
|
|
||||||
return object();
|
|
||||||
}
|
|
||||||
PyTypeObject *type_obj = Py_TYPE(obj);
|
|
||||||
str attr_name("_pybind11_conduit_v1_");
|
|
||||||
bool assumed_to_be_callable = false;
|
|
||||||
if (type_is_managed_by_our_internals(type_obj)) {
|
|
||||||
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) {
|
|
||||||
return object();
|
|
||||||
}
|
|
||||||
assumed_to_be_callable = true;
|
|
||||||
}
|
|
||||||
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr());
|
|
||||||
if (method == nullptr) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return object();
|
|
||||||
}
|
|
||||||
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) {
|
|
||||||
Py_DECREF(method);
|
|
||||||
return object();
|
|
||||||
}
|
|
||||||
return reinterpret_steal<object>(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src,
|
|
||||||
const std::type_info *cpp_type_info) {
|
|
||||||
object method = try_get_cpp_conduit_method(src.ptr());
|
|
||||||
if (method) {
|
|
||||||
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
|
|
||||||
typeid(std::type_info).name());
|
|
||||||
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID),
|
|
||||||
cpp_type_info_capsule,
|
|
||||||
bytes("raw_pointer_ephemeral"));
|
|
||||||
if (isinstance<capsule>(cpp_conduit)) {
|
|
||||||
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PYBIND11_HAS_CPP_CONDUIT 1
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/detail/exception_translation.h: means to translate C++ exceptions to Python exceptions
|
|
||||||
|
|
||||||
Copyright (c) 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 "internals.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
// Apply all the extensions translators from a list
|
|
||||||
// Return true if one of the translators completed without raising an exception
|
|
||||||
// itself. Return of false indicates that if there are other translators
|
|
||||||
// available, they should be tried.
|
|
||||||
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
|
|
||||||
auto last_exception = std::current_exception();
|
|
||||||
|
|
||||||
for (auto &translator : translators) {
|
|
||||||
try {
|
|
||||||
translator(last_exception);
|
|
||||||
return true;
|
|
||||||
} catch (...) {
|
|
||||||
last_exception = std::current_exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void try_translate_exceptions() {
|
|
||||||
/* When an exception is caught, give each registered exception
|
|
||||||
translator a chance to translate it to a Python exception. First
|
|
||||||
all module-local translators will be tried in reverse order of
|
|
||||||
registration. If none of the module-locale translators handle
|
|
||||||
the exception (or there are no module-locale translators) then
|
|
||||||
the global translators will be tried, also in reverse order of
|
|
||||||
registration.
|
|
||||||
|
|
||||||
A translator may choose to do one of the following:
|
|
||||||
|
|
||||||
- catch the exception and call py::set_error()
|
|
||||||
to set a standard (or custom) Python exception, or
|
|
||||||
- do nothing and let the exception fall through to the next translator, or
|
|
||||||
- delegate translation to the next translator by throwing a new type of exception.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool handled = with_exception_translators(
|
|
||||||
[&](std::forward_list<ExceptionTranslator> &exception_translators,
|
|
||||||
std::forward_list<ExceptionTranslator> &local_exception_translators) {
|
|
||||||
if (detail::apply_exception_translators(local_exception_translators)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (detail::apply_exception_translators(exception_translators)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!handled) {
|
|
||||||
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -128,13 +128,11 @@ 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
|
// the holder and destruction happens when we leave the C++ scope, and the holder
|
||||||
// class gets to handle the destruction however it likes.
|
// class gets to handle the destruction however it likes.
|
||||||
v_h.value_ptr() = ptr;
|
v_h.value_ptr() = ptr;
|
||||||
v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
|
v_h.set_instance_registered(true); // 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
|
||||||
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
|
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.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
||||||
v_h.set_instance_registered(false);
|
v_h.set_instance_registered(false);
|
||||||
// DANGER ZONE END.
|
|
||||||
|
|
||||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,15 +11,13 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
# include <pybind11/gil.h>
|
# include "../gil.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <pybind11/pytypes.h>
|
#include "../pytypes.h"
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
|
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
|
||||||
///
|
///
|
||||||
@ -39,11 +37,7 @@
|
|||||||
# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
|
# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
|
||||||
// Version bump for Python 3.12+, before first 3.12 beta release.
|
// Version bump for Python 3.12+, before first 3.12 beta release.
|
||||||
// Version bump for MSVC piggy-backed on PR #4779. See comments there.
|
// Version bump for MSVC piggy-backed on PR #4779. See comments there.
|
||||||
# ifdef Py_GIL_DISABLED
|
# define PYBIND11_INTERNALS_VERSION 5
|
||||||
# define PYBIND11_INTERNALS_VERSION 6
|
|
||||||
# else
|
|
||||||
# define PYBIND11_INTERNALS_VERSION 5
|
|
||||||
# endif
|
|
||||||
# else
|
# else
|
||||||
# define PYBIND11_INTERNALS_VERSION 4
|
# define PYBIND11_INTERNALS_VERSION 4
|
||||||
# endif
|
# endif
|
||||||
@ -68,41 +62,65 @@ 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
|
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
||||||
// Thread Specific Storage (TSS) API.
|
// Thread Specific Storage (TSS) API.
|
||||||
|
#if PY_VERSION_HEX >= 0x03070000
|
||||||
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
|
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
|
||||||
// `Py_LIMITED_API` anyway.
|
// `Py_LIMITED_API` anyway.
|
||||||
#if PYBIND11_INTERNALS_VERSION > 4
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
# define PYBIND11_TLS_KEY_REF Py_tss_t &
|
# define PYBIND11_TLS_KEY_REF Py_tss_t &
|
||||||
# if defined(__clang__)
|
# if defined(__clang__)
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) \
|
# define PYBIND11_TLS_KEY_INIT(var) \
|
||||||
_Pragma("clang diagnostic push") /**/ \
|
_Pragma("clang diagnostic push") /**/ \
|
||||||
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
||||||
Py_tss_t var \
|
Py_tss_t var \
|
||||||
= Py_tss_NEEDS_INIT; \
|
= Py_tss_NEEDS_INIT; \
|
||||||
_Pragma("clang diagnostic pop")
|
_Pragma("clang diagnostic pop")
|
||||||
# elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
# elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) \
|
# define PYBIND11_TLS_KEY_INIT(var) \
|
||||||
_Pragma("GCC diagnostic push") /**/ \
|
_Pragma("GCC diagnostic push") /**/ \
|
||||||
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
||||||
Py_tss_t var \
|
Py_tss_t var \
|
||||||
= Py_tss_NEEDS_INIT; \
|
= Py_tss_NEEDS_INIT; \
|
||||||
_Pragma("GCC diagnostic pop")
|
_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))
|
||||||
# else
|
# else
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
|
# 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
|
# 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
|
#else
|
||||||
# define PYBIND11_TLS_KEY_REF Py_tss_t *
|
// Usually an int but a long on Cygwin64 with Python 3.x
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
|
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) \
|
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
||||||
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
|
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
# if defined(PYPY_VERSION)
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
||||||
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
// 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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
||||||
@ -150,49 +168,15 @@ 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.
|
/// Internal data structure used to track registered instances and types.
|
||||||
/// Whenever binary incompatible changes are made to this structure,
|
/// Whenever binary incompatible changes are made to this structure,
|
||||||
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
||||||
struct internals {
|
struct internals {
|
||||||
#ifdef Py_GIL_DISABLED
|
|
||||||
pymutex mutex;
|
|
||||||
pymutex exception_translator_mutex;
|
|
||||||
#endif
|
|
||||||
// std::type_index -> pybind11's type information
|
// std::type_index -> pybind11's type information
|
||||||
type_map<type_info *> registered_types_cpp;
|
type_map<type_info *> registered_types_cpp;
|
||||||
// PyTypeObject* -> base type_info(s)
|
// PyTypeObject* -> base type_info(s)
|
||||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
|
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
|
||||||
#ifdef Py_GIL_DISABLED
|
std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
|
||||||
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>
|
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
|
||||||
inactive_override_cache;
|
inactive_override_cache;
|
||||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||||
@ -208,27 +192,28 @@ struct internals {
|
|||||||
PyTypeObject *static_property_type;
|
PyTypeObject *static_property_type;
|
||||||
PyTypeObject *default_metaclass;
|
PyTypeObject *default_metaclass;
|
||||||
PyObject *instance_base;
|
PyObject *instance_base;
|
||||||
|
#if defined(WITH_THREAD)
|
||||||
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
|
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
|
||||||
PYBIND11_TLS_KEY_INIT(tstate)
|
PYBIND11_TLS_KEY_INIT(tstate)
|
||||||
#if PYBIND11_INTERNALS_VERSION > 4
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
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:
|
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
|
||||||
PyInterpreterState *istate = nullptr;
|
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
|
// 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
|
// We want unique addresses since we use pointer equality to compare function records
|
||||||
std::string function_record_capsule_name = internals_function_record_capsule_name;
|
std::string function_record_capsule_name = internals_function_record_capsule_name;
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
internals() = default;
|
internals() = default;
|
||||||
internals(const internals &other) = delete;
|
internals(const internals &other) = delete;
|
||||||
internals &operator=(const internals &other) = delete;
|
internals &operator=(const internals &other) = delete;
|
||||||
~internals() {
|
~internals() {
|
||||||
#if PYBIND11_INTERNALS_VERSION > 4
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
PYBIND11_TLS_FREE(loader_life_support_tls_key);
|
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().
|
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
|
||||||
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
|
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
|
||||||
@ -239,6 +224,7 @@ struct internals {
|
|||||||
// that the `tstate` be allocated with the CPython allocator.
|
// that the `tstate` be allocated with the CPython allocator.
|
||||||
PYBIND11_TLS_FREE(tstate);
|
PYBIND11_TLS_FREE(tstate);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Additional type information which does not fit into the PyTypeObject.
|
/// Additional type information which does not fit into the PyTypeObject.
|
||||||
@ -323,20 +309,22 @@ struct type_info {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PYBIND11_INTERNALS_KIND
|
#ifndef PYBIND11_INTERNALS_KIND
|
||||||
# define PYBIND11_INTERNALS_KIND ""
|
# if defined(WITH_THREAD)
|
||||||
|
# define PYBIND11_INTERNALS_KIND ""
|
||||||
|
# else
|
||||||
|
# define PYBIND11_INTERNALS_KIND "_without_thread"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PYBIND11_PLATFORM_ABI_ID \
|
|
||||||
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
|
||||||
PYBIND11_BUILD_TYPE
|
|
||||||
|
|
||||||
#define PYBIND11_INTERNALS_ID \
|
#define PYBIND11_INTERNALS_ID \
|
||||||
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||||
PYBIND11_PLATFORM_ABI_ID "__"
|
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
|
||||||
|
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
||||||
|
|
||||||
#define PYBIND11_MODULE_LOCAL_ID \
|
#define PYBIND11_MODULE_LOCAL_ID \
|
||||||
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||||
PYBIND11_PLATFORM_ABI_ID "__"
|
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
|
/// Each module locally stores a pointer to the `internals` data. The data
|
||||||
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
||||||
@ -454,7 +442,7 @@ inline void translate_local_exception(std::exception_ptr p) {
|
|||||||
|
|
||||||
inline object get_python_state_dict() {
|
inline object get_python_state_dict() {
|
||||||
object state_dict;
|
object state_dict;
|
||||||
#if PYBIND11_INTERNALS_VERSION <= 4 || defined(PYPY_VERSION)
|
#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
|
||||||
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
|
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
|
||||||
#else
|
#else
|
||||||
# if PY_VERSION_HEX < 0x03090000
|
# if PY_VERSION_HEX < 0x03090000
|
||||||
@ -474,8 +462,7 @@ inline object get_python_state_dict() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline object get_internals_obj_from_state_dict(handle state_dict) {
|
inline object get_internals_obj_from_state_dict(handle state_dict) {
|
||||||
return reinterpret_steal<object>(
|
return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));
|
||||||
dict_getitemstringref(state_dict.ptr(), PYBIND11_INTERNALS_ID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline internals **get_internals_pp_from_capsule(handle obj) {
|
inline internals **get_internals_pp_from_capsule(handle obj) {
|
||||||
@ -487,20 +474,6 @@ inline internals **get_internals_pp_from_capsule(handle obj) {
|
|||||||
return static_cast<internals **>(raw_ptr);
|
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
|
/// Return a reference to the current `internals` data
|
||||||
PYBIND11_NOINLINE internals &get_internals() {
|
PYBIND11_NOINLINE internals &get_internals() {
|
||||||
auto **&internals_pp = get_internals_pp();
|
auto **&internals_pp = get_internals_pp();
|
||||||
@ -508,9 +481,10 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
return **internals_pp;
|
return **internals_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(WITH_THREAD)
|
||||||
|
# if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
gil_scoped_acquire gil;
|
gil_scoped_acquire gil;
|
||||||
#else
|
# else
|
||||||
// Ensure that the GIL is held since we will need to make Python calls.
|
// 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.
|
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
|
||||||
struct gil_scoped_acquire_local {
|
struct gil_scoped_acquire_local {
|
||||||
@ -520,6 +494,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
||||||
const PyGILState_STATE state;
|
const PyGILState_STATE state;
|
||||||
} gil;
|
} gil;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
error_scope err_scope;
|
error_scope err_scope;
|
||||||
|
|
||||||
@ -544,6 +519,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
}
|
}
|
||||||
auto *&internals_ptr = *internals_pp;
|
auto *&internals_ptr = *internals_pp;
|
||||||
internals_ptr = new internals();
|
internals_ptr = new internals();
|
||||||
|
#if defined(WITH_THREAD)
|
||||||
|
|
||||||
PyThreadState *tstate = PyThreadState_Get();
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
||||||
@ -552,29 +528,20 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
}
|
}
|
||||||
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
|
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
|
||||||
|
|
||||||
#if PYBIND11_INTERNALS_VERSION > 4
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
||||||
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
|
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
|
||||||
pybind11_fail("get_internals: could not successfully initialize the "
|
pybind11_fail("get_internals: could not successfully initialize the "
|
||||||
"loader_life_support TSS key!");
|
"loader_life_support TSS key!");
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
internals_ptr->istate = tstate->interp;
|
internals_ptr->istate = tstate->interp;
|
||||||
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
|
#endif
|
||||||
|
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
|
||||||
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
||||||
internals_ptr->static_property_type = make_static_property_type();
|
internals_ptr->static_property_type = make_static_property_type();
|
||||||
internals_ptr->default_metaclass = make_default_metaclass();
|
internals_ptr->default_metaclass = make_default_metaclass();
|
||||||
internals_ptr->instance_base = make_object_base_type(internals_ptr->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;
|
return **internals_pp;
|
||||||
}
|
}
|
||||||
@ -588,7 +555,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
struct local_internals {
|
struct local_internals {
|
||||||
type_map<type_info *> registered_types_cpp;
|
type_map<type_info *> registered_types_cpp;
|
||||||
std::forward_list<ExceptionTranslator> registered_exception_translators;
|
std::forward_list<ExceptionTranslator> registered_exception_translators;
|
||||||
#if PYBIND11_INTERNALS_VERSION == 4
|
#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
||||||
|
|
||||||
// For ABI compatibility, we can't store the loader_life_support TLS key in
|
// 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
|
// the `internals` struct directly. Instead, we store it in `shared_data` and
|
||||||
@ -621,7 +588,7 @@ struct local_internals {
|
|||||||
loader_life_support_tls_key
|
loader_life_support_tls_key
|
||||||
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
|
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
|
||||||
}
|
}
|
||||||
#endif // PYBIND11_INTERNALS_VERSION == 4
|
#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Works like `get_internals`, but for things which are locally registered.
|
/// Works like `get_internals`, but for things which are locally registered.
|
||||||
@ -635,93 +602,13 @@ inline local_internals &get_local_internals() {
|
|||||||
return *locals;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
inline auto with_exception_translators(const F &cb)
|
|
||||||
-> decltype(cb(get_internals().registered_exception_translators,
|
|
||||||
get_local_internals().registered_exception_translators)) {
|
|
||||||
auto &internals = get_internals();
|
|
||||||
#ifdef Py_GIL_DISABLED
|
|
||||||
std::unique_lock<pymutex> lock((internals).exception_translator_mutex);
|
|
||||||
#endif
|
|
||||||
auto &local_internals = get_local_internals();
|
|
||||||
return cb(internals.registered_exception_translators,
|
|
||||||
local_internals.registered_exception_translators);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
/// 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
|
/// `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
|
/// 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).
|
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
const char *c_str(Args &&...args) {
|
const char *c_str(Args &&...args) {
|
||||||
// GCC 4.8 doesn't like parameter unpack within lambda capture, so use
|
auto &strings = get_internals().static_strings;
|
||||||
// PYBIND11_LOCK_INTERNALS.
|
|
||||||
auto &internals = get_internals();
|
|
||||||
PYBIND11_LOCK_INTERNALS(internals);
|
|
||||||
auto &strings = internals.static_strings;
|
|
||||||
strings.emplace_front(std::forward<Args>(args)...);
|
strings.emplace_front(std::forward<Args>(args)...);
|
||||||
return strings.front().c_str();
|
return strings.front().c_str();
|
||||||
}
|
}
|
||||||
@ -751,18 +638,15 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
||||||
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
||||||
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
||||||
return detail::with_internals([&](detail::internals &internals) {
|
auto &internals = detail::get_internals();
|
||||||
auto it = internals.shared_data.find(name);
|
auto it = internals.shared_data.find(name);
|
||||||
return it != internals.shared_data.end() ? it->second : nullptr;
|
return it != internals.shared_data.end() ? it->second : nullptr;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
/// 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) {
|
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
||||||
return detail::with_internals([&](detail::internals &internals) {
|
detail::get_internals().shared_data[name] = data;
|
||||||
internals.shared_data[name] = data;
|
return data;
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
||||||
@ -770,15 +654,14 @@ 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.
|
/// added to the shared data under the given name and a reference to it is returned.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T &get_or_create_shared_data(const std::string &name) {
|
T &get_or_create_shared_data(const std::string &name) {
|
||||||
return *detail::with_internals([&](detail::internals &internals) {
|
auto &internals = detail::get_internals();
|
||||||
auto it = internals.shared_data.find(name);
|
auto it = internals.shared_data.find(name);
|
||||||
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
|
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
ptr = new T();
|
ptr = new T();
|
||||||
internals.shared_data[name] = ptr;
|
internals.shared_data[name] = ptr;
|
||||||
}
|
}
|
||||||
return ptr;
|
return *ptr;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -9,20 +9,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pybind11/pytypes.h>
|
#include "../pytypes.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "cpp_conduit.h"
|
|
||||||
#include "descr.h"
|
#include "descr.h"
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
#include "typeid.h"
|
#include "typeid.h"
|
||||||
#include "value_and_holder.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
@ -41,13 +36,14 @@ private:
|
|||||||
loader_life_support *parent = nullptr;
|
loader_life_support *parent = nullptr;
|
||||||
std::unordered_set<PyObject *> keep_alive;
|
std::unordered_set<PyObject *> keep_alive;
|
||||||
|
|
||||||
|
#if defined(WITH_THREAD)
|
||||||
// Store stack pointer in thread-local storage.
|
// Store stack pointer in thread-local storage.
|
||||||
static PYBIND11_TLS_KEY_REF get_stack_tls_key() {
|
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;
|
return get_local_internals().loader_life_support_tls_key;
|
||||||
#else
|
# else
|
||||||
return get_internals().loader_life_support_tls_key;
|
return get_internals().loader_life_support_tls_key;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
static loader_life_support *get_stack_top() {
|
static loader_life_support *get_stack_top() {
|
||||||
return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));
|
return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));
|
||||||
@ -55,6 +51,15 @@ private:
|
|||||||
static void set_stack_top(loader_life_support *value) {
|
static void set_stack_top(loader_life_support *value) {
|
||||||
PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), 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:
|
public:
|
||||||
/// A new patient frame is created when a function is entered
|
/// A new patient frame is created when a function is entered
|
||||||
@ -212,15 +217,12 @@ 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) {
|
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
||||||
return with_internals([&](internals &internals) {
|
auto &types = get_internals().registered_types_cpp;
|
||||||
detail::type_info *type_info = nullptr;
|
auto it = types.find(tp);
|
||||||
auto &types = internals.registered_types_cpp;
|
if (it != types.end()) {
|
||||||
auto it = types.find(tp);
|
return it->second;
|
||||||
if (it != types.end()) {
|
}
|
||||||
type_info = it->second;
|
return nullptr;
|
||||||
}
|
|
||||||
return type_info;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the type info for a given C++ type; on lookup failure can either throw or return
|
/// Return the type info for a given C++ type; on lookup failure can either throw or return
|
||||||
@ -251,19 +253,78 @@ 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().
|
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
||||||
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
||||||
const detail::type_info *tinfo) {
|
const detail::type_info *tinfo) {
|
||||||
return with_instance_map(src, [&](instance_map &instances) {
|
auto it_instances = get_internals().registered_instances.equal_range(src);
|
||||||
auto it_instances = instances.equal_range(src);
|
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
||||||
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))) {
|
||||||
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
||||||
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
return handle((PyObject *) it_i->second).inc_ref();
|
||||||
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
|
// Container for accessing and iterating over an instance's values/holders
|
||||||
struct values_and_holders {
|
struct values_and_holders {
|
||||||
private:
|
private:
|
||||||
@ -432,7 +493,7 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
|
|||||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||||
PYBIND11_NOINLINE void instance::deallocate_layout() {
|
PYBIND11_NOINLINE void instance::deallocate_layout() {
|
||||||
if (!simple_layout) {
|
if (!simple_layout) {
|
||||||
PyMem_Free(reinterpret_cast<void *>(nonsimple.values_and_holders));
|
PyMem_Free(nonsimple.values_and_holders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,17 +506,16 @@ 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) {
|
PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) {
|
||||||
return with_instance_map(ptr, [&](instance_map &instances) {
|
auto &instances = get_internals().registered_instances;
|
||||||
auto range = instances.equal_range(ptr);
|
auto range = instances.equal_range(ptr);
|
||||||
for (auto it = range.first; it != range.second; ++it) {
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
for (const auto &vh : values_and_holders(it->second)) {
|
for (const auto &vh : values_and_holders(it->second)) {
|
||||||
if (vh.type == type) {
|
if (vh.type == type) {
|
||||||
return handle((PyObject *) it->second);
|
return handle((PyObject *) it->second);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handle();
|
}
|
||||||
});
|
return handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyThreadState *get_thread_state_unchecked() {
|
inline PyThreadState *get_thread_state_unchecked() {
|
||||||
@ -614,13 +674,6 @@ public:
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool try_cpp_conduit(handle src) {
|
|
||||||
value = try_raw_pointer_ephemeral_from_cpp_conduit(src, cpptype);
|
|
||||||
if (value != nullptr) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void check_holder_compat() {}
|
void check_holder_compat() {}
|
||||||
|
|
||||||
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
|
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
|
||||||
@ -752,10 +805,6 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convert && cpptype && this_.try_cpp_conduit(src)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,32 +832,6 @@ public:
|
|||||||
void *value = nullptr;
|
void *value = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline object cpp_conduit_method(handle self,
|
|
||||||
const bytes &pybind11_platform_abi_id,
|
|
||||||
const capsule &cpp_type_info_capsule,
|
|
||||||
const bytes &pointer_kind) {
|
|
||||||
#ifdef PYBIND11_HAS_STRING_VIEW
|
|
||||||
using cpp_str = std::string_view;
|
|
||||||
#else
|
|
||||||
using cpp_str = std::string;
|
|
||||||
#endif
|
|
||||||
if (cpp_str(pybind11_platform_abi_id) != PYBIND11_PLATFORM_ABI_ID) {
|
|
||||||
return none();
|
|
||||||
}
|
|
||||||
if (std::strcmp(cpp_type_info_capsule.name(), typeid(std::type_info).name()) != 0) {
|
|
||||||
return none();
|
|
||||||
}
|
|
||||||
if (cpp_str(pointer_kind) != "raw_pointer_ephemeral") {
|
|
||||||
throw std::runtime_error("Invalid pointer_kind: \"" + std::string(pointer_kind) + "\"");
|
|
||||||
}
|
|
||||||
const auto *cpp_type_info = cpp_type_info_capsule.get_pointer<const std::type_info>();
|
|
||||||
type_caster_generic caster(*cpp_type_info);
|
|
||||||
if (!caster.load(self, false)) {
|
|
||||||
return none();
|
|
||||||
}
|
|
||||||
return capsule(caster.value, cpp_type_info->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster
|
* Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster
|
||||||
* needs to provide `operator T*()` and `operator T&()` operators.
|
* needs to provide `operator T*()` and `operator T&()` operators.
|
||||||
@ -1088,11 +1111,11 @@ public:
|
|||||||
|| policy == return_value_policy::automatic_reference) {
|
|| policy == return_value_policy::automatic_reference) {
|
||||||
policy = return_value_policy::copy;
|
policy = return_value_policy::copy;
|
||||||
}
|
}
|
||||||
return cast(std::addressof(src), policy, parent);
|
return cast(&src, policy, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static handle cast(itype &&src, return_value_policy, handle parent) {
|
static handle cast(itype &&src, return_value_policy, handle parent) {
|
||||||
return cast(std::addressof(src), return_value_policy::move, parent);
|
return cast(&src, return_value_policy::move, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
// 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)
|
|
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pybind11/numpy.h>
|
#include "../numpy.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
|
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pybind11/numpy.h>
|
#include "../numpy.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||||
@ -470,6 +469,9 @@ struct type_caster<Eigen::TensorMap<Type, Options>,
|
|||||||
parent_object = reinterpret_borrow<object>(parent);
|
parent_object = reinterpret_borrow<object>(parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case return_value_policy::take_ownership:
|
||||||
|
delete src;
|
||||||
|
// fallthrough
|
||||||
default:
|
default:
|
||||||
// move, take_ownership don't make any sense for a ref/map:
|
// 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 "
|
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
|
||||||
|
@ -103,6 +103,19 @@ inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
|
|||||||
bool add_program_dir_to_path) {
|
bool add_program_dir_to_path) {
|
||||||
detail::precheck_interpreter();
|
detail::precheck_interpreter();
|
||||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
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);
|
auto argv_size = static_cast<size_t>(argc);
|
||||||
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
||||||
@ -110,7 +123,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;
|
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
|
||||||
widened_argv_entries.reserve(argv_size);
|
widened_argv_entries.reserve(argv_size);
|
||||||
for (size_t ii = 0; ii < argv_size; ++ii) {
|
for (size_t ii = 0; ii < argv_size; ++ii) {
|
||||||
widened_argv_entries.emplace_back(detail::widen_chars(argv[ii]));
|
widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));
|
||||||
if (!widened_argv_entries.back()) {
|
if (!widened_argv_entries.back()) {
|
||||||
// A null here indicates a character-encoding failure or the python
|
// A null here indicates a character-encoding failure or the python
|
||||||
// interpreter out of memory. Give up.
|
// interpreter out of memory. Give up.
|
||||||
|
@ -19,7 +19,7 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
inline void ensure_builtins_in_globals(object &global) {
|
inline void ensure_builtins_in_globals(object &global) {
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
||||||
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
||||||
// globals if not yet present. Python 3.8 made PyRun_String behave
|
// globals if not yet present. Python 3.8 made PyRun_String behave
|
||||||
// similarly. Let's also do that for older versions, for consistency. This
|
// similarly. Let's also do that for older versions, for consistency. This
|
||||||
|
@ -9,55 +9,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
|
|
||||||
|
|
||||||
// ensure GIL is held during functor destruction
|
|
||||||
struct func_handle {
|
|
||||||
function f;
|
|
||||||
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
|
||||||
// This triggers a syntax error under very special conditions (very weird indeed).
|
|
||||||
explicit
|
|
||||||
#endif
|
|
||||||
func_handle(function &&f_) noexcept
|
|
||||||
: f(std::move(f_)) {
|
|
||||||
}
|
|
||||||
func_handle(const func_handle &f_) { operator=(f_); }
|
|
||||||
func_handle &operator=(const func_handle &f_) {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
f = f_.f;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
~func_handle() {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
function kill_f(std::move(f));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// to emulate 'move initialization capture' in C++11
|
|
||||||
struct func_wrapper_base {
|
|
||||||
func_handle hfunc;
|
|
||||||
explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(hf) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Return, typename... Args>
|
|
||||||
struct func_wrapper : func_wrapper_base {
|
|
||||||
using func_wrapper_base::func_wrapper_base;
|
|
||||||
Return operator()(Args... args) const {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
// casts the returned object as a rvalue to the return type
|
|
||||||
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
|
|
||||||
|
|
||||||
template <typename Return, typename... Args>
|
template <typename Return, typename... Args>
|
||||||
struct type_caster<std::function<Return(Args...)>> {
|
struct type_caster<std::function<Return(Args...)>> {
|
||||||
@ -120,8 +77,40 @@ public:
|
|||||||
// See PR #1413 for full details
|
// See PR #1413 for full details
|
||||||
}
|
}
|
||||||
|
|
||||||
value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
|
// ensure GIL is held during functor destruction
|
||||||
type_caster_std_function_specializations::func_handle(std::move(func)));
|
struct func_handle {
|
||||||
|
function f;
|
||||||
|
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
||||||
|
// This triggers a syntax error under very special conditions (very weird indeed).
|
||||||
|
explicit
|
||||||
|
#endif
|
||||||
|
func_handle(function &&f_) noexcept
|
||||||
|
: f(std::move(f_)) {
|
||||||
|
}
|
||||||
|
func_handle(const func_handle &f_) { operator=(f_); }
|
||||||
|
func_handle &operator=(const func_handle &f_) {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
f = f_.f;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
~func_handle() {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
function kill_f(std::move(f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// to emulate 'move initialization capture' in C++11
|
||||||
|
struct func_wrapper {
|
||||||
|
func_handle hfunc;
|
||||||
|
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
||||||
|
Return operator()(Args... args) const {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
// casts the returned object as a rvalue to the return type
|
||||||
|
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
value = func_wrapper(func_handle(std::move(func)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
# include "detail/internals.h"
|
# include "detail/internals.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -26,7 +26,9 @@ PyThreadState *get_thread_state_unchecked();
|
|||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(WITH_THREAD)
|
||||||
|
|
||||||
|
# if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
|
|
||||||
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
||||||
* pattern, but there are a few important differences:
|
* pattern, but there are a few important differences:
|
||||||
@ -67,11 +69,11 @@ public:
|
|||||||
|
|
||||||
if (!tstate) {
|
if (!tstate) {
|
||||||
tstate = PyThreadState_New(internals.istate);
|
tstate = PyThreadState_New(internals.istate);
|
||||||
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
if (!tstate) {
|
if (!tstate) {
|
||||||
pybind11_fail("scoped_acquire: could not create thread state!");
|
pybind11_fail("scoped_acquire: could not create thread state!");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
tstate->gilstate_counter = 0;
|
tstate->gilstate_counter = 0;
|
||||||
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
|
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
|
||||||
} else {
|
} else {
|
||||||
@ -92,20 +94,20 @@ public:
|
|||||||
|
|
||||||
PYBIND11_NOINLINE void dec_ref() {
|
PYBIND11_NOINLINE void dec_ref() {
|
||||||
--tstate->gilstate_counter;
|
--tstate->gilstate_counter;
|
||||||
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
if (detail::get_thread_state_unchecked() != tstate) {
|
if (detail::get_thread_state_unchecked() != tstate) {
|
||||||
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
|
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
|
||||||
}
|
}
|
||||||
if (tstate->gilstate_counter < 0) {
|
if (tstate->gilstate_counter < 0) {
|
||||||
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
|
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
if (tstate->gilstate_counter == 0) {
|
if (tstate->gilstate_counter == 0) {
|
||||||
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
if (!release) {
|
if (!release) {
|
||||||
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
|
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
PyThreadState_Clear(tstate);
|
PyThreadState_Clear(tstate);
|
||||||
if (active) {
|
if (active) {
|
||||||
PyThreadState_DeleteCurrent();
|
PyThreadState_DeleteCurrent();
|
||||||
@ -147,7 +149,9 @@ public:
|
|||||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||||
tstate = PyEval_SaveThread();
|
tstate = PyEval_SaveThread();
|
||||||
if (disassoc) {
|
if (disassoc) {
|
||||||
auto key = internals.tstate; // NOLINT(readability-qualified-auto)
|
// Python >= 3.7 can remove this, it's an int before 3.7
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto)
|
||||||
|
auto key = internals.tstate;
|
||||||
PYBIND11_TLS_DELETE_VALUE(key);
|
PYBIND11_TLS_DELETE_VALUE(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +175,9 @@ public:
|
|||||||
PyEval_RestoreThread(tstate);
|
PyEval_RestoreThread(tstate);
|
||||||
}
|
}
|
||||||
if (disassoc) {
|
if (disassoc) {
|
||||||
auto key = detail::get_internals().tstate; // NOLINT(readability-qualified-auto)
|
// Python >= 3.7 can remove this, it's an int before 3.7
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto)
|
||||||
|
auto key = detail::get_internals().tstate;
|
||||||
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
|
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +188,7 @@ private:
|
|||||||
bool active = true;
|
bool active = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#else // PYBIND11_SIMPLE_GIL_MANAGEMENT
|
# else // PYBIND11_SIMPLE_GIL_MANAGEMENT
|
||||||
|
|
||||||
class gil_scoped_acquire {
|
class gil_scoped_acquire {
|
||||||
PyGILState_STATE state;
|
PyGILState_STATE state;
|
||||||
@ -210,6 +216,32 @@ public:
|
|||||||
void disarm() {}
|
void disarm() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
|
# 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
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#ifdef Py_GIL_DISABLED
|
|
||||||
# include <atomic>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
// Use the `gil_safe_call_once_and_store` class below instead of the naive
|
// Use the `gil_safe_call_once_and_store` class below instead of the naive
|
||||||
@ -86,12 +82,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
alignas(T) char storage_[sizeof(T)] = {};
|
alignas(T) char storage_[sizeof(T)] = {};
|
||||||
std::once_flag once_flag_ = {};
|
std::once_flag once_flag_ = {};
|
||||||
#ifdef Py_GIL_DISABLED
|
bool is_initialized_ = false;
|
||||||
std::atomic_bool
|
|
||||||
#else
|
|
||||||
bool
|
|
||||||
#endif
|
|
||||||
is_initialized_{false};
|
|
||||||
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
|
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
|
||||||
// but the latter does not have the triviality properties of former,
|
// but the latter does not have the triviality properties of former,
|
||||||
// therefore `std::optional` is not a viable alternative here.
|
// therefore `std::optional` is not a viable alternative here.
|
||||||
|
@ -901,11 +901,7 @@ public:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
||||||
: array(pybind11::dtype::of<T>(),
|
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
|
||||||
std::move(shape),
|
|
||||||
std::move(strides),
|
|
||||||
reinterpret_cast<const void *>(ptr),
|
|
||||||
base) {}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
||||||
@ -1557,9 +1553,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor>
|
|||||||
|
|
||||||
auto tindex = std::type_index(tinfo);
|
auto tindex = std::type_index(tinfo);
|
||||||
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)};
|
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)};
|
||||||
with_internals([tindex, &direct_converter](internals &internals) {
|
get_internals().direct_conversions[tindex].push_back(direct_converter);
|
||||||
internals.direct_conversions[tindex].push_back(direct_converter);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename SFINAE>
|
template <typename T, typename SFINAE>
|
||||||
@ -1990,7 +1984,7 @@ private:
|
|||||||
// Pointers to values the function was called with; the vectorized ones set here will start
|
// 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
|
// 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.
|
// call the wrapped function. Non-vectorized pointers are left as-is.
|
||||||
std::array<void *, N> params{{reinterpret_cast<void *>(&args)...}};
|
std::array<void *, N> params{{&args...}};
|
||||||
|
|
||||||
// The array of `buffer_info`s of vectorized arguments:
|
// The array of `buffer_info`s of vectorized arguments:
|
||||||
std::array<buffer_info, NVectorized> buffers{
|
std::array<buffer_info, NVectorized> buffers{
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "detail/class.h"
|
#include "detail/class.h"
|
||||||
#include "detail/exception_translation.h"
|
|
||||||
#include "detail/init.h"
|
#include "detail/init.h"
|
||||||
#include "attr.h"
|
#include "attr.h"
|
||||||
#include "gil.h"
|
#include "gil.h"
|
||||||
@ -95,6 +95,24 @@ inline std::string replace_newlines_and_squash(const char *text) {
|
|||||||
return result.substr(str_begin, str_range);
|
return result.substr(str_begin, str_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply all the extensions translators from a list
|
||||||
|
// Return true if one of the translators completed without raising an exception
|
||||||
|
// itself. Return of false indicates that if there are other translators
|
||||||
|
// available, they should be tried.
|
||||||
|
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
|
||||||
|
auto last_exception = std::current_exception();
|
||||||
|
|
||||||
|
for (auto &translator : translators) {
|
||||||
|
try {
|
||||||
|
translator(last_exception);
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
last_exception = std::current_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# define PYBIND11_COMPAT_STRDUP _strdup
|
# define PYBIND11_COMPAT_STRDUP _strdup
|
||||||
#else
|
#else
|
||||||
@ -592,8 +610,7 @@ protected:
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
/* Create a nice pydoc rec including all signatures and
|
/* Create a nice pydoc rec including all signatures and
|
||||||
docstrings of the functions in the overload chain */
|
docstrings of the functions in the overload chain */
|
||||||
if (chain && options::show_function_signatures()
|
if (chain && options::show_function_signatures()) {
|
||||||
&& std::strcmp(rec->name, "_pybind11_conduit_v1_") != 0) {
|
|
||||||
// First a generic signature
|
// First a generic signature
|
||||||
signatures += rec->name;
|
signatures += rec->name;
|
||||||
signatures += "(*args, **kwargs)\n";
|
signatures += "(*args, **kwargs)\n";
|
||||||
@ -602,8 +619,7 @@ protected:
|
|||||||
// Then specific overload signatures
|
// Then specific overload signatures
|
||||||
bool first_user_def = true;
|
bool first_user_def = true;
|
||||||
for (auto *it = chain_start; it != nullptr; it = it->next) {
|
for (auto *it = chain_start; it != nullptr; it = it->next) {
|
||||||
if (options::show_function_signatures()
|
if (options::show_function_signatures()) {
|
||||||
&& std::strcmp(rec->name, "_pybind11_conduit_v1_") != 0) {
|
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
signatures += '\n';
|
signatures += '\n';
|
||||||
}
|
}
|
||||||
@ -1022,7 +1038,33 @@ protected:
|
|||||||
throw;
|
throw;
|
||||||
#endif
|
#endif
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
try_translate_exceptions();
|
/* When an exception is caught, give each registered exception
|
||||||
|
translator a chance to translate it to a Python exception. First
|
||||||
|
all module-local translators will be tried in reverse order of
|
||||||
|
registration. If none of the module-locale translators handle
|
||||||
|
the exception (or there are no module-locale translators) then
|
||||||
|
the global translators will be tried, also in reverse order of
|
||||||
|
registration.
|
||||||
|
|
||||||
|
A translator may choose to do one of the following:
|
||||||
|
|
||||||
|
- catch the exception and call py::set_error()
|
||||||
|
to set a standard (or custom) Python exception, or
|
||||||
|
- do nothing and let the exception fall through to the next translator, or
|
||||||
|
- 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)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,16 +1199,6 @@ struct handle_type_name<cpp_function> {
|
|||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
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
|
/// Wrapper for Python extension modules
|
||||||
class module_ : public object {
|
class module_ : public object {
|
||||||
public:
|
public:
|
||||||
@ -1267,11 +1299,7 @@ public:
|
|||||||
|
|
||||||
``def`` should point to a statically allocated module_def.
|
``def`` should point to a statically allocated module_def.
|
||||||
\endrst */
|
\endrst */
|
||||||
static module_ create_extension_module(const char *name,
|
static module_ create_extension_module(const char *name, const char *doc, module_def *def) {
|
||||||
const char *doc,
|
|
||||||
module_def *def,
|
|
||||||
mod_gil_not_used gil_not_used
|
|
||||||
= mod_gil_not_used(false)) {
|
|
||||||
// module_def is PyModuleDef
|
// module_def is PyModuleDef
|
||||||
// Placement new (not an allocation).
|
// Placement new (not an allocation).
|
||||||
def = new (def)
|
def = new (def)
|
||||||
@ -1291,11 +1319,6 @@ public:
|
|||||||
}
|
}
|
||||||
pybind11_fail("Internal error in module_::create_extension_module()");
|
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
|
// TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when
|
||||||
// returned from PyInit_...
|
// returned from PyInit_...
|
||||||
// For Python 2, reinterpret_borrow was correct.
|
// For Python 2, reinterpret_borrow was correct.
|
||||||
@ -1374,26 +1397,15 @@ protected:
|
|||||||
tinfo->default_holder = rec.default_holder;
|
tinfo->default_holder = rec.default_holder;
|
||||||
tinfo->module_local = rec.module_local;
|
tinfo->module_local = rec.module_local;
|
||||||
|
|
||||||
with_internals([&](internals &internals) {
|
auto &internals = get_internals();
|
||||||
auto tindex = std::type_index(*rec.type);
|
auto tindex = std::type_index(*rec.type);
|
||||||
tinfo->direct_conversions = &internals.direct_conversions[tindex];
|
tinfo->direct_conversions = &internals.direct_conversions[tindex];
|
||||||
if (rec.module_local) {
|
if (rec.module_local) {
|
||||||
get_local_internals().registered_types_cpp[tindex] = tinfo;
|
get_local_internals().registered_types_cpp[tindex] = tinfo;
|
||||||
} else {
|
} else {
|
||||||
internals.registered_types_cpp[tindex] = tinfo;
|
internals.registered_types_cpp[tindex] = tinfo;
|
||||||
}
|
}
|
||||||
|
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
|
||||||
PYBIND11_WARNING_PUSH
|
|
||||||
#if defined(__GNUC__) && __GNUC__ == 12
|
|
||||||
// When using GCC 12 these warnings are disabled as they trigger
|
|
||||||
// false positive warnings. Discussed here:
|
|
||||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115824.
|
|
||||||
PYBIND11_WARNING_DISABLE_GCC("-Warray-bounds")
|
|
||||||
PYBIND11_WARNING_DISABLE_GCC("-Wstringop-overread")
|
|
||||||
#endif
|
|
||||||
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
|
|
||||||
PYBIND11_WARNING_POP
|
|
||||||
});
|
|
||||||
|
|
||||||
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
|
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
|
||||||
mark_parents_nonsimple(tinfo->type);
|
mark_parents_nonsimple(tinfo->type);
|
||||||
@ -1606,14 +1618,11 @@ public:
|
|||||||
generic_type::initialize(record);
|
generic_type::initialize(record);
|
||||||
|
|
||||||
if (has_alias) {
|
if (has_alias) {
|
||||||
with_internals([&](internals &internals) {
|
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
|
||||||
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
|
: get_internals().registered_types_cpp;
|
||||||
: internals.registered_types_cpp;
|
instances[std::type_index(typeid(type_alias))]
|
||||||
instances[std::type_index(typeid(type_alias))]
|
= instances[std::type_index(typeid(type))];
|
||||||
= instances[std::type_index(typeid(type))];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
def("_pybind11_conduit_v1_", cpp_conduit_method);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>
|
template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>
|
||||||
@ -2327,32 +2336,28 @@ keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
|
|||||||
|
|
||||||
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
||||||
all_type_info_get_cache(PyTypeObject *type) {
|
all_type_info_get_cache(PyTypeObject *type) {
|
||||||
auto res = with_internals([type](internals &internals) {
|
auto res = get_internals()
|
||||||
return internals
|
.registered_types_py
|
||||||
.registered_types_py
|
|
||||||
#ifdef __cpp_lib_unordered_map_try_emplace
|
#ifdef __cpp_lib_unordered_map_try_emplace
|
||||||
.try_emplace(type);
|
.try_emplace(type);
|
||||||
#else
|
#else
|
||||||
.emplace(type, std::vector<detail::type_info *>());
|
.emplace(type, std::vector<detail::type_info *>());
|
||||||
#endif
|
#endif
|
||||||
});
|
|
||||||
if (res.second) {
|
if (res.second) {
|
||||||
// New cache entry created; set up a weak reference to automatically remove it if the type
|
// New cache entry created; set up a weak reference to automatically remove it if the type
|
||||||
// gets destroyed:
|
// gets destroyed:
|
||||||
weakref((PyObject *) type, cpp_function([type](handle wr) {
|
weakref((PyObject *) type, cpp_function([type](handle wr) {
|
||||||
with_internals([type](internals &internals) {
|
get_internals().registered_types_py.erase(type);
|
||||||
internals.registered_types_py.erase(type);
|
|
||||||
|
|
||||||
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
|
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
|
||||||
auto &cache = internals.inactive_override_cache;
|
auto &cache = get_internals().inactive_override_cache;
|
||||||
for (auto it = cache.begin(), last = cache.end(); it != last;) {
|
for (auto it = cache.begin(), last = cache.end(); it != last;) {
|
||||||
if (it->first == reinterpret_cast<PyObject *>(type)) {
|
if (it->first == reinterpret_cast<PyObject *>(type)) {
|
||||||
it = cache.erase(it);
|
it = cache.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
wr.dec_ref();
|
wr.dec_ref();
|
||||||
}))
|
}))
|
||||||
@ -2557,11 +2562,7 @@ void implicitly_convertible() {
|
|||||||
~set_flag() { flag = false; }
|
~set_flag() { flag = false; }
|
||||||
};
|
};
|
||||||
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
|
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
|
||||||
#ifdef Py_GIL_DISABLED
|
|
||||||
thread_local bool currently_used = false;
|
|
||||||
#else
|
|
||||||
static bool currently_used = false;
|
static bool currently_used = false;
|
||||||
#endif
|
|
||||||
if (currently_used) { // implicit conversions are non-reentrant
|
if (currently_used) { // implicit conversions are non-reentrant
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -2586,12 +2587,8 @@ void implicitly_convertible() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void register_exception_translator(ExceptionTranslator &&translator) {
|
inline void register_exception_translator(ExceptionTranslator &&translator) {
|
||||||
detail::with_exception_translators(
|
detail::get_internals().registered_exception_translators.push_front(
|
||||||
[&](std::forward_list<ExceptionTranslator> &exception_translators,
|
std::forward<ExceptionTranslator>(translator));
|
||||||
std::forward_list<ExceptionTranslator> &local_exception_translators) {
|
|
||||||
(void) local_exception_translators;
|
|
||||||
exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2601,12 +2598,8 @@ inline void register_exception_translator(ExceptionTranslator &&translator) {
|
|||||||
* the exception.
|
* the exception.
|
||||||
*/
|
*/
|
||||||
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
|
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
|
||||||
detail::with_exception_translators(
|
detail::get_local_internals().registered_exception_translators.push_front(
|
||||||
[&](std::forward_list<ExceptionTranslator> &exception_translators,
|
std::forward<ExceptionTranslator>(translator));
|
||||||
std::forward_list<ExceptionTranslator> &local_exception_translators) {
|
|
||||||
(void) exception_translators;
|
|
||||||
local_exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2763,19 +2756,14 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
|
|||||||
|
|
||||||
/* Cache functions that aren't overridden in Python to avoid
|
/* Cache functions that aren't overridden in Python to avoid
|
||||||
many costly Python dictionary lookups below */
|
many costly Python dictionary lookups below */
|
||||||
bool not_overridden = with_internals([&key](internals &internals) {
|
auto &cache = get_internals().inactive_override_cache;
|
||||||
auto &cache = internals.inactive_override_cache;
|
if (cache.find(key) != cache.end()) {
|
||||||
return cache.find(key) != cache.end();
|
|
||||||
});
|
|
||||||
if (not_overridden) {
|
|
||||||
return function();
|
return function();
|
||||||
}
|
}
|
||||||
|
|
||||||
function override = getattr(self, name, function());
|
function override = getattr(self, name, function());
|
||||||
if (override.is_cpp_function()) {
|
if (override.is_cpp_function()) {
|
||||||
with_internals([&](internals &internals) {
|
cache.insert(std::move(key));
|
||||||
internals.inactive_override_cache.insert(std::move(key));
|
|
||||||
});
|
|
||||||
return function();
|
return function();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,23 +980,6 @@ inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
|||||||
return rv;
|
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
|
// 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++
|
// 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`.
|
// type, the value goes through pybind11::cast(obj) to convert it to an `object`.
|
||||||
@ -1259,7 +1242,6 @@ protected:
|
|||||||
using pointer = arrow_proxy<const handle>;
|
using pointer = arrow_proxy<const handle>;
|
||||||
|
|
||||||
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
|
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
|
||||||
sequence_fast_readonly() = default;
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
||||||
reference dereference() const { return *ptr; }
|
reference dereference() const { return *ptr; }
|
||||||
@ -1282,7 +1264,6 @@ protected:
|
|||||||
using pointer = arrow_proxy<const sequence_accessor>;
|
using pointer = arrow_proxy<const sequence_accessor>;
|
||||||
|
|
||||||
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}
|
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}
|
||||||
sequence_slow_readwrite() = default;
|
|
||||||
|
|
||||||
reference dereference() const { return {obj, static_cast<size_t>(index)}; }
|
reference dereference() const { return {obj, static_cast<size_t>(index)}; }
|
||||||
void increment() { ++index; }
|
void increment() { ++index; }
|
||||||
|
@ -11,14 +11,10 @@
|
|||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
#include "detail/common.h"
|
#include "detail/common.h"
|
||||||
#include "detail/descr.h"
|
|
||||||
#include "detail/type_caster_base.h"
|
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <initializer_list>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -39,89 +35,6 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
//
|
|
||||||
// Begin: Equivalent of
|
|
||||||
// https://github.com/google/clif/blob/ae4eee1de07cdf115c0c9bf9fec9ff28efce6f6c/clif/python/runtime.cc#L388-L438
|
|
||||||
/*
|
|
||||||
The three `PyObjectTypeIsConvertibleTo*()` functions below are
|
|
||||||
the result of converging the behaviors of pybind11 and PyCLIF
|
|
||||||
(http://github.com/google/clif).
|
|
||||||
|
|
||||||
Originally PyCLIF was extremely far on the permissive side of the spectrum,
|
|
||||||
while pybind11 was very far on the strict side. Originally PyCLIF accepted any
|
|
||||||
Python iterable as input for a C++ `vector`/`set`/`map` argument, as long as
|
|
||||||
the elements were convertible. The obvious (in hindsight) problem was that
|
|
||||||
any empty Python iterable could be passed to any of these C++ types, e.g. `{}`
|
|
||||||
was accepted for C++ `vector`/`set` arguments, or `[]` for C++ `map` arguments.
|
|
||||||
|
|
||||||
The functions below strike a practical permissive-vs-strict compromise,
|
|
||||||
informed by tens of thousands of use cases in the wild. A main objective is
|
|
||||||
to prevent accidents and improve readability:
|
|
||||||
|
|
||||||
- Python literals must match the C++ types.
|
|
||||||
|
|
||||||
- For C++ `set`: The potentially reducing conversion from a Python sequence
|
|
||||||
(e.g. Python `list` or `tuple`) to a C++ `set` must be explicit, by going
|
|
||||||
through a Python `set`.
|
|
||||||
|
|
||||||
- However, a Python `set` can still be passed to a C++ `vector`. The rationale
|
|
||||||
is that this conversion is not reducing. Implicit conversions of this kind
|
|
||||||
are also fairly commonly used, therefore enforcing explicit conversions
|
|
||||||
would have an unfavorable cost : benefit ratio; more sloppily speaking,
|
|
||||||
such an enforcement would be more annoying than helpful.
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline bool PyObjectIsInstanceWithOneOfTpNames(PyObject *obj,
|
|
||||||
std::initializer_list<const char *> tp_names) {
|
|
||||||
if (PyType_Check(obj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const char *obj_tp_name = Py_TYPE(obj)->tp_name;
|
|
||||||
for (const auto *tp_name : tp_names) {
|
|
||||||
if (std::strcmp(obj_tp_name, tp_name) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool PyObjectTypeIsConvertibleToStdVector(PyObject *obj) {
|
|
||||||
if (PySequence_Check(obj) != 0) {
|
|
||||||
return !PyUnicode_Check(obj) && !PyBytes_Check(obj);
|
|
||||||
}
|
|
||||||
return (PyGen_Check(obj) != 0) || (PyAnySet_Check(obj) != 0)
|
|
||||||
|| PyObjectIsInstanceWithOneOfTpNames(
|
|
||||||
obj, {"dict_keys", "dict_values", "dict_items", "map", "zip"});
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool PyObjectTypeIsConvertibleToStdSet(PyObject *obj) {
|
|
||||||
return (PyAnySet_Check(obj) != 0) || PyObjectIsInstanceWithOneOfTpNames(obj, {"dict_keys"});
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool PyObjectTypeIsConvertibleToStdMap(PyObject *obj) {
|
|
||||||
if (PyDict_Check(obj)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Implicit requirement in the conditions below:
|
|
||||||
// A type with `.__getitem__()` & `.items()` methods must implement these
|
|
||||||
// to be compatible with https://docs.python.org/3/c-api/mapping.html
|
|
||||||
if (PyMapping_Check(obj) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PyObject *items = PyObject_GetAttrString(obj, "items");
|
|
||||||
if (items == nullptr) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool is_convertible = (PyCallable_Check(items) != 0);
|
|
||||||
Py_DECREF(items);
|
|
||||||
return is_convertible;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// End: Equivalent of clif/python/runtime.cc
|
|
||||||
//
|
|
||||||
|
|
||||||
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
||||||
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
@ -153,10 +66,17 @@ private:
|
|||||||
}
|
}
|
||||||
void reserve_maybe(const anyset &, void *) {}
|
void reserve_maybe(const anyset &, void *) {}
|
||||||
|
|
||||||
bool convert_iterable(const iterable &itbl, bool convert) {
|
public:
|
||||||
for (const auto &it : itbl) {
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<anyset>(src)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto s = reinterpret_borrow<anyset>(src);
|
||||||
|
value.clear();
|
||||||
|
reserve_maybe(s, &value);
|
||||||
|
for (auto entry : s) {
|
||||||
key_conv conv;
|
key_conv conv;
|
||||||
if (!conv.load(it, convert)) {
|
if (!conv.load(entry, convert)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
value.insert(cast_op<Key &&>(std::move(conv)));
|
value.insert(cast_op<Key &&>(std::move(conv)));
|
||||||
@ -164,29 +84,6 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool convert_anyset(anyset s, bool convert) {
|
|
||||||
value.clear();
|
|
||||||
reserve_maybe(s, &value);
|
|
||||||
return convert_iterable(s, convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!PyObjectTypeIsConvertibleToStdSet(src.ptr())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isinstance<anyset>(src)) {
|
|
||||||
value.clear();
|
|
||||||
return convert_anyset(reinterpret_borrow<anyset>(src), convert);
|
|
||||||
}
|
|
||||||
if (!convert) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assert(isinstance<iterable>(src));
|
|
||||||
value.clear();
|
|
||||||
return convert_iterable(reinterpret_borrow<iterable>(src), convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
if (!std::is_lvalue_reference<T>::value) {
|
if (!std::is_lvalue_reference<T>::value) {
|
||||||
@ -218,10 +115,15 @@ private:
|
|||||||
}
|
}
|
||||||
void reserve_maybe(const dict &, void *) {}
|
void reserve_maybe(const dict &, void *) {}
|
||||||
|
|
||||||
bool convert_elements(const dict &d, bool convert) {
|
public:
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<dict>(src)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto d = reinterpret_borrow<dict>(src);
|
||||||
value.clear();
|
value.clear();
|
||||||
reserve_maybe(d, &value);
|
reserve_maybe(d, &value);
|
||||||
for (const auto &it : d) {
|
for (auto it : d) {
|
||||||
key_conv kconv;
|
key_conv kconv;
|
||||||
value_conv vconv;
|
value_conv vconv;
|
||||||
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
|
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
|
||||||
@ -232,25 +134,6 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!PyObjectTypeIsConvertibleToStdMap(src.ptr())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isinstance<dict>(src)) {
|
|
||||||
return convert_elements(reinterpret_borrow<dict>(src), convert);
|
|
||||||
}
|
|
||||||
if (!convert) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto items = reinterpret_steal<object>(PyMapping_Items(src.ptr()));
|
|
||||||
if (!items) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
assert(isinstance<iterable>(items));
|
|
||||||
return convert_elements(dict(reinterpret_borrow<iterable>(items)), convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
dict d;
|
dict d;
|
||||||
@ -283,35 +166,13 @@ struct list_caster {
|
|||||||
using value_conv = make_caster<Value>;
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
|
if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isinstance<sequence>(src)) {
|
auto s = reinterpret_borrow<sequence>(src);
|
||||||
return convert_elements(src, convert);
|
|
||||||
}
|
|
||||||
if (!convert) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Designed to be behavior-equivalent to passing tuple(src) from Python:
|
|
||||||
// The conversion to a tuple will first exhaust the generator object, to ensure that
|
|
||||||
// the generator is not left in an unpredictable (to the caller) partially-consumed
|
|
||||||
// state.
|
|
||||||
assert(isinstance<iterable>(src));
|
|
||||||
return convert_elements(tuple(reinterpret_borrow<iterable>(src)), convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
|
||||||
void reserve_maybe(const sequence &s, Type *) {
|
|
||||||
value.reserve(s.size());
|
|
||||||
}
|
|
||||||
void reserve_maybe(const sequence &, void *) {}
|
|
||||||
|
|
||||||
bool convert_elements(handle seq, bool convert) {
|
|
||||||
auto s = reinterpret_borrow<sequence>(seq);
|
|
||||||
value.clear();
|
value.clear();
|
||||||
reserve_maybe(s, &value);
|
reserve_maybe(s, &value);
|
||||||
for (const auto &it : seq) {
|
for (const auto &it : s) {
|
||||||
value_conv conv;
|
value_conv conv;
|
||||||
if (!conv.load(it, convert)) {
|
if (!conv.load(it, convert)) {
|
||||||
return false;
|
return false;
|
||||||
@ -321,6 +182,13 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
||||||
|
void reserve_maybe(const sequence &s, Type *) {
|
||||||
|
value.reserve(s.size());
|
||||||
|
}
|
||||||
|
void reserve_maybe(const sequence &, void *) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
@ -352,87 +220,43 @@ struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc
|
|||||||
template <typename Type, typename Alloc>
|
template <typename Type, typename Alloc>
|
||||||
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
||||||
|
|
||||||
template <typename ArrayType, typename V, size_t... I>
|
|
||||||
ArrayType vector_to_array_impl(V &&v, index_sequence<I...>) {
|
|
||||||
return {{std::move(v[I])...}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Based on https://en.cppreference.com/w/cpp/container/array/to_array
|
|
||||||
template <typename ArrayType, size_t N, typename V>
|
|
||||||
ArrayType vector_to_array(V &&v) {
|
|
||||||
return vector_to_array_impl<ArrayType, V>(std::forward<V>(v), make_index_sequence<N>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
||||||
struct array_caster {
|
struct array_caster {
|
||||||
using value_conv = make_caster<Value>;
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ArrayType> value;
|
template <bool R = Resizable>
|
||||||
|
bool require_size(enable_if_t<R, size_t> size) {
|
||||||
|
if (value.size() != size) {
|
||||||
|
value.resize(size);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template <bool R = Resizable>
|
||||||
|
bool require_size(enable_if_t<!R, size_t> size) {
|
||||||
|
return size == Size;
|
||||||
|
}
|
||||||
|
|
||||||
template <bool R = Resizable, enable_if_t<R, int> = 0>
|
public:
|
||||||
bool convert_elements(handle seq, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
auto l = reinterpret_borrow<sequence>(seq);
|
if (!isinstance<sequence>(src)) {
|
||||||
value.reset(new ArrayType{});
|
return false;
|
||||||
// Using `resize` to preserve the behavior exactly as it was before PR #5305
|
}
|
||||||
// For the `resize` to work, `Value` must be default constructible.
|
auto l = reinterpret_borrow<sequence>(src);
|
||||||
// For `std::valarray`, this is a requirement:
|
if (!require_size(l.size())) {
|
||||||
// https://en.cppreference.com/w/cpp/named_req/NumericType
|
return false;
|
||||||
value->resize(l.size());
|
}
|
||||||
size_t ctr = 0;
|
size_t ctr = 0;
|
||||||
for (const auto &it : l) {
|
for (const auto &it : l) {
|
||||||
value_conv conv;
|
value_conv conv;
|
||||||
if (!conv.load(it, convert)) {
|
if (!conv.load(it, convert)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
(*value)[ctr++] = cast_op<Value &&>(std::move(conv));
|
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool R = Resizable, enable_if_t<!R, int> = 0>
|
|
||||||
bool convert_elements(handle seq, bool convert) {
|
|
||||||
auto l = reinterpret_borrow<sequence>(seq);
|
|
||||||
if (l.size() != Size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// The `temp` storage is needed to support `Value` types that are not
|
|
||||||
// default-constructible.
|
|
||||||
// Deliberate choice: no template specializations, for simplicity, and
|
|
||||||
// because the compile time overhead for the specializations is deemed
|
|
||||||
// more significant than the runtime overhead for the `temp` storage.
|
|
||||||
std::vector<Value> temp;
|
|
||||||
temp.reserve(l.size());
|
|
||||||
for (auto it : l) {
|
|
||||||
value_conv conv;
|
|
||||||
if (!conv.load(it, convert)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
temp.emplace_back(cast_op<Value &&>(std::move(conv)));
|
|
||||||
}
|
|
||||||
value.reset(new ArrayType(vector_to_array<ArrayType, Size>(std::move(temp))));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isinstance<sequence>(src)) {
|
|
||||||
return convert_elements(src, convert);
|
|
||||||
}
|
|
||||||
if (!convert) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Designed to be behavior-equivalent to passing tuple(src) from Python:
|
|
||||||
// The conversion to a tuple will first exhaust the generator object, to ensure that
|
|
||||||
// the generator is not left in an unpredictable (to the caller) partially-consumed
|
|
||||||
// state.
|
|
||||||
assert(isinstance<iterable>(src));
|
|
||||||
return convert_elements(tuple(reinterpret_borrow<iterable>(src)), convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
list l(src.size());
|
list l(src.size());
|
||||||
@ -448,36 +272,12 @@ public:
|
|||||||
return l.release();
|
return l.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code copied from PYBIND11_TYPE_CASTER macro.
|
PYBIND11_TYPE_CASTER(ArrayType,
|
||||||
// Intentionally preserving the behavior exactly as it was before PR #5305
|
const_name<Resizable>(const_name(""), const_name("Annotated["))
|
||||||
template <typename T_, enable_if_t<std::is_same<ArrayType, remove_cv_t<T_>>::value, int> = 0>
|
+ const_name("list[") + value_conv::name + const_name("]")
|
||||||
static handle cast(T_ *src, return_value_policy policy, handle parent) {
|
+ const_name<Resizable>(const_name(""),
|
||||||
if (!src) {
|
const_name(", FixedSize(")
|
||||||
return none().release();
|
+ const_name<Size>() + const_name(")]")));
|
||||||
}
|
|
||||||
if (policy == return_value_policy::take_ownership) {
|
|
||||||
auto h = cast(std::move(*src), policy, parent);
|
|
||||||
delete src; // WARNING: Assumes `src` was allocated with `new`.
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
return cast(*src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator ArrayType *() { return &(*value); }
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator ArrayType &() { return *value; }
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator ArrayType &&() && { return std::move(*value); }
|
|
||||||
|
|
||||||
template <typename T_>
|
|
||||||
using cast_op_type = movable_cast_op_type<T_>;
|
|
||||||
|
|
||||||
static constexpr auto name
|
|
||||||
= const_name<Resizable>(const_name(""), const_name("Annotated[")) + const_name("list[")
|
|
||||||
+ value_conv::name + const_name("]")
|
|
||||||
+ const_name<Resizable>(
|
|
||||||
const_name(""), const_name(", FixedSize(") + const_name<Size>() + const_name(")]"));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, size_t Size>
|
template <typename Type, size_t Size>
|
||||||
|
@ -4,17 +4,18 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pybind11/cast.h>
|
#include "../pybind11.h"
|
||||||
#include <pybind11/detail/common.h>
|
#include "../detail/common.h"
|
||||||
#include <pybind11/detail/descr.h>
|
#include "../detail/descr.h"
|
||||||
#include <pybind11/pybind11.h>
|
#include "../cast.h"
|
||||||
#include <pybind11/pytypes.h>
|
#include "../pytypes.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef __has_include
|
#ifdef __has_include
|
||||||
# if defined(PYBIND11_CPP17)
|
# if defined(PYBIND11_CPP17)
|
||||||
# if __has_include(<filesystem>)
|
# if __has_include(<filesystem>) && \
|
||||||
|
PY_VERSION_HEX >= 0x03060000
|
||||||
# include <filesystem>
|
# include <filesystem>
|
||||||
# define PYBIND11_HAS_FILESYSTEM 1
|
# define PYBIND11_HAS_FILESYSTEM 1
|
||||||
# elif __has_include(<experimental/filesystem>)
|
# elif __has_include(<experimental/filesystem>)
|
||||||
@ -33,13 +34,6 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
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)
|
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct path_caster {
|
struct path_caster {
|
||||||
@ -79,8 +73,7 @@ public:
|
|||||||
}
|
}
|
||||||
PyObject *native = nullptr;
|
PyObject *native = nullptr;
|
||||||
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
||||||
if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
|
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
||||||
!= 0) {
|
|
||||||
if (auto *c_str = PyBytes_AsString(native)) {
|
if (auto *c_str = PyBytes_AsString(native)) {
|
||||||
// AsString returns a pointer to the internal buffer, which
|
// AsString returns a pointer to the internal buffer, which
|
||||||
// must not be free'd.
|
// must not be free'd.
|
||||||
@ -88,8 +81,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
||||||
if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
|
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
||||||
!= 0) {
|
|
||||||
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
||||||
// AsWideCharString returns a new string that must be free'd.
|
// AsWideCharString returns a new string that must be free'd.
|
||||||
value = c_str; // Copies the string.
|
value = c_str; // Copies the string.
|
||||||
|
@ -180,7 +180,7 @@ void vector_modifiers(
|
|||||||
v.end());
|
v.end());
|
||||||
try {
|
try {
|
||||||
v.shrink_to_fit();
|
v.shrink_to_fit();
|
||||||
} catch (const std::exception &) { // NOLINT(bugprone-empty-catch)
|
} catch (const std::exception &) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
#include "cast.h"
|
#include "cast.h"
|
||||||
#include "pytypes.h"
|
#include "pytypes.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(typing)
|
PYBIND11_NAMESPACE_BEGIN(typing)
|
||||||
|
|
||||||
@ -65,63 +63,6 @@ class Callable<Return(Args...)> : public function {
|
|||||||
using function::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_args) && __cpp_nontype_template_args >= 201911L
|
|
||||||
# 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_END(typing)
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
@ -180,63 +121,5 @@ struct handle_type_name<typing::Callable<Return(Args...)>> {
|
|||||||
+ const_name("], ") + make_caster<retval_type>::name + const_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(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/warnings.h: Python warnings wrappers.
|
|
||||||
|
|
||||||
Copyright (c) 2024 Jan Iwaszkiewicz <jiwaszkiewicz6@gmail.com>
|
|
||||||
|
|
||||||
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 "pybind11.h"
|
|
||||||
#include "detail/common.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
inline bool PyWarning_Check(PyObject *obj) {
|
|
||||||
int result = PyObject_IsSubclass(obj, PyExc_Warning);
|
|
||||||
if (result == 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (result == -1) {
|
|
||||||
raise_from(PyExc_SystemError,
|
|
||||||
"pybind11::detail::PyWarning_Check(): PyObject_IsSubclass() call failed.");
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(warnings)
|
|
||||||
|
|
||||||
inline object
|
|
||||||
new_warning_type(handle scope, const char *name, handle base = PyExc_RuntimeWarning) {
|
|
||||||
if (!detail::PyWarning_Check(base.ptr())) {
|
|
||||||
pybind11_fail("pybind11::warnings::new_warning_type(): cannot create custom warning, base "
|
|
||||||
"must be a subclass of "
|
|
||||||
"PyExc_Warning!");
|
|
||||||
}
|
|
||||||
if (hasattr(scope, name)) {
|
|
||||||
pybind11_fail("pybind11::warnings::new_warning_type(): an attribute with name \""
|
|
||||||
+ std::string(name) + "\" exists already.");
|
|
||||||
}
|
|
||||||
std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name;
|
|
||||||
handle h(PyErr_NewException(full_name.c_str(), base.ptr(), nullptr));
|
|
||||||
if (!h) {
|
|
||||||
raise_from(PyExc_SystemError,
|
|
||||||
"pybind11::warnings::new_warning_type(): PyErr_NewException() call failed.");
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
auto obj = reinterpret_steal<object>(h);
|
|
||||||
scope.attr(name) = obj;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to Python `warnings.warn()`
|
|
||||||
inline void
|
|
||||||
warn(const char *message, handle category = PyExc_RuntimeWarning, int stack_level = 2) {
|
|
||||||
if (!detail::PyWarning_Check(category.ptr())) {
|
|
||||||
pybind11_fail(
|
|
||||||
"pybind11::warnings::warn(): cannot raise warning, category must be a subclass of "
|
|
||||||
"PyExc_Warning!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyErr_WarnEx(category.ptr(), message, stack_level) == -1) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(warnings)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import nox
|
import nox
|
||||||
@ -45,7 +43,7 @@ def tests_packaging(session: nox.Session) -> None:
|
|||||||
Run the packaging tests.
|
Run the packaging tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
session.install("-r", "tests/requirements.txt", "pip")
|
session.install("-r", "tests/requirements.txt")
|
||||||
session.run("pytest", "tests/extra_python_package", *session.posargs)
|
session.run("pytest", "tests/extra_python_package", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info < (3, 8): # noqa: UP036
|
if sys.version_info < (3, 6): # noqa: UP036
|
||||||
msg = "pybind11 does not support Python < 3.8. v2.13 was the last release supporting Python 3.7."
|
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
|
||||||
raise ImportError(msg)
|
raise ImportError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,36 +1,12 @@
|
|||||||
# pylint: disable=missing-function-docstring
|
# pylint: disable=missing-function-docstring
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
|
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
||||||
|
|
||||||
# This is the conditional used for os.path being posixpath
|
|
||||||
if "posix" in sys.builtin_module_names:
|
|
||||||
from shlex import quote
|
|
||||||
elif "nt" in sys.builtin_module_names:
|
|
||||||
# See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121
|
|
||||||
# and the original documents:
|
|
||||||
# https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
|
|
||||||
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
|
||||||
UNSAFE = re.compile("[ \t\n\r]")
|
|
||||||
|
|
||||||
def quote(s: str) -> str:
|
|
||||||
if s and not UNSAFE.search(s):
|
|
||||||
return s
|
|
||||||
|
|
||||||
# Paths cannot contain a '"' on Windows, so we don't need to worry
|
|
||||||
# about nuanced counting here.
|
|
||||||
return f'"{s}\\"' if s.endswith("\\") else f'"{s}"'
|
|
||||||
else:
|
|
||||||
|
|
||||||
def quote(s: str) -> str:
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def print_includes() -> None:
|
def print_includes() -> None:
|
||||||
dirs = [
|
dirs = [
|
||||||
@ -45,7 +21,7 @@ def print_includes() -> None:
|
|||||||
if d and d not in unique_dirs:
|
if d and d not in unique_dirs:
|
||||||
unique_dirs.append(d)
|
unique_dirs.append(d)
|
||||||
|
|
||||||
print(" ".join(quote(f"-I{d}") for d in unique_dirs))
|
print(" ".join("-I" + d for d in unique_dirs))
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@ -77,9 +53,9 @@ def main() -> None:
|
|||||||
if args.includes:
|
if args.includes:
|
||||||
print_includes()
|
print_includes()
|
||||||
if args.cmakedir:
|
if args.cmakedir:
|
||||||
print(quote(get_cmake_dir()))
|
print(get_cmake_dir())
|
||||||
if args.pkgconfigdir:
|
if args.pkgconfigdir:
|
||||||
print(quote(get_pkgconfig_dir()))
|
print(get_pkgconfig_dir())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
from __future__ import annotations
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
def _to_int(s: str) -> int | str:
|
def _to_int(s: str) -> Union[int, str]:
|
||||||
try:
|
try:
|
||||||
return int(s)
|
return int(s)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
__version__ = "2.14.0.dev1"
|
__version__ = "2.13.0.dev1"
|
||||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
@ -36,7 +36,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#
|
#
|
||||||
# If you copy this file in, you don't
|
# If you copy this file in, you don't
|
||||||
# need the .pyi file; it's just an interface file for static type checkers.
|
# need the .pyi file; it's just an interface file for static type checkers.
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
@ -53,6 +52,7 @@ from pathlib import Path
|
|||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
|
Dict,
|
||||||
Iterable,
|
Iterable,
|
||||||
Iterator,
|
Iterator,
|
||||||
List,
|
List,
|
||||||
@ -113,10 +113,10 @@ class Pybind11Extension(_Extension):
|
|||||||
# flags are prepended, so that they can be further overridden, e.g. by
|
# flags are prepended, so that they can be further overridden, e.g. by
|
||||||
# ``extra_compile_args=["-g"]``.
|
# ``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
|
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
|
self.extra_link_args[:0] = flags
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
@ -249,8 +249,8 @@ def has_flag(compiler: Any, flag: str) -> bool:
|
|||||||
cpp_flag_cache = None
|
cpp_flag_cache = None
|
||||||
|
|
||||||
|
|
||||||
@lru_cache
|
@lru_cache()
|
||||||
def auto_cpp_level(compiler: Any) -> str | int:
|
def auto_cpp_level(compiler: Any) -> Union[str, int]:
|
||||||
"""
|
"""
|
||||||
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
|
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(
|
def intree_extensions(
|
||||||
paths: Iterable[str], package_dir: dict[str, str] | None = None
|
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None
|
||||||
) -> list[Pybind11Extension]:
|
) -> List[Pybind11Extension]:
|
||||||
"""
|
"""
|
||||||
Generate Pybind11Extensions from source files directly located in a Python
|
Generate Pybind11Extensions from source files directly located in a Python
|
||||||
source tree.
|
source tree.
|
||||||
@ -409,7 +409,7 @@ class ParallelCompile:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
envvar: str | None = None,
|
envvar: Optional[str] = None,
|
||||||
default: int = 0,
|
default: int = 0,
|
||||||
max: int = 0, # pylint: disable=redefined-builtin
|
max: int = 0, # pylint: disable=redefined-builtin
|
||||||
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
||||||
@ -418,7 +418,7 @@ class ParallelCompile:
|
|||||||
self.default = default
|
self.default = default
|
||||||
self.max = max
|
self.max = max
|
||||||
self.needs_recompile = needs_recompile
|
self.needs_recompile = needs_recompile
|
||||||
self._old: list[CCompilerMethod] = []
|
self._old: List[CCompilerMethod] = []
|
||||||
|
|
||||||
def function(self) -> CCompilerMethod:
|
def function(self) -> CCompilerMethod:
|
||||||
"""
|
"""
|
||||||
@ -427,14 +427,14 @@ class ParallelCompile:
|
|||||||
|
|
||||||
def compile_function(
|
def compile_function(
|
||||||
compiler: distutils.ccompiler.CCompiler,
|
compiler: distutils.ccompiler.CCompiler,
|
||||||
sources: list[str],
|
sources: List[str],
|
||||||
output_dir: str | None = None,
|
output_dir: Optional[str] = None,
|
||||||
macros: list[tuple[str] | tuple[str, str | None]] | None = None,
|
macros: Optional[List[Union[Tuple[str], Tuple[str, Optional[str]]]]] = None,
|
||||||
include_dirs: list[str] | None = None,
|
include_dirs: Optional[List[str]] = None,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
extra_preargs: list[str] | None = None,
|
extra_preargs: Optional[List[str]] = None,
|
||||||
extra_postargs: list[str] | None = None,
|
extra_postargs: Optional[List[str]] = None,
|
||||||
depends: list[str] | None = None,
|
depends: Optional[List[str]] = None,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
# These lines are directly from distutils.ccompiler.CCompiler
|
# These lines are directly from distutils.ccompiler.CCompiler
|
||||||
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]
|
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]
|
||||||
|
@ -30,7 +30,7 @@ ignore_missing_imports = true
|
|||||||
|
|
||||||
|
|
||||||
[tool.pylint]
|
[tool.pylint]
|
||||||
master.py-version = "3.8"
|
master.py-version = "3.6"
|
||||||
reports.output-format = "colorized"
|
reports.output-format = "colorized"
|
||||||
messages_control.disable = [
|
messages_control.disable = [
|
||||||
"design",
|
"design",
|
||||||
@ -45,7 +45,7 @@ messages_control.disable = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py38"
|
target-version = "py37"
|
||||||
src = ["src"]
|
src = ["src"]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
@ -76,8 +76,6 @@ ignore = [
|
|||||||
]
|
]
|
||||||
unfixable = ["T20"]
|
unfixable = ["T20"]
|
||||||
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
|
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
|
||||||
isort.required-imports = ["from __future__ import annotations"]
|
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff.lint.per-file-ignores]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
"tests/**" = ["EM", "N", "E721"]
|
"tests/**" = ["EM", "N", "E721"]
|
||||||
|
@ -14,12 +14,13 @@ classifiers =
|
|||||||
Topic :: Utilities
|
Topic :: Utilities
|
||||||
Programming Language :: C++
|
Programming Language :: C++
|
||||||
Programming Language :: Python :: 3 :: Only
|
Programming Language :: Python :: 3 :: Only
|
||||||
|
Programming Language :: Python :: 3.6
|
||||||
|
Programming Language :: Python :: 3.7
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
Programming Language :: Python :: 3.10
|
Programming Language :: Python :: 3.10
|
||||||
Programming Language :: Python :: 3.11
|
Programming Language :: Python :: 3.11
|
||||||
Programming Language :: Python :: 3.12
|
Programming Language :: Python :: 3.12
|
||||||
Programming Language :: Python :: 3.13
|
|
||||||
License :: OSI Approved :: BSD License
|
License :: OSI Approved :: BSD License
|
||||||
Programming Language :: Python :: Implementation :: PyPy
|
Programming Language :: Python :: Implementation :: PyPy
|
||||||
Programming Language :: Python :: Implementation :: CPython
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
@ -38,5 +39,5 @@ project_urls =
|
|||||||
Chat = https://gitter.im/pybind/Lobby
|
Chat = https://gitter.im/pybind/Lobby
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
python_requires = >=3.8
|
python_requires = >=3.6
|
||||||
zip_safe = False
|
zip_safe = False
|
||||||
|
15
setup.py
15
setup.py
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
@ -10,9 +9,9 @@ import shutil
|
|||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from collections.abc import Generator
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import Dict, Iterator, List, Union
|
||||||
|
|
||||||
import setuptools.command.sdist
|
import setuptools.command.sdist
|
||||||
|
|
||||||
@ -24,7 +23,7 @@ VERSION_FILE = Path("pybind11/_version.py")
|
|||||||
COMMON_FILE = Path("include/pybind11/detail/common.h")
|
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"]
|
patch_level_serial = matches["PATCH"]
|
||||||
serial = None
|
serial = None
|
||||||
major = int(matches["MAJOR"])
|
major = int(matches["MAJOR"])
|
||||||
@ -65,7 +64,7 @@ to_src = (
|
|||||||
|
|
||||||
|
|
||||||
# Read the listed version
|
# 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")
|
code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
|
||||||
exec(code, loc)
|
exec(code, loc)
|
||||||
version = loc["__version__"]
|
version = loc["__version__"]
|
||||||
@ -85,7 +84,9 @@ if version_hex != exp_version_hex:
|
|||||||
|
|
||||||
|
|
||||||
# TODO: use literals & overload (typing extensions or Python 3.8)
|
# TODO: use literals & overload (typing extensions or Python 3.8)
|
||||||
def get_and_replace(filename: Path, binary: bool = False, **opts: str) -> bytes | str:
|
def get_and_replace(
|
||||||
|
filename: Path, binary: bool = False, **opts: str
|
||||||
|
) -> Union[bytes, str]:
|
||||||
if binary:
|
if binary:
|
||||||
contents = filename.read_bytes()
|
contents = filename.read_bytes()
|
||||||
return string.Template(contents.decode()).substitute(opts).encode()
|
return string.Template(contents.decode()).substitute(opts).encode()
|
||||||
@ -96,7 +97,7 @@ def get_and_replace(filename: Path, binary: bool = False, **opts: str) -> bytes
|
|||||||
# Use our input files instead when making the SDist (and anything that depends
|
# Use our input files instead when making the SDist (and anything that depends
|
||||||
# on it, like a wheel)
|
# on it, like a wheel)
|
||||||
class SDist(setuptools.command.sdist.sdist):
|
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)
|
super().make_release_tree(base_dir, files)
|
||||||
|
|
||||||
for to, src in to_src:
|
for to, src in to_src:
|
||||||
@ -111,7 +112,7 @@ class SDist(setuptools.command.sdist.sdist):
|
|||||||
|
|
||||||
# Remove the CMake install directory when done
|
# Remove the CMake install directory when done
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def remove_output(*sources: str) -> Generator[None, None, None]:
|
def remove_output(*sources: str) -> Iterator[None]:
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
@ -5,7 +5,16 @@
|
|||||||
# All rights reserved. Use of this source code is governed by a
|
# All rights reserved. Use of this source code is governed by a
|
||||||
# BSD-style license that can be found in the LICENSE file.
|
# BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Filter out items; print an optional message if any items filtered. This ignores extensions.
|
# Filter out items; print an optional message if any items filtered. This ignores extensions.
|
||||||
#
|
#
|
||||||
@ -67,8 +76,8 @@ project(pybind11_tests CXX)
|
|||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools")
|
||||||
|
|
||||||
option(PYBIND11_WERROR "Report all warnings as errors" OFF)
|
option(PYBIND11_WERROR "Report all warnings as errors" OFF)
|
||||||
option(DOWNLOAD_EIGEN "Download EIGEN" OFF)
|
option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF)
|
||||||
option(PYBIND11_CUDA_TESTS "Enable building CUDA tests" OFF)
|
option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF)
|
||||||
set(PYBIND11_TEST_OVERRIDE
|
set(PYBIND11_TEST_OVERRIDE
|
||||||
""
|
""
|
||||||
CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
|
CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
|
||||||
@ -79,12 +88,7 @@ set(PYBIND11_TEST_FILTER
|
|||||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
# 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
|
# 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()
|
endif()
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||||
@ -118,7 +122,6 @@ set(PYBIND11_TEST_FILES
|
|||||||
test_const_name
|
test_const_name
|
||||||
test_constants_and_functions
|
test_constants_and_functions
|
||||||
test_copy_move
|
test_copy_move
|
||||||
test_cpp_conduit
|
|
||||||
test_custom_type_casters
|
test_custom_type_casters
|
||||||
test_custom_type_setup
|
test_custom_type_setup
|
||||||
test_docstring_options
|
test_docstring_options
|
||||||
@ -150,13 +153,11 @@ set(PYBIND11_TEST_FILES
|
|||||||
test_tagbased_polymorphic
|
test_tagbased_polymorphic
|
||||||
test_thread
|
test_thread
|
||||||
test_type_caster_pyobject_ptr
|
test_type_caster_pyobject_ptr
|
||||||
test_type_caster_std_function_specializations
|
|
||||||
test_union
|
test_union
|
||||||
test_unnamed_namespace_a
|
test_unnamed_namespace_a
|
||||||
test_unnamed_namespace_b
|
test_unnamed_namespace_b
|
||||||
test_vector_unique_ptr_member
|
test_vector_unique_ptr_member
|
||||||
test_virtual_functions
|
test_virtual_functions)
|
||||||
test_warnings)
|
|
||||||
|
|
||||||
# Invoking cmake with something like:
|
# Invoking cmake with something like:
|
||||||
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
|
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
|
||||||
@ -219,8 +220,6 @@ tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_
|
|||||||
# And add additional targets for other tests.
|
# And add additional targets for other tests.
|
||||||
tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set")
|
tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set")
|
||||||
tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
|
tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
|
||||||
tests_extra_targets("test_cpp_conduit.py"
|
|
||||||
"exo_planet_pybind11;exo_planet_c_api;home_planet_very_lonely_traveler")
|
|
||||||
|
|
||||||
set(PYBIND11_EIGEN_REPO
|
set(PYBIND11_EIGEN_REPO
|
||||||
"https://gitlab.com/libeigen/eigen.git"
|
"https://gitlab.com/libeigen/eigen.git"
|
||||||
@ -244,21 +243,25 @@ endif()
|
|||||||
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
||||||
# Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
|
# Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
|
||||||
# Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
|
# Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
|
||||||
|
# produces a fatal error if loaded from a pre-3.0 cmake.
|
||||||
if(DOWNLOAD_EIGEN)
|
if(DOWNLOAD_EIGEN)
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.18)
|
if(CMAKE_VERSION VERSION_LESS 3.11)
|
||||||
set(_opts)
|
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
|
||||||
else()
|
|
||||||
set(_opts SOURCE_SUBDIR no-cmake-build)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
eigen
|
eigen
|
||||||
GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}"
|
GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}"
|
||||||
GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}"
|
GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}")
|
||||||
${_opts})
|
|
||||||
FetchContent_MakeAvailable(eigen)
|
FetchContent_GetProperties(eigen)
|
||||||
if(NOT CMAKE_VERSION VERSION_LESS 3.18)
|
if(NOT eigen_POPULATED)
|
||||||
set(EIGEN3_INCLUDE_DIR "${eigen_SOURCE_DIR}")
|
message(
|
||||||
|
STATUS
|
||||||
|
"Downloading Eigen ${PYBIND11_EIGEN_VERSION_STRING} (${PYBIND11_EIGEN_VERSION_HASH}) from ${PYBIND11_EIGEN_REPO}"
|
||||||
|
)
|
||||||
|
FetchContent_Populate(eigen)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
|
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
|
||||||
@ -306,7 +309,8 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
|||||||
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
||||||
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON to download")
|
message(
|
||||||
|
STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -386,9 +390,6 @@ function(pybind11_enable_warnings target_name)
|
|||||||
-Wdeprecated
|
-Wdeprecated
|
||||||
-Wundef
|
-Wundef
|
||||||
-Wnon-virtual-dtor)
|
-Wnon-virtual-dtor)
|
||||||
if(DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD VERSION_LESS 20)
|
|
||||||
target_compile_options(${target_name} PRIVATE -Wpedantic)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PYBIND11_WERROR)
|
if(PYBIND11_WERROR)
|
||||||
@ -488,16 +489,15 @@ foreach(target ${test_targets})
|
|||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(SKBUILD)
|
|
||||||
install(TARGETS ${target} LIBRARY DESTINATION .)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Provide nice organisation in IDEs
|
# Provide nice organisation in IDEs
|
||||||
source_group(
|
if(NOT CMAKE_VERSION VERSION_LESS 3.8)
|
||||||
TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
source_group(
|
||||||
PREFIX "Header Files"
|
TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
||||||
FILES ${PYBIND11_HEADERS})
|
PREFIX "Header Files"
|
||||||
|
FILES ${PYBIND11_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Make sure pytest is found or produce a warning
|
# Make sure pytest is found or produce a warning
|
||||||
pybind11_find_import(pytest VERSION 3.1)
|
pybind11_find_import(pytest VERSION 3.1)
|
||||||
|
@ -4,8 +4,6 @@ Extends output capture as needed by pybind11: ignore constructors, optional unor
|
|||||||
Adds docstring and exceptions message sanitizers.
|
Adds docstring and exceptions message sanitizers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import difflib
|
import difflib
|
||||||
import gc
|
import gc
|
||||||
@ -136,7 +134,7 @@ class Capture:
|
|||||||
return Output(self.err)
|
return Output(self.err)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture()
|
||||||
def capture(capsys):
|
def capture(capsys):
|
||||||
"""Extended `capsys` with context manager and custom equality operators"""
|
"""Extended `capsys` with context manager and custom equality operators"""
|
||||||
return Capture(capsys)
|
return Capture(capsys)
|
||||||
@ -172,7 +170,7 @@ def _sanitize_docstring(thing):
|
|||||||
return _sanitize_general(s)
|
return _sanitize_general(s)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture()
|
||||||
def doc():
|
def doc():
|
||||||
"""Sanitize docstrings and add custom failure explanation"""
|
"""Sanitize docstrings and add custom failure explanation"""
|
||||||
return SanitizedString(_sanitize_docstring)
|
return SanitizedString(_sanitize_docstring)
|
||||||
@ -184,7 +182,7 @@ def _sanitize_message(thing):
|
|||||||
return _hexadecimal.sub("0", s)
|
return _hexadecimal.sub("0", s)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture()
|
||||||
def msg():
|
def msg():
|
||||||
"""Sanitize messages and add custom failure explanation"""
|
"""Sanitize messages and add custom failure explanation"""
|
||||||
return SanitizedString(_sanitize_message)
|
return SanitizedString(_sanitize_message)
|
||||||
|
@ -190,7 +190,7 @@ public:
|
|||||||
t1 = &p.first;
|
t1 = &p.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const std::out_of_range &) { // NOLINT(bugprone-empty-catch)
|
} catch (const std::out_of_range &) {
|
||||||
}
|
}
|
||||||
if (!t1) {
|
if (!t1) {
|
||||||
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
||||||
|
@ -92,9 +92,6 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
|
|||||||
if (m != nullptr) {
|
if (m != nullptr) {
|
||||||
static_assert(sizeof(&gil_acquire) == sizeof(void *),
|
static_assert(sizeof(&gil_acquire) == sizeof(void *),
|
||||||
"Function pointer must have the same size as 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_acquire_funcaddr", gil_acquire)
|
||||||
ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release)
|
ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release)
|
||||||
ADD_FUNCTION("gil_acquire_inner_custom_funcaddr",
|
ADD_FUNCTION("gil_acquire_inner_custom_funcaddr",
|
||||||
|
@ -42,9 +42,6 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_interleaved_error_alrea
|
|||||||
if (m != nullptr) {
|
if (m != nullptr) {
|
||||||
static_assert(sizeof(&interleaved_error_already_set) == sizeof(void *),
|
static_assert(sizeof(&interleaved_error_already_set) == sizeof(void *),
|
||||||
"Function pointer must have the same size as 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(
|
PyModule_AddObject(
|
||||||
m,
|
m,
|
||||||
"funcaddr",
|
"funcaddr",
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class PythonMyException7(Exception):
|
|
||||||
def __init__(self, message):
|
|
||||||
self.message = message
|
|
||||||
super().__init__(message)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "[PythonMyException7]: " + self.message.a
|
|
@ -11,6 +11,4 @@
|
|||||||
|
|
||||||
#include "test_eigen_tensor.inl"
|
#include "test_eigen_tensor.inl"
|
||||||
|
|
||||||
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m, pybind11::mod_gil_not_used()) {
|
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m) { eigen_tensor_test::test_module(m); }
|
||||||
eigen_tensor_test::test_module(m);
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -12,7 +9,6 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
|||||||
|
|
||||||
CPYTHON = platform.python_implementation() == "CPython"
|
CPYTHON = platform.python_implementation() == "CPython"
|
||||||
PYPY = platform.python_implementation() == "PyPy"
|
PYPY = platform.python_implementation() == "PyPy"
|
||||||
PY_GIL_DISABLED = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
|
|
||||||
|
|
||||||
|
|
||||||
def deprecated_call():
|
def deprecated_call():
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
// Copyright (c) 2024 The pybind Community.
|
|
||||||
|
|
||||||
// THIS MUST STAY AT THE TOP!
|
|
||||||
#include <pybind11/pybind11.h> // EXCLUSIVELY for PYBIND11_PLATFORM_ABI_ID
|
|
||||||
// Potential future direction to maximize reusability:
|
|
||||||
// (e.g. for use from SWIG, Cython, PyCLIF, nanobind):
|
|
||||||
// #include <pybind11/compat/platform_abi_id.h>
|
|
||||||
// This would only depend on:
|
|
||||||
// 1. A C++ compiler, WITHOUT requiring -fexceptions.
|
|
||||||
// 2. Python.h
|
|
||||||
|
|
||||||
#include "test_cpp_conduit_traveler_types.h"
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void *get_cpp_conduit_void_ptr(PyObject *py_obj, const std::type_info *cpp_type_info) {
|
|
||||||
PyObject *cpp_type_info_capsule
|
|
||||||
= PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
|
|
||||||
typeid(std::type_info).name(),
|
|
||||||
nullptr);
|
|
||||||
if (cpp_type_info_capsule == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
PyObject *cpp_conduit = PyObject_CallMethod(py_obj,
|
|
||||||
"_pybind11_conduit_v1_",
|
|
||||||
"yOy",
|
|
||||||
PYBIND11_PLATFORM_ABI_ID,
|
|
||||||
cpp_type_info_capsule,
|
|
||||||
"raw_pointer_ephemeral");
|
|
||||||
Py_DECREF(cpp_type_info_capsule);
|
|
||||||
if (cpp_conduit == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
void *void_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name());
|
|
||||||
Py_DECREF(cpp_conduit);
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return void_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T *get_cpp_conduit_type_ptr(PyObject *py_obj) {
|
|
||||||
void *void_ptr = get_cpp_conduit_void_ptr(py_obj, &typeid(T));
|
|
||||||
if (void_ptr == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return static_cast<T *>(void_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) {
|
|
||||||
const auto *cpp_traveler
|
|
||||||
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::Traveler>(traveler);
|
|
||||||
if (cpp_traveler == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return PyUnicode_FromString(cpp_traveler->luggage.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) {
|
|
||||||
const auto *cpp_premium_traveler
|
|
||||||
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::PremiumTraveler>(
|
|
||||||
premium_traveler);
|
|
||||||
if (cpp_premium_traveler == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return PyLong_FromLong(static_cast<long>(cpp_premium_traveler->points));
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMethodDef ThisMethodDef[] = {{"GetLuggage", wrapGetLuggage, METH_O, nullptr},
|
|
||||||
{"GetPoints", wrapGetPoints, METH_O, nullptr},
|
|
||||||
{nullptr, nullptr, 0, nullptr}};
|
|
||||||
|
|
||||||
struct PyModuleDef ThisModuleDef = {
|
|
||||||
PyModuleDef_HEAD_INIT, // m_base
|
|
||||||
"exo_planet_c_api", // m_name
|
|
||||||
nullptr, // m_doc
|
|
||||||
-1, // m_size
|
|
||||||
ThisMethodDef, // m_methods
|
|
||||||
nullptr, // m_slots
|
|
||||||
nullptr, // m_traverse
|
|
||||||
nullptr, // m_clear
|
|
||||||
nullptr // m_free
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#if defined(WIN32) || defined(_WIN32)
|
|
||||||
# define EXO_PLANET_C_API_EXPORT __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
# define EXO_PLANET_C_API_EXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C" EXO_PLANET_C_API_EXPORT PyObject *PyInit_exo_planet_c_api() {
|
|
||||||
PyObject *m = PyModule_Create(&ThisModuleDef);
|
|
||||||
if (m == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) 2024 The pybind Community.
|
|
||||||
|
|
||||||
#if defined(PYBIND11_INTERNALS_VERSION)
|
|
||||||
# undef PYBIND11_INTERNALS_VERSION
|
|
||||||
#endif
|
|
||||||
#define PYBIND11_INTERNALS_VERSION 900000001
|
|
||||||
|
|
||||||
#include "test_cpp_conduit_traveler_bindings.h"
|
|
||||||
|
|
||||||
namespace pybind11_tests {
|
|
||||||
namespace test_cpp_conduit {
|
|
||||||
|
|
||||||
PYBIND11_MODULE(exo_planet_pybind11, m) {
|
|
||||||
wrap_traveler(m);
|
|
||||||
m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); });
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test_cpp_conduit
|
|
||||||
} // namespace pybind11_tests
|
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
@ -9,6 +7,7 @@ import tarfile
|
|||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
# These tests must be run explicitly
|
# These tests must be run explicitly
|
||||||
|
# They require CMake 3.15+ (--install)
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
||||||
@ -47,20 +46,16 @@ main_headers = {
|
|||||||
"include/pybind11/stl_bind.h",
|
"include/pybind11/stl_bind.h",
|
||||||
"include/pybind11/type_caster_pyobject_ptr.h",
|
"include/pybind11/type_caster_pyobject_ptr.h",
|
||||||
"include/pybind11/typing.h",
|
"include/pybind11/typing.h",
|
||||||
"include/pybind11/warnings.h",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detail_headers = {
|
detail_headers = {
|
||||||
"include/pybind11/detail/class.h",
|
"include/pybind11/detail/class.h",
|
||||||
"include/pybind11/detail/common.h",
|
"include/pybind11/detail/common.h",
|
||||||
"include/pybind11/detail/cpp_conduit.h",
|
|
||||||
"include/pybind11/detail/descr.h",
|
"include/pybind11/detail/descr.h",
|
||||||
"include/pybind11/detail/init.h",
|
"include/pybind11/detail/init.h",
|
||||||
"include/pybind11/detail/internals.h",
|
"include/pybind11/detail/internals.h",
|
||||||
"include/pybind11/detail/type_caster_base.h",
|
"include/pybind11/detail/type_caster_base.h",
|
||||||
"include/pybind11/detail/typeid.h",
|
"include/pybind11/detail/typeid.h",
|
||||||
"include/pybind11/detail/value_and_holder.h",
|
|
||||||
"include/pybind11/detail/exception_translation.h",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eigen_headers = {
|
eigen_headers = {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) 2024 The pybind Community.
|
|
||||||
|
|
||||||
#include "test_cpp_conduit_traveler_bindings.h"
|
|
||||||
|
|
||||||
namespace pybind11_tests {
|
|
||||||
namespace test_cpp_conduit {
|
|
||||||
|
|
||||||
PYBIND11_MODULE(home_planet_very_lonely_traveler, m) {
|
|
||||||
m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); });
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test_cpp_conduit
|
|
||||||
} // namespace pybind11_tests
|
|
@ -56,13 +56,13 @@ private:
|
|||||||
std::string message = "";
|
std::string message = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
PYBIND11_MAKE_OPAQUE(LocalVec)
|
PYBIND11_MAKE_OPAQUE(LocalVec);
|
||||||
PYBIND11_MAKE_OPAQUE(LocalVec2)
|
PYBIND11_MAKE_OPAQUE(LocalVec2);
|
||||||
PYBIND11_MAKE_OPAQUE(LocalMap)
|
PYBIND11_MAKE_OPAQUE(LocalMap);
|
||||||
PYBIND11_MAKE_OPAQUE(NonLocalVec)
|
PYBIND11_MAKE_OPAQUE(NonLocalVec);
|
||||||
// PYBIND11_MAKE_OPAQUE(NonLocalVec2) // same type as LocalVec2
|
// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
|
||||||
PYBIND11_MAKE_OPAQUE(NonLocalMap)
|
PYBIND11_MAKE_OPAQUE(NonLocalMap);
|
||||||
PYBIND11_MAKE_OPAQUE(NonLocalMap2)
|
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
|
||||||
|
|
||||||
// Simple bindings (used with the above):
|
// Simple bindings (used with the above):
|
||||||
template <typename T, int Adjust = 0, typename... Args>
|
template <typename T, int Adjust = 0, typename... Args>
|
||||||
@ -70,7 +70,7 @@ py::class_<T> bind_local(Args &&...args) {
|
|||||||
return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
|
return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
|
||||||
return i.i + Adjust;
|
return i.i + Adjust;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Simulate a foreign library base class (to match the example in the docs):
|
// Simulate a foreign library base class (to match the example in the docs):
|
||||||
namespace pets {
|
namespace pets {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
PYBIND11_MODULE(pybind11_cross_module_tests, m, py::mod_gil_not_used()) {
|
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||||
m.doc() = "pybind11 cross-module test module";
|
m.doc() = "pybind11 cross-module test module";
|
||||||
|
|
||||||
// test_local_bindings.py tests:
|
// 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)
|
// registered instances to allow instance cleanup checks (invokes a GC first)
|
||||||
.def_static("detail_reg_inst", []() {
|
.def_static("detail_reg_inst", []() {
|
||||||
ConstructorStats::gc();
|
ConstructorStats::gc();
|
||||||
return py::detail::num_registered_instances();
|
return py::detail::get_internals().registered_instances.size();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ const char *cpp_std() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_MODULE(pybind11_tests, m, py::mod_gil_not_used()) {
|
PYBIND11_MODULE(pybind11_tests, m) {
|
||||||
m.doc() = "pybind11 test module";
|
m.doc() = "pybind11 test module";
|
||||||
|
|
||||||
// Intentionally kept minimal to not create a maintenance chore
|
// Intentionally kept minimal to not create a maintenance chore
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
#include <pybind11/eval.h>
|
#include <pybind11/eval.h>
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
using namespace pybind11::literals;
|
using namespace pybind11::literals;
|
||||||
|
|
||||||
@ -54,17 +52,6 @@ union IntFloat {
|
|||||||
float f;
|
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
|
/// 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).
|
/// context. Used to test recursive casters (e.g. std::tuple, stl containers).
|
||||||
struct RValueCaster {};
|
struct RValueCaster {};
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
# 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"
|
|
@ -1,12 +1,15 @@
|
|||||||
--only-binary=:all:
|
--only-binary=:all:
|
||||||
build~=1.0; python_version>="3.8"
|
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"
|
||||||
numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy"
|
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.25.0; python_version=="3.9" and platform_python_implementation=='PyPy'
|
||||||
numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.8" and python_version<"3.10"
|
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.22.2; platform_python_implementation!="PyPy" 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" and python_version<"3.13"
|
numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13"
|
||||||
pytest~=7.0
|
pytest~=7.0
|
||||||
pytest-timeout
|
pytest-timeout
|
||||||
scipy~=1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10"
|
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" and sys_platform!='win32'
|
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" and python_version<"3.13" and sys_platform!='win32'
|
scipy~=1.11.1; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13"
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
asyncio = pytest.importorskip("asyncio")
|
asyncio = pytest.importorskip("asyncio")
|
||||||
m = pytest.importorskip("pybind11_tests.async_module")
|
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()
|
||||||
@pytest.fixture
|
|
||||||
def event_loop():
|
def event_loop():
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
yield loop
|
yield loop
|
||||||
|
@ -167,18 +167,6 @@ TEST_SUBMODULE(buffers, m) {
|
|||||||
sizeof(float)});
|
sizeof(float)});
|
||||||
});
|
});
|
||||||
|
|
||||||
class BrokenMatrix : public Matrix {
|
|
||||||
public:
|
|
||||||
BrokenMatrix(py::ssize_t rows, py::ssize_t cols) : Matrix(rows, cols) {}
|
|
||||||
void throw_runtime_error() { throw std::runtime_error("See PR #5324 for context."); }
|
|
||||||
};
|
|
||||||
py::class_<BrokenMatrix>(m, "BrokenMatrix", py::buffer_protocol())
|
|
||||||
.def(py::init<py::ssize_t, py::ssize_t>())
|
|
||||||
.def_buffer([](BrokenMatrix &m) {
|
|
||||||
m.throw_runtime_error();
|
|
||||||
return py::buffer_info();
|
|
||||||
});
|
|
||||||
|
|
||||||
// test_inherited_protocol
|
// test_inherited_protocol
|
||||||
class SquareMatrix : public Matrix {
|
class SquareMatrix : public Matrix {
|
||||||
public:
|
public:
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import io
|
import io
|
||||||
import struct
|
import struct
|
||||||
@ -228,10 +226,3 @@ def test_buffer_docstring():
|
|||||||
m.get_buffer_info.__doc__.strip()
|
m.get_buffer_info.__doc__.strip()
|
||||||
== "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info"
|
== "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_buffer_exception():
|
|
||||||
with pytest.raises(BufferError, match="Error getting buffer") as excinfo:
|
|
||||||
memoryview(m.BrokenMatrix(1, 1))
|
|
||||||
assert isinstance(excinfo.value.__cause__, RuntimeError)
|
|
||||||
assert "for context" in str(excinfo.value.__cause__)
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -297,7 +295,7 @@ def test_int_convert():
|
|||||||
cant_convert(3.14159)
|
cant_convert(3.14159)
|
||||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||||
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
||||||
if sys.version_info < (3, 10) and env.CPYTHON:
|
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
||||||
with env.deprecated_call():
|
with env.deprecated_call():
|
||||||
assert convert(Int()) == 42
|
assert convert(Int()) == 42
|
||||||
else:
|
else:
|
||||||
@ -368,8 +366,6 @@ def test_tuple(doc):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert doc(m.empty_tuple) == """empty_tuple() -> tuple[()]"""
|
|
||||||
|
|
||||||
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
||||||
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
||||||
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
||||||
|
@ -95,7 +95,7 @@ TEST_SUBMODULE(call_policies, m) {
|
|||||||
},
|
},
|
||||||
py::call_guard<DependentGuard, CustomGuard>());
|
py::call_guard<DependentGuard, CustomGuard>());
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
||||||
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
||||||
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
|
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
|
||||||
auto report_gil_status = []() {
|
auto report_gil_status = []() {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
|
@ -148,7 +148,7 @@ TEST_SUBMODULE(callbacks, m) {
|
|||||||
m.def("dummy_function2", [](int i, int j) { return i + j; });
|
m.def("dummy_function2", [](int i, int j) { return i + j; });
|
||||||
m.def(
|
m.def(
|
||||||
"roundtrip",
|
"roundtrip",
|
||||||
[](std::function<int(int)> f, bool expect_none) {
|
[](std::function<int(int)> f, bool expect_none = false) {
|
||||||
if (expect_none && f) {
|
if (expect_none && f) {
|
||||||
throw std::runtime_error("Expected None to be converted to empty std::function");
|
throw std::runtime_error("Expected None to be converted to empty std::function");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
@ -154,7 +151,6 @@ def test_python_builtins():
|
|||||||
assert m.test_sum_builtin(sum, []) == 0
|
assert m.test_sum_builtin(sum, []) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
|
||||||
def test_async_callbacks():
|
def test_async_callbacks():
|
||||||
# serves as state for async callback
|
# serves as state for async callback
|
||||||
class Item:
|
class Item:
|
||||||
@ -178,7 +174,6 @@ def test_async_callbacks():
|
|||||||
assert sum(res) == sum(x + 3 for x in work)
|
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():
|
def test_async_async_callbacks():
|
||||||
t = Thread(target=test_async_callbacks)
|
t = Thread(target=test_async_callbacks)
|
||||||
t.start()
|
t.start()
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(test_installed_embed CXX)
|
project(test_installed_embed CXX)
|
||||||
|
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
project(test_installed_module CXX)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(test_installed_function CXX)
|
project(test_installed_function CXX)
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(test_installed_target CXX)
|
project(test_installed_target CXX)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
|
||||||
PYBIND11_MODULE(test_cmake_build, m, py::mod_gil_not_used()) {
|
PYBIND11_MODULE(test_cmake_build, m) {
|
||||||
m.def("add", [](int i, int j) { return i + j; });
|
m.def("add", [](int i, int j) { return i + j; });
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(test_subdirectory_embed CXX)
|
project(test_subdirectory_embed CXX)
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(test_subdirectory_function CXX)
|
project(test_subdirectory_function CXX)
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.15...3.30)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
# 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.29)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(test_subdirectory_target CXX)
|
project(test_subdirectory_target CXX)
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import test_cmake_build
|
import test_cmake_build
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import const_name as m
|
from pybind11_tests import const_name as m
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
||||||
|
@ -157,13 +157,6 @@ public:
|
|||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(pybind11)
|
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_SUBMODULE(copy_move_policies, m) {
|
||||||
// test_lacking_copy_ctor
|
// test_lacking_copy_ctor
|
||||||
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
|
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
|
||||||
@ -300,11 +293,6 @@ TEST_SUBMODULE(copy_move_policies, m) {
|
|||||||
|
|
||||||
// Make sure that cast from pytype rvalue to other pytype works
|
// 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_>(); });
|
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,5 +1,3 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import copy_move_policies as m
|
from pybind11_tests import copy_move_policies as m
|
||||||
@ -132,9 +130,3 @@ def test_pytype_rvalue_cast():
|
|||||||
|
|
||||||
value = m.get_pytype_rvalue_castissue(1.0)
|
value = m.get_pytype_rvalue_castissue(1.0)
|
||||||
assert value == 1
|
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"
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) 2024 The pybind Community.
|
|
||||||
|
|
||||||
#include "pybind11_tests.h"
|
|
||||||
#include "test_cpp_conduit_traveler_bindings.h"
|
|
||||||
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
namespace pybind11_tests {
|
|
||||||
namespace test_cpp_conduit {
|
|
||||||
|
|
||||||
TEST_SUBMODULE(cpp_conduit, m) {
|
|
||||||
m.attr("PYBIND11_PLATFORM_ABI_ID") = py::bytes(PYBIND11_PLATFORM_ABI_ID);
|
|
||||||
m.attr("cpp_type_info_capsule_Traveler")
|
|
||||||
= py::capsule(&typeid(Traveler), typeid(std::type_info).name());
|
|
||||||
m.attr("cpp_type_info_capsule_int") = py::capsule(&typeid(int), typeid(std::type_info).name());
|
|
||||||
|
|
||||||
wrap_traveler(m);
|
|
||||||
wrap_lonely_traveler(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test_cpp_conduit
|
|
||||||
} // namespace pybind11_tests
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user