Merging 'master' into 'wrap'
commit
3d40ceb033
|
@ -12,7 +12,7 @@ The python wrapper supports keyword arguments for functions/methods. Hence, the
|
||||||
- Only one Method/Constructor per line, though methods/constructors can extend across multiple lines.
|
- Only one Method/Constructor per line, though methods/constructors can extend across multiple lines.
|
||||||
|
|
||||||
- Methods can return
|
- Methods can return
|
||||||
- Eigen types: `Matrix`, `Vector`.
|
- Eigen types: `gtsam::Matrix`, `gtsam::Vector`.
|
||||||
- C/C++ basic types: `string`, `bool`, `size_t`, `int`, `double`, `char`, `unsigned char`.
|
- C/C++ basic types: `string`, `bool`, `size_t`, `int`, `double`, `char`, `unsigned char`.
|
||||||
- `void`
|
- `void`
|
||||||
- Any class with which be copied with `std::make_shared()`.
|
- Any class with which be copied with `std::make_shared()`.
|
||||||
|
@ -34,7 +34,7 @@ The python wrapper supports keyword arguments for functions/methods. Hence, the
|
||||||
- Overloads are supported, but arguments of different types *have* to have different names.
|
- Overloads are supported, but arguments of different types *have* to have different names.
|
||||||
|
|
||||||
- Arguments to functions can be any of
|
- Arguments to functions can be any of
|
||||||
- Eigen types: `Matrix`, `Vector`.
|
- Eigen types: `gtsam::Matrix`, `gtsam::Vector`.
|
||||||
- Eigen types and classes as an optionally const reference.
|
- Eigen types and classes as an optionally const reference.
|
||||||
- C/C++ basic types: `string`, `bool`, `size_t`, `size_t`, `double`, `char`, `unsigned char`.
|
- C/C++ basic types: `string`, `bool`, `size_t`, `size_t`, `double`, `char`, `unsigned char`.
|
||||||
- Any class with which be copied with `std::make_shared()` (except Eigen).
|
- Any class with which be copied with `std::make_shared()` (except Eigen).
|
||||||
|
|
|
@ -63,9 +63,6 @@ class Typename:
|
||||||
else:
|
else:
|
||||||
self.instantiations = []
|
self.instantiations = []
|
||||||
|
|
||||||
if self.name in ["Matrix", "Vector"] and not self.namespaces:
|
|
||||||
self.namespaces = ["gtsam"]
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_parse_result(parse_result: Union[str, list]):
|
def from_parse_result(parse_result: Union[str, list]):
|
||||||
"""Unpack the parsed result to get the Typename instance."""
|
"""Unpack the parsed result to get the Typename instance."""
|
||||||
|
@ -220,7 +217,6 @@ class Type:
|
||||||
Generate the C++ code for wrapping.
|
Generate the C++ code for wrapping.
|
||||||
|
|
||||||
Treat all pointers as "const shared_ptr<T>&"
|
Treat all pointers as "const shared_ptr<T>&"
|
||||||
Treat Matrix and Vector as "const Matrix&" and "const Vector&" resp.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.is_shared_ptr:
|
if self.is_shared_ptr:
|
||||||
|
@ -228,17 +224,14 @@ class Type:
|
||||||
typename=self.typename.to_cpp())
|
typename=self.typename.to_cpp())
|
||||||
elif self.is_ptr:
|
elif self.is_ptr:
|
||||||
typename = "{typename}*".format(typename=self.typename.to_cpp())
|
typename = "{typename}*".format(typename=self.typename.to_cpp())
|
||||||
elif self.is_ref or self.typename.name in ["Matrix", "Vector"]:
|
elif self.is_ref:
|
||||||
typename = typename = "{typename}&".format(
|
typename = typename = "{typename}&".format(
|
||||||
typename=self.typename.to_cpp())
|
typename=self.typename.to_cpp())
|
||||||
else:
|
else:
|
||||||
typename = self.typename.to_cpp()
|
typename = self.typename.to_cpp()
|
||||||
|
|
||||||
return ("{const}{typename}".format(
|
return ("{const}{typename}".format(
|
||||||
const="const " if
|
const="const " if self.is_const else "", typename=typename))
|
||||||
(self.is_const
|
|
||||||
or self.typename.name in ["Matrix", "Vector"]) else "",
|
|
||||||
typename=typename))
|
|
||||||
|
|
||||||
def get_typename(self):
|
def get_typename(self):
|
||||||
"""Convenience method to get the typename of this type."""
|
"""Convenience method to get the typename of this type."""
|
||||||
|
@ -305,13 +298,10 @@ class TemplatedType:
|
||||||
typename = f"std::shared_ptr<{typename}>"
|
typename = f"std::shared_ptr<{typename}>"
|
||||||
elif self.is_ptr:
|
elif self.is_ptr:
|
||||||
typename = "{typename}*".format(typename=typename)
|
typename = "{typename}*".format(typename=typename)
|
||||||
elif self.is_ref or self.typename.name in ["Matrix", "Vector"]:
|
elif self.is_ref:
|
||||||
typename = typename = "{typename}&".format(typename=typename)
|
typename = typename = "{typename}&".format(typename=typename)
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return ("{const}{typename}".format(
|
return ("{const}{typename}".format(
|
||||||
const="const " if
|
const="const " if self.is_const else "", typename=typename))
|
||||||
(self.is_const
|
|
||||||
or self.typename.name in ["Matrix", "Vector"]) else "",
|
|
||||||
typename=typename))
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ platform:
|
||||||
- x86
|
- x86
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- PYTHON: 36
|
- PYTHON: 38
|
||||||
CONFIG: Debug
|
CONFIG: Debug
|
||||||
install:
|
install:
|
||||||
- ps: |
|
- ps: |
|
||||||
|
|
|
@ -135,7 +135,7 @@ The valid options are:
|
||||||
* Use `-G` and the name of a generator to use something different. `cmake
|
* Use `-G` and the name of a generator to use something different. `cmake
|
||||||
--help` lists the generators available.
|
--help` lists the generators available.
|
||||||
- On Unix, setting `CMAKE_GENERATER=Ninja` in your environment will give
|
- On Unix, setting `CMAKE_GENERATER=Ninja` in your environment will give
|
||||||
you automatic mulithreading on all your CMake projects!
|
you automatic multithreading on all your CMake projects!
|
||||||
* Open the `CMakeLists.txt` with QtCreator to generate for that IDE.
|
* Open the `CMakeLists.txt` with QtCreator to generate for that IDE.
|
||||||
* You can use `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` to generate the `.json` file
|
* You can use `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` to generate the `.json` file
|
||||||
that some tools expect.
|
that some tools expect.
|
||||||
|
|
|
@ -4,4 +4,12 @@ updates:
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "weekly"
|
||||||
|
groups:
|
||||||
|
actions:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
||||||
|
ignore:
|
||||||
|
- dependency-name: actions/checkout
|
||||||
|
versions:
|
||||||
|
- "<5"
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
docs:
|
docs:
|
||||||
- any:
|
all:
|
||||||
- 'docs/**/*.rst'
|
- changed-files:
|
||||||
- '!docs/changelog.rst'
|
- all-globs-to-all-files:
|
||||||
- '!docs/upgrade.rst'
|
- '!docs/changelog.rst'
|
||||||
|
- '!docs/upgrade.rst'
|
||||||
|
- base-branch: "^(?!dependabot).*"
|
||||||
|
- base-branch: "^(?!pre-commit-ci).*"
|
||||||
|
|
||||||
ci:
|
ci:
|
||||||
- '.github/workflows/*.yml'
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '.github/workflows/*.yml'
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
# Add 'needs changelog` label to any change to code files as long as the `CHANGELOG` hasn't changed
|
||||||
|
# Skip dependabot and pre-commit-ci PRs
|
||||||
needs changelog:
|
needs changelog:
|
||||||
- all:
|
- all:
|
||||||
- '!docs/changelog.rst'
|
- changed-files:
|
||||||
|
- all-globs-to-all-files: "!docs/changelog.rst"
|
||||||
|
- base-branch: "^(?!dependabot).*"
|
||||||
|
- base-branch: "^(?!pre-commit-ci).*"
|
||||||
|
|
|
@ -30,13 +30,12 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-20.04, windows-2022, macos-latest]
|
runs-on: [ubuntu-20.04, windows-2022, macos-13]
|
||||||
python:
|
python:
|
||||||
- '3.6'
|
- '3.8'
|
||||||
- '3.9'
|
- '3.9'
|
||||||
- '3.10'
|
|
||||||
- '3.11'
|
|
||||||
- '3.12'
|
- '3.12'
|
||||||
|
- '3.13'
|
||||||
- 'pypy-3.8'
|
- 'pypy-3.8'
|
||||||
- 'pypy-3.9'
|
- 'pypy-3.9'
|
||||||
- 'pypy-3.10'
|
- 'pypy-3.10'
|
||||||
|
@ -49,37 +48,42 @@ jobs:
|
||||||
include:
|
include:
|
||||||
# Just add a key
|
# Just add a key
|
||||||
- runs-on: ubuntu-20.04
|
- runs-on: ubuntu-20.04
|
||||||
python: '3.6'
|
python: '3.8'
|
||||||
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.6'
|
python: '3.8'
|
||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
# Inject a couple Windows 2019 runs
|
# Inject a couple Windows 2019 runs
|
||||||
- runs-on: windows-2019
|
- runs-on: windows-2019
|
||||||
python: '3.9'
|
python: '3.9'
|
||||||
|
# Extra ubuntu latest job
|
||||||
|
- runs-on: ubuntu-latest
|
||||||
|
python: '3.11'
|
||||||
|
|
||||||
|
|
||||||
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
|
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
allow-prereleases: true
|
allow-prereleases: true
|
||||||
|
|
||||||
- name: Setup Boost (Linux)
|
- name: Setup Boost (Linux)
|
||||||
# Can't use boost + define _
|
# Can't use boost + define _
|
||||||
if: runner.os == 'Linux' && matrix.python != '3.6'
|
if: runner.os == 'Linux' && matrix.exercise_D_ != 1
|
||||||
run: sudo apt-get install libboost-dev
|
run: sudo apt-get install libboost-dev
|
||||||
|
|
||||||
- name: Setup Boost (macOS)
|
- name: Setup Boost (macOS)
|
||||||
|
@ -87,11 +91,11 @@ jobs:
|
||||||
run: brew install boost
|
run: brew install boost
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Cache wheels
|
- name: Cache wheels
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
# This path is specific to macOS - we really only need it for PyPy NumPy wheels
|
# This path is specific to macOS - we really only need it for PyPy NumPy wheels
|
||||||
# See https://github.com/actions/cache/blob/master/examples.md#python---pip
|
# See https://github.com/actions/cache/blob/master/examples.md#python---pip
|
||||||
|
@ -109,12 +113,15 @@ jobs:
|
||||||
run: python -m pip install pytest-github-actions-annotate-failures
|
run: python -m pip install pytest-github-actions-annotate-failures
|
||||||
|
|
||||||
# First build - C++11 mode and inplace
|
# First build - C++11 mode and inplace
|
||||||
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here.
|
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here
|
||||||
|
# (same for PYBIND11_NUMPY_1_ONLY, but requires a NumPy 1.x at runtime).
|
||||||
- name: Configure C++11 ${{ matrix.args }}
|
- name: Configure C++11 ${{ matrix.args }}
|
||||||
run: >
|
run: >
|
||||||
cmake -S . -B .
|
cmake -S . -B .
|
||||||
-DPYBIND11_WERROR=ON
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON
|
||||||
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
|
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
|
||||||
|
-DPYBIND11_NUMPY_1_ONLY=ON
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DCMAKE_CXX_STANDARD=11
|
-DCMAKE_CXX_STANDARD=11
|
||||||
|
@ -127,9 +134,7 @@ jobs:
|
||||||
run: cmake --build . --target pytest -j 2
|
run: cmake --build . --target pytest -j 2
|
||||||
|
|
||||||
- name: C++11 tests
|
- name: C++11 tests
|
||||||
# TODO: Figure out how to load the DLL on Python 3.8+
|
run: cmake --build . --target cpptest -j 2
|
||||||
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
|
||||||
|
@ -139,11 +144,13 @@ jobs:
|
||||||
|
|
||||||
# Second build - C++17 mode and in a build directory
|
# Second build - C++17 mode and in a build directory
|
||||||
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here.
|
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here.
|
||||||
|
# (same for PYBIND11_NUMPY_1_ONLY, but requires a NumPy 1.x at runtime).
|
||||||
- name: Configure C++17
|
- name: Configure C++17
|
||||||
run: >
|
run: >
|
||||||
cmake -S . -B build2
|
cmake -S . -B build2
|
||||||
-DPYBIND11_WERROR=ON
|
-DPYBIND11_WERROR=ON
|
||||||
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
|
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
|
||||||
|
-DPYBIND11_NUMPY_1_ONLY=ON
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DCMAKE_CXX_STANDARD=17
|
-DCMAKE_CXX_STANDARD=17
|
||||||
|
@ -156,8 +163,6 @@ 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
|
||||||
|
@ -188,6 +193,35 @@ jobs:
|
||||||
pytest tests/extra_setuptools
|
pytest tests/extra_setuptools
|
||||||
if: "!(matrix.runs-on == 'windows-2022')"
|
if: "!(matrix.runs-on == 'windows-2022')"
|
||||||
|
|
||||||
|
manylinux:
|
||||||
|
name: Manylinux on 🐍 3.13t • GIL
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 40
|
||||||
|
container: quay.io/pypa/musllinux_1_2_x86_64:latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Prepare venv
|
||||||
|
run: python3.13t -m venv .venv
|
||||||
|
|
||||||
|
- name: Install Python deps
|
||||||
|
run: .venv/bin/pip install -r tests/requirements.txt
|
||||||
|
|
||||||
|
- name: Configure C++11
|
||||||
|
run: >
|
||||||
|
cmake -S. -Bbuild
|
||||||
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DDOWNLOAD_CATCH=ON
|
||||||
|
-DDOWNLOAD_EIGEN=ON
|
||||||
|
-DPython_ROOT_DIR=.venv
|
||||||
|
|
||||||
|
- name: Build C++11
|
||||||
|
run: cmake --build build -j2
|
||||||
|
|
||||||
|
- name: Python tests C++11
|
||||||
|
run: cmake --build build --target pytest -j2
|
||||||
|
|
||||||
deadsnakes:
|
deadsnakes:
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -195,9 +229,10 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# TODO: Fails on 3.10, investigate
|
# TODO: Fails on 3.10, investigate
|
||||||
- python-version: "3.9"
|
# JOB DISABLED (NEEDS WORK): https://github.com/pybind/pybind11/issues/4889
|
||||||
python-debug: true
|
# - python-version: "3.9"
|
||||||
valgrind: true
|
# python-debug: true
|
||||||
|
# valgrind: true
|
||||||
- python-version: "3.11"
|
- python-version: "3.11"
|
||||||
python-debug: false
|
python-debug: false
|
||||||
|
|
||||||
|
@ -205,20 +240,20 @@ jobs:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
|
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
|
||||||
uses: deadsnakes/action@v3.0.1
|
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 }}
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Valgrind cache
|
- name: Valgrind cache
|
||||||
if: matrix.valgrind
|
if: matrix.valgrind
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-valgrind
|
id: cache-valgrind
|
||||||
with:
|
with:
|
||||||
path: valgrind
|
path: valgrind
|
||||||
|
@ -302,12 +337,15 @@ jobs:
|
||||||
- clang: 15
|
- clang: 15
|
||||||
std: 20
|
std: 20
|
||||||
container_suffix: "-bullseye"
|
container_suffix: "-bullseye"
|
||||||
|
- clang: 16
|
||||||
|
std: 20
|
||||||
|
container_suffix: "-bullseye"
|
||||||
|
|
||||||
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 }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Add wget and python3
|
- name: Add wget and python3
|
||||||
run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev
|
run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev
|
||||||
|
@ -341,7 +379,7 @@ jobs:
|
||||||
container: nvidia/cuda:12.2.0-devel-ubuntu22.04
|
container: nvidia/cuda:12.2.0-devel-ubuntu22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
|
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
|
||||||
- name: Install 🐍 3
|
- name: Install 🐍 3
|
||||||
|
@ -365,7 +403,7 @@ jobs:
|
||||||
# container: centos:8
|
# container: centos:8
|
||||||
#
|
#
|
||||||
# steps:
|
# steps:
|
||||||
# - uses: actions/checkout@v3
|
# - uses: actions/checkout@v4
|
||||||
#
|
#
|
||||||
# - name: Add Python 3 and a few requirements
|
# - name: Add Python 3 and a few requirements
|
||||||
# run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules
|
# run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules
|
||||||
|
@ -401,54 +439,55 @@ jobs:
|
||||||
# run: cmake --build build --target test_cmake_build
|
# run: cmake --build build --target test_cmake_build
|
||||||
|
|
||||||
|
|
||||||
# Testing on CentOS 7 + PGI compilers, which seems to require more workarounds
|
# Testing on Ubuntu + NVHPC (previous PGI) compilers, which seems to require more workarounds
|
||||||
centos-nvhpc7:
|
ubuntu-nvhpc7:
|
||||||
if: ${{ false }} # JOB DISABLED (NEEDS WORK): https://github.com/pybind/pybind11/issues/4690
|
runs-on: ubuntu-20.04
|
||||||
runs-on: ubuntu-latest
|
name: "🐍 3 • NVHPC 23.5 • C++17 • x64"
|
||||||
name: "🐍 3 • CentOS7 / PGI 22.9 • x64"
|
|
||||||
container: centos:7
|
|
||||||
|
|
||||||
|
env:
|
||||||
|
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
|
||||||
|
DEBIAN_FRONTEND: 'noninteractive'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Add Python 3 and a few requirements
|
- name: Add NVHPC Repo
|
||||||
run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 yum-utils
|
run: |
|
||||||
|
echo 'deb [trusted=yes] https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64 /' | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/nvhpc.list
|
||||||
|
|
||||||
- name: Install NVidia HPC SDK
|
- name: Install 🐍 3 & NVHPC
|
||||||
run: yum-config-manager --add-repo https://developer.download.nvidia.com/hpc-sdk/rhel/nvhpc.repo && yum -y install nvhpc-22.9
|
run: |
|
||||||
|
sudo apt-get update -y && \
|
||||||
|
sudo apt-get install -y cmake environment-modules git python3-dev python3-pip python3-numpy && \
|
||||||
|
sudo apt-get install -y --no-install-recommends nvhpc-23-5 && \
|
||||||
|
sudo rm -rf /var/lib/apt/lists/*
|
||||||
|
python3 -m pip install --upgrade pip
|
||||||
|
python3 -m pip install --upgrade pytest
|
||||||
|
|
||||||
# On CentOS 7, we have to filter a few tests (compiler internal error)
|
# On some systems, you many need further workarounds:
|
||||||
# and allow deeper template recursion (not needed on CentOS 8 with a newer
|
|
||||||
# standard library). On some systems, you many need further workarounds:
|
|
||||||
# https://github.com/pybind/pybind11/pull/2475
|
# https://github.com/pybind/pybind11/pull/2475
|
||||||
- name: Configure
|
- name: Configure
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
source /etc/profile.d/modules.sh
|
source /etc/profile.d/modules.sh
|
||||||
module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.9
|
module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/23.5
|
||||||
cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \
|
cmake -S . -B build -DDOWNLOAD_CATCH=ON \
|
||||||
-DCMAKE_CXX_STANDARD=11 \
|
-DCMAKE_CXX_STANDARD=17 \
|
||||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
|
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
|
||||||
-DCMAKE_CXX_FLAGS="-Wc,--pending_instantiations=0" \
|
-DCMAKE_CXX_FLAGS="-Wc,--pending_instantiations=0" \
|
||||||
-DPYBIND11_TEST_FILTER="test_smart_ptr.cpp"
|
-DPYBIND11_TEST_FILTER="test_smart_ptr.cpp"
|
||||||
|
|
||||||
# Building before installing Pip should produce a warning but not an error
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake3 --build build -j 2 --verbose
|
run: cmake --build build -j 2 --verbose
|
||||||
|
|
||||||
- name: Install CMake with pip
|
|
||||||
run: |
|
|
||||||
python3 -m pip install --upgrade pip
|
|
||||||
python3 -m pip install pytest
|
|
||||||
|
|
||||||
- name: Python tests
|
- name: Python tests
|
||||||
run: cmake3 --build build --target pytest
|
run: cmake --build build --target pytest
|
||||||
|
|
||||||
- name: C++ tests
|
- name: C++ tests
|
||||||
run: cmake3 --build build --target cpptest
|
run: cmake --build build --target cpptest
|
||||||
|
|
||||||
- name: Interface test
|
- name: Interface test
|
||||||
run: cmake3 --build build --target test_cmake_build
|
run: cmake --build build --target test_cmake_build
|
||||||
|
|
||||||
|
|
||||||
# Testing on GCC using the GCC docker images (only recent images supported)
|
# Testing on GCC using the GCC docker images (only recent images supported)
|
||||||
|
@ -465,12 +504,13 @@ jobs:
|
||||||
- { gcc: 10, std: 17 }
|
- { gcc: 10, std: 17 }
|
||||||
- { gcc: 11, std: 20 }
|
- { gcc: 11, std: 20 }
|
||||||
- { gcc: 12, std: 20 }
|
- { gcc: 12, std: 20 }
|
||||||
|
- { gcc: 13, std: 20 }
|
||||||
|
|
||||||
name: "🐍 3 • GCC ${{ matrix.gcc }} • C++${{ matrix.std }}• x64"
|
name: "🐍 3 • GCC ${{ matrix.gcc }} • C++${{ matrix.std }}• x64"
|
||||||
container: "gcc:${{ matrix.gcc }}"
|
container: "gcc:${{ matrix.gcc }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Add Python 3
|
- name: Add Python 3
|
||||||
run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev
|
run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev
|
||||||
|
@ -479,7 +519,7 @@ jobs:
|
||||||
run: python3 -m pip install --upgrade pip
|
run: python3 -m pip install --upgrade pip
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -524,13 +564,11 @@ jobs:
|
||||||
# Testing on ICC using the oneAPI apt repo
|
# Testing on ICC using the oneAPI apt repo
|
||||||
icc:
|
icc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
|
|
||||||
name: "🐍 3 • ICC latest • x64"
|
name: "🐍 3 • ICC latest • x64"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Add apt repo
|
- name: Add apt repo
|
||||||
run: |
|
run: |
|
||||||
|
@ -618,15 +656,13 @@ 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, and this is an easy way
|
# Testing on CentOS (manylinux uses a centos base).
|
||||||
# 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"
|
||||||
|
|
||||||
|
@ -634,14 +670,15 @@ jobs:
|
||||||
container: "${{ matrix.container }}"
|
container: "${{ matrix.container }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- name: Latest actions/checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Add Python 3 (RHEL 7)
|
- name: Add Python 3.8
|
||||||
if: matrix.container == 'centos:7'
|
if: matrix.container == 'almalinux:8'
|
||||||
run: yum update -y && yum install -y python3-devel gcc-c++ make git
|
run: dnf update -y && dnf install -y python38-devel gcc-c++ make git
|
||||||
|
|
||||||
- name: Add Python 3 (RHEL 8+)
|
- name: Add Python 3 (default)
|
||||||
if: matrix.container != 'centos:7'
|
if: matrix.container != 'almalinux:8'
|
||||||
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
|
||||||
|
@ -651,6 +688,11 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install cmake -r tests/requirements.txt
|
python3 -m pip install cmake -r tests/requirements.txt
|
||||||
|
|
||||||
|
- name: Ensure NumPy 2 is used (required Python >= 3.9)
|
||||||
|
if: matrix.container == 'almalinux:9'
|
||||||
|
run: |
|
||||||
|
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
shell: bash
|
shell: bash
|
||||||
run: >
|
run: >
|
||||||
|
@ -682,7 +724,7 @@ jobs:
|
||||||
container: i386/debian:buster
|
container: i386/debian:buster
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1 # Required to run inside docker
|
- uses: actions/checkout@v1 # v1 is required to run inside docker
|
||||||
|
|
||||||
- name: Install requirements
|
- name: Install requirements
|
||||||
run: |
|
run: |
|
||||||
|
@ -725,9 +767,9 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
|
|
||||||
|
@ -759,17 +801,25 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- 3.6
|
- '3.7'
|
||||||
- 3.7
|
- '3.8'
|
||||||
- 3.8
|
- '3.9'
|
||||||
- 3.9
|
- '3.10'
|
||||||
|
- '3.11'
|
||||||
|
- '3.12'
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- python: 3.9
|
- python: '3.12'
|
||||||
args: -DCMAKE_CXX_STANDARD=20
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
- python: 3.8
|
- python: '3.11'
|
||||||
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
|
- python: '3.10'
|
||||||
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
|
- python: '3.9'
|
||||||
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
|
- python: '3.8'
|
||||||
args: -DCMAKE_CXX_STANDARD=17
|
args: -DCMAKE_CXX_STANDARD=17
|
||||||
- python: 3.7
|
- python: '3.7'
|
||||||
args: -DCMAKE_CXX_STANDARD=14
|
args: -DCMAKE_CXX_STANDARD=14
|
||||||
|
|
||||||
|
|
||||||
|
@ -777,19 +827,19 @@ jobs:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
architecture: x86
|
architecture: x86
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Prepare MSVC
|
- name: Prepare MSVC
|
||||||
uses: ilammy/msvc-dev-cmd@v1.12.1
|
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||||
with:
|
with:
|
||||||
arch: x86
|
arch: x86
|
||||||
|
|
||||||
|
@ -830,19 +880,19 @@ jobs:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
architecture: x86
|
architecture: x86
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Prepare MSVC
|
- name: Prepare MSVC
|
||||||
uses: ilammy/msvc-dev-cmd@v1.12.1
|
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||||
with:
|
with:
|
||||||
arch: x86
|
arch: x86
|
||||||
|
|
||||||
|
@ -878,19 +928,21 @@ jobs:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
|
# Ensure use of NumPy 2 (via NumPy nightlies but can be changed soon)
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install -r tests/requirements.txt
|
python3 -m pip install -r tests/requirements.txt
|
||||||
|
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Configure C++20
|
- name: Configure C++20
|
||||||
run: >
|
run: >
|
||||||
|
@ -948,20 +1000,30 @@ jobs:
|
||||||
mingw-w64-${{matrix.env}}-gcc
|
mingw-w64-${{matrix.env}}-gcc
|
||||||
mingw-w64-${{matrix.env}}-python-pip
|
mingw-w64-${{matrix.env}}-python-pip
|
||||||
mingw-w64-${{matrix.env}}-python-numpy
|
mingw-w64-${{matrix.env}}-python-numpy
|
||||||
mingw-w64-${{matrix.env}}-python-scipy
|
|
||||||
mingw-w64-${{matrix.env}}-cmake
|
mingw-w64-${{matrix.env}}-cmake
|
||||||
mingw-w64-${{matrix.env}}-make
|
mingw-w64-${{matrix.env}}-make
|
||||||
mingw-w64-${{matrix.env}}-python-pytest
|
mingw-w64-${{matrix.env}}-python-pytest
|
||||||
mingw-w64-${{matrix.env}}-eigen3
|
|
||||||
mingw-w64-${{matrix.env}}-boost
|
mingw-w64-${{matrix.env}}-boost
|
||||||
mingw-w64-${{matrix.env}}-catch
|
mingw-w64-${{matrix.env}}-catch
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: msys2/setup-msys2@v2
|
||||||
|
if: matrix.sys == 'mingw64'
|
||||||
|
with:
|
||||||
|
msystem: ${{matrix.sys}}
|
||||||
|
install: >-
|
||||||
|
git
|
||||||
|
mingw-w64-${{matrix.env}}-python-scipy
|
||||||
|
mingw-w64-${{matrix.env}}-eigen3
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Configure C++11
|
- name: Configure C++11
|
||||||
# LTO leads to many undefined reference like
|
# LTO leads to many undefined reference like
|
||||||
# `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&)
|
# `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&)
|
||||||
run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build
|
run: >-
|
||||||
|
cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
|
||||||
|
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
|
||||||
|
-S . -B build
|
||||||
|
|
||||||
- name: Build C++11
|
- name: Build C++11
|
||||||
run: cmake --build build -j 2
|
run: cmake --build build -j 2
|
||||||
|
@ -979,7 +1041,10 @@ jobs:
|
||||||
run: git clean -fdx
|
run: git clean -fdx
|
||||||
|
|
||||||
- name: Configure C++14
|
- name: Configure C++14
|
||||||
run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build2
|
run: >-
|
||||||
|
cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
|
||||||
|
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
|
||||||
|
-S . -B build2
|
||||||
|
|
||||||
- name: Build C++14
|
- name: Build C++14
|
||||||
run: cmake --build build2 -j 2
|
run: cmake --build build2 -j 2
|
||||||
|
@ -997,7 +1062,10 @@ jobs:
|
||||||
run: git clean -fdx
|
run: git clean -fdx
|
||||||
|
|
||||||
- name: Configure C++17
|
- name: Configure C++17
|
||||||
run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build3
|
run: >-
|
||||||
|
cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
|
||||||
|
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
|
||||||
|
-S . -B build3
|
||||||
|
|
||||||
- name: Build C++17
|
- name: Build C++17
|
||||||
run: cmake --build build3 -j 2
|
run: cmake --build build3 -j 2
|
||||||
|
@ -1027,21 +1095,21 @@ jobs:
|
||||||
run: env
|
run: env
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Clang
|
- name: Set up Clang
|
||||||
uses: egor-tensin/setup-clang@v1
|
uses: egor-tensin/setup-clang@v1
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Install ninja-build tool
|
- name: Install ninja-build tool
|
||||||
uses: seanmiddleditch/gha-setup-ninja@v3
|
uses: seanmiddleditch/gha-setup-ninja@v5
|
||||||
|
|
||||||
- name: Run pip installs
|
- name: Run pip installs
|
||||||
run: |
|
run: |
|
||||||
|
@ -1081,8 +1149,8 @@ jobs:
|
||||||
run: git clean -fdx
|
run: git clean -fdx
|
||||||
|
|
||||||
macos_brew_install_llvm:
|
macos_brew_install_llvm:
|
||||||
name: "macos-latest • brew install llvm"
|
name: "macos-13 • brew install llvm"
|
||||||
runs-on: macos-latest
|
runs-on: macos-13
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# https://apple.stackexchange.com/questions/227026/how-to-install-recent-clang-with-homebrew
|
# https://apple.stackexchange.com/questions/227026/how-to-install-recent-clang-with-homebrew
|
||||||
|
@ -1096,7 +1164,7 @@ jobs:
|
||||||
run: env
|
run: env
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Show Clang++ version before brew install llvm
|
- name: Show Clang++ version before brew install llvm
|
||||||
run: clang++ --version
|
run: clang++ --version
|
||||||
|
@ -1108,7 +1176,7 @@ jobs:
|
||||||
run: clang++ --version
|
run: clang++ --version
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Run pip installs
|
- name: Run pip installs
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-20.04, macos-latest, windows-latest]
|
runs-on: [ubuntu-20.04, macos-13, windows-latest]
|
||||||
arch: [x64]
|
arch: [x64]
|
||||||
cmake: ["3.26"]
|
cmake: ["3.26"]
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ jobs:
|
||||||
|
|
||||||
- runs-on: ubuntu-20.04
|
- runs-on: ubuntu-20.04
|
||||||
arch: x64
|
arch: x64
|
||||||
cmake: "3.27"
|
cmake: "3.29"
|
||||||
|
|
||||||
- runs-on: macos-latest
|
- runs-on: macos-13
|
||||||
arch: x64
|
arch: x64
|
||||||
cmake: "3.7"
|
cmake: "3.7"
|
||||||
|
|
||||||
|
@ -49,10 +49,10 @@ jobs:
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python 3.7
|
- name: Setup Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
architecture: ${{ matrix.arch }}
|
architecture: ${{ matrix.arch }}
|
||||||
|
@ -63,7 +63,7 @@ jobs:
|
||||||
# An action for adding a specific version of CMake:
|
# An action for adding a specific version of CMake:
|
||||||
# https://github.com/jwlawson/actions-setup-cmake
|
# https://github.com/jwlawson/actions-setup-cmake
|
||||||
- name: Setup CMake ${{ matrix.cmake }}
|
- name: Setup CMake ${{ matrix.cmake }}
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
with:
|
with:
|
||||||
cmake-version: ${{ matrix.cmake }}
|
cmake-version: ${{ matrix.cmake }}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,13 @@ jobs:
|
||||||
name: Format
|
name: Format
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
- name: Add matchers
|
- name: Add matchers
|
||||||
run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
|
run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
|
||||||
- uses: pre-commit/action@v3.0.0
|
- uses: pre-commit/action@v3.0.1
|
||||||
with:
|
with:
|
||||||
# Slow hooks are marked with manual - slow is okay here, run them too
|
# Slow hooks are marked with manual - slow is okay here, run them too
|
||||||
extra_args: --hook-stage manual --all-files
|
extra_args: --hook-stage manual --all-files
|
||||||
|
@ -43,7 +43,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: silkeh/clang:15-bullseye
|
container: silkeh/clang:15-bullseye
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install requirements
|
- name: Install requirements
|
||||||
run: apt-get update && apt-get install -y git python3-dev python3-pytest
|
run: apt-get update && apt-get install -y git python3-dev python3-pytest
|
||||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/labeler@main
|
- uses: actions/labeler@v5
|
||||||
if: >
|
if: >
|
||||||
github.event.pull_request.merged == true &&
|
github.event.pull_request.merged == true &&
|
||||||
!startsWith(github.event.pull_request.title, 'chore(deps):') &&
|
!startsWith(github.event.pull_request.title, 'chore(deps):') &&
|
||||||
|
|
|
@ -21,19 +21,18 @@ 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. Using Windows and Python 3.6, since that is often the most
|
# expected.
|
||||||
# challenging matrix element.
|
|
||||||
test-packaging:
|
test-packaging:
|
||||||
name: 🐍 3.6 • 📦 tests • windows-latest
|
name: 🐍 3.8 • 📦 tests • windows-latest
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup 🐍 3.6
|
- name: Setup 🐍 3.8
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.6
|
python-version: 3.8
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
run: |
|
run: |
|
||||||
|
@ -50,10 +49,10 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup 🐍 3.8
|
- name: Setup 🐍 3.8
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
|
@ -73,13 +72,13 @@ jobs:
|
||||||
run: twine check dist/*
|
run: twine check dist/*
|
||||||
|
|
||||||
- name: Save standard package
|
- name: Save standard package
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: standard
|
name: standard
|
||||||
path: dist/pybind11-*
|
path: dist/pybind11-*
|
||||||
|
|
||||||
- name: Save global package
|
- name: Save global package
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: global
|
name: global
|
||||||
path: dist/pybind11_global-*
|
path: dist/pybind11_global-*
|
||||||
|
@ -92,23 +91,27 @@ 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: pypi
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
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@v3
|
- uses: actions/download-artifact@v4
|
||||||
|
|
||||||
|
- name: Generate artifact attestation for sdist and wheel
|
||||||
|
uses: actions/attest-build-provenance@173725a1209d09b31f9d30a3890cf2757ebbff0d # v1.1.2
|
||||||
|
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/
|
||||||
|
|
||||||
- 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/
|
||||||
|
|
|
@ -13,30 +13,30 @@ concurrency:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PIP_BREAK_SYSTEM_PACKAGES: 1
|
PIP_BREAK_SYSTEM_PACKAGES: 1
|
||||||
PIP_ONLY_BINARY: ":all:"
|
|
||||||
# For cmake:
|
# For cmake:
|
||||||
VERBOSE: 1
|
VERBOSE: 1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
standard:
|
standard:
|
||||||
name: "🐍 3.12 latest • ubuntu-latest • x64"
|
name: "🐍 3.13 latest • ubuntu-latest • x64"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# Only runs when the 'python dev' label is selected
|
# Only runs when the 'python dev' label is selected
|
||||||
if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
|
if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Python 3.12
|
- name: Setup Python 3.13
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.12-dev"
|
python-version: "3.13"
|
||||||
|
allow-prereleases: true
|
||||||
|
|
||||||
- name: Setup Boost
|
- name: Setup Boost
|
||||||
run: sudo apt-get install libboost-dev
|
run: sudo apt-get install libboost-dev
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.14
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
|
|
||||||
- name: Run pip installs
|
- name: Run pip installs
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -25,33 +25,28 @@ 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: "v16.0.6"
|
rev: "v18.1.5"
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
types_or: [c++, c, cuda]
|
types_or: [c++, c, cuda]
|
||||||
|
|
||||||
# Black, the code formatter, natively supports pre-commit
|
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
||||||
- repo: https://github.com/psf/black
|
|
||||||
rev: "23.3.0" # Keep in sync with blacken-docs
|
|
||||||
hooks:
|
|
||||||
- id: black
|
|
||||||
|
|
||||||
# Ruff, the Python auto-correcting linter written in Rust
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.0.276
|
rev: v0.4.7
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["--fix", "--show-fixes"]
|
args: ["--fix", "--show-fixes"]
|
||||||
|
- id: ruff-format
|
||||||
|
|
||||||
# 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.4.1"
|
rev: "v1.10.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args: []
|
args: []
|
||||||
exclude: ^(tests|docs)/
|
exclude: ^(tests|docs)/
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- markdown-it-py<3 # Drop this together with dropping Python 3.7 support.
|
- markdown-it-py
|
||||||
- nox
|
- nox
|
||||||
- rich
|
- rich
|
||||||
- types-setuptools
|
- types-setuptools
|
||||||
|
@ -67,7 +62,7 @@ repos:
|
||||||
|
|
||||||
# Standard hooks
|
# Standard hooks
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: "v4.4.0"
|
rev: "v4.6.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
|
@ -83,22 +78,22 @@ repos:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
# Also code format the docs
|
# Also code format the docs
|
||||||
- repo: https://github.com/asottile/blacken-docs
|
- repo: https://github.com/adamchainz/blacken-docs
|
||||||
rev: "1.14.0"
|
rev: "1.16.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- black==23.3.0 # keep in sync with black hook
|
- black==23.*
|
||||||
|
|
||||||
# Changes tabs to spaces
|
# Changes tabs to spaces
|
||||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||||
rev: "v1.5.1"
|
rev: "v1.5.5"
|
||||||
hooks:
|
hooks:
|
||||||
- id: remove-tabs
|
- id: remove-tabs
|
||||||
|
|
||||||
# Avoid directional quotes
|
# Avoid directional quotes
|
||||||
- repo: https://github.com/sirosen/texthooks
|
- repo: https://github.com/sirosen/texthooks
|
||||||
rev: "0.5.0"
|
rev: "0.6.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: fix-ligatures
|
- id: fix-ligatures
|
||||||
- id: fix-smartquotes
|
- id: fix-smartquotes
|
||||||
|
@ -124,15 +119,15 @@ repos:
|
||||||
# Use tools/codespell_ignore_lines_from_errors.py
|
# Use tools/codespell_ignore_lines_from_errors.py
|
||||||
# to rebuild .codespell-ignore-lines
|
# to rebuild .codespell-ignore-lines
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/codespell-project/codespell
|
||||||
rev: "v2.2.5"
|
rev: "v2.3.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell
|
- id: codespell
|
||||||
exclude: ".supp$"
|
exclude: ".supp$"
|
||||||
args: ["-x.codespell-ignore-lines", "-Lccompiler"]
|
args: ["-x.codespell-ignore-lines", "-Lccompiler,intstruct"]
|
||||||
|
|
||||||
# Check for common shell mistakes
|
# Check for common shell mistakes
|
||||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||||
rev: "v0.9.0.5"
|
rev: "v0.10.0.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: shellcheck
|
- id: shellcheck
|
||||||
|
|
||||||
|
@ -142,12 +137,20 @@ repos:
|
||||||
- id: disallow-caps
|
- id: disallow-caps
|
||||||
name: Disallow improper capitalization
|
name: Disallow improper capitalization
|
||||||
language: pygrep
|
language: pygrep
|
||||||
entry: PyBind|Numpy|Cmake|CCache|PyTest
|
entry: PyBind|\bNumpy\b|Cmake|CCache|PyTest
|
||||||
exclude: ^\.pre-commit-config.yaml$
|
exclude: ^\.pre-commit-config.yaml$
|
||||||
|
|
||||||
# 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.0.0a6"
|
rev: "v3.2.2"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pylint
|
- id: pylint
|
||||||
files: ^pybind11
|
files: ^pybind11
|
||||||
|
|
||||||
|
# Check schemas on some of our YAML files
|
||||||
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||||
|
rev: 0.28.4
|
||||||
|
hooks:
|
||||||
|
- id: check-readthedocs
|
||||||
|
- id: check-github-workflows
|
||||||
|
- id: check-dependabot
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
# https://blog.readthedocs.com/migrate-configuration-v2/
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
apt_packages:
|
||||||
|
- librsvg2-bin
|
||||||
|
tools:
|
||||||
|
python: "3.11"
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/conf.py
|
||||||
|
|
||||||
python:
|
python:
|
||||||
version: 3
|
install:
|
||||||
requirements_file: docs/requirements.txt
|
- requirements: docs/requirements.txt
|
||||||
|
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
|
|
@ -5,15 +5,25 @@
|
||||||
# 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.
|
||||||
|
|
||||||
|
# Propagate this policy (FindPythonInterp removal) so it can be detected later
|
||||||
|
if(NOT CMAKE_VERSION VERSION_LESS "3.27")
|
||||||
|
cmake_policy(GET CMP0148 _pybind11_cmp0148)
|
||||||
|
endif()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_pybind11_cmp0148)
|
||||||
|
cmake_policy(SET CMP0148 ${_pybind11_cmp0148})
|
||||||
|
unset(_pybind11_cmp0148)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Avoid infinite recursion if tests include this as a subdirectory
|
# Avoid infinite recursion if tests include this as a subdirectory
|
||||||
|
@ -82,33 +92,59 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||||
set(pybind11_system "")
|
set(pybind11_system "")
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.18")
|
||||||
|
set(_pybind11_findpython_default OFF)
|
||||||
|
else()
|
||||||
|
set(_pybind11_findpython_default ON)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
set(PYBIND11_MASTER_PROJECT OFF)
|
set(PYBIND11_MASTER_PROJECT OFF)
|
||||||
set(pybind11_system SYSTEM)
|
set(pybind11_system SYSTEM)
|
||||||
|
set(_pybind11_findpython_default OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
|
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
|
||||||
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
|
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
|
||||||
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
|
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
|
||||||
|
option(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION
|
||||||
|
"To enforce that a handle_type_name<> specialization exists" OFF)
|
||||||
option(PYBIND11_SIMPLE_GIL_MANAGEMENT
|
option(PYBIND11_SIMPLE_GIL_MANAGEMENT
|
||||||
"Use simpler GIL management logic that does not support disassociation" OFF)
|
"Use simpler GIL management logic that does not support disassociation" OFF)
|
||||||
|
option(PYBIND11_NUMPY_1_ONLY
|
||||||
|
"Disable NumPy 2 support to avoid changes to previous pybind11 versions." OFF)
|
||||||
set(PYBIND11_INTERNALS_VERSION
|
set(PYBIND11_INTERNALS_VERSION
|
||||||
""
|
""
|
||||||
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
|
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
|
||||||
|
option(PYBIND11_USE_CROSSCOMPILING "Respect CMAKE_CROSSCOMPILING" OFF)
|
||||||
|
|
||||||
|
if(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
|
||||||
|
add_compile_definitions(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
|
||||||
|
endif()
|
||||||
if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
endif()
|
endif()
|
||||||
|
if(PYBIND11_NUMPY_1_ONLY)
|
||||||
|
add_compile_definitions(PYBIND11_NUMPY_1_ONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
cmake_dependent_option(
|
cmake_dependent_option(
|
||||||
USE_PYTHON_INCLUDE_DIR
|
USE_PYTHON_INCLUDE_DIR
|
||||||
"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)
|
||||||
|
|
||||||
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" OFF
|
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default}
|
||||||
"NOT CMAKE_VERSION VERSION_LESS 3.12" OFF)
|
"NOT CMAKE_VERSION VERSION_LESS 3.12" OFF)
|
||||||
|
|
||||||
|
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
|
||||||
|
# (makes transition easier while we support both modes).
|
||||||
|
if(PYBIND11_MASTER_PROJECT
|
||||||
|
AND PYBIND11_FINDPYTHON
|
||||||
|
AND DEFINED PYTHON_EXECUTABLE
|
||||||
|
AND NOT DEFINED Python_EXECUTABLE)
|
||||||
|
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# NB: when adding a header don't forget to also add it to setup.py
|
# NB: when adding a header don't forget to also add it to setup.py
|
||||||
set(PYBIND11_HEADERS
|
set(PYBIND11_HEADERS
|
||||||
include/pybind11/detail/class.h
|
include/pybind11/detail/class.h
|
||||||
|
@ -132,6 +168,7 @@ set(PYBIND11_HEADERS
|
||||||
include/pybind11/embed.h
|
include/pybind11/embed.h
|
||||||
include/pybind11/eval.h
|
include/pybind11/eval.h
|
||||||
include/pybind11/gil.h
|
include/pybind11/gil.h
|
||||||
|
include/pybind11/gil_safe_call_once.h
|
||||||
include/pybind11/iostream.h
|
include/pybind11/iostream.h
|
||||||
include/pybind11/functional.h
|
include/pybind11/functional.h
|
||||||
include/pybind11/numpy.h
|
include/pybind11/numpy.h
|
||||||
|
@ -141,7 +178,8 @@ set(PYBIND11_HEADERS
|
||||||
include/pybind11/stl.h
|
include/pybind11/stl.h
|
||||||
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)
|
||||||
|
|
||||||
# Compare with grep and warn if mismatched
|
# Compare with grep and warn if mismatched
|
||||||
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
|
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||||
|
@ -262,6 +300,7 @@ if(PYBIND11_INSTALL)
|
||||||
tools/pybind11Common.cmake
|
tools/pybind11Common.cmake
|
||||||
tools/pybind11Tools.cmake
|
tools/pybind11Tools.cmake
|
||||||
tools/pybind11NewTools.cmake
|
tools/pybind11NewTools.cmake
|
||||||
|
tools/pybind11GuessPythonExtSuffix.cmake
|
||||||
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
|
|
||||||
if(NOT PYBIND11_EXPORT_NAME)
|
if(NOT PYBIND11_EXPORT_NAME)
|
||||||
|
@ -277,7 +316,21 @@ if(PYBIND11_INSTALL)
|
||||||
|
|
||||||
# pkg-config support
|
# pkg-config support
|
||||||
if(NOT prefix_for_pc_file)
|
if(NOT prefix_for_pc_file)
|
||||||
set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
|
if(IS_ABSOLUTE "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||||
|
set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
|
||||||
|
else()
|
||||||
|
set(pc_datarootdir "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||||
|
if(CMAKE_VERSION VERSION_LESS 3.20)
|
||||||
|
set(prefix_for_pc_file "\${pcfiledir}/..")
|
||||||
|
while(pc_datarootdir)
|
||||||
|
get_filename_component(pc_datarootdir "${pc_datarootdir}" DIRECTORY)
|
||||||
|
string(APPEND prefix_for_pc_file "/..")
|
||||||
|
endwhile()
|
||||||
|
else()
|
||||||
|
cmake_path(RELATIVE_PATH CMAKE_INSTALL_PREFIX BASE_DIRECTORY CMAKE_INSTALL_DATAROOTDIR
|
||||||
|
OUTPUT_VARIABLE prefix_for_pc_file)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in"
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in"
|
||||||
|
|
|
@ -34,12 +34,12 @@ 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.6+, or PyPy) and the C++
|
lines of code and depend on Python (3.7+, or PyPy) and the C++
|
||||||
standard library. This compact implementation was possible thanks to
|
standard library. This compact implementation was possible thanks to
|
||||||
some of the new C++11 language features (specifically: tuples, lambda
|
some C++11 language features (specifically: tuples, lambda functions and
|
||||||
functions and variadic templates). Since its creation, this library has
|
variadic templates). Since its creation, this library has grown beyond
|
||||||
grown beyond Boost.Python in many ways, leading to dramatically simpler
|
Boost.Python in many ways, leading to dramatically simpler binding code in many
|
||||||
binding code in many common situations.
|
common situations.
|
||||||
|
|
||||||
Tutorial and reference documentation is provided at
|
Tutorial and reference documentation is provided at
|
||||||
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
|
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
|
||||||
|
@ -71,6 +71,7 @@ pybind11 can map the following core C++ features to Python:
|
||||||
- Internal references with correct reference counting
|
- Internal references with correct reference counting
|
||||||
- C++ classes with virtual (and pure virtual) methods can be extended
|
- C++ classes with virtual (and pure virtual) methods can be extended
|
||||||
in Python
|
in Python
|
||||||
|
- Integrated NumPy support (NumPy 2 requires pybind11 2.12+)
|
||||||
|
|
||||||
Goodies
|
Goodies
|
||||||
-------
|
-------
|
||||||
|
@ -78,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.6+, and PyPy3 7.3 are supported with an implementation-agnostic
|
- Python 3.7+, 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
|
||||||
|
|
|
@ -18,7 +18,7 @@ information, see :doc:`/compiling`.
|
||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5...3.26)
|
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)`
|
||||||
|
|
|
@ -127,8 +127,7 @@ before a global translator is tried.
|
||||||
Inside the translator, ``std::rethrow_exception`` should be used within
|
Inside the translator, ``std::rethrow_exception`` should be used within
|
||||||
a try block to re-throw the exception. One or more catch clauses to catch
|
a try block to re-throw the exception. One or more catch clauses to catch
|
||||||
the appropriate exceptions should then be used with each clause using
|
the appropriate exceptions should then be used with each clause using
|
||||||
``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set
|
``py::set_error()`` (see below).
|
||||||
the python exception to a custom exception type (see below).
|
|
||||||
|
|
||||||
To declare a custom Python exception type, declare a ``py::exception`` variable
|
To declare a custom Python exception type, declare a ``py::exception`` variable
|
||||||
and use this in the associated exception translator (note: it is often useful
|
and use this in the associated exception translator (note: it is often useful
|
||||||
|
@ -142,14 +141,16 @@ standard python RuntimeError:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
static py::exception<MyCustomException> exc(m, "MyCustomError");
|
PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> exc_storage;
|
||||||
|
exc_storage.call_once_and_store_result(
|
||||||
|
[&]() { return py::exception<MyCustomException>(m, "MyCustomError"); });
|
||||||
py::register_exception_translator([](std::exception_ptr p) {
|
py::register_exception_translator([](std::exception_ptr p) {
|
||||||
try {
|
try {
|
||||||
if (p) std::rethrow_exception(p);
|
if (p) std::rethrow_exception(p);
|
||||||
} catch (const MyCustomException &e) {
|
} catch (const MyCustomException &e) {
|
||||||
exc(e.what());
|
py::set_error(exc_storage.get_stored(), e.what());
|
||||||
} catch (const OtherException &e) {
|
} catch (const OtherException &e) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, e.what());
|
py::set_error(PyExc_RuntimeError, e.what());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -168,8 +169,7 @@ section.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Call either ``PyErr_SetString`` or a custom exception's call
|
Call ``py::set_error()`` for every exception caught in a custom exception
|
||||||
operator (``exc(string)``) for every exception caught in a custom exception
|
|
||||||
translator. Failure to do so will cause Python to crash with ``SystemError:
|
translator. Failure to do so will cause Python to crash with ``SystemError:
|
||||||
error return without exception set``.
|
error return without exception set``.
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ If module1 has the following translator:
|
||||||
try {
|
try {
|
||||||
if (p) std::rethrow_exception(p);
|
if (p) std::rethrow_exception(p);
|
||||||
} catch (const std::invalid_argument &e) {
|
} catch (const std::invalid_argument &e) {
|
||||||
PyErr_SetString("module1 handled this")
|
py::set_error(PyExc_ArgumentError, "module1 handled this");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ and module2 has the following similar translator:
|
||||||
try {
|
try {
|
||||||
if (p) std::rethrow_exception(p);
|
if (p) std::rethrow_exception(p);
|
||||||
} catch (const std::invalid_argument &e) {
|
} catch (const std::invalid_argument &e) {
|
||||||
PyErr_SetString("module2 handled this")
|
py::set_error(PyExc_ArgumentError, "module2 handled this");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,11 +312,11 @@ error protocol, which is outlined here.
|
||||||
After calling the Python C API, if Python returns an error,
|
After calling the Python C API, if Python returns an error,
|
||||||
``throw py::error_already_set();``, which allows pybind11 to deal with the
|
``throw py::error_already_set();``, which allows pybind11 to deal with the
|
||||||
exception and pass it back to the Python interpreter. This includes calls to
|
exception and pass it back to the Python interpreter. This includes calls to
|
||||||
the error setting functions such as ``PyErr_SetString``.
|
the error setting functions such as ``py::set_error()``.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
PyErr_SetString(PyExc_TypeError, "C API type error demo");
|
py::set_error(PyExc_TypeError, "C API type error demo");
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
|
|
||||||
// But it would be easier to simply...
|
// But it would be easier to simply...
|
||||||
|
|
|
@ -16,7 +16,7 @@ lifetime of objects managed by them. This can lead to issues when creating
|
||||||
bindings for functions that return a non-trivial type. Just by looking at the
|
bindings for functions that return a non-trivial type. Just by looking at the
|
||||||
type information, it is not clear whether Python should take charge of the
|
type information, it is not clear whether Python should take charge of the
|
||||||
returned value and eventually free its resources, or if this is handled on the
|
returned value and eventually free its resources, or if this is handled on the
|
||||||
C++ side. For this reason, pybind11 provides a several *return value policy*
|
C++ side. For this reason, pybind11 provides several *return value policy*
|
||||||
annotations that can be passed to the :func:`module_::def` and
|
annotations that can be passed to the :func:`module_::def` and
|
||||||
:func:`class_::def` functions. The default policy is
|
:func:`class_::def` functions. The default policy is
|
||||||
:enum:`return_value_policy::automatic`.
|
:enum:`return_value_policy::automatic`.
|
||||||
|
|
|
@ -398,3 +398,32 @@ before they are used as a parameter or return type of a function:
|
||||||
pyFoo.def(py::init<const ns::Bar&>());
|
pyFoo.def(py::init<const ns::Bar&>());
|
||||||
pyBar.def(py::init<const ns::Foo&>());
|
pyBar.def(py::init<const ns::Foo&>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Setting inner type hints in docstrings
|
||||||
|
======================================
|
||||||
|
|
||||||
|
When you use pybind11 wrappers for ``list``, ``dict``, and other generic python
|
||||||
|
types, the docstring will just display the generic type. You can convey the
|
||||||
|
inner types in the docstring by using a special 'typed' version of the generic
|
||||||
|
type.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m) {
|
||||||
|
m.def("pass_list_of_str", [](py::typing::List<py::str> arg) {
|
||||||
|
// arg can be used just like py::list
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
The resulting docstring will be ``pass_list_of_str(arg0: list[str]) -> None``.
|
||||||
|
|
||||||
|
The following special types are available in ``pybind11/typing.h``:
|
||||||
|
|
||||||
|
* ``py::Tuple<Args...>``
|
||||||
|
* ``py::Dict<K, V>``
|
||||||
|
* ``py::List<V>``
|
||||||
|
* ``py::Set<V>``
|
||||||
|
* ``py::Callable<Signature>``
|
||||||
|
|
||||||
|
.. warning:: Just like in python, these are merely hints. They don't actually
|
||||||
|
enforce the types of their contents at runtime or compile time.
|
||||||
|
|
|
@ -378,8 +378,6 @@ uses of ``py::array``:
|
||||||
|
|
||||||
- ``.itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
|
- ``.itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
|
||||||
|
|
||||||
- ``.ndim()`` returns the number of dimensions.
|
|
||||||
|
|
||||||
- ``.shape(n)`` returns the size of dimension ``n``
|
- ``.shape(n)`` returns the size of dimension ``n``
|
||||||
|
|
||||||
- ``.size()`` returns the total number of elements (i.e. the product of the shapes).
|
- ``.size()`` returns the total number of elements (i.e. the product of the shapes).
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
@ -70,7 +72,7 @@ def generate_dummy_code_boost(nclasses=10):
|
||||||
|
|
||||||
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
|
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
|
||||||
print("{")
|
print("{")
|
||||||
for i in range(0, 10):
|
for i in range(10):
|
||||||
nclasses = 2**i
|
nclasses = 2**i
|
||||||
with open("test.cpp", "w") as f:
|
with open("test.cpp", "w") as f:
|
||||||
f.write(codegen(nclasses))
|
f.write(codegen(nclasses))
|
||||||
|
|
|
@ -10,8 +10,303 @@ Changes will be added here periodically from the "Suggested changelog entry"
|
||||||
block in pull request descriptions.
|
block in pull request descriptions.
|
||||||
|
|
||||||
|
|
||||||
|
IN DEVELOPMENT
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Changes will be summarized here periodically.
|
||||||
|
|
||||||
|
Version 2.13.1 (June 26, 2024)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
* Add support for ``Typing.Callable[..., T]``.
|
||||||
|
`#5202 <https://github.com/pybind/pybind11/pull/5202>`_
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Avoid aligned allocation in free-threaded build in order to support macOS
|
||||||
|
versions before 10.14.
|
||||||
|
`#5200 <https://github.com/pybind/pybind11/pull/5200>`_
|
||||||
|
|
||||||
|
Version 2.13.0 (June 25, 2024)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
* Support free-threaded CPython (3.13t). Add ``py::mod_gil_not_used()`` tag to
|
||||||
|
indicate if a module supports running with the GIL disabled.
|
||||||
|
`#5148 <https://github.com/pybind/pybind11/pull/5148>`_
|
||||||
|
|
||||||
|
* Support for Python 3.6 was removed. (Official end-of-life: 2021-12-23).
|
||||||
|
`#5177 <https://github.com/pybind/pybind11/pull/5177>`_
|
||||||
|
|
||||||
|
* ``py::list`` gained a ``.clear()`` method.
|
||||||
|
`#5153 <https://github.com/pybind/pybind11/pull/5153>`_
|
||||||
|
|
||||||
|
|
||||||
|
.. feat(types)
|
||||||
|
|
||||||
|
* Support for ``Union``, ``Optional``, ``type[T]``, ``typing.TypeGuard``,
|
||||||
|
``typing.TypeIs``, ``typing.Never``, ``typing.NoReturn`` and
|
||||||
|
``typing.Literal`` was added to ``pybind11/typing.h``.
|
||||||
|
`#5166 <https://github.com/pybind/pybind11/pull/5166>`_
|
||||||
|
`#5165 <https://github.com/pybind/pybind11/pull/5165>`_
|
||||||
|
`#5194 <https://github.com/pybind/pybind11/pull/5194>`_
|
||||||
|
`#5193 <https://github.com/pybind/pybind11/pull/5193>`_
|
||||||
|
`#5192 <https://github.com/pybind/pybind11/pull/5192>`_
|
||||||
|
|
||||||
|
|
||||||
|
.. feat(cmake)
|
||||||
|
|
||||||
|
* In CMake, if ``PYBIND11_USE_CROSSCOMPILING`` is enabled, then
|
||||||
|
``CMAKE_CROSSCOMPILING`` will be respected and will keep pybind11 from
|
||||||
|
accessing the interpreter during configuration. Several CMake variables will
|
||||||
|
be required in this case, but can be deduced from the environment variable
|
||||||
|
``SETUPTOOLS_EXT_SUFFIX``. The default (currently ``OFF``) may be changed in
|
||||||
|
the future.
|
||||||
|
`#5083 <https://github.com/pybind/pybind11/pull/5083>`_
|
||||||
|
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* A refcount bug (leading to heap-use-after-free) involving trampoline
|
||||||
|
functions with ``PyObject *`` return type was fixed.
|
||||||
|
`#5156 <https://github.com/pybind/pybind11/pull/5156>`_
|
||||||
|
|
||||||
|
* Return ``py::ssize_t`` from ``.ref_count()`` instead of ``int``.
|
||||||
|
`#5139 <https://github.com/pybind/pybind11/pull/5139>`_
|
||||||
|
|
||||||
|
* A subtle bug involving C++ types with unusual ``operator&`` overrides
|
||||||
|
was fixed.
|
||||||
|
`#5189 <https://github.com/pybind/pybind11/pull/5189>`_
|
||||||
|
|
||||||
|
* Support Python 3.13 with minor fix, add to CI.
|
||||||
|
`#5127 <https://github.com/pybind/pybind11/pull/5127>`_
|
||||||
|
|
||||||
|
|
||||||
|
.. fix(cmake)
|
||||||
|
|
||||||
|
* Fix mistake affecting old cmake and old boost.
|
||||||
|
`#5149 <https://github.com/pybind/pybind11/pull/5149>`_
|
||||||
|
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
|
||||||
|
* Build docs updated to feature scikit-build-core and meson-python, and updated
|
||||||
|
setuptools instructions.
|
||||||
|
`#5168 <https://github.com/pybind/pybind11/pull/5168>`_
|
||||||
|
|
||||||
|
|
||||||
|
Tests:
|
||||||
|
|
||||||
|
* Avoid immortal objects in tests.
|
||||||
|
`#5150 <https://github.com/pybind/pybind11/pull/5150>`_
|
||||||
|
|
||||||
|
|
||||||
|
CI:
|
||||||
|
|
||||||
|
* Compile against Python 3.13t in CI.
|
||||||
|
|
||||||
|
* Use ``macos-13`` (Intel) for CI jobs for now (will drop Python 3.7 soon).
|
||||||
|
`#5109 <https://github.com/pybind/pybind11/pull/5109>`_
|
||||||
|
|
||||||
|
* Releases now have artifact attestations, visible at
|
||||||
|
https://github.com/pybind/pybind11/attestations.
|
||||||
|
`#5196 <https://github.com/pybind/pybind11/pull/5196>`_
|
||||||
|
|
||||||
|
Other:
|
||||||
|
|
||||||
|
* Some cleanup in preparation for 3.13 support.
|
||||||
|
`#5137 <https://github.com/pybind/pybind11/pull/5137>`_
|
||||||
|
|
||||||
|
* Avoid a warning by ensuring an iterator end check is included in release mode.
|
||||||
|
`#5129 <https://github.com/pybind/pybind11/pull/5129>`_
|
||||||
|
|
||||||
|
* Bump max cmake to 3.29.
|
||||||
|
`#5075 <https://github.com/pybind/pybind11/pull/5075>`_
|
||||||
|
|
||||||
|
* Update docs and noxfile.
|
||||||
|
`#5071 <https://github.com/pybind/pybind11/pull/5071>`_
|
||||||
|
|
||||||
|
|
||||||
|
Version 2.12.0 (March 27, 2024)
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
* ``pybind11`` now supports compiling for
|
||||||
|
`NumPy 2 <https://numpy.org/devdocs/numpy_2_0_migration_guide.html>`_. Most
|
||||||
|
code shouldn't change (see :ref:`upgrade-guide-2.12` for details). However,
|
||||||
|
if you experience issues you can define ``PYBIND11_NUMPY_1_ONLY`` to disable
|
||||||
|
the new support for now, but this will be removed in the future.
|
||||||
|
`#5050 <https://github.com/pybind/pybind11/pull/5050>`_
|
||||||
|
|
||||||
|
* ``pybind11/gil_safe_call_once.h`` was added (it needs to be included
|
||||||
|
explicitly). The primary use case is GIL-safe initialization of C++
|
||||||
|
``static`` variables.
|
||||||
|
`#4877 <https://github.com/pybind/pybind11/pull/4877>`_
|
||||||
|
|
||||||
|
* Support move-only iterators in ``py::make_iterator``,
|
||||||
|
``py::make_key_iterator``, ``py::make_value_iterator``.
|
||||||
|
`#4834 <https://github.com/pybind/pybind11/pull/4834>`_
|
||||||
|
|
||||||
|
* Two simple ``py::set_error()`` functions were added and the documentation was
|
||||||
|
updated accordingly. In particular, ``py::exception<>::operator()`` was
|
||||||
|
deprecated (use one of the new functions instead). The documentation for
|
||||||
|
``py::exception<>`` was further updated to not suggest code that may result
|
||||||
|
in undefined behavior.
|
||||||
|
`#4772 <https://github.com/pybind/pybind11/pull/4772>`_
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Removes potential for Undefined Behavior during process teardown.
|
||||||
|
`#4897 <https://github.com/pybind/pybind11/pull/4897>`_
|
||||||
|
|
||||||
|
* Improve compatibility with the nvcc compiler (especially CUDA 12.1/12.2).
|
||||||
|
`#4893 <https://github.com/pybind/pybind11/pull/4893>`_
|
||||||
|
|
||||||
|
* ``pybind11/numpy.h`` now imports NumPy's ``multiarray`` and ``_internal``
|
||||||
|
submodules with paths depending on the installed version of NumPy (for
|
||||||
|
compatibility with NumPy 2).
|
||||||
|
`#4857 <https://github.com/pybind/pybind11/pull/4857>`_
|
||||||
|
|
||||||
|
* Builtins collections names in docstrings are now consistently rendered in
|
||||||
|
lowercase (list, set, dict, tuple), in accordance with PEP 585.
|
||||||
|
`#4833 <https://github.com/pybind/pybind11/pull/4833>`_
|
||||||
|
|
||||||
|
* Added ``py::typing::Iterator<T>``, ``py::typing::Iterable<T>``.
|
||||||
|
`#4832 <https://github.com/pybind/pybind11/pull/4832>`_
|
||||||
|
|
||||||
|
* Render ``py::function`` as ``Callable`` in docstring.
|
||||||
|
`#4829 <https://github.com/pybind/pybind11/pull/4829>`_
|
||||||
|
|
||||||
|
* Also bump ``PYBIND11_INTERNALS_VERSION`` for MSVC, which unlocks two new
|
||||||
|
features without creating additional incompatibilities.
|
||||||
|
`#4819 <https://github.com/pybind/pybind11/pull/4819>`_
|
||||||
|
|
||||||
|
* Guard against crashes/corruptions caused by modules built with different MSVC
|
||||||
|
versions.
|
||||||
|
`#4779 <https://github.com/pybind/pybind11/pull/4779>`_
|
||||||
|
|
||||||
|
* A long-standing bug in the handling of Python multiple inheritance was fixed.
|
||||||
|
See PR #4762 for the rather complex details.
|
||||||
|
`#4762 <https://github.com/pybind/pybind11/pull/4762>`_
|
||||||
|
|
||||||
|
* Fix ``bind_map`` with ``using`` declarations.
|
||||||
|
`#4952 <https://github.com/pybind/pybind11/pull/4952>`_
|
||||||
|
|
||||||
|
* Qualify ``py::detail::concat`` usage to avoid ADL selecting one from
|
||||||
|
somewhere else, such as modernjson's concat.
|
||||||
|
`#4955 <https://github.com/pybind/pybind11/pull/4955>`_
|
||||||
|
|
||||||
|
* Use new PyCode API on Python 3.12+.
|
||||||
|
`#4916 <https://github.com/pybind/pybind11/pull/4916>`_
|
||||||
|
|
||||||
|
* Minor cleanup from warnings reported by Clazy.
|
||||||
|
`#4988 <https://github.com/pybind/pybind11/pull/4988>`_
|
||||||
|
|
||||||
|
* Remove typing and duplicate ``class_`` for ``KeysView``/``ValuesView``/``ItemsView``.
|
||||||
|
`#4985 <https://github.com/pybind/pybind11/pull/4985>`_
|
||||||
|
|
||||||
|
* Use ``PyObject_VisitManagedDict()`` and ``PyObject_ClearManagedDict()`` on Python 3.13 and newer.
|
||||||
|
`#4973 <https://github.com/pybind/pybind11/pull/4973>`_
|
||||||
|
|
||||||
|
* Update ``make_static_property_type()`` to make it compatible with Python 3.13.
|
||||||
|
`#4971 <https://github.com/pybind/pybind11/pull/4971>`_
|
||||||
|
|
||||||
|
.. fix(types)
|
||||||
|
|
||||||
|
* Render typed iterators for ``make_iterator``, ``make_key_iterator``,
|
||||||
|
``make_value_iterator``.
|
||||||
|
`#4876 <https://github.com/pybind/pybind11/pull/4876>`_
|
||||||
|
|
||||||
|
* Add several missing type name specializations.
|
||||||
|
`#5073 <https://github.com/pybind/pybind11/pull/5073>`_
|
||||||
|
|
||||||
|
* Change docstring render for ``py::buffer``, ``py::sequence`` and
|
||||||
|
``py::handle`` (to ``Buffer``, ``Sequence``, ``Any``).
|
||||||
|
`#4831 <https://github.com/pybind/pybind11/pull/4831>`_
|
||||||
|
|
||||||
|
* Fixed ``base_enum.__str__`` docstring.
|
||||||
|
`#4827 <https://github.com/pybind/pybind11/pull/4827>`_
|
||||||
|
|
||||||
|
* Enforce single line docstring signatures.
|
||||||
|
`#4735 <https://github.com/pybind/pybind11/pull/4735>`_
|
||||||
|
|
||||||
|
* Special 'typed' wrappers now available in ``typing.h`` to annotate tuple, dict,
|
||||||
|
list, set, and function.
|
||||||
|
`#4259 <https://github.com/pybind/pybind11/pull/4259>`_
|
||||||
|
|
||||||
|
* Create ``handle_type_name`` specialization to type-hint variable length tuples.
|
||||||
|
`#5051 <https://github.com/pybind/pybind11/pull/5051>`_
|
||||||
|
|
||||||
|
.. fix(build)
|
||||||
|
|
||||||
|
* Setting ``PYBIND11_FINDPYTHON`` to OFF will force the old FindPythonLibs mechanism to be used.
|
||||||
|
`#5042 <https://github.com/pybind/pybind11/pull/5042>`_
|
||||||
|
|
||||||
|
* Skip empty ``PYBIND11_PYTHON_EXECUTABLE_LAST`` for the first cmake run.
|
||||||
|
`#4856 <https://github.com/pybind/pybind11/pull/4856>`_
|
||||||
|
|
||||||
|
* Fix FindPython mode exports & avoid ``pkg_resources`` if
|
||||||
|
``importlib.metadata`` available.
|
||||||
|
`#4941 <https://github.com/pybind/pybind11/pull/4941>`_
|
||||||
|
|
||||||
|
* ``Python_ADDITIONAL_VERSIONS`` (classic search) now includes 3.12.
|
||||||
|
`#4909 <https://github.com/pybind/pybind11/pull/4909>`_
|
||||||
|
|
||||||
|
* ``pybind11.pc`` is now relocatable by default as long as install destinations
|
||||||
|
are not absolute paths.
|
||||||
|
`#4830 <https://github.com/pybind/pybind11/pull/4830>`_
|
||||||
|
|
||||||
|
* Correctly detect CMake FindPython removal when used as a subdirectory.
|
||||||
|
`#4806 <https://github.com/pybind/pybind11/pull/4806>`_
|
||||||
|
|
||||||
|
* Don't require the libs component on CMake 3.18+ when using
|
||||||
|
PYBIND11_FINDPYTHON (fixes manylinux builds).
|
||||||
|
`#4805 <https://github.com/pybind/pybind11/pull/4805>`_
|
||||||
|
|
||||||
|
* ``pybind11_strip`` is no longer automatically applied when
|
||||||
|
``CMAKE_BUILD_TYPE`` is unset.
|
||||||
|
`#4780 <https://github.com/pybind/pybind11/pull/4780>`_
|
||||||
|
|
||||||
|
* Support ``DEBUG_POSFIX`` correctly for debug builds.
|
||||||
|
`#4761 <https://github.com/pybind/pybind11/pull/4761>`_
|
||||||
|
|
||||||
|
* Hardcode lto/thin lto for Emscripten cross-compiles.
|
||||||
|
`#4642 <https://github.com/pybind/pybind11/pull/4642>`_
|
||||||
|
|
||||||
|
* Upgrade maximum supported CMake version to 3.27 to fix CMP0148 warnings.
|
||||||
|
`#4786 <https://github.com/pybind/pybind11/pull/4786>`_
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
|
||||||
|
* Small fix to grammar in ``functions.rst``.
|
||||||
|
`#4791 <https://github.com/pybind/pybind11/pull/4791>`_
|
||||||
|
|
||||||
|
* Remove upper bound in example pyproject.toml for setuptools.
|
||||||
|
`#4774 <https://github.com/pybind/pybind11/pull/4774>`_
|
||||||
|
|
||||||
|
CI:
|
||||||
|
|
||||||
|
* CI: Update NVHPC to 23.5 and Ubuntu 20.04.
|
||||||
|
`#4764 <https://github.com/pybind/pybind11/pull/4764>`_
|
||||||
|
|
||||||
|
* Test on PyPy 3.10.
|
||||||
|
`#4714 <https://github.com/pybind/pybind11/pull/4714>`_
|
||||||
|
|
||||||
|
Other:
|
||||||
|
|
||||||
|
* Use Ruff formatter instead of Black.
|
||||||
|
`#4912 <https://github.com/pybind/pybind11/pull/4912>`_
|
||||||
|
|
||||||
|
* An ``assert()`` was added to help Coverty avoid generating a false positive.
|
||||||
|
`#4817 <https://github.com/pybind/pybind11/pull/4817>`_
|
||||||
|
|
||||||
|
|
||||||
Version 2.11.1 (July 17, 2023)
|
Version 2.11.1 (July 17, 2023)
|
||||||
-----------------------------
|
------------------------------
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
|
|
||||||
|
@ -26,7 +321,7 @@ Changes:
|
||||||
|
|
||||||
|
|
||||||
Version 2.11.0 (July 14, 2023)
|
Version 2.11.0 (July 14, 2023)
|
||||||
-----------------------------
|
------------------------------
|
||||||
|
|
||||||
New features:
|
New features:
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,123 @@
|
||||||
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.29)
|
||||||
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(PYBIND11_FINDPYTHON ON)
|
||||||
|
find_package(pybind11 CONFIG REQUIRED)
|
||||||
|
|
||||||
|
pybind11_add_module(example example.cpp)
|
||||||
|
install(TARGET example DESTINATION .)
|
||||||
|
|
||||||
|
(You use the ``add_subdirectory`` instead, see the example in :ref:`cmake`.) In
|
||||||
|
this example, the code is located in a file named :file:`example.cpp`. Either
|
||||||
|
method will import the pybind11 project which provides the
|
||||||
|
``pybind11_add_module`` function. It will take care of all the details needed
|
||||||
|
to build a Python extension module on any platform.
|
||||||
|
|
||||||
|
To build with pip, build, cibuildwheel, uv, or other Python tools, you can
|
||||||
|
add a ``pyproject.toml`` file like this:
|
||||||
|
|
||||||
|
.. code-block:: toml
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["scikit-build-core", "pybind11"]
|
||||||
|
build-backend = "scikit_build_core.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "example"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
You don't need setuptools files like ``MANIFEST.in``, ``setup.py``, or
|
||||||
|
``setup.cfg``, as this is not setuptools. See `scikit-build-core`_ for details.
|
||||||
|
For projects you plan to upload to PyPI, be sure to fill out the ``[project]``
|
||||||
|
table with other important metadata as well (see `Writing pyproject.toml`_).
|
||||||
|
|
||||||
|
A working sample project can be found in the [scikit_build_example]_
|
||||||
|
repository. An older and harder-to-maintain method is in [cmake_example]_. More
|
||||||
|
details about our cmake support can be found below in :ref:`cmake`.
|
||||||
|
|
||||||
|
.. _scikit-build-core: https://scikit-build-core.readthedocs.io
|
||||||
|
|
||||||
|
.. [scikit_build_example] https://github.com/pybind/scikit_build_example
|
||||||
|
|
||||||
|
.. [cmake_example] https://github.com/pybind/cmake_example
|
||||||
|
|
||||||
|
.. _modules-meson-python:
|
||||||
|
|
||||||
|
Modules with meson-python
|
||||||
|
=========================
|
||||||
|
|
||||||
|
You can also build a package with `Meson`_ using `meson-python`_, if you prefer
|
||||||
|
that. Your ``meson.build`` file would look something like this:
|
||||||
|
|
||||||
|
.. _meson-example:
|
||||||
|
|
||||||
|
.. code-block:: meson
|
||||||
|
|
||||||
|
project(
|
||||||
|
'example',
|
||||||
|
'cpp',
|
||||||
|
version: '0.1.0',
|
||||||
|
default_options: [
|
||||||
|
'cpp_std=c++11',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
py = import('python').find_installation(pure: false)
|
||||||
|
pybind11_dep = dependency('pybind11')
|
||||||
|
|
||||||
|
py.extension_module('example',
|
||||||
|
'example.cpp',
|
||||||
|
install: true,
|
||||||
|
dependencies : [pybind11_dep],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
And you would need a ``pyproject.toml`` file like this:
|
||||||
|
|
||||||
|
.. code-block:: toml
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["meson-python", "pybind11"]
|
||||||
|
build-backend = "mesonpy"
|
||||||
|
|
||||||
|
Meson-python *requires* your project to be in git (or mercurial) as it uses it
|
||||||
|
for the SDist creation. For projects you plan to upload to PyPI, be sure to fill out the
|
||||||
|
``[project]`` table as well (see `Writing pyproject.toml`_).
|
||||||
|
|
||||||
|
|
||||||
|
.. _Writing pyproject.toml: https://packaging.python.org/en/latest/guides/writing-pyproject-toml
|
||||||
|
|
||||||
|
.. _meson: https://mesonbuild.com
|
||||||
|
|
||||||
|
.. _meson-python: https://meson-python.readthedocs.io/en/latest
|
||||||
|
|
||||||
.. _build-setuptools:
|
.. _build-setuptools:
|
||||||
|
|
||||||
Building with setuptools
|
Modules with setuptools
|
||||||
========================
|
=======================
|
||||||
|
|
||||||
For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay
|
For projects on PyPI, a historically popular option is setuptools. Sylvain
|
||||||
has kindly provided an example project which shows how to set up everything,
|
Corlay has kindly provided an example project which shows how to set up
|
||||||
including automatic generation of documentation using Sphinx. Please refer to
|
everything, including automatic generation of documentation using Sphinx.
|
||||||
the [python_example]_ repository.
|
Please refer to the [python_example]_ repository.
|
||||||
|
|
||||||
.. [python_example] https://github.com/pybind/python_example
|
.. [python_example] https://github.com/pybind/python_example
|
||||||
|
|
||||||
|
@ -21,11 +129,11 @@ To use pybind11 inside your ``setup.py``, you have to have some system to
|
||||||
ensure that ``pybind11`` is installed when you build your package. There are
|
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, but very new and requires Pip 10),
|
:ref:`setup_helpers-pep518` (good), ``setup_requires=`` (discouraged), or you
|
||||||
:ref:`setup_helpers-setup_requires` (discouraged by Python packagers now that
|
can :ref:`setup_helpers-copy-manually` (works but you have to manually sync
|
||||||
PEP 518 is available, but it still works everywhere), or you can
|
your copy to get updates). Third party packagers like conda-forge generally
|
||||||
:ref:`setup_helpers-copy-manually` (always works but you have to manually sync
|
strongly prefer the ``pyproject.toml`` method, as it gives them control over
|
||||||
your copy to get updates).
|
the ``pybind11`` version, and they may apply patches, etc.
|
||||||
|
|
||||||
An example of a ``setup.py`` using pybind11's helpers:
|
An example of a ``setup.py`` using pybind11's helpers:
|
||||||
|
|
||||||
|
@ -122,70 +230,41 @@ version number that includes the number of commits since your last tag and a
|
||||||
hash for a dirty directory. Another way to force a rebuild is purge your cache
|
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:
|
||||||
|
|
||||||
PEP 518 requirements (Pip 10+ required)
|
Build requirements
|
||||||
---------------------------------------
|
------------------
|
||||||
|
|
||||||
If you use `PEP 518's <https://www.python.org/dev/peps/pep-0518/>`_
|
With a ``pyproject.toml`` file, you can ensure that ``pybind11`` is available
|
||||||
``pyproject.toml`` file, you can ensure that ``pybind11`` is available during
|
during the compilation of your project. When this file exists, Pip will make a
|
||||||
the compilation of your project. When this file exists, Pip will make a new
|
new virtual environment, download just the packages listed here in
|
||||||
virtual environment, download just the packages listed here in ``requires=``,
|
``requires=``, and build a wheel (binary Python package). It will then throw
|
||||||
and build a wheel (binary Python package). It will then throw away the
|
away the environment, and install your wheel.
|
||||||
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>=42", "wheel", "pybind11~=2.6.1"]
|
requires = ["setuptools", "pybind11"]
|
||||||
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.readthedocs.io
|
.. _cibuildwheel: https://cibuildwheel.pypa.io
|
||||||
.. _pypa-build: https://pypa-build.readthedocs.io/en/latest/
|
.. _pypa-build: https://build.pypa.io/en/latest/
|
||||||
|
.. _check-manifest: https://pypi.io/project/check-manifest
|
||||||
.. _setup_helpers-setup_requires:
|
.. _check-sdist: https://pypi.io/project/check-sdist
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
|
@ -231,32 +310,22 @@ the C++ source file. Python is then able to find the module and load it.
|
||||||
|
|
||||||
.. [cppimport] https://github.com/tbenthompson/cppimport
|
.. [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:
|
extension module can be created with just a few lines of code, as seen above in
|
||||||
|
the module section. Pybind11 currently supports a lower minimum if you don't
|
||||||
|
use the modern FindPython, though be aware that CMake 3.27 removed the old
|
||||||
|
mechanism, so pybind11 will automatically switch if the old mechanism is not
|
||||||
|
available. Please opt into the new mechanism if at all possible. Our default
|
||||||
|
may change in future versions. This is the minimum required:
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5...3.26)
|
|
||||||
project(example LANGUAGES CXX)
|
|
||||||
|
|
||||||
add_subdirectory(pybind11)
|
|
||||||
pybind11_add_module(example example.cpp)
|
|
||||||
|
|
||||||
This assumes that the pybind11 repository is located in a subdirectory named
|
|
||||||
:file:`pybind11` and that the code is located in a file named :file:`example.cpp`.
|
|
||||||
The CMake command ``add_subdirectory`` will import the pybind11 project which
|
|
||||||
provides the ``pybind11_add_module`` function. It will take care of all the
|
|
||||||
details needed to build a Python extension module on any platform.
|
|
||||||
|
|
||||||
A working sample project, including a way to invoke CMake from :file:`setup.py` for
|
|
||||||
PyPI integration, can be found in the [cmake_example]_ repository.
|
|
||||||
|
|
||||||
.. [cmake_example] https://github.com/pybind/cmake_example
|
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
.. versionchanged:: 2.6
|
||||||
CMake 3.4+ is required.
|
CMake 3.4+ is required.
|
||||||
|
@ -264,6 +333,7 @@ PyPI integration, can be found in the [cmake_example]_ repository.
|
||||||
.. versionchanged:: 2.11
|
.. versionchanged:: 2.11
|
||||||
CMake 3.5+ is required.
|
CMake 3.5+ 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
|
||||||
|
@ -356,7 +426,7 @@ with ``PYTHON_EXECUTABLE``. For example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cmake -DPYBIND11_PYTHON_VERSION=3.6 ..
|
cmake -DPYBIND11_PYTHON_VERSION=3.7 ..
|
||||||
|
|
||||||
# Another method:
|
# Another method:
|
||||||
cmake -DPYTHON_EXECUTABLE=/path/to/python ..
|
cmake -DPYTHON_EXECUTABLE=/path/to/python ..
|
||||||
|
@ -423,7 +493,7 @@ existing targets instead:
|
||||||
cmake_minimum_required(VERSION 3.15...3.22)
|
cmake_minimum_required(VERSION 3.15...3.22)
|
||||||
project(example LANGUAGES CXX)
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED)
|
find_package(Python 3.7 COMPONENTS Interpreter Development REQUIRED)
|
||||||
find_package(pybind11 CONFIG REQUIRED)
|
find_package(pybind11 CONFIG REQUIRED)
|
||||||
# or add_subdirectory(pybind11)
|
# or add_subdirectory(pybind11)
|
||||||
|
|
||||||
|
@ -498,7 +568,7 @@ You can use these targets to build complex applications. For example, the
|
||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5...3.26)
|
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)
|
||||||
|
@ -556,7 +626,7 @@ information about usage in C++, see :doc:`/advanced/embedding`.
|
||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5...3.26)
|
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)
|
||||||
|
@ -616,6 +686,13 @@ 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
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
@ -639,3 +716,11 @@ cross-project dependency management. Additionally, it is able to autogenerate
|
||||||
customizable pybind11-based wrappers by parsing C++ header files.
|
customizable pybind11-based wrappers by parsing C++ header files.
|
||||||
|
|
||||||
.. [robotpy-build] https://robotpy-build.readthedocs.io
|
.. [robotpy-build] https://robotpy-build.readthedocs.io
|
||||||
|
|
||||||
|
[litgen]_ is an automatic python bindings generator with a focus on generating
|
||||||
|
documented and discoverable bindings: bindings will nicely reproduce the documentation
|
||||||
|
found in headers. It is is based on srcML (srcml.org), a highly scalable, multi-language
|
||||||
|
parsing tool with a developer centric approach. The API that you want to expose to python
|
||||||
|
must be C++14 compatible (but your implementation can use more modern constructs).
|
||||||
|
|
||||||
|
.. [litgen] https://pthom.github.io/litgen
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#
|
#
|
||||||
# All configuration values have a default; values that are commented out
|
# 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
|
||||||
|
@ -81,7 +82,7 @@ version = loc["__version__"]
|
||||||
#
|
#
|
||||||
# This is also used if you do content translation via gettext catalogs.
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
# Usually you set "language" from the command line for these cases.
|
# Usually you set "language" from the command line for these cases.
|
||||||
language = None
|
language = "en"
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
|
|
|
@ -15,8 +15,8 @@ For example:
|
||||||
|
|
||||||
For beta, ``PYBIND11_VERSION_PATCH`` should be ``Z.b1``. RC's can be ``Z.rc1``.
|
For beta, ``PYBIND11_VERSION_PATCH`` should be ``Z.b1``. RC's can be ``Z.rc1``.
|
||||||
Always include the dot (even though PEP 440 allows it to be dropped). For a
|
Always include the dot (even though PEP 440 allows it to be dropped). For a
|
||||||
final release, this must be a simple integer. There is also a HEX version of
|
final release, this must be a simple integer. There is also
|
||||||
the version just below.
|
``PYBIND11_VERSION_HEX`` just below that needs to be updated.
|
||||||
|
|
||||||
|
|
||||||
To release a new version of pybind11:
|
To release a new version of pybind11:
|
||||||
|
@ -26,53 +26,93 @@ If you don't have nox, you should either use ``pipx run nox`` instead, or use
|
||||||
``pipx install nox`` or ``brew install nox`` (Unix).
|
``pipx install nox`` or ``brew install nox`` (Unix).
|
||||||
|
|
||||||
- Update the version number
|
- Update the version number
|
||||||
- Update ``PYBIND11_VERSION_MAJOR`` etc. in
|
|
||||||
``include/pybind11/detail/common.h``. PATCH should be a simple integer.
|
- Update ``PYBIND11_VERSION_MAJOR`` etc. in
|
||||||
- Update the version HEX just below, as well.
|
``include/pybind11/detail/common.h``. PATCH should be a simple integer.
|
||||||
- Update ``pybind11/_version.py`` (match above)
|
|
||||||
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
|
- Update ``PYBIND11_VERSION_HEX`` just below as well.
|
||||||
- Ensure that all the information in ``setup.cfg`` is up-to-date, like
|
|
||||||
supported Python versions.
|
- Update ``pybind11/_version.py`` (match above).
|
||||||
- Add release date in ``docs/changelog.rst`` and integrate the output of
|
|
||||||
``nox -s make_changelog``.
|
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
|
||||||
- Note that the ``make_changelog`` command inspects
|
|
||||||
`needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_.
|
- Ensure that all the information in ``setup.cfg`` is up-to-date, like
|
||||||
- Manually clear the ``needs changelog`` labels using the GitHub web
|
supported Python versions.
|
||||||
interface (very easy: start by clicking the link above).
|
|
||||||
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
|
- Add release date in ``docs/changelog.rst`` and integrate the output of
|
||||||
fails due to a known flake issue, either ignore or restart CI.)
|
``nox -s make_changelog``.
|
||||||
- Add a release branch if this is a new minor version, or update the existing release branch if it is a patch version
|
|
||||||
- New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y``
|
- Note that the ``nox -s make_changelog`` command inspects
|
||||||
- Update branch: ``git checkout vX.Y``, ``git merge <release branch>``, ``git push``
|
`needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_.
|
||||||
|
|
||||||
|
- Manually clear the ``needs changelog`` labels using the GitHub web
|
||||||
|
interface (very easy: start by clicking the link above).
|
||||||
|
|
||||||
|
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
|
||||||
|
fails due to a known flake issue, either ignore or restart CI.)
|
||||||
|
|
||||||
|
- Add a release branch if this is a new MINOR version, or update the existing
|
||||||
|
release branch if it is a patch version
|
||||||
|
|
||||||
|
- New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y``
|
||||||
|
|
||||||
|
- Update branch: ``git checkout vX.Y``, ``git merge <release branch>``, ``git push``
|
||||||
|
|
||||||
- Update tags (optional; if you skip this, the GitHub release makes a
|
- Update tags (optional; if you skip this, the GitHub release makes a
|
||||||
non-annotated tag for you)
|
non-annotated tag for you)
|
||||||
- ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``.
|
|
||||||
- ``git push --tags``.
|
- ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``
|
||||||
|
|
||||||
|
- ``grep ^__version__ pybind11/_version.py``
|
||||||
|
|
||||||
|
- Last-minute consistency check: same as tag?
|
||||||
|
|
||||||
|
- ``git push --tags``
|
||||||
|
|
||||||
- Update stable
|
- Update stable
|
||||||
- ``git checkout stable``
|
|
||||||
- ``git merge master``
|
- ``git checkout stable``
|
||||||
- ``git push``
|
|
||||||
|
- ``git merge -X theirs vX.Y.Z``
|
||||||
|
|
||||||
|
- ``git diff vX.Y.Z``
|
||||||
|
|
||||||
|
- Carefully review and reconcile any diffs. There should be none.
|
||||||
|
|
||||||
|
- ``git push``
|
||||||
|
|
||||||
- Make a GitHub release (this shows up in the UI, sends new release
|
- Make a GitHub release (this shows up in the UI, sends new release
|
||||||
notifications to users watching releases, and also uploads PyPI packages).
|
notifications to users watching releases, and also uploads PyPI packages).
|
||||||
(Note: if you do not use an existing tag, this creates a new lightweight tag
|
(Note: if you do not use an existing tag, this creates a new lightweight tag
|
||||||
for you, so you could skip the above step.)
|
for you, so you could skip the above step.)
|
||||||
- GUI method: Under `releases <https://github.com/pybind/pybind11/releases>`_
|
|
||||||
click "Draft a new release" on the far right, fill in the tag name
|
- GUI method: Under `releases <https://github.com/pybind/pybind11/releases>`_
|
||||||
(if you didn't tag above, it will be made here), fill in a release name
|
click "Draft a new release" on the far right, fill in the tag name
|
||||||
like "Version X.Y.Z", and copy-and-paste the markdown-formatted (!) changelog
|
(if you didn't tag above, it will be made here), fill in a release name
|
||||||
into the description (usually ``cat docs/changelog.rst | pandoc -f rst -t gfm``).
|
like "Version X.Y.Z", and copy-and-paste the markdown-formatted (!) changelog
|
||||||
Check "pre-release" if this is a beta/RC.
|
into the description. You can use ``cat docs/changelog.rst | pandoc -f rst -t gfm``,
|
||||||
- CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"``
|
then manually remove line breaks and strip links to PRs and issues,
|
||||||
If this is a pre-release, add ``-p``.
|
e.g. to a bare ``#1234``, without the surrounding ``<...>_`` hyperlink markup.
|
||||||
|
Check "pre-release" if this is a beta/RC.
|
||||||
|
|
||||||
|
- CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"``
|
||||||
|
If this is a pre-release, add ``-p``.
|
||||||
|
|
||||||
- Get back to work
|
- Get back to work
|
||||||
- Make sure you are on master, not somewhere else: ``git checkout master``
|
|
||||||
- Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to
|
- Make sure you are on master, not somewhere else: ``git checkout master``
|
||||||
``0.dev1`` and increment MINOR).
|
|
||||||
- Update ``_version.py`` to match
|
- Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to
|
||||||
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
|
``0.dev1`` and increment MINOR).
|
||||||
- Add a spot for in-development updates in ``docs/changelog.rst``.
|
|
||||||
- ``git add``, ``git commit``, ``git push``
|
- Update ``pybind11/_version.py`` to match.
|
||||||
|
|
||||||
|
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
|
||||||
|
|
||||||
|
- If the release was a new MINOR version, add a new ``IN DEVELOPMENT``
|
||||||
|
section in ``docs/changelog.rst``.
|
||||||
|
|
||||||
|
- ``git add``, ``git commit``, ``git push``
|
||||||
|
|
||||||
If a version branch is updated, remember to set PATCH to ``1.dev1``.
|
If a version branch is updated, remember to set PATCH to ``1.dev1``.
|
||||||
|
|
||||||
|
@ -89,7 +129,11 @@ merge it if there are no issues.
|
||||||
Manual packaging
|
Manual packaging
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
If you need to manually upload releases, you can download the releases from the job artifacts and upload them with twine. You can also make the files locally (not recommended in general, as your local directory is more likely to be "dirty" and SDists love picking up random unrelated/hidden files); this is the procedure:
|
If you need to manually upload releases, you can download the releases from
|
||||||
|
the job artifacts and upload them with twine. You can also make the files
|
||||||
|
locally (not recommended in general, as your local directory is more likely
|
||||||
|
to be "dirty" and SDists love picking up random unrelated/hidden files);
|
||||||
|
this is the procedure:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
breathe
|
||||||
|
furo
|
||||||
|
sphinx
|
||||||
|
sphinx-copybutton
|
||||||
|
sphinxcontrib-moderncmakedomain
|
||||||
|
sphinxcontrib-svg2pdfconverter
|
|
@ -1,6 +1,275 @@
|
||||||
breathe==4.34.0
|
# This file was autogenerated by uv via the following command:
|
||||||
furo==2022.6.21
|
# uv pip compile --generate-hashes docs/requirements.in -o docs/requirements.txt
|
||||||
sphinx==5.0.2
|
alabaster==0.7.16 \
|
||||||
sphinx-copybutton==0.5.0
|
--hash=sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65 \
|
||||||
sphinxcontrib-moderncmakedomain==3.21.4
|
--hash=sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92
|
||||||
sphinxcontrib-svg2pdfconverter==1.2.0
|
# via sphinx
|
||||||
|
babel==2.14.0 \
|
||||||
|
--hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
|
||||||
|
--hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
|
||||||
|
# via sphinx
|
||||||
|
beautifulsoup4==4.12.3 \
|
||||||
|
--hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \
|
||||||
|
--hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed
|
||||||
|
# via furo
|
||||||
|
breathe==4.35.0 \
|
||||||
|
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
|
||||||
|
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
|
||||||
|
# via -r requirements.in
|
||||||
|
certifi==2024.2.2 \
|
||||||
|
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||||
|
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||||
|
# via requests
|
||||||
|
charset-normalizer==3.3.2 \
|
||||||
|
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||||
|
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
|
||||||
|
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
|
||||||
|
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
|
||||||
|
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
|
||||||
|
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
|
||||||
|
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
|
||||||
|
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
|
||||||
|
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
|
||||||
|
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
|
||||||
|
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
|
||||||
|
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
|
||||||
|
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
|
||||||
|
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
|
||||||
|
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
|
||||||
|
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
|
||||||
|
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
|
||||||
|
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
|
||||||
|
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
|
||||||
|
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
|
||||||
|
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
|
||||||
|
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
|
||||||
|
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
|
||||||
|
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
|
||||||
|
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
|
||||||
|
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
|
||||||
|
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
|
||||||
|
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
|
||||||
|
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
|
||||||
|
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
|
||||||
|
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
|
||||||
|
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
|
||||||
|
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
|
||||||
|
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
|
||||||
|
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
|
||||||
|
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
|
||||||
|
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
|
||||||
|
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
|
||||||
|
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
|
||||||
|
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
|
||||||
|
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
|
||||||
|
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
|
||||||
|
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
|
||||||
|
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
|
||||||
|
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
|
||||||
|
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
|
||||||
|
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
|
||||||
|
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
|
||||||
|
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
|
||||||
|
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
|
||||||
|
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
|
||||||
|
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
|
||||||
|
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
|
||||||
|
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
|
||||||
|
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
|
||||||
|
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
|
||||||
|
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
|
||||||
|
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
|
||||||
|
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
|
||||||
|
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
|
||||||
|
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
|
||||||
|
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
|
||||||
|
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
|
||||||
|
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
|
||||||
|
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
|
||||||
|
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
|
||||||
|
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
|
||||||
|
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
|
||||||
|
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
|
||||||
|
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
|
||||||
|
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
|
||||||
|
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
|
||||||
|
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
|
||||||
|
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
|
||||||
|
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
|
||||||
|
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
|
||||||
|
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
|
||||||
|
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
|
||||||
|
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
|
||||||
|
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
|
||||||
|
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
|
||||||
|
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
|
||||||
|
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
|
||||||
|
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
|
||||||
|
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
|
||||||
|
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
|
||||||
|
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
|
||||||
|
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
|
||||||
|
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
|
||||||
|
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
|
||||||
|
# via requests
|
||||||
|
docutils==0.20.1 \
|
||||||
|
--hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
|
||||||
|
--hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
|
||||||
|
# via
|
||||||
|
# breathe
|
||||||
|
# sphinx
|
||||||
|
furo==2024.1.29 \
|
||||||
|
--hash=sha256:3548be2cef45a32f8cdc0272d415fcb3e5fa6a0eb4ddfe21df3ecf1fe45a13cf \
|
||||||
|
--hash=sha256:4d6b2fe3f10a6e36eb9cc24c1e7beb38d7a23fc7b3c382867503b7fcac8a1e02
|
||||||
|
# via -r requirements.in
|
||||||
|
idna==3.7 \
|
||||||
|
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
|
||||||
|
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
|
||||||
|
# via requests
|
||||||
|
imagesize==1.4.1 \
|
||||||
|
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
|
||||||
|
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
|
||||||
|
# via sphinx
|
||||||
|
jinja2==3.1.4 \
|
||||||
|
--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
|
||||||
|
--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
|
||||||
|
# via sphinx
|
||||||
|
markupsafe==2.1.5 \
|
||||||
|
--hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \
|
||||||
|
--hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \
|
||||||
|
--hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \
|
||||||
|
--hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \
|
||||||
|
--hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \
|
||||||
|
--hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \
|
||||||
|
--hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \
|
||||||
|
--hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \
|
||||||
|
--hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \
|
||||||
|
--hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \
|
||||||
|
--hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \
|
||||||
|
--hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \
|
||||||
|
--hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \
|
||||||
|
--hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \
|
||||||
|
--hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \
|
||||||
|
--hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \
|
||||||
|
--hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \
|
||||||
|
--hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \
|
||||||
|
--hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \
|
||||||
|
--hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \
|
||||||
|
--hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \
|
||||||
|
--hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \
|
||||||
|
--hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \
|
||||||
|
--hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \
|
||||||
|
--hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \
|
||||||
|
--hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \
|
||||||
|
--hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \
|
||||||
|
--hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \
|
||||||
|
--hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \
|
||||||
|
--hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \
|
||||||
|
--hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \
|
||||||
|
--hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \
|
||||||
|
--hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \
|
||||||
|
--hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \
|
||||||
|
--hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \
|
||||||
|
--hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \
|
||||||
|
--hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \
|
||||||
|
--hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \
|
||||||
|
--hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \
|
||||||
|
--hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \
|
||||||
|
--hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \
|
||||||
|
--hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \
|
||||||
|
--hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \
|
||||||
|
--hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \
|
||||||
|
--hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \
|
||||||
|
--hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \
|
||||||
|
--hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \
|
||||||
|
--hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \
|
||||||
|
--hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \
|
||||||
|
--hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \
|
||||||
|
--hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \
|
||||||
|
--hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \
|
||||||
|
--hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \
|
||||||
|
--hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \
|
||||||
|
--hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \
|
||||||
|
--hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \
|
||||||
|
--hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \
|
||||||
|
--hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \
|
||||||
|
--hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \
|
||||||
|
--hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68
|
||||||
|
# via jinja2
|
||||||
|
packaging==24.0 \
|
||||||
|
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
|
||||||
|
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
|
||||||
|
# via sphinx
|
||||||
|
pygments==2.17.2 \
|
||||||
|
--hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
|
||||||
|
--hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
|
||||||
|
# via
|
||||||
|
# furo
|
||||||
|
# sphinx
|
||||||
|
requests==2.32.0 \
|
||||||
|
--hash=sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5 \
|
||||||
|
--hash=sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8
|
||||||
|
# via sphinx
|
||||||
|
snowballstemmer==2.2.0 \
|
||||||
|
--hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
|
||||||
|
--hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
|
||||||
|
# via sphinx
|
||||||
|
soupsieve==2.5 \
|
||||||
|
--hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \
|
||||||
|
--hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7
|
||||||
|
# via beautifulsoup4
|
||||||
|
sphinx==7.2.6 \
|
||||||
|
--hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
|
||||||
|
--hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
|
||||||
|
# via
|
||||||
|
# -r requirements.in
|
||||||
|
# breathe
|
||||||
|
# furo
|
||||||
|
# sphinx-basic-ng
|
||||||
|
# sphinx-copybutton
|
||||||
|
# sphinxcontrib-moderncmakedomain
|
||||||
|
# sphinxcontrib-svg2pdfconverter
|
||||||
|
sphinx-basic-ng==1.0.0b2 \
|
||||||
|
--hash=sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9 \
|
||||||
|
--hash=sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b
|
||||||
|
# via furo
|
||||||
|
sphinx-copybutton==0.5.2 \
|
||||||
|
--hash=sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd \
|
||||||
|
--hash=sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e
|
||||||
|
# via -r requirements.in
|
||||||
|
sphinxcontrib-applehelp==1.0.8 \
|
||||||
|
--hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \
|
||||||
|
--hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4
|
||||||
|
# via sphinx
|
||||||
|
sphinxcontrib-devhelp==1.0.6 \
|
||||||
|
--hash=sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f \
|
||||||
|
--hash=sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3
|
||||||
|
# via sphinx
|
||||||
|
sphinxcontrib-htmlhelp==2.0.5 \
|
||||||
|
--hash=sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015 \
|
||||||
|
--hash=sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04
|
||||||
|
# via sphinx
|
||||||
|
sphinxcontrib-jsmath==1.0.1 \
|
||||||
|
--hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
|
||||||
|
--hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
|
||||||
|
# via sphinx
|
||||||
|
sphinxcontrib-moderncmakedomain==3.27.0 \
|
||||||
|
--hash=sha256:51e259e91f58d17cc0fac9307fd40106aa59d5acaa741887903fc3660361d1a1 \
|
||||||
|
--hash=sha256:70a73e0e7cff1b117074e968ccb7f72383ed0f572414df0e216cea06914de988
|
||||||
|
# via -r requirements.in
|
||||||
|
sphinxcontrib-qthelp==1.0.7 \
|
||||||
|
--hash=sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6 \
|
||||||
|
--hash=sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182
|
||||||
|
# via sphinx
|
||||||
|
sphinxcontrib-serializinghtml==1.1.10 \
|
||||||
|
--hash=sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7 \
|
||||||
|
--hash=sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f
|
||||||
|
# via sphinx
|
||||||
|
sphinxcontrib-svg2pdfconverter==1.2.2 \
|
||||||
|
--hash=sha256:04ec767b55780a6b18d89cc1a8ada6d900c6efde9d1683abdb98a49b144465ca \
|
||||||
|
--hash=sha256:80a55ca61f70eae93efc65f3814f2f177c86ba55934a9f6c5022f1778b62146b
|
||||||
|
# via -r requirements.in
|
||||||
|
urllib3==2.2.2 \
|
||||||
|
--hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
|
||||||
|
--hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
|
||||||
|
# via requests
|
||||||
|
|
|
@ -8,6 +8,34 @@ to a new version. But it goes into more detail. This includes things like
|
||||||
deprecated APIs and their replacements, build system changes, general code
|
deprecated APIs and their replacements, build system changes, general code
|
||||||
modernization and other useful information.
|
modernization and other useful information.
|
||||||
|
|
||||||
|
.. _upgrade-guide-2.12:
|
||||||
|
|
||||||
|
v2.12
|
||||||
|
=====
|
||||||
|
|
||||||
|
NumPy support has been upgraded to support the 2.x series too. The two relevant
|
||||||
|
changes are that:
|
||||||
|
|
||||||
|
* ``dtype.flags()`` is now a ``uint64`` and ``dtype.alignment()`` an
|
||||||
|
``ssize_t`` (and NumPy may return an larger than integer value for
|
||||||
|
``itemsize()`` in NumPy 2.x).
|
||||||
|
|
||||||
|
* The long deprecated NumPy function ``PyArray_GetArrayParamsFromObject``
|
||||||
|
function is not available anymore.
|
||||||
|
|
||||||
|
Due to NumPy changes, you may experience difficulties updating to NumPy 2.
|
||||||
|
Please see the [NumPy 2 migration guide](https://numpy.org/devdocs/numpy_2_0_migration_guide.html) for details.
|
||||||
|
For example, a more direct change could be that the default integer ``"int_"``
|
||||||
|
(and ``"uint"``) is now ``ssize_t`` and not ``long`` (affects 64bit windows).
|
||||||
|
|
||||||
|
If you want to only support NumPy 1.x for now and are having problems due to
|
||||||
|
the two internal changes listed above, you can define
|
||||||
|
``PYBIND11_NUMPY_1_ONLY`` to disable the new support for now. Make sure you
|
||||||
|
define this on all pybind11 compile units, since it could be a source of ODR
|
||||||
|
violations if used inconsistently. This option will be removed in the future,
|
||||||
|
so adapting your code is highly recommended.
|
||||||
|
|
||||||
|
|
||||||
.. _upgrade-guide-2.11:
|
.. _upgrade-guide-2.11:
|
||||||
|
|
||||||
v2.11
|
v2.11
|
||||||
|
|
|
@ -102,22 +102,22 @@ struct buffer_info {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
|
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
|
||||||
: buffer_info(
|
: buffer_info(
|
||||||
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
|
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
|
||||||
|
|
||||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||||
: buffer_info(
|
: buffer_info(
|
||||||
view->buf,
|
view->buf,
|
||||||
view->itemsize,
|
view->itemsize,
|
||||||
view->format,
|
view->format,
|
||||||
view->ndim,
|
view->ndim,
|
||||||
{view->shape, view->shape + view->ndim},
|
{view->shape, view->shape + view->ndim},
|
||||||
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
|
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
|
||||||
* ignore this flag and return a view with NULL strides.
|
* ignore this flag and return a view with NULL strides.
|
||||||
* When strides are NULL, build them manually. */
|
* When strides are NULL, build them manually. */
|
||||||
view->strides
|
view->strides
|
||||||
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
|
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
|
||||||
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
|
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
|
||||||
(view->readonly != 0)) {
|
(view->readonly != 0)) {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||||
this->m_view = view;
|
this->m_view = view;
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||||
|
@ -176,7 +176,7 @@ private:
|
||||||
detail::any_container<ssize_t> &&strides_in,
|
detail::any_container<ssize_t> &&strides_in,
|
||||||
bool readonly)
|
bool readonly)
|
||||||
: buffer_info(
|
: buffer_info(
|
||||||
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
|
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
|
||||||
|
|
||||||
Py_buffer *m_view = nullptr;
|
Py_buffer *m_view = nullptr;
|
||||||
bool ownview = false;
|
bool ownview = false;
|
||||||
|
|
|
@ -42,13 +42,15 @@ using make_caster = type_caster<intrinsic_t<type>>;
|
||||||
// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
|
// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
|
typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
|
||||||
return caster.operator typename make_caster<T>::template cast_op_type<T>();
|
using result_t = typename make_caster<T>::template cast_op_type<T>; // See PR #4893
|
||||||
|
return caster.operator result_t();
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>
|
typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>
|
||||||
cast_op(make_caster<T> &&caster) {
|
cast_op(make_caster<T> &&caster) {
|
||||||
return std::move(caster).operator typename make_caster<T>::
|
using result_t = typename make_caster<T>::template cast_op_type<
|
||||||
template cast_op_type<typename std::add_rvalue_reference<T>::type>();
|
typename std::add_rvalue_reference<T>::type>; // See PR #4893
|
||||||
|
return std::move(caster).operator result_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
|
@ -325,8 +327,9 @@ public:
|
||||||
value = false;
|
value = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) {
|
if (convert || is_numpy_bool(src)) {
|
||||||
// (allow non-implicit conversion for numpy booleans)
|
// (allow non-implicit conversion for numpy booleans), use strncmp
|
||||||
|
// since NumPy 1.x had an additional trailing underscore.
|
||||||
|
|
||||||
Py_ssize_t res = -1;
|
Py_ssize_t res = -1;
|
||||||
if (src.is_none()) {
|
if (src.is_none()) {
|
||||||
|
@ -358,6 +361,15 @@ public:
|
||||||
return handle(src ? Py_True : Py_False).inc_ref();
|
return handle(src ? Py_True : Py_False).inc_ref();
|
||||||
}
|
}
|
||||||
PYBIND11_TYPE_CASTER(bool, const_name("bool"));
|
PYBIND11_TYPE_CASTER(bool, const_name("bool"));
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Test if an object is a NumPy boolean (without fetching the type).
|
||||||
|
static inline bool is_numpy_bool(handle object) {
|
||||||
|
const char *type_name = Py_TYPE(object.ptr())->tp_name;
|
||||||
|
// Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support
|
||||||
|
return std::strcmp("numpy.bool", type_name) == 0
|
||||||
|
|| std::strcmp("numpy.bool_", type_name) == 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper class for UTF-{8,16,32} C++ stl strings:
|
// Helper class for UTF-{8,16,32} C++ stl strings:
|
||||||
|
@ -660,8 +672,9 @@ public:
|
||||||
return cast(*src, policy, parent);
|
return cast(*src, policy, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto name
|
static constexpr auto name = const_name("tuple[")
|
||||||
= const_name("Tuple[") + concat(make_caster<Ts>::name...) + const_name("]");
|
+ ::pybind11::detail::concat(make_caster<Ts>::name...)
|
||||||
|
+ const_name("]");
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using cast_op_type = type;
|
using cast_op_type = type;
|
||||||
|
@ -869,10 +882,53 @@ struct is_holder_type
|
||||||
template <typename base, typename deleter>
|
template <typename base, typename deleter>
|
||||||
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
|
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
|
||||||
|
|
||||||
|
#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888
|
||||||
|
|
||||||
|
// This leads to compilation errors if a specialization is missing.
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct handle_type_name {
|
struct handle_type_name {
|
||||||
static constexpr auto name = const_name<T>();
|
static constexpr auto name = const_name<T>();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<object> {
|
||||||
|
static constexpr auto name = const_name("object");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<list> {
|
||||||
|
static constexpr auto name = const_name("list");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<dict> {
|
||||||
|
static constexpr auto name = const_name("dict");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<anyset> {
|
||||||
|
static constexpr auto name = const_name("Union[set, frozenset]");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<set> {
|
||||||
|
static constexpr auto name = const_name("set");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<frozenset> {
|
||||||
|
static constexpr auto name = const_name("frozenset");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<str> {
|
||||||
|
static constexpr auto name = const_name("str");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<tuple> {
|
||||||
|
static constexpr auto name = const_name("tuple");
|
||||||
|
};
|
||||||
template <>
|
template <>
|
||||||
struct handle_type_name<bool_> {
|
struct handle_type_name<bool_> {
|
||||||
static constexpr auto name = const_name("bool");
|
static constexpr auto name = const_name("bool");
|
||||||
|
@ -882,6 +938,10 @@ struct handle_type_name<bytes> {
|
||||||
static constexpr auto name = const_name(PYBIND11_BYTES_NAME);
|
static constexpr auto name = const_name(PYBIND11_BYTES_NAME);
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
|
struct handle_type_name<buffer> {
|
||||||
|
static constexpr auto name = const_name("Buffer");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
struct handle_type_name<int_> {
|
struct handle_type_name<int_> {
|
||||||
static constexpr auto name = const_name("int");
|
static constexpr auto name = const_name("int");
|
||||||
};
|
};
|
||||||
|
@ -898,10 +958,50 @@ struct handle_type_name<float_> {
|
||||||
static constexpr auto name = const_name("float");
|
static constexpr auto name = const_name("float");
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
|
struct handle_type_name<function> {
|
||||||
|
static constexpr auto name = const_name("Callable");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<handle> {
|
||||||
|
static constexpr auto name = handle_type_name<object>::name;
|
||||||
|
};
|
||||||
|
template <>
|
||||||
struct handle_type_name<none> {
|
struct handle_type_name<none> {
|
||||||
static constexpr auto name = const_name("None");
|
static constexpr auto name = const_name("None");
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
|
struct handle_type_name<sequence> {
|
||||||
|
static constexpr auto name = const_name("Sequence");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<bytearray> {
|
||||||
|
static constexpr auto name = const_name("bytearray");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<memoryview> {
|
||||||
|
static constexpr auto name = const_name("memoryview");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<slice> {
|
||||||
|
static constexpr auto name = const_name("slice");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<type> {
|
||||||
|
static constexpr auto name = const_name("type");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<capsule> {
|
||||||
|
static constexpr auto name = const_name("capsule");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<ellipsis> {
|
||||||
|
static constexpr auto name = const_name("ellipsis");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<weakref> {
|
||||||
|
static constexpr auto name = const_name("weakref");
|
||||||
|
};
|
||||||
|
template <>
|
||||||
struct handle_type_name<args> {
|
struct handle_type_name<args> {
|
||||||
static constexpr auto name = const_name("*args");
|
static constexpr auto name = const_name("*args");
|
||||||
};
|
};
|
||||||
|
@ -909,6 +1009,30 @@ template <>
|
||||||
struct handle_type_name<kwargs> {
|
struct handle_type_name<kwargs> {
|
||||||
static constexpr auto name = const_name("**kwargs");
|
static constexpr auto name = const_name("**kwargs");
|
||||||
};
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<obj_attr_accessor> {
|
||||||
|
static constexpr auto name = const_name<obj_attr_accessor>();
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<str_attr_accessor> {
|
||||||
|
static constexpr auto name = const_name<str_attr_accessor>();
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<item_accessor> {
|
||||||
|
static constexpr auto name = const_name<item_accessor>();
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<sequence_accessor> {
|
||||||
|
static constexpr auto name = const_name<sequence_accessor>();
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<list_accessor> {
|
||||||
|
static constexpr auto name = const_name<list_accessor>();
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<tuple_accessor> {
|
||||||
|
static constexpr auto name = const_name<tuple_accessor>();
|
||||||
|
};
|
||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
struct pyobject_caster {
|
struct pyobject_caster {
|
||||||
|
@ -1215,13 +1339,24 @@ enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&,
|
||||||
// static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast
|
// static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast
|
||||||
// that only does anything in cases where pybind11::cast is valid.
|
// that only does anything in cases where pybind11::cast is valid.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
|
enable_if_t<cast_is_temporary_value_reference<T>::value
|
||||||
|
&& !detail::is_same_ignoring_cvref<T, PyObject *>::value,
|
||||||
|
T>
|
||||||
|
cast_safe(object &&) {
|
||||||
pybind11_fail("Internal error: cast_safe fallback invoked");
|
pybind11_fail("Internal error: cast_safe fallback invoked");
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<std::is_void<T>::value, void> cast_safe(object &&) {}
|
enable_if_t<std::is_void<T>::value, void> cast_safe(object &&) {}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>, std::is_void<T>>::value, T>
|
enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value, PyObject *>
|
||||||
|
cast_safe(object &&o) {
|
||||||
|
return o.release().ptr();
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>,
|
||||||
|
detail::is_same_ignoring_cvref<T, PyObject *>,
|
||||||
|
std::is_void<T>>::value,
|
||||||
|
T>
|
||||||
cast_safe(object &&o) {
|
cast_safe(object &&o) {
|
||||||
return pybind11::cast<T>(std::move(o));
|
return pybind11::cast<T>(std::move(o));
|
||||||
}
|
}
|
||||||
|
@ -1377,7 +1512,15 @@ inline namespace literals {
|
||||||
/** \rst
|
/** \rst
|
||||||
String literal version of `arg`
|
String literal version of `arg`
|
||||||
\endrst */
|
\endrst */
|
||||||
constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
|
constexpr arg
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
|
||||||
|
operator"" _a // gcc 4.8.5 insists on having a space (hard error).
|
||||||
|
#else
|
||||||
|
operator""_a // clang 17 generates a deprecation warning if there is a space.
|
||||||
|
#endif
|
||||||
|
(const char *name, size_t) {
|
||||||
|
return arg(name);
|
||||||
|
}
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
@ -1438,7 +1581,8 @@ public:
|
||||||
static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(),
|
static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(),
|
||||||
"py::args cannot be specified more than once");
|
"py::args cannot be specified more than once");
|
||||||
|
|
||||||
static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...);
|
static constexpr auto arg_names
|
||||||
|
= ::pybind11::detail::concat(type_descr(make_caster<Args>::name)...);
|
||||||
|
|
||||||
bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }
|
bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }
|
||||||
|
|
||||||
|
|
|
@ -86,17 +86,16 @@ inline PyTypeObject *make_static_property_type() {
|
||||||
type->tp_descr_get = pybind11_static_get;
|
type->tp_descr_get = pybind11_static_get;
|
||||||
type->tp_descr_set = pybind11_static_set;
|
type->tp_descr_set = pybind11_static_set;
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
|
||||||
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
|
|
||||||
}
|
|
||||||
|
|
||||||
# if PY_VERSION_HEX >= 0x030C0000
|
# if PY_VERSION_HEX >= 0x030C0000
|
||||||
// PRE 3.12 FEATURE FREEZE. PLEASE REVIEW AFTER FREEZE.
|
|
||||||
// Since Python-3.12 property-derived types are required to
|
// Since Python-3.12 property-derived types are required to
|
||||||
// have dynamic attributes (to set `__doc__`)
|
// have dynamic attributes (to set `__doc__`)
|
||||||
enable_dynamic_attributes(heap_type);
|
enable_dynamic_attributes(heap_type);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
if (PyType_Ready(type) < 0) {
|
||||||
|
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
|
||||||
|
}
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
|
|
||||||
|
@ -189,12 +188,10 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This must be a pybind11 instance
|
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
|
||||||
|
|
||||||
// Ensure that the base __init__ function(s) were called
|
// Ensure that the base __init__ function(s) were called
|
||||||
for (const auto &vh : values_and_holders(instance)) {
|
values_and_holders vhs(self);
|
||||||
if (!vh.holder_constructed()) {
|
for (const auto &vh : vhs) {
|
||||||
|
if (!vh.holder_constructed() && !vhs.is_redundant_value_and_holder(vh)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s.__init__() must be called when overriding __init__",
|
"%.200s.__init__() must be called when overriding __init__",
|
||||||
get_fully_qualified_tp_name(vh.type->type).c_str());
|
get_fully_qualified_tp_name(vh.type->type).c_str());
|
||||||
|
@ -208,39 +205,40 @@ 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) {
|
||||||
auto *type = (PyTypeObject *) obj;
|
with_internals([obj](internals &internals) {
|
||||||
auto &internals = get_internals();
|
auto *type = (PyTypeObject *) obj;
|
||||||
|
|
||||||
// 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 {
|
|
||||||
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 {
|
} else {
|
||||||
++it;
|
internals.registered_types_cpp.erase(tindex);
|
||||||
}
|
}
|
||||||
}
|
internals.registered_types_py.erase(tinfo->type);
|
||||||
|
|
||||||
delete tinfo;
|
// Actually just `std::erase_if`, but that's only available in C++20
|
||||||
}
|
auto &cache = internals.inactive_override_cache;
|
||||||
|
for (auto it = cache.begin(), last = cache.end(); it != last;) {
|
||||||
|
if (it->first == (PyObject *) tinfo->type) {
|
||||||
|
it = cache.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete tinfo;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
PyType_Type.tp_dealloc(obj);
|
PyType_Type.tp_dealloc(obj);
|
||||||
}
|
}
|
||||||
|
@ -313,19 +311,20 @@ 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) {
|
||||||
get_internals().registered_instances.emplace(ptr, self);
|
with_instance_map(ptr, [&](instance_map &instances) { instances.emplace(ptr, self); });
|
||||||
return true; // unused, but gives the same signature as the deregister func
|
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) {
|
||||||
auto ®istered_instances = get_internals().registered_instances;
|
return with_instance_map(ptr, [&](instance_map &instances) {
|
||||||
auto range = registered_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) {
|
||||||
if (self == it->second) {
|
if (self == it->second) {
|
||||||
registered_instances.erase(it);
|
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) {
|
||||||
|
@ -375,28 +374,37 @@ extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *,
|
||||||
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
||||||
PyTypeObject *type = Py_TYPE(self);
|
PyTypeObject *type = Py_TYPE(self);
|
||||||
std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!";
|
std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!";
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
set_error(PyExc_TypeError, msg.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
auto &internals = get_internals();
|
std::vector<PyObject *> patients;
|
||||||
auto pos = internals.patients.find(self);
|
|
||||||
assert(pos != internals.patients.end());
|
with_internals([&](internals &internals) {
|
||||||
// Clearing the patients can cause more Python code to run, which
|
auto pos = internals.patients.find(self);
|
||||||
// can invalidate the iterator. Extract the vector of patients
|
|
||||||
// from the unordered_map first.
|
if (pos == internals.patients.end()) {
|
||||||
auto patients = std::move(pos->second);
|
pybind11_fail(
|
||||||
internals.patients.erase(pos);
|
"FATAL: Internal consistency check failed: Invalid clear_patients() call.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clearing the patients can cause more Python code to run, which
|
||||||
|
// can invalidate the iterator. Extract the vector of patients
|
||||||
|
// from the unordered_map first.
|
||||||
|
patients = std::move(pos->second);
|
||||||
|
internals.patients.erase(pos);
|
||||||
|
});
|
||||||
|
|
||||||
instance->has_patients = false;
|
instance->has_patients = false;
|
||||||
for (PyObject *&patient : patients) {
|
for (PyObject *&patient : patients) {
|
||||||
Py_CLEAR(patient);
|
Py_CLEAR(patient);
|
||||||
|
@ -522,8 +530,12 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
||||||
|
|
||||||
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
|
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
|
||||||
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
||||||
|
#if PY_VERSION_HEX >= 0x030D0000
|
||||||
|
PyObject_VisitManagedDict(self, visit, arg);
|
||||||
|
#else
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
Py_VISIT(dict);
|
Py_VISIT(dict);
|
||||||
|
#endif
|
||||||
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
|
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
|
||||||
#if PY_VERSION_HEX >= 0x03090000
|
#if PY_VERSION_HEX >= 0x03090000
|
||||||
Py_VISIT(Py_TYPE(self));
|
Py_VISIT(Py_TYPE(self));
|
||||||
|
@ -533,8 +545,12 @@ extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *a
|
||||||
|
|
||||||
/// dynamic_attr: Allow the GC to clear the dictionary.
|
/// dynamic_attr: Allow the GC to clear the dictionary.
|
||||||
extern "C" inline int pybind11_clear(PyObject *self) {
|
extern "C" inline int pybind11_clear(PyObject *self) {
|
||||||
|
#if PY_VERSION_HEX >= 0x030D0000
|
||||||
|
PyObject_ClearManagedDict(self);
|
||||||
|
#else
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
Py_CLEAR(dict);
|
Py_CLEAR(dict);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,17 +567,9 @@ 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[]
|
||||||
#if PY_VERSION_HEX < 0x03070000
|
= {{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, nullptr, nullptr},
|
||||||
const_cast<char *>("__dict__"),
|
{nullptr, nullptr, nullptr, nullptr, nullptr}};
|
||||||
#else
|
|
||||||
"__dict__",
|
|
||||||
#endif
|
|
||||||
PyObject_GenericGetDict,
|
|
||||||
PyObject_GenericSetDict,
|
|
||||||
nullptr,
|
|
||||||
nullptr},
|
|
||||||
{nullptr, nullptr, nullptr, nullptr, nullptr}};
|
|
||||||
type->tp_getset = getset;
|
type->tp_getset = getset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,7 +587,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
||||||
if (view) {
|
if (view) {
|
||||||
view->obj = nullptr;
|
view->obj = nullptr;
|
||||||
}
|
}
|
||||||
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
set_error(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
std::memset(view, 0, sizeof(Py_buffer));
|
std::memset(view, 0, sizeof(Py_buffer));
|
||||||
|
@ -587,7 +595,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
||||||
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
|
||||||
PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
set_error(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
view->obj = obj;
|
view->obj = obj;
|
||||||
|
@ -653,10 +661,13 @@ 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 (using PyObject_MALLOC, since
|
/* Allocate memory for docstring (Python will free this later on) */
|
||||||
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 11
|
#define PYBIND11_VERSION_MINOR 13
|
||||||
#define PYBIND11_VERSION_PATCH 1
|
#define PYBIND11_VERSION_PATCH 1
|
||||||
|
|
||||||
// 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 0x020B0100
|
#define PYBIND11_VERSION_HEX 0x020D0100
|
||||||
|
|
||||||
// Define some generic pybind11 helper macros for warning management.
|
// Define some generic pybind11 helper macros for warning management.
|
||||||
//
|
//
|
||||||
|
@ -118,6 +118,14 @@
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(PYBIND11_CPP20)
|
||||||
|
# define PYBIND11_CONSTINIT constinit
|
||||||
|
# define PYBIND11_DTOR_CONSTEXPR constexpr
|
||||||
|
#else
|
||||||
|
# define PYBIND11_CONSTINIT
|
||||||
|
# define PYBIND11_DTOR_CONSTEXPR
|
||||||
|
#endif
|
||||||
|
|
||||||
// Compiler version assertions
|
// Compiler version assertions
|
||||||
#if defined(__INTEL_COMPILER)
|
#if defined(__INTEL_COMPILER)
|
||||||
# if __INTEL_COMPILER < 1800
|
# if __INTEL_COMPILER < 1800
|
||||||
|
@ -264,9 +272,8 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000
|
#if PY_VERSION_HEX < 0x03070000
|
||||||
#if PY_VERSION_HEX < 0x03060000
|
# error "PYTHON < 3.7 IS UNSUPPORTED. pybind11 v2.12 was the last to support Python 3.6."
|
||||||
# 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>
|
||||||
|
@ -288,6 +295,10 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
|
||||||
# undef copysign
|
# undef copysign
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(PYBIND11_NUMPY_1_ONLY)
|
||||||
|
# define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
# define PYBIND11_SIMPLE_GIL_MANAGEMENT
|
# define PYBIND11_SIMPLE_GIL_MANAGEMENT
|
||||||
#endif
|
#endif
|
||||||
|
@ -399,7 +410,7 @@ PYBIND11_WARNING_POP
|
||||||
return nullptr; \
|
return nullptr; \
|
||||||
} \
|
} \
|
||||||
catch (const std::exception &e) { \
|
catch (const std::exception &e) { \
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
::pybind11::set_error(PyExc_ImportError, e.what()); \
|
||||||
return nullptr; \
|
return nullptr; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +463,7 @@ PYBIND11_WARNING_POP
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
\endrst */
|
\endrst */
|
||||||
#define PYBIND11_MODULE(name, variable) \
|
#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 \
|
||||||
|
@ -461,7 +472,10 @@ PYBIND11_WARNING_POP
|
||||||
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), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
PYBIND11_TOSTRING(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(); \
|
||||||
|
@ -913,8 +927,7 @@ using is_template_base_of
|
||||||
= decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr));
|
= decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr));
|
||||||
#else
|
#else
|
||||||
struct is_template_base_of
|
struct is_template_base_of
|
||||||
: decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)) {
|
: decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)){};
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Check if T is an instantiation of the template `Class`. For example:
|
/// Check if T is an instantiation of the template `Class`. For example:
|
||||||
|
@ -1096,14 +1109,14 @@ struct overload_cast_impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Return, typename Class>
|
template <typename Return, typename Class>
|
||||||
constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
|
constexpr auto operator()(Return (Class::*pmf)(Args...),
|
||||||
-> decltype(pmf) {
|
std::false_type = {}) const noexcept -> decltype(pmf) {
|
||||||
return pmf;
|
return pmf;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Return, typename Class>
|
template <typename Return, typename Class>
|
||||||
constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
|
constexpr auto operator()(Return (Class::*pmf)(Args...) const,
|
||||||
-> decltype(pmf) {
|
std::true_type) const noexcept -> decltype(pmf) {
|
||||||
return pmf;
|
return pmf;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -156,8 +156,9 @@ constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <size_t N, typename... Ts, typename... Args>
|
template <size_t N, typename... Ts, typename... Args>
|
||||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
constexpr auto concat(const descr<N, Ts...> &d,
|
||||||
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
const Args &...args) -> decltype(std::declval<descr<N + 2, Ts...>>()
|
||||||
|
+ concat(args...)) {
|
||||||
return d + const_name(", ") + concat(args...);
|
return d + const_name(", ") + concat(args...);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -65,7 +65,7 @@ constexpr bool is_alias(void *) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
||||||
// back to brace aggregate initiailization so that for aggregate initialization can be used with
|
// back to brace aggregate initialization so that for aggregate initialization can be used with
|
||||||
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
||||||
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
||||||
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
||||||
|
|
|
@ -11,13 +11,15 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
# include "../gil.h"
|
# include "../gil.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../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.
|
||||||
///
|
///
|
||||||
|
@ -34,8 +36,9 @@
|
||||||
/// further ABI-incompatible changes may be made before the ABI is officially
|
/// further ABI-incompatible changes may be made before the ABI is officially
|
||||||
/// changed to the new version.
|
/// changed to the new version.
|
||||||
#ifndef PYBIND11_INTERNALS_VERSION
|
#ifndef PYBIND11_INTERNALS_VERSION
|
||||||
# if PY_VERSION_HEX >= 0x030C0000
|
# 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.
|
||||||
# define PYBIND11_INTERNALS_VERSION 5
|
# define PYBIND11_INTERNALS_VERSION 5
|
||||||
# else
|
# else
|
||||||
# define PYBIND11_INTERNALS_VERSION 4
|
# define PYBIND11_INTERNALS_VERSION 4
|
||||||
|
@ -61,60 +64,41 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
||||||
|
|
||||||
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
// 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(__GNUC__) && !defined(__INTEL_COMPILER)
|
# if defined(__clang__)
|
||||||
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
|
# define PYBIND11_TLS_KEY_INIT(var) \
|
||||||
// for every field.
|
_Pragma("clang diagnostic push") /**/ \
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) \
|
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
||||||
_Pragma("GCC diagnostic push") /**/ \
|
Py_tss_t var \
|
||||||
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
= Py_tss_NEEDS_INIT; \
|
||||||
Py_tss_t var \
|
_Pragma("clang diagnostic pop")
|
||||||
= Py_tss_NEEDS_INIT; \
|
# elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||||
_Pragma("GCC diagnostic pop")
|
# define PYBIND11_TLS_KEY_INIT(var) \
|
||||||
# else
|
_Pragma("GCC diagnostic push") /**/ \
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
|
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
||||||
# endif
|
Py_tss_t var \
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
|
= Py_tss_NEEDS_INIT; \
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
|
_Pragma("GCC diagnostic pop")
|
||||||
# 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 *
|
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
|
||||||
# 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
|
||||||
// Usually an int but a long on Cygwin64 with Python 3.x
|
# define PYBIND11_TLS_KEY_REF Py_tss_t *
|
||||||
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
|
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
# define PYBIND11_TLS_KEY_CREATE(var) \
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
||||||
# if defined(PYPY_VERSION)
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
||||||
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
||||||
// the value if it has already been set. Instead, it must first be deleted and
|
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
||||||
// 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
|
||||||
|
@ -162,15 +146,33 @@ struct override_hash {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using instance_map = std::unordered_multimap<const void *, instance *>;
|
||||||
|
|
||||||
|
// Instance map shards are used to reduce mutex contention in free-threaded Python.
|
||||||
|
struct instance_map_shard {
|
||||||
|
std::mutex mutex;
|
||||||
|
instance_map registered_instances;
|
||||||
|
// alignas(64) would be better, but causes compile errors in macOS before 10.14 (see #5200)
|
||||||
|
char padding[64 - (sizeof(std::mutex) + sizeof(instance_map)) % 64];
|
||||||
|
};
|
||||||
|
|
||||||
/// 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
|
||||||
|
std::mutex 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;
|
||||||
std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
|
#ifdef Py_GIL_DISABLED
|
||||||
|
std::unique_ptr<instance_map_shard[]> instance_shards; // void * -> instance*
|
||||||
|
size_t instance_shards_mask;
|
||||||
|
#else
|
||||||
|
instance_map registered_instances; // void * -> instance*
|
||||||
|
#endif
|
||||||
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
|
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;
|
||||||
|
@ -186,28 +188,27 @@ 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
|
||||||
|
@ -218,7 +219,6 @@ 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.
|
||||||
|
@ -291,31 +291,30 @@ struct type_info {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
|
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
|
||||||
|
/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898).
|
||||||
#ifndef PYBIND11_BUILD_ABI
|
#ifndef PYBIND11_BUILD_ABI
|
||||||
# if defined(__GXX_ABI_VERSION)
|
# if defined(__GXX_ABI_VERSION)
|
||||||
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
|
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# define PYBIND11_BUILD_ABI "_mscver" PYBIND11_TOSTRING(_MSC_VER)
|
||||||
# else
|
# else
|
||||||
# define PYBIND11_BUILD_ABI ""
|
# define PYBIND11_BUILD_ABI ""
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PYBIND11_INTERNALS_KIND
|
#ifndef PYBIND11_INTERNALS_KIND
|
||||||
# if defined(WITH_THREAD)
|
# define PYBIND11_INTERNALS_KIND ""
|
||||||
# define PYBIND11_INTERNALS_KIND ""
|
|
||||||
# else
|
|
||||||
# define PYBIND11_INTERNALS_KIND "_without_thread"
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
|
||||||
PYBIND11_BUILD_TYPE "__"
|
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_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
|
||||||
PYBIND11_BUILD_TYPE "__"
|
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`.
|
||||||
|
@ -352,7 +351,7 @@ inline bool raise_err(PyObject *exc_type, const char *msg) {
|
||||||
raise_from(exc_type, msg);
|
raise_from(exc_type, msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PyErr_SetString(exc_type, msg);
|
set_error(exc_type, msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,22 +446,39 @@ inline object get_python_state_dict() {
|
||||||
#endif
|
#endif
|
||||||
if (!state_dict) {
|
if (!state_dict) {
|
||||||
raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
|
raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
|
||||||
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return state_dict;
|
return 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_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));
|
return reinterpret_steal<object>(
|
||||||
|
dict_getitemstringref(state_dict.ptr(), PYBIND11_INTERNALS_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline internals **get_internals_pp_from_capsule(handle obj) {
|
inline internals **get_internals_pp_from_capsule(handle obj) {
|
||||||
void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr);
|
void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr);
|
||||||
if (raw_ptr == nullptr) {
|
if (raw_ptr == nullptr) {
|
||||||
raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED");
|
raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED");
|
||||||
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
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();
|
||||||
|
@ -470,10 +486,9 @@ PYBIND11_NOINLINE internals &get_internals() {
|
||||||
return **internals_pp;
|
return **internals_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WITH_THREAD)
|
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
# 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 {
|
||||||
|
@ -483,7 +498,6 @@ 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;
|
||||||
|
|
||||||
|
@ -508,7 +522,6 @@ 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)
|
||||||
|
@ -517,20 +530,29 @@ 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
|
|
||||||
internals_ptr->istate = tstate->interp;
|
|
||||||
#endif
|
#endif
|
||||||
|
internals_ptr->istate = tstate->interp;
|
||||||
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -544,7 +566,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 defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
#if PYBIND11_INTERNALS_VERSION == 4
|
||||||
|
|
||||||
// For ABI compatibility, we can't store the loader_life_support TLS key in
|
// 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
|
||||||
|
@ -577,7 +599,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 // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
#endif // 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.
|
||||||
|
@ -591,13 +613,80 @@ inline local_internals &get_local_internals() {
|
||||||
return *locals;
|
return *locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<std::mutex> lock((internals).mutex)
|
||||||
|
#else
|
||||||
|
# define PYBIND11_LOCK_INTERNALS(internals)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline auto with_internals(const F &cb) -> decltype(cb(get_internals())) {
|
||||||
|
auto &internals = get_internals();
|
||||||
|
PYBIND11_LOCK_INTERNALS(internals);
|
||||||
|
return cb(internals);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::uint64_t mix64(std::uint64_t z) {
|
||||||
|
// David Stafford's variant 13 of the MurmurHash3 finalizer popularized
|
||||||
|
// by the SplitMix PRNG.
|
||||||
|
// https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
|
||||||
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||||
|
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||||
|
return z ^ (z >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline auto with_instance_map(const void *ptr,
|
||||||
|
const F &cb) -> decltype(cb(std::declval<instance_map &>())) {
|
||||||
|
auto &internals = get_internals();
|
||||||
|
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
// Hash address to compute shard, but ignore low bits. We'd like allocations
|
||||||
|
// from the same thread/core to map to the same shard and allocations from
|
||||||
|
// other threads/cores to map to other shards. Using the high bits is a good
|
||||||
|
// heuristic because memory allocators often have a per-thread
|
||||||
|
// arena/superblock/segment from which smaller allocations are served.
|
||||||
|
auto addr = reinterpret_cast<std::uintptr_t>(ptr);
|
||||||
|
auto hash = mix64(static_cast<std::uint64_t>(addr >> 20));
|
||||||
|
auto idx = static_cast<size_t>(hash & internals.instance_shards_mask);
|
||||||
|
|
||||||
|
auto &shard = internals.instance_shards[idx];
|
||||||
|
std::unique_lock<std::mutex> 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<std::mutex> 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) {
|
||||||
auto &strings = get_internals().static_strings;
|
// GCC 4.8 doesn't like parameter unpack within lambda capture, so use
|
||||||
|
// PYBIND11_LOCK_INTERNALS.
|
||||||
|
auto &internals = get_internals();
|
||||||
|
PYBIND11_LOCK_INTERNALS(internals);
|
||||||
|
auto &strings = internals.static_strings;
|
||||||
strings.emplace_front(std::forward<Args>(args)...);
|
strings.emplace_front(std::forward<Args>(args)...);
|
||||||
return strings.front().c_str();
|
return strings.front().c_str();
|
||||||
}
|
}
|
||||||
|
@ -627,15 +716,18 @@ 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) {
|
||||||
auto &internals = detail::get_internals();
|
return detail::with_internals([&](detail::internals &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) {
|
||||||
detail::get_internals().shared_data[name] = data;
|
return detail::with_internals([&](detail::internals &internals) {
|
||||||
return data;
|
internals.shared_data[name] = 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
|
||||||
|
@ -643,14 +735,15 @@ PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
||||||
/// added to the shared data under the given name and a reference to it is returned.
|
/// 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) {
|
||||||
auto &internals = detail::get_internals();
|
return *detail::with_internals([&](detail::internals &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)
|
||||||
|
|
|
@ -36,14 +36,13 @@ 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()));
|
||||||
|
@ -51,15 +50,6 @@ 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
|
||||||
|
@ -102,8 +92,22 @@ public:
|
||||||
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);
|
||||||
|
|
||||||
|
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
||||||
|
inline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases,
|
||||||
|
type_info *addl_base) {
|
||||||
|
for (auto it = bases.begin(); it != bases.end(); it++) {
|
||||||
|
type_info *existing_base = *it;
|
||||||
|
if (PyType_IsSubtype(addl_base->type, existing_base->type) != 0) {
|
||||||
|
bases.insert(it, addl_base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bases.push_back(addl_base);
|
||||||
|
}
|
||||||
|
|
||||||
// Populates a just-created cache entry.
|
// Populates a just-created cache entry.
|
||||||
PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
||||||
|
assert(bases.empty());
|
||||||
std::vector<PyTypeObject *> check;
|
std::vector<PyTypeObject *> check;
|
||||||
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {
|
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {
|
||||||
check.push_back((PyTypeObject *) parent.ptr());
|
check.push_back((PyTypeObject *) parent.ptr());
|
||||||
|
@ -136,7 +140,7 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
bases.push_back(tinfo);
|
all_type_info_add_base_most_derived_first(bases, tinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type->tp_bases) {
|
} else if (type->tp_bases) {
|
||||||
|
@ -203,12 +207,15 @@ inline detail::type_info *get_local_type_info(const std::type_index &tp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
||||||
auto &types = get_internals().registered_types_cpp;
|
return with_internals([&](internals &internals) {
|
||||||
auto it = types.find(tp);
|
detail::type_info *type_info = nullptr;
|
||||||
if (it != types.end()) {
|
auto &types = internals.registered_types_cpp;
|
||||||
return it->second;
|
auto it = types.find(tp);
|
||||||
}
|
if (it != types.end()) {
|
||||||
return nullptr;
|
type_info = it->second;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
@ -239,15 +246,17 @@ 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) {
|
||||||
auto it_instances = get_internals().registered_instances.equal_range(src);
|
return with_instance_map(src, [&](instance_map &instances) {
|
||||||
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
auto it_instances = instances.equal_range(src);
|
||||||
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
||||||
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
||||||
return handle((PyObject *) it_i->second).inc_ref();
|
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
||||||
|
return handle((PyObject *) it_i->second).inc_ref();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return handle();
|
||||||
return handle();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value_and_holder {
|
struct value_and_holder {
|
||||||
|
@ -322,18 +331,29 @@ public:
|
||||||
explicit values_and_holders(instance *inst)
|
explicit values_and_holders(instance *inst)
|
||||||
: inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
: inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
||||||
|
|
||||||
|
explicit values_and_holders(PyObject *obj)
|
||||||
|
: inst{nullptr}, tinfo(all_type_info(Py_TYPE(obj))) {
|
||||||
|
if (!tinfo.empty()) {
|
||||||
|
inst = reinterpret_cast<instance *>(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct iterator {
|
struct iterator {
|
||||||
private:
|
private:
|
||||||
instance *inst = nullptr;
|
instance *inst = nullptr;
|
||||||
const type_vec *types = nullptr;
|
const type_vec *types = nullptr;
|
||||||
value_and_holder curr;
|
value_and_holder curr;
|
||||||
friend struct values_and_holders;
|
friend struct values_and_holders;
|
||||||
iterator(instance *inst, const type_vec *tinfo)
|
iterator(instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} {
|
||||||
: inst{inst}, types{tinfo},
|
if (inst != nullptr) {
|
||||||
curr(inst /* instance */,
|
assert(!types->empty());
|
||||||
types->empty() ? nullptr : (*types)[0] /* type info */,
|
curr = value_and_holder(
|
||||||
0, /* vpos: (non-simple types only): the first vptr comes first */
|
inst /* instance */,
|
||||||
0 /* index */) {}
|
(*types)[0] /* type info */,
|
||||||
|
0, /* vpos: (non-simple types only): the first vptr comes first */
|
||||||
|
0 /* index */);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Past-the-end iterator:
|
// Past-the-end iterator:
|
||||||
explicit iterator(size_t end) : curr(end) {}
|
explicit iterator(size_t end) : curr(end) {}
|
||||||
|
|
||||||
|
@ -364,6 +384,16 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() { return tinfo.size(); }
|
size_t size() { return tinfo.size(); }
|
||||||
|
|
||||||
|
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
||||||
|
bool is_redundant_value_and_holder(const value_and_holder &vh) {
|
||||||
|
for (size_t i = 0; i < vh.index; i++) {
|
||||||
|
if (PyType_IsSubtype(tinfo[i]->type, tinfo[vh.index]->type) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -471,23 +501,26 @@ 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) {
|
||||||
auto &instances = get_internals().registered_instances;
|
return with_instance_map(ptr, [&](instance_map &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() {
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
return PyThreadState_GET();
|
return PyThreadState_GET();
|
||||||
#else
|
#elif PY_VERSION_HEX < 0x030D0000
|
||||||
return _PyThreadState_UncheckedGet();
|
return _PyThreadState_UncheckedGet();
|
||||||
|
#else
|
||||||
|
return PyThreadState_GetUnchecked();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,7 +819,7 @@ public:
|
||||||
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
||||||
detail::clean_type_id(tname);
|
detail::clean_type_id(tname);
|
||||||
std::string msg = "Unregistered type : " + tname;
|
std::string msg = "Unregistered type : " + tname;
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
set_error(PyExc_TypeError, msg.c_str());
|
||||||
return {nullptr, nullptr};
|
return {nullptr, nullptr};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1074,11 +1107,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(&src, policy, parent);
|
return cast(std::addressof(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(&src, return_value_policy::move, parent);
|
return cast(std::addressof(src), return_value_policy::move, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
||||||
|
@ -1147,14 +1180,14 @@ protected:
|
||||||
does not have a private operator new implementation. A comma operator is used in the
|
does not have a private operator new implementation. A comma operator is used in the
|
||||||
decltype argument to apply SFINAE to the public copy/move constructors.*/
|
decltype argument to apply SFINAE to the public copy/move constructors.*/
|
||||||
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
|
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
|
||||||
static auto make_copy_constructor(const T *)
|
static auto make_copy_constructor(const T *) -> decltype(new T(std::declval<const T>()),
|
||||||
-> decltype(new T(std::declval<const T>()), Constructor{}) {
|
Constructor{}) {
|
||||||
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
|
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
|
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
|
||||||
static auto make_move_constructor(const T *)
|
static auto make_move_constructor(const T *) -> decltype(new T(std::declval<T &&>()),
|
||||||
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
|
Constructor{}) {
|
||||||
return [](const void *arg) -> void * {
|
return [](const void *arg) -> void * {
|
||||||
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
|
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
|
||||||
};
|
};
|
||||||
|
@ -1164,13 +1197,17 @@ protected:
|
||||||
static Constructor make_move_constructor(...) { return nullptr; }
|
static Constructor make_move_constructor(...) { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::string quote_cpp_type_name(const std::string &cpp_type_name) {
|
||||||
|
return cpp_type_name; // No-op for now. See PR #4888
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
|
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
|
||||||
if (auto *type_data = get_type_info(ti)) {
|
if (auto *type_data = get_type_info(ti)) {
|
||||||
handle th((PyObject *) type_data->type);
|
handle th((PyObject *) type_data->type);
|
||||||
return th.attr("__module__").cast<std::string>() + '.'
|
return th.attr("__module__").cast<std::string>() + '.'
|
||||||
+ th.attr("__qualname__").cast<std::string>();
|
+ th.attr("__qualname__").cast<std::string>();
|
||||||
}
|
}
|
||||||
return clean_type_id(ti.name());
|
return quote_cpp_type_name(clean_type_id(ti.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexTy
|
||||||
|
|
||||||
template <size_t... Is>
|
template <size_t... Is>
|
||||||
struct helper<index_sequence<Is...>> {
|
struct helper<index_sequence<Is...>> {
|
||||||
static constexpr auto value = concat(const_name(((void) Is, "?"))...);
|
static constexpr auto value = ::pybind11::detail::concat(const_name(((void) Is, "?"))...);
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto dimensions_descriptor
|
static constexpr auto dimensions_descriptor
|
||||||
|
@ -104,7 +104,8 @@ struct eigen_tensor_helper<
|
||||||
return get_shape() == shape;
|
return get_shape() == shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto dimensions_descriptor = concat(const_name<Indices>()...);
|
static constexpr auto dimensions_descriptor
|
||||||
|
= ::pybind11::detail::concat(const_name<Indices>()...);
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static Type *alloc(Args &&...args) {
|
static Type *alloc(Args &&...args) {
|
||||||
|
|
|
@ -103,9 +103,6 @@ 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
|
// 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.
|
// caused a segfault, so we have to reimplement the special case ourselves.
|
||||||
|
|
|
@ -128,7 +128,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type,
|
PYBIND11_TYPE_CASTER(type,
|
||||||
const_name("Callable[[") + concat(make_caster<Args>::name...)
|
const_name("Callable[[")
|
||||||
|
+ ::pybind11::detail::concat(make_caster<Args>::name...)
|
||||||
+ const_name("], ") + make_caster<retval_type>::name
|
+ const_name("], ") + make_caster<retval_type>::name
|
||||||
+ const_name("]"));
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
|
|
||||||
#include "detail/common.h"
|
#include "detail/common.h"
|
||||||
|
|
||||||
#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#include <cassert>
|
||||||
|
|
||||||
|
#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
# include "detail/internals.h"
|
# include "detail/internals.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -24,9 +26,7 @@ PyThreadState *get_thread_state_unchecked();
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
#if defined(WITH_THREAD)
|
#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
|
|
||||||
# if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
|
||||||
|
|
||||||
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
/* 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 +67,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 +92,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();
|
||||||
|
@ -137,7 +137,9 @@ private:
|
||||||
|
|
||||||
class gil_scoped_release {
|
class gil_scoped_release {
|
||||||
public:
|
public:
|
||||||
|
// PRECONDITION: The GIL must be held when this constructor is called.
|
||||||
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
|
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
|
||||||
|
assert(PyGILState_Check());
|
||||||
// `get_internals()` must be called here unconditionally in order to initialize
|
// `get_internals()` must be called here unconditionally in order to initialize
|
||||||
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
|
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
|
||||||
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
|
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
|
||||||
|
@ -184,7 +186,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;
|
||||||
|
@ -201,39 +203,17 @@ class gil_scoped_release {
|
||||||
PyThreadState *state;
|
PyThreadState *state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
gil_scoped_release() : state{PyEval_SaveThread()} {}
|
// PRECONDITION: The GIL must be held when this constructor is called.
|
||||||
|
gil_scoped_release() {
|
||||||
|
assert(PyGILState_Check());
|
||||||
|
state = PyEval_SaveThread();
|
||||||
|
}
|
||||||
gil_scoped_release(const gil_scoped_release &) = delete;
|
gil_scoped_release(const gil_scoped_release &) = delete;
|
||||||
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
|
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
|
||||||
~gil_scoped_release() { PyEval_RestoreThread(state); }
|
~gil_scoped_release() { PyEval_RestoreThread(state); }
|
||||||
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)
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright (c) 2023 The pybind Community.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
|
#include "gil.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
// Use the `gil_safe_call_once_and_store` class below instead of the naive
|
||||||
|
//
|
||||||
|
// static auto imported_obj = py::module_::import("module_name"); // BAD, DO NOT USE!
|
||||||
|
//
|
||||||
|
// which has two serious issues:
|
||||||
|
//
|
||||||
|
// 1. Py_DECREF() calls potentially after the Python interpreter was finalized already, and
|
||||||
|
// 2. deadlocks in multi-threaded processes (because of missing lock ordering).
|
||||||
|
//
|
||||||
|
// The following alternative avoids both problems:
|
||||||
|
//
|
||||||
|
// PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> storage;
|
||||||
|
// auto &imported_obj = storage // Do NOT make this `static`!
|
||||||
|
// .call_once_and_store_result([]() {
|
||||||
|
// return py::module_::import("module_name");
|
||||||
|
// })
|
||||||
|
// .get_stored();
|
||||||
|
//
|
||||||
|
// The parameter of `call_once_and_store_result()` must be callable. It can make
|
||||||
|
// CPython API calls, and in particular, it can temporarily release the GIL.
|
||||||
|
//
|
||||||
|
// `T` can be any C++ type, it does not have to involve CPython API types.
|
||||||
|
//
|
||||||
|
// The behavior with regard to signals, e.g. `SIGINT` (`KeyboardInterrupt`),
|
||||||
|
// is not ideal. If the main thread is the one to actually run the `Callable`,
|
||||||
|
// then a `KeyboardInterrupt` will interrupt it if it is running normal Python
|
||||||
|
// code. The situation is different if a non-main thread runs the
|
||||||
|
// `Callable`, and then the main thread starts waiting for it to complete:
|
||||||
|
// a `KeyboardInterrupt` will not interrupt the non-main thread, but it will
|
||||||
|
// get processed only when it is the main thread's turn again and it is running
|
||||||
|
// normal Python code. However, this will be unnoticeable for quick call-once
|
||||||
|
// functions, which is usually the case.
|
||||||
|
template <typename T>
|
||||||
|
class gil_safe_call_once_and_store {
|
||||||
|
public:
|
||||||
|
// PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called.
|
||||||
|
template <typename Callable>
|
||||||
|
gil_safe_call_once_and_store &call_once_and_store_result(Callable &&fn) {
|
||||||
|
if (!is_initialized_) { // This read is guarded by the GIL.
|
||||||
|
// Multiple threads may enter here, because the GIL is released in the next line and
|
||||||
|
// CPython API calls in the `fn()` call below may release and reacquire the GIL.
|
||||||
|
gil_scoped_release gil_rel; // Needed to establish lock ordering.
|
||||||
|
std::call_once(once_flag_, [&] {
|
||||||
|
// Only one thread will ever enter here.
|
||||||
|
gil_scoped_acquire gil_acq;
|
||||||
|
::new (storage_) T(fn()); // fn may release, but will reacquire, the GIL.
|
||||||
|
is_initialized_ = true; // This write is guarded by the GIL.
|
||||||
|
});
|
||||||
|
// All threads will observe `is_initialized_` as true here.
|
||||||
|
}
|
||||||
|
// Intentionally not returning `T &` to ensure the calling code is self-documenting.
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This must only be called after `call_once_and_store_result()` was called.
|
||||||
|
T &get_stored() {
|
||||||
|
assert(is_initialized_);
|
||||||
|
PYBIND11_WARNING_PUSH
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
|
||||||
|
// Needed for gcc 4.8.5
|
||||||
|
PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing")
|
||||||
|
#endif
|
||||||
|
return *reinterpret_cast<T *>(storage_);
|
||||||
|
PYBIND11_WARNING_POP
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr gil_safe_call_once_and_store() = default;
|
||||||
|
PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
alignas(T) char storage_[sizeof(T)] = {};
|
||||||
|
std::once_flag once_flag_ = {};
|
||||||
|
bool is_initialized_ = false;
|
||||||
|
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
|
||||||
|
// but the latter does not have the triviality properties of former,
|
||||||
|
// therefore `std::optional` is not a viable alternative here.
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -10,7 +10,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
#include "detail/common.h"
|
||||||
#include "complex.h"
|
#include "complex.h"
|
||||||
|
#include "gil_safe_call_once.h"
|
||||||
|
#include "pytypes.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -26,10 +29,15 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#if defined(PYBIND11_NUMPY_1_ONLY) && !defined(PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED)
|
||||||
|
# error PYBIND11_NUMPY_1_ONLY must be defined before any pybind11 header is included.
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This will be true on all flat address space platforms and allows us to reduce the
|
/* This will be true on all flat address space platforms and allows us to reduce the
|
||||||
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
|
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
|
||||||
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
|
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
|
||||||
upon the library user. */
|
upon the library user.
|
||||||
|
Note that NumPy 2 now uses ssize_t for `npy_intp` to simplify this. */
|
||||||
static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
|
static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
|
||||||
static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
|
static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
|
||||||
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
|
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
|
||||||
|
@ -38,10 +46,16 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
||||||
|
|
||||||
|
class dtype; // Forward declaration
|
||||||
class array; // Forward declaration
|
class array; // Forward declaration
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<dtype> {
|
||||||
|
static constexpr auto name = const_name("numpy.dtype");
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct handle_type_name<array> {
|
struct handle_type_name<array> {
|
||||||
static constexpr auto name = const_name("numpy.ndarray");
|
static constexpr auto name = const_name("numpy.ndarray");
|
||||||
|
@ -50,7 +64,8 @@ struct handle_type_name<array> {
|
||||||
template <typename type, typename SFINAE = void>
|
template <typename type, typename SFINAE = void>
|
||||||
struct npy_format_descriptor;
|
struct npy_format_descriptor;
|
||||||
|
|
||||||
struct PyArrayDescr_Proxy {
|
/* NumPy 1 proxy (always includes legacy fields) */
|
||||||
|
struct PyArrayDescr1_Proxy {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *typeobj;
|
PyObject *typeobj;
|
||||||
char kind;
|
char kind;
|
||||||
|
@ -65,6 +80,43 @@ struct PyArrayDescr_Proxy {
|
||||||
PyObject *names;
|
PyObject *names;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef PYBIND11_NUMPY_1_ONLY
|
||||||
|
struct PyArrayDescr_Proxy {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyObject *typeobj;
|
||||||
|
char kind;
|
||||||
|
char type;
|
||||||
|
char byteorder;
|
||||||
|
char _former_flags;
|
||||||
|
int type_num;
|
||||||
|
/* Additional fields are NumPy version specific. */
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
/* NumPy 1.x only, we can expose all fields */
|
||||||
|
using PyArrayDescr_Proxy = PyArrayDescr1_Proxy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* NumPy 2 proxy, including legacy fields */
|
||||||
|
struct PyArrayDescr2_Proxy {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyObject *typeobj;
|
||||||
|
char kind;
|
||||||
|
char type;
|
||||||
|
char byteorder;
|
||||||
|
char _former_flags;
|
||||||
|
int type_num;
|
||||||
|
std::uint64_t flags;
|
||||||
|
ssize_t elsize;
|
||||||
|
ssize_t alignment;
|
||||||
|
PyObject *metadata;
|
||||||
|
Py_hash_t hash;
|
||||||
|
void *reserved_null[2];
|
||||||
|
/* The following fields only exist if 0 <= type_num < 2056 */
|
||||||
|
char *subarray;
|
||||||
|
PyObject *fields;
|
||||||
|
PyObject *names;
|
||||||
|
};
|
||||||
|
|
||||||
struct PyArray_Proxy {
|
struct PyArray_Proxy {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
char *data;
|
char *data;
|
||||||
|
@ -120,6 +172,28 @@ inline numpy_internals &get_numpy_internals() {
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name) {
|
||||||
|
module_ numpy = module_::import("numpy");
|
||||||
|
str version_string = numpy.attr("__version__");
|
||||||
|
|
||||||
|
module_ numpy_lib = module_::import("numpy.lib");
|
||||||
|
object numpy_version = numpy_lib.attr("NumpyVersion")(version_string);
|
||||||
|
int major_version = numpy_version.attr("major").cast<int>();
|
||||||
|
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
|
if (major_version >= 2) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"This extension was built with PYBIND11_NUMPY_1_ONLY defined, "
|
||||||
|
"but NumPy 2 is used in this process. For NumPy2 compatibility, "
|
||||||
|
"this extension needs to be rebuilt without the PYBIND11_NUMPY_1_ONLY define.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially
|
||||||
|
became a private module. */
|
||||||
|
std::string numpy_core_path = major_version >= 2 ? "numpy._core" : "numpy.core";
|
||||||
|
return module_::import((numpy_core_path + "." + submodule_name).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct same_size {
|
struct same_size {
|
||||||
template <typename U>
|
template <typename U>
|
||||||
|
@ -186,14 +260,16 @@ struct npy_api {
|
||||||
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
|
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsigned int PyArray_RUNTIME_VERSION_;
|
||||||
|
|
||||||
struct PyArray_Dims {
|
struct PyArray_Dims {
|
||||||
Py_intptr_t *ptr;
|
Py_intptr_t *ptr;
|
||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static npy_api &get() {
|
static npy_api &get() {
|
||||||
static npy_api api = lookup();
|
PYBIND11_CONSTINIT static gil_safe_call_once_and_store<npy_api> storage;
|
||||||
return api;
|
return storage.call_once_and_store_result(lookup).get_stored();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PyArray_Check_(PyObject *obj) const {
|
bool PyArray_Check_(PyObject *obj) const {
|
||||||
|
@ -224,6 +300,7 @@ struct npy_api {
|
||||||
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
|
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
|
||||||
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
|
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
|
||||||
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
|
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
|
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
|
||||||
PyObject *,
|
PyObject *,
|
||||||
unsigned char,
|
unsigned char,
|
||||||
|
@ -232,6 +309,7 @@ struct npy_api {
|
||||||
Py_intptr_t *,
|
Py_intptr_t *,
|
||||||
PyObject **,
|
PyObject **,
|
||||||
PyObject *);
|
PyObject *);
|
||||||
|
#endif
|
||||||
PyObject *(*PyArray_Squeeze_)(PyObject *);
|
PyObject *(*PyArray_Squeeze_)(PyObject *);
|
||||||
// Unused. Not removed because that affects ABI of the class.
|
// Unused. Not removed because that affects ABI of the class.
|
||||||
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
|
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
|
||||||
|
@ -249,7 +327,8 @@ private:
|
||||||
API_PyArray_DescrFromScalar = 57,
|
API_PyArray_DescrFromScalar = 57,
|
||||||
API_PyArray_FromAny = 69,
|
API_PyArray_FromAny = 69,
|
||||||
API_PyArray_Resize = 80,
|
API_PyArray_Resize = 80,
|
||||||
API_PyArray_CopyInto = 82,
|
// CopyInto was slot 82 and 50 was effectively an alias. NumPy 2 removed 82.
|
||||||
|
API_PyArray_CopyInto = 50,
|
||||||
API_PyArray_NewCopy = 85,
|
API_PyArray_NewCopy = 85,
|
||||||
API_PyArray_NewFromDescr = 94,
|
API_PyArray_NewFromDescr = 94,
|
||||||
API_PyArray_DescrNewFromType = 96,
|
API_PyArray_DescrNewFromType = 96,
|
||||||
|
@ -258,18 +337,25 @@ private:
|
||||||
API_PyArray_View = 137,
|
API_PyArray_View = 137,
|
||||||
API_PyArray_DescrConverter = 174,
|
API_PyArray_DescrConverter = 174,
|
||||||
API_PyArray_EquivTypes = 182,
|
API_PyArray_EquivTypes = 182,
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
API_PyArray_GetArrayParamsFromObject = 278,
|
API_PyArray_GetArrayParamsFromObject = 278,
|
||||||
|
#endif
|
||||||
API_PyArray_SetBaseObject = 282
|
API_PyArray_SetBaseObject = 282
|
||||||
};
|
};
|
||||||
|
|
||||||
static npy_api lookup() {
|
static npy_api lookup() {
|
||||||
module_ m = module_::import("numpy.core.multiarray");
|
module_ m = detail::import_numpy_core_submodule("multiarray");
|
||||||
auto c = m.attr("_ARRAY_API");
|
auto c = m.attr("_ARRAY_API");
|
||||||
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr);
|
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr);
|
||||||
|
if (api_ptr == nullptr) {
|
||||||
|
raise_from(PyExc_SystemError, "FAILURE obtaining numpy _ARRAY_API pointer.");
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
npy_api api;
|
npy_api api;
|
||||||
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
||||||
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
|
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
|
||||||
if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) {
|
api.PyArray_RUNTIME_VERSION_ = api.PyArray_GetNDArrayCFeatureVersion_();
|
||||||
|
if (api.PyArray_RUNTIME_VERSION_ < 0x7) {
|
||||||
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
|
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
|
||||||
}
|
}
|
||||||
DECL_NPY_API(PyArray_Type);
|
DECL_NPY_API(PyArray_Type);
|
||||||
|
@ -288,7 +374,9 @@ private:
|
||||||
DECL_NPY_API(PyArray_View);
|
DECL_NPY_API(PyArray_View);
|
||||||
DECL_NPY_API(PyArray_DescrConverter);
|
DECL_NPY_API(PyArray_DescrConverter);
|
||||||
DECL_NPY_API(PyArray_EquivTypes);
|
DECL_NPY_API(PyArray_EquivTypes);
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
|
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
|
||||||
|
#endif
|
||||||
DECL_NPY_API(PyArray_SetBaseObject);
|
DECL_NPY_API(PyArray_SetBaseObject);
|
||||||
|
|
||||||
#undef DECL_NPY_API
|
#undef DECL_NPY_API
|
||||||
|
@ -310,6 +398,14 @@ inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {
|
||||||
return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);
|
return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const PyArrayDescr1_Proxy *array_descriptor1_proxy(const PyObject *ptr) {
|
||||||
|
return reinterpret_cast<const PyArrayDescr1_Proxy *>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const PyArrayDescr2_Proxy *array_descriptor2_proxy(const PyObject *ptr) {
|
||||||
|
return reinterpret_cast<const PyArrayDescr2_Proxy *>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool check_flags(const void *ptr, int flag) {
|
inline bool check_flags(const void *ptr, int flag) {
|
||||||
return (flag == (array_proxy(ptr)->flags & flag));
|
return (flag == (array_proxy(ptr)->flags & flag));
|
||||||
}
|
}
|
||||||
|
@ -350,7 +446,7 @@ struct array_info<std::array<T, N>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto extents = const_name<array_info<T>::is_array>(
|
static constexpr auto extents = const_name<array_info<T>::is_array>(
|
||||||
concat(const_name<N>(), array_info<T>::extents), const_name<N>());
|
::pybind11::detail::concat(const_name<N>(), array_info<T>::extents), const_name<N>());
|
||||||
};
|
};
|
||||||
// For numpy we have special handling for arrays of characters, so we don't include
|
// For numpy we have special handling for arrays of characters, so we don't include
|
||||||
// the size in the array extents.
|
// the size in the array extents.
|
||||||
|
@ -589,10 +685,32 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Size of the data type in bytes.
|
/// Size of the data type in bytes.
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
|
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
|
||||||
|
#else
|
||||||
|
ssize_t itemsize() const {
|
||||||
|
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
|
||||||
|
return detail::array_descriptor1_proxy(m_ptr)->elsize;
|
||||||
|
}
|
||||||
|
return detail::array_descriptor2_proxy(m_ptr)->elsize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Returns true for structured data types.
|
/// Returns true for structured data types.
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }
|
bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }
|
||||||
|
#else
|
||||||
|
bool has_fields() const {
|
||||||
|
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
|
||||||
|
return detail::array_descriptor1_proxy(m_ptr)->names != nullptr;
|
||||||
|
}
|
||||||
|
const auto *proxy = detail::array_descriptor2_proxy(m_ptr);
|
||||||
|
if (proxy->type_num < 0 || proxy->type_num >= 2056) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return proxy->names != nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Single-character code for dtype's kind.
|
/// Single-character code for dtype's kind.
|
||||||
/// For example, floating point types are 'f' and integral types are 'i'.
|
/// For example, floating point types are 'f' and integral types are 'i'.
|
||||||
|
@ -618,20 +736,39 @@ public:
|
||||||
/// Single character for byteorder
|
/// Single character for byteorder
|
||||||
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
|
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
|
||||||
|
|
||||||
/// Alignment of the data type
|
/// Alignment of the data type
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
|
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
|
||||||
|
#else
|
||||||
|
ssize_t alignment() const {
|
||||||
|
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
|
||||||
|
return detail::array_descriptor1_proxy(m_ptr)->alignment;
|
||||||
|
}
|
||||||
|
return detail::array_descriptor2_proxy(m_ptr)->alignment;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Flags for the array descriptor
|
/// Flags for the array descriptor
|
||||||
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
|
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
|
||||||
|
#else
|
||||||
|
std::uint64_t flags() const {
|
||||||
|
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
|
||||||
|
return (unsigned char) detail::array_descriptor1_proxy(m_ptr)->flags;
|
||||||
|
}
|
||||||
|
return detail::array_descriptor2_proxy(m_ptr)->flags;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static object _dtype_from_pep3118() {
|
static object &_dtype_from_pep3118() {
|
||||||
static PyObject *obj = module_::import("numpy.core._internal")
|
PYBIND11_CONSTINIT static gil_safe_call_once_and_store<object> storage;
|
||||||
.attr("_dtype_from_pep3118")
|
return storage
|
||||||
.cast<object>()
|
.call_once_and_store_result([]() {
|
||||||
.release()
|
return detail::import_numpy_core_submodule("_internal")
|
||||||
.ptr();
|
.attr("_dtype_from_pep3118");
|
||||||
return reinterpret_borrow<object>(obj);
|
})
|
||||||
|
.get_stored();
|
||||||
}
|
}
|
||||||
|
|
||||||
dtype strip_padding(ssize_t itemsize) {
|
dtype strip_padding(ssize_t itemsize) {
|
||||||
|
@ -788,9 +925,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Byte size of a single element
|
/// Byte size of a single element
|
||||||
ssize_t itemsize() const {
|
ssize_t itemsize() const { return dtype().itemsize(); }
|
||||||
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Total number of bytes
|
/// Total number of bytes
|
||||||
ssize_t nbytes() const { return size() * itemsize(); }
|
ssize_t nbytes() const { return size() * itemsize(); }
|
||||||
|
@ -1008,7 +1143,7 @@ protected:
|
||||||
/// Create array from any object -- always returns a new reference
|
/// Create array from any object -- always returns a new reference
|
||||||
static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
|
static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
|
||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
|
set_error(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return detail::npy_api::get().PyArray_FromAny_(
|
return detail::npy_api::get().PyArray_FromAny_(
|
||||||
|
@ -1155,7 +1290,7 @@ protected:
|
||||||
/// Create array from any object -- always returns a new reference
|
/// Create array from any object -- always returns a new reference
|
||||||
static PyObject *raw_array_t(PyObject *ptr) {
|
static PyObject *raw_array_t(PyObject *ptr) {
|
||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
|
set_error(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return detail::npy_api::get().PyArray_FromAny_(ptr,
|
return detail::npy_api::get().PyArray_FromAny_(ptr,
|
||||||
|
@ -1418,7 +1553,9 @@ 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)};
|
||||||
get_internals().direct_conversions[tindex].push_back(direct_converter);
|
with_internals([tindex, &direct_converter](internals &internals) {
|
||||||
|
internals.direct_conversions[tindex].push_back(direct_converter);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename SFINAE>
|
template <typename T, typename SFINAE>
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
#include "detail/init.h"
|
#include "detail/init.h"
|
||||||
#include "attr.h"
|
#include "attr.h"
|
||||||
#include "gil.h"
|
#include "gil.h"
|
||||||
|
#include "gil_safe_call_once.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "typing.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -52,6 +54,47 @@ PYBIND11_WARNING_DISABLE_MSVC(4127)
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
inline std::string replace_newlines_and_squash(const char *text) {
|
||||||
|
const char *whitespaces = " \t\n\r\f\v";
|
||||||
|
std::string result(text);
|
||||||
|
bool previous_is_whitespace = false;
|
||||||
|
|
||||||
|
if (result.size() >= 2) {
|
||||||
|
// Do not modify string representations
|
||||||
|
char first_char = result[0];
|
||||||
|
char last_char = result[result.size() - 1];
|
||||||
|
if (first_char == last_char && first_char == '\'') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.clear();
|
||||||
|
|
||||||
|
// Replace characters in whitespaces array with spaces and squash consecutive spaces
|
||||||
|
while (*text != '\0') {
|
||||||
|
if (std::strchr(whitespaces, *text)) {
|
||||||
|
if (!previous_is_whitespace) {
|
||||||
|
result += ' ';
|
||||||
|
previous_is_whitespace = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += *text;
|
||||||
|
previous_is_whitespace = false;
|
||||||
|
}
|
||||||
|
++text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip leading and trailing whitespaces
|
||||||
|
const size_t str_begin = result.find_first_not_of(whitespaces);
|
||||||
|
if (str_begin == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t str_end = result.find_last_not_of(whitespaces);
|
||||||
|
const size_t str_range = str_end - str_begin + 1;
|
||||||
|
|
||||||
|
return result.substr(str_begin, str_range);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply all the extensions translators from a list
|
// Apply all the extensions translators from a list
|
||||||
// Return true if one of the translators completed without raising an exception
|
// Return true if one of the translators completed without raising an exception
|
||||||
// itself. Return of false indicates that if there are other translators
|
// itself. Return of false indicates that if there are other translators
|
||||||
|
@ -424,7 +467,7 @@ protected:
|
||||||
// Write default value if available.
|
// Write default value if available.
|
||||||
if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {
|
if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {
|
||||||
signature += " = ";
|
signature += " = ";
|
||||||
signature += rec->args[arg_index].descr;
|
signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr);
|
||||||
}
|
}
|
||||||
// Separator for positional-only arguments (placed after the
|
// Separator for positional-only arguments (placed after the
|
||||||
// argument, rather than before like *
|
// argument, rather than before like *
|
||||||
|
@ -449,9 +492,7 @@ protected:
|
||||||
signature += rec->scope.attr("__module__").cast<std::string>() + "."
|
signature += rec->scope.attr("__module__").cast<std::string>() + "."
|
||||||
+ rec->scope.attr("__qualname__").cast<std::string>();
|
+ rec->scope.attr("__qualname__").cast<std::string>();
|
||||||
} else {
|
} else {
|
||||||
std::string tname(t->name());
|
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
|
||||||
detail::clean_type_id(tname);
|
|
||||||
signature += tname;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
signature += c;
|
signature += c;
|
||||||
|
@ -680,7 +721,7 @@ protected:
|
||||||
/* Iterator over the list of potentially admissible overloads */
|
/* Iterator over the list of potentially admissible overloads */
|
||||||
const function_record *overloads = reinterpret_cast<function_record *>(
|
const function_record *overloads = reinterpret_cast<function_record *>(
|
||||||
PyCapsule_GetPointer(self, get_function_record_capsule_name())),
|
PyCapsule_GetPointer(self, get_function_record_capsule_name())),
|
||||||
*it = overloads;
|
*current_overload = overloads;
|
||||||
assert(overloads != nullptr);
|
assert(overloads != nullptr);
|
||||||
|
|
||||||
/* Need to know how many arguments + keyword arguments there are to pick the right
|
/* Need to know how many arguments + keyword arguments there are to pick the right
|
||||||
|
@ -694,9 +735,8 @@ protected:
|
||||||
if (overloads->is_constructor) {
|
if (overloads->is_constructor) {
|
||||||
if (!parent
|
if (!parent
|
||||||
|| !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {
|
|| !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {
|
||||||
PyErr_SetString(
|
set_error(PyExc_TypeError,
|
||||||
PyExc_TypeError,
|
"__init__(self, ...) called with invalid or missing `self` argument");
|
||||||
"__init__(self, ...) called with invalid or missing `self` argument");
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,9 +759,10 @@ protected:
|
||||||
std::vector<function_call> second_pass;
|
std::vector<function_call> second_pass;
|
||||||
|
|
||||||
// However, if there are no overloads, we can just skip the no-convert pass entirely
|
// However, if there are no overloads, we can just skip the no-convert pass entirely
|
||||||
const bool overloaded = it != nullptr && it->next != nullptr;
|
const bool overloaded
|
||||||
|
= current_overload != nullptr && current_overload->next != nullptr;
|
||||||
|
|
||||||
for (; it != nullptr; it = it->next) {
|
for (; current_overload != nullptr; current_overload = current_overload->next) {
|
||||||
|
|
||||||
/* For each overload:
|
/* For each overload:
|
||||||
1. Copy all positional arguments we were given, also checking to make sure that
|
1. Copy all positional arguments we were given, also checking to make sure that
|
||||||
|
@ -742,7 +783,7 @@ protected:
|
||||||
a result other than PYBIND11_TRY_NEXT_OVERLOAD.
|
a result other than PYBIND11_TRY_NEXT_OVERLOAD.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const function_record &func = *it;
|
const function_record &func = *current_overload;
|
||||||
size_t num_args = func.nargs; // Number of positional arguments that we need
|
size_t num_args = func.nargs; // Number of positional arguments that we need
|
||||||
if (func.has_args) {
|
if (func.has_args) {
|
||||||
--num_args; // (but don't count py::args
|
--num_args; // (but don't count py::args
|
||||||
|
@ -980,10 +1021,10 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) {
|
if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) {
|
||||||
// The error reporting logic below expects 'it' to be valid, as it would be
|
// The error reporting logic below expects 'current_overload' to be valid,
|
||||||
// if we'd encountered this failure in the first-pass loop.
|
// as it would be if we'd encountered this failure in the first-pass loop.
|
||||||
if (!result) {
|
if (!result) {
|
||||||
it = &call.func;
|
current_overload = &call.func;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1007,24 +1048,30 @@ protected:
|
||||||
|
|
||||||
A translator may choose to do one of the following:
|
A translator may choose to do one of the following:
|
||||||
|
|
||||||
- catch the exception and call PyErr_SetString or PyErr_SetObject
|
- catch the exception and call py::set_error()
|
||||||
to set a standard (or custom) Python exception, or
|
to set a standard (or custom) Python exception, or
|
||||||
- do nothing and let the exception fall through to the next translator, 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.
|
- delegate translation to the next translator by throwing a new type of exception.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
auto &local_exception_translators
|
bool handled = with_internals([&](internals &internals) {
|
||||||
= get_local_internals().registered_exception_translators;
|
auto &local_exception_translators
|
||||||
if (detail::apply_exception_translators(local_exception_translators)) {
|
= get_local_internals().registered_exception_translators;
|
||||||
return nullptr;
|
if (detail::apply_exception_translators(local_exception_translators)) {
|
||||||
}
|
return true;
|
||||||
auto &exception_translators = get_internals().registered_exception_translators;
|
}
|
||||||
if (detail::apply_exception_translators(exception_translators)) {
|
auto &exception_translators = internals.registered_exception_translators;
|
||||||
|
if (detail::apply_exception_translators(exception_translators)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyErr_SetString(PyExc_SystemError,
|
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
|
||||||
"Exception escaped from default exception translator!");
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,7 +1149,7 @@ protected:
|
||||||
}
|
}
|
||||||
msg += "kwargs: ";
|
msg += "kwargs: ";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto kwarg : kwargs) {
|
for (const auto &kwarg : kwargs) {
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1125,20 +1172,21 @@ protected:
|
||||||
raise_from(PyExc_TypeError, msg.c_str());
|
raise_from(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
set_error(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
std::string msg = "Unable to convert function return value to a "
|
std::string msg = "Unable to convert function return value to a "
|
||||||
"Python type! The signature was\n\t";
|
"Python type! The signature was\n\t";
|
||||||
msg += it->signature;
|
assert(current_overload != nullptr);
|
||||||
|
msg += current_overload->signature;
|
||||||
append_note_if_missing_header_is_suspected(msg);
|
append_note_if_missing_header_is_suspected(msg);
|
||||||
// Attach additional error info to the exception if supported
|
// Attach additional error info to the exception if supported
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
raise_from(PyExc_TypeError, msg.c_str());
|
raise_from(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
set_error(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) {
|
if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) {
|
||||||
|
@ -1149,6 +1197,25 @@ protected:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<cpp_function> {
|
||||||
|
static constexpr auto name = const_name("Callable");
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
// Use to activate Py_MOD_GIL_NOT_USED.
|
||||||
|
class mod_gil_not_used {
|
||||||
|
public:
|
||||||
|
explicit mod_gil_not_used(bool flag = true) : flag_(flag) {}
|
||||||
|
bool flag() const { return flag_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool flag_;
|
||||||
|
};
|
||||||
|
|
||||||
/// Wrapper for Python extension modules
|
/// Wrapper for Python extension modules
|
||||||
class module_ : public object {
|
class module_ : public object {
|
||||||
public:
|
public:
|
||||||
|
@ -1249,7 +1316,11 @@ 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, const char *doc, module_def *def) {
|
static module_ create_extension_module(const char *name,
|
||||||
|
const char *doc,
|
||||||
|
module_def *def,
|
||||||
|
mod_gil_not_used gil_not_used
|
||||||
|
= mod_gil_not_used(false)) {
|
||||||
// module_def is PyModuleDef
|
// module_def is PyModuleDef
|
||||||
// Placement new (not an allocation).
|
// Placement new (not an allocation).
|
||||||
def = new (def)
|
def = new (def)
|
||||||
|
@ -1269,6 +1340,11 @@ 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.
|
||||||
|
@ -1276,6 +1352,15 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<module_> {
|
||||||
|
static constexpr auto name = const_name("module");
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
// When inside a namespace (or anywhere as long as it's not the first item on a line),
|
// When inside a namespace (or anywhere as long as it's not the first item on a line),
|
||||||
// C++20 allows "module" to be used. This is provided for backward compatibility, and for
|
// C++20 allows "module" to be used. This is provided for backward compatibility, and for
|
||||||
// simplicity, if someone wants to use py::module for example, that is perfectly safe.
|
// simplicity, if someone wants to use py::module for example, that is perfectly safe.
|
||||||
|
@ -1285,8 +1370,14 @@ using module = module_;
|
||||||
/// Return a dictionary representing the global variables in the current execution frame,
|
/// Return a dictionary representing the global variables in the current execution frame,
|
||||||
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
|
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
|
||||||
inline dict globals() {
|
inline dict globals() {
|
||||||
|
#if PY_VERSION_HEX >= 0x030d0000
|
||||||
|
PyObject *p = PyEval_GetFrameGlobals();
|
||||||
|
return p ? reinterpret_steal<dict>(p)
|
||||||
|
: reinterpret_borrow<dict>(module_::import("__main__").attr("__dict__").ptr());
|
||||||
|
#else
|
||||||
PyObject *p = PyEval_GetGlobals();
|
PyObject *p = PyEval_GetGlobals();
|
||||||
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
|
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
|
||||||
|
@ -1332,15 +1423,16 @@ 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;
|
||||||
|
|
||||||
auto &internals = get_internals();
|
with_internals([&](internals &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};
|
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
|
||||||
|
});
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1553,10 +1645,12 @@ public:
|
||||||
generic_type::initialize(record);
|
generic_type::initialize(record);
|
||||||
|
|
||||||
if (has_alias) {
|
if (has_alias) {
|
||||||
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
|
with_internals([&](internals &internals) {
|
||||||
: get_internals().registered_types_cpp;
|
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
|
||||||
instances[std::type_index(typeid(type_alias))]
|
: internals.registered_types_cpp;
|
||||||
= instances[std::type_index(typeid(type))];
|
instances[std::type_index(typeid(type_alias))]
|
||||||
|
= instances[std::type_index(typeid(type))];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1977,7 +2071,7 @@ struct enum_base {
|
||||||
object type_name = type::handle_of(arg).attr("__name__");
|
object type_name = type::handle_of(arg).attr("__name__");
|
||||||
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
|
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
|
||||||
},
|
},
|
||||||
name("name"),
|
name("__str__"),
|
||||||
is_method(m_base));
|
is_method(m_base));
|
||||||
|
|
||||||
if (options::show_enum_members_docstring()) {
|
if (options::show_enum_members_docstring()) {
|
||||||
|
@ -2271,28 +2365,32 @@ keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
|
||||||
|
|
||||||
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
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 = get_internals()
|
auto res = with_internals([type](internals &internals) {
|
||||||
.registered_types_py
|
return internals
|
||||||
|
.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) {
|
||||||
get_internals().registered_types_py.erase(type);
|
with_internals([type](internals &internals) {
|
||||||
|
internals.registered_types_py.erase(type);
|
||||||
|
|
||||||
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
|
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
|
||||||
auto &cache = get_internals().inactive_override_cache;
|
auto &cache = 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();
|
||||||
}))
|
}))
|
||||||
|
@ -2395,7 +2493,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
||||||
Policy);
|
Policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cast(state{first, last, true});
|
return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
@ -2406,13 +2504,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||||
typename Sentinel,
|
typename Sentinel,
|
||||||
typename ValueType = typename detail::iterator_access<Iterator>::result_type,
|
typename ValueType = typename detail::iterator_access<Iterator>::result_type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
typing::Iterator<ValueType> make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
||||||
return detail::make_iterator_impl<detail::iterator_access<Iterator>,
|
return detail::make_iterator_impl<detail::iterator_access<Iterator>,
|
||||||
Policy,
|
Policy,
|
||||||
Iterator,
|
Iterator,
|
||||||
Sentinel,
|
Sentinel,
|
||||||
ValueType,
|
ValueType,
|
||||||
Extra...>(first, last, std::forward<Extra>(extra)...);
|
Extra...>(std::forward<Iterator>(first),
|
||||||
|
std::forward<Sentinel>(last),
|
||||||
|
std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
|
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
|
||||||
|
@ -2422,13 +2522,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||||
typename Sentinel,
|
typename Sentinel,
|
||||||
typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
|
typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
typing::Iterator<KeyType> make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
||||||
return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,
|
return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,
|
||||||
Policy,
|
Policy,
|
||||||
Iterator,
|
Iterator,
|
||||||
Sentinel,
|
Sentinel,
|
||||||
KeyType,
|
KeyType,
|
||||||
Extra...>(first, last, std::forward<Extra>(extra)...);
|
Extra...>(std::forward<Iterator>(first),
|
||||||
|
std::forward<Sentinel>(last),
|
||||||
|
std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
|
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
|
||||||
|
@ -2438,21 +2540,25 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||||
typename Sentinel,
|
typename Sentinel,
|
||||||
typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
|
typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
typing::Iterator<ValueType> make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
||||||
return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,
|
return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,
|
||||||
Policy,
|
Policy,
|
||||||
Iterator,
|
Iterator,
|
||||||
Sentinel,
|
Sentinel,
|
||||||
ValueType,
|
ValueType,
|
||||||
Extra...>(first, last, std::forward<Extra>(extra)...);
|
Extra...>(std::forward<Iterator>(first),
|
||||||
|
std::forward<Sentinel>(last),
|
||||||
|
std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes an iterator over values of an stl container or other container supporting
|
/// Makes an iterator over values of an stl container or other container supporting
|
||||||
/// `std::begin()`/`std::end()`
|
/// `std::begin()`/`std::end()`
|
||||||
template <return_value_policy Policy = return_value_policy::reference_internal,
|
template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||||
typename Type,
|
typename Type,
|
||||||
|
typename ValueType = typename detail::iterator_access<
|
||||||
|
decltype(std::begin(std::declval<Type &>()))>::result_type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_iterator(Type &value, Extra &&...extra) {
|
typing::Iterator<ValueType> make_iterator(Type &value, Extra &&...extra) {
|
||||||
return make_iterator<Policy>(
|
return make_iterator<Policy>(
|
||||||
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
@ -2461,8 +2567,10 @@ iterator make_iterator(Type &value, Extra &&...extra) {
|
||||||
/// `std::begin()`/`std::end()`
|
/// `std::begin()`/`std::end()`
|
||||||
template <return_value_policy Policy = return_value_policy::reference_internal,
|
template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||||
typename Type,
|
typename Type,
|
||||||
|
typename KeyType = typename detail::iterator_key_access<
|
||||||
|
decltype(std::begin(std::declval<Type &>()))>::result_type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_key_iterator(Type &value, Extra &&...extra) {
|
typing::Iterator<KeyType> make_key_iterator(Type &value, Extra &&...extra) {
|
||||||
return make_key_iterator<Policy>(
|
return make_key_iterator<Policy>(
|
||||||
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
@ -2471,8 +2579,10 @@ iterator make_key_iterator(Type &value, Extra &&...extra) {
|
||||||
/// `std::begin()`/`std::end()`
|
/// `std::begin()`/`std::end()`
|
||||||
template <return_value_policy Policy = return_value_policy::reference_internal,
|
template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||||
typename Type,
|
typename Type,
|
||||||
|
typename ValueType = typename detail::iterator_value_access<
|
||||||
|
decltype(std::begin(std::declval<Type &>()))>::result_type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_value_iterator(Type &value, Extra &&...extra) {
|
typing::Iterator<ValueType> make_value_iterator(Type &value, Extra &&...extra) {
|
||||||
return make_value_iterator<Policy>(
|
return make_value_iterator<Policy>(
|
||||||
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
@ -2485,7 +2595,11 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -2510,8 +2624,10 @@ void implicitly_convertible() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void register_exception_translator(ExceptionTranslator &&translator) {
|
inline void register_exception_translator(ExceptionTranslator &&translator) {
|
||||||
detail::get_internals().registered_exception_translators.push_front(
|
detail::with_internals([&](detail::internals &internals) {
|
||||||
std::forward<ExceptionTranslator>(translator));
|
internals.registered_exception_translators.push_front(
|
||||||
|
std::forward<ExceptionTranslator>(translator));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2521,14 +2637,17 @@ 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::get_local_internals().registered_exception_translators.push_front(
|
detail::with_internals([&](detail::internals &internals) {
|
||||||
std::forward<ExceptionTranslator>(translator));
|
(void) internals;
|
||||||
|
detail::get_local_internals().registered_exception_translators.push_front(
|
||||||
|
std::forward<ExceptionTranslator>(translator));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper to generate a new Python exception type.
|
* Wrapper to generate a new Python exception type.
|
||||||
*
|
*
|
||||||
* This should only be used with PyErr_SetString for now.
|
* This should only be used with py::set_error() for now.
|
||||||
* It is not (yet) possible to use as a py::base.
|
* It is not (yet) possible to use as a py::base.
|
||||||
* Template type argument is reserved for future use.
|
* Template type argument is reserved for future use.
|
||||||
*/
|
*/
|
||||||
|
@ -2549,27 +2668,25 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the current python exception to this exception object with the given message
|
// Sets the current python exception to this exception object with the given message
|
||||||
void operator()(const char *message) { PyErr_SetString(m_ptr, message); }
|
PYBIND11_DEPRECATED("Please use py::set_error() instead "
|
||||||
|
"(https://github.com/pybind/pybind11/pull/4772)")
|
||||||
|
void operator()(const char *message) const { set_error(*this, message); }
|
||||||
};
|
};
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
// Returns a reference to a function-local static exception object used in the simple
|
|
||||||
// register_exception approach below. (It would be simpler to have the static local variable
|
template <>
|
||||||
// directly in register_exception, but that makes clang <3.5 segfault - issue #1349).
|
struct handle_type_name<exception<void>> {
|
||||||
template <typename CppException>
|
static constexpr auto name = const_name("Exception");
|
||||||
exception<CppException> &get_exception_object() {
|
};
|
||||||
static exception<CppException> ex;
|
|
||||||
return ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function for register_exception and register_local_exception
|
// Helper function for register_exception and register_local_exception
|
||||||
template <typename CppException>
|
template <typename CppException>
|
||||||
exception<CppException> &
|
exception<CppException> &
|
||||||
register_exception_impl(handle scope, const char *name, handle base, bool isLocal) {
|
register_exception_impl(handle scope, const char *name, handle base, bool isLocal) {
|
||||||
auto &ex = detail::get_exception_object<CppException>();
|
PYBIND11_CONSTINIT static gil_safe_call_once_and_store<exception<CppException>> exc_storage;
|
||||||
if (!ex) {
|
exc_storage.call_once_and_store_result(
|
||||||
ex = exception<CppException>(scope, name, base);
|
[&]() { return exception<CppException>(scope, name, base); });
|
||||||
}
|
|
||||||
|
|
||||||
auto register_func
|
auto register_func
|
||||||
= isLocal ? ®ister_local_exception_translator : ®ister_exception_translator;
|
= isLocal ? ®ister_local_exception_translator : ®ister_exception_translator;
|
||||||
|
@ -2581,10 +2698,10 @@ register_exception_impl(handle scope, const char *name, handle base, bool isLoca
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(p);
|
std::rethrow_exception(p);
|
||||||
} catch (const CppException &e) {
|
} catch (const CppException &e) {
|
||||||
detail::get_exception_object<CppException>()(e.what());
|
set_error(exc_storage.get_stored(), e.what());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return ex;
|
return exc_storage.get_stored();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
@ -2681,14 +2798,19 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
|
||||||
|
|
||||||
/* Cache functions that aren't overridden in Python to avoid
|
/* Cache functions that aren't overridden in Python to avoid
|
||||||
many costly Python dictionary lookups below */
|
many costly Python dictionary lookups below */
|
||||||
auto &cache = get_internals().inactive_override_cache;
|
bool not_overridden = with_internals([&key](internals &internals) {
|
||||||
if (cache.find(key) != cache.end()) {
|
auto &cache = internals.inactive_override_cache;
|
||||||
|
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()) {
|
||||||
cache.insert(std::move(key));
|
with_internals([&](internals &internals) {
|
||||||
|
internals.inactive_override_cache.insert(std::move(key));
|
||||||
|
});
|
||||||
return function();
|
return function();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2701,12 +2823,22 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
|
||||||
PyCodeObject *f_code = PyFrame_GetCode(frame);
|
PyCodeObject *f_code = PyFrame_GetCode(frame);
|
||||||
// f_code is guaranteed to not be NULL
|
// f_code is guaranteed to not be NULL
|
||||||
if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) {
|
if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) {
|
||||||
|
# if PY_VERSION_HEX >= 0x030d0000
|
||||||
|
PyObject *locals = PyEval_GetFrameLocals();
|
||||||
|
# else
|
||||||
PyObject *locals = PyEval_GetLocals();
|
PyObject *locals = PyEval_GetLocals();
|
||||||
|
Py_XINCREF(locals);
|
||||||
|
# endif
|
||||||
if (locals != nullptr) {
|
if (locals != nullptr) {
|
||||||
|
# if PY_VERSION_HEX >= 0x030b0000
|
||||||
|
PyObject *co_varnames = PyCode_GetVarnames(f_code);
|
||||||
|
# else
|
||||||
PyObject *co_varnames = PyObject_GetAttrString((PyObject *) f_code, "co_varnames");
|
PyObject *co_varnames = PyObject_GetAttrString((PyObject *) f_code, "co_varnames");
|
||||||
|
# endif
|
||||||
PyObject *self_arg = PyTuple_GET_ITEM(co_varnames, 0);
|
PyObject *self_arg = PyTuple_GET_ITEM(co_varnames, 0);
|
||||||
Py_DECREF(co_varnames);
|
Py_DECREF(co_varnames);
|
||||||
PyObject *self_caller = dict_getitem(locals, self_arg);
|
PyObject *self_caller = dict_getitem(locals, self_arg);
|
||||||
|
Py_DECREF(locals);
|
||||||
if (self_caller == self.ptr()) {
|
if (self_caller == self.ptr()) {
|
||||||
Py_DECREF(f_code);
|
Py_DECREF(f_code);
|
||||||
Py_DECREF(frame);
|
Py_DECREF(frame);
|
||||||
|
@ -2783,10 +2915,14 @@ function get_override(const T *this_ptr, const char *name) {
|
||||||
= pybind11::get_override(static_cast<const cname *>(this), name); \
|
= pybind11::get_override(static_cast<const cname *>(this), name); \
|
||||||
if (override) { \
|
if (override) { \
|
||||||
auto o = override(__VA_ARGS__); \
|
auto o = override(__VA_ARGS__); \
|
||||||
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
|
PYBIND11_WARNING_PUSH \
|
||||||
|
PYBIND11_WARNING_DISABLE_MSVC(4127) \
|
||||||
|
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value \
|
||||||
|
&& !pybind11::detail::is_same_ignoring_cvref<ret_type, PyObject *>::value) { \
|
||||||
static pybind11::detail::override_caster_t<ret_type> caster; \
|
static pybind11::detail::override_caster_t<ret_type> caster; \
|
||||||
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
||||||
} \
|
} \
|
||||||
|
PYBIND11_WARNING_POP \
|
||||||
return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
|
return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
|
||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
|
@ -59,6 +59,7 @@ struct sequence_item;
|
||||||
struct list_item;
|
struct list_item;
|
||||||
struct tuple_item;
|
struct tuple_item;
|
||||||
} // namespace accessor_policies
|
} // namespace accessor_policies
|
||||||
|
// PLEASE KEEP handle_type_name SPECIALIZATIONS IN SYNC.
|
||||||
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
||||||
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
||||||
using item_accessor = accessor<accessor_policies::generic_item>;
|
using item_accessor = accessor<accessor_policies::generic_item>;
|
||||||
|
@ -182,7 +183,15 @@ public:
|
||||||
str_attr_accessor doc() const;
|
str_attr_accessor doc() const;
|
||||||
|
|
||||||
/// Return the object's current reference count
|
/// Return the object's current reference count
|
||||||
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
|
ssize_t ref_count() const {
|
||||||
|
#ifdef PYPY_VERSION
|
||||||
|
// PyPy uses the top few bits for REFCNT_FROM_PYPY & REFCNT_FROM_PYPY_LIGHT
|
||||||
|
// Following pybind11 2.12.1 and older behavior and removing this part
|
||||||
|
return static_cast<ssize_t>(static_cast<int>(Py_REFCNT(derived().ptr())));
|
||||||
|
#else
|
||||||
|
return Py_REFCNT(derived().ptr());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// TODO PYBIND11_DEPRECATED(
|
// TODO PYBIND11_DEPRECATED(
|
||||||
// "Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()")
|
// "Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()")
|
||||||
|
@ -305,19 +314,19 @@ private:
|
||||||
"https://pybind11.readthedocs.io/en/stable/advanced/"
|
"https://pybind11.readthedocs.io/en/stable/advanced/"
|
||||||
"misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n"
|
"misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n"
|
||||||
"If you are convinced there is no bug in your code, you can #define "
|
"If you are convinced there is no bug in your code, you can #define "
|
||||||
"PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF"
|
"PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF "
|
||||||
"to disable this check. In that case you have to ensure this #define is consistently "
|
"to disable this check. In that case you have to ensure this #define is consistently "
|
||||||
"used for all translation units linked into a given pybind11 extension, otherwise "
|
"used for all translation units linked into a given pybind11 extension, otherwise "
|
||||||
"there will be ODR violations.",
|
"there will be ODR violations.",
|
||||||
function_name.c_str());
|
function_name.c_str());
|
||||||
fflush(stderr);
|
|
||||||
if (Py_TYPE(m_ptr)->tp_name != nullptr) {
|
if (Py_TYPE(m_ptr)->tp_name != nullptr) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"The failing %s call was triggered on a %s object.\n",
|
" The failing %s call was triggered on a %s object.",
|
||||||
function_name.c_str(),
|
function_name.c_str(),
|
||||||
Py_TYPE(m_ptr)->tp_name);
|
Py_TYPE(m_ptr)->tp_name);
|
||||||
fflush(stderr);
|
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fflush(stderr);
|
||||||
throw std::runtime_error(function_name + " PyGILState_Check() failure.");
|
throw std::runtime_error(function_name + " PyGILState_Check() failure.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -334,6 +343,14 @@ public:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void set_error(const handle &type, const char *message) {
|
||||||
|
PyErr_SetString(type.ptr(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_error(const handle &type, const handle &value) {
|
||||||
|
PyErr_SetObject(type.ptr(), value.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Holds a reference to a Python object (with reference counting)
|
Holds a reference to a Python object (with reference counting)
|
||||||
|
|
||||||
|
@ -963,6 +980,23 @@ 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`.
|
||||||
|
@ -1612,7 +1646,15 @@ inline namespace literals {
|
||||||
/** \rst
|
/** \rst
|
||||||
String literal version of `str`
|
String literal version of `str`
|
||||||
\endrst */
|
\endrst */
|
||||||
inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
|
inline str
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
|
||||||
|
operator"" _s // gcc 4.8.5 insists on having a space (hard error).
|
||||||
|
#else
|
||||||
|
operator""_s // clang 17 generates a deprecation warning if there is a space.
|
||||||
|
#endif
|
||||||
|
(const char *s, size_t size) {
|
||||||
|
return {s, size};
|
||||||
|
}
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
|
|
||||||
/// \addtogroup pytypes
|
/// \addtogroup pytypes
|
||||||
|
@ -2158,6 +2200,11 @@ public:
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void clear() /* py-non-const */ {
|
||||||
|
if (PyList_SetSlice(m_ptr, 0, PyList_Size(m_ptr), nullptr) == -1) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class args : public tuple {
|
class args : public tuple {
|
||||||
|
|
|
@ -100,7 +100,7 @@ public:
|
||||||
return s.release();
|
return s.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]"));
|
PYBIND11_TYPE_CASTER(type, const_name("set[") + key_conv::name + const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, typename Key, typename Value>
|
template <typename Type, typename Key, typename Value>
|
||||||
|
@ -157,7 +157,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type,
|
PYBIND11_TYPE_CASTER(Type,
|
||||||
const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name
|
const_name("dict[") + key_conv::name + const_name(", ") + value_conv::name
|
||||||
+ const_name("]"));
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ struct list_caster {
|
||||||
auto s = reinterpret_borrow<sequence>(src);
|
auto s = reinterpret_borrow<sequence>(src);
|
||||||
value.clear();
|
value.clear();
|
||||||
reserve_maybe(s, &value);
|
reserve_maybe(s, &value);
|
||||||
for (auto it : s) {
|
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;
|
||||||
|
@ -208,7 +208,7 @@ public:
|
||||||
return l.release();
|
return l.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]"));
|
PYBIND11_TYPE_CASTER(Type, const_name("list[") + value_conv::name + const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, typename Alloc>
|
template <typename Type, typename Alloc>
|
||||||
|
@ -247,7 +247,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t ctr = 0;
|
size_t ctr = 0;
|
||||||
for (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;
|
||||||
|
@ -274,7 +274,7 @@ public:
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(ArrayType,
|
PYBIND11_TYPE_CASTER(ArrayType,
|
||||||
const_name<Resizable>(const_name(""), const_name("Annotated["))
|
const_name<Resizable>(const_name(""), const_name("Annotated["))
|
||||||
+ const_name("List[") + value_conv::name + const_name("]")
|
+ const_name("list[") + value_conv::name + const_name("]")
|
||||||
+ const_name<Resizable>(const_name(""),
|
+ const_name<Resizable>(const_name(""),
|
||||||
const_name(", FixedSize(")
|
const_name(", FixedSize(")
|
||||||
+ const_name<Size>() + const_name(")]")));
|
+ const_name<Size>() + const_name(")]")));
|
||||||
|
@ -421,7 +421,8 @@ struct variant_caster<V<Ts...>> {
|
||||||
|
|
||||||
using Type = V<Ts...>;
|
using Type = V<Ts...>;
|
||||||
PYBIND11_TYPE_CASTER(Type,
|
PYBIND11_TYPE_CASTER(Type,
|
||||||
const_name("Union[") + detail::concat(make_caster<Ts>::name...)
|
const_name("Union[")
|
||||||
|
+ ::pybind11::detail::concat(make_caster<Ts>::name...)
|
||||||
+ const_name("]"));
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
|
|
||||||
#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>)
|
||||||
|
|
|
@ -158,8 +158,7 @@ void vector_modifiers(
|
||||||
return v.release();
|
return v.release();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cl.def(
|
cl.def("clear", [](Vector &v) { v.clear(); }, "Clear the contents");
|
||||||
"clear", [](Vector &v) { v.clear(); }, "Clear the contents");
|
|
||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"extend",
|
"extend",
|
||||||
|
@ -525,7 +524,7 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
|
||||||
[](const Vector &v) -> bool { return !v.empty(); },
|
[](const Vector &v) -> bool { return !v.empty(); },
|
||||||
"Check whether the list is nonempty");
|
"Check whether the list is nonempty");
|
||||||
|
|
||||||
cl.def("__len__", &Vector::size);
|
cl.def("__len__", [](const Vector &vec) { return vec.size(); });
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// C++ style functions deprecated, leaving it here as an example
|
// C++ style functions deprecated, leaving it here as an example
|
||||||
|
@ -645,49 +644,50 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||||
"Return the canonical string representation of this map.");
|
"Return the canonical string representation of this map.");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename KeyType>
|
|
||||||
struct keys_view {
|
struct keys_view {
|
||||||
virtual size_t len() = 0;
|
virtual size_t len() = 0;
|
||||||
virtual iterator iter() = 0;
|
virtual iterator iter() = 0;
|
||||||
virtual bool contains(const KeyType &k) = 0;
|
virtual bool contains(const handle &k) = 0;
|
||||||
virtual bool contains(const object &k) = 0;
|
|
||||||
virtual ~keys_view() = default;
|
virtual ~keys_view() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename MappedType>
|
|
||||||
struct values_view {
|
struct values_view {
|
||||||
virtual size_t len() = 0;
|
virtual size_t len() = 0;
|
||||||
virtual iterator iter() = 0;
|
virtual iterator iter() = 0;
|
||||||
virtual ~values_view() = default;
|
virtual ~values_view() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename KeyType, typename MappedType>
|
|
||||||
struct items_view {
|
struct items_view {
|
||||||
virtual size_t len() = 0;
|
virtual size_t len() = 0;
|
||||||
virtual iterator iter() = 0;
|
virtual iterator iter() = 0;
|
||||||
virtual ~items_view() = default;
|
virtual ~items_view() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Map, typename KeysView>
|
template <typename Map>
|
||||||
struct KeysViewImpl : public KeysView {
|
struct KeysViewImpl : public detail::keys_view {
|
||||||
explicit KeysViewImpl(Map &map) : map(map) {}
|
explicit KeysViewImpl(Map &map) : map(map) {}
|
||||||
size_t len() override { return map.size(); }
|
size_t len() override { return map.size(); }
|
||||||
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
|
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
|
||||||
bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); }
|
bool contains(const handle &k) override {
|
||||||
bool contains(const object &) override { return false; }
|
try {
|
||||||
|
return map.find(k.template cast<typename Map::key_type>()) != map.end();
|
||||||
|
} catch (const cast_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Map ↦
|
Map ↦
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Map, typename ValuesView>
|
template <typename Map>
|
||||||
struct ValuesViewImpl : public ValuesView {
|
struct ValuesViewImpl : public detail::values_view {
|
||||||
explicit ValuesViewImpl(Map &map) : map(map) {}
|
explicit ValuesViewImpl(Map &map) : map(map) {}
|
||||||
size_t len() override { return map.size(); }
|
size_t len() override { return map.size(); }
|
||||||
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
|
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
|
||||||
Map ↦
|
Map ↦
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Map, typename ItemsView>
|
template <typename Map>
|
||||||
struct ItemsViewImpl : public ItemsView {
|
struct ItemsViewImpl : public detail::items_view {
|
||||||
explicit ItemsViewImpl(Map &map) : map(map) {}
|
explicit ItemsViewImpl(Map &map) : map(map) {}
|
||||||
size_t len() override { return map.size(); }
|
size_t len() override { return map.size(); }
|
||||||
iterator iter() override { return make_iterator(map.begin(), map.end()); }
|
iterator iter() override { return make_iterator(map.begin(), map.end()); }
|
||||||
|
@ -700,11 +700,9 @@ template <typename Map, typename holder_type = std::unique_ptr<Map>, typename...
|
||||||
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
||||||
using KeyType = typename Map::key_type;
|
using KeyType = typename Map::key_type;
|
||||||
using MappedType = typename Map::mapped_type;
|
using MappedType = typename Map::mapped_type;
|
||||||
using StrippedKeyType = detail::remove_cvref_t<KeyType>;
|
using KeysView = detail::keys_view;
|
||||||
using StrippedMappedType = detail::remove_cvref_t<MappedType>;
|
using ValuesView = detail::values_view;
|
||||||
using KeysView = detail::keys_view<StrippedKeyType>;
|
using ItemsView = detail::items_view;
|
||||||
using ValuesView = detail::values_view<StrippedMappedType>;
|
|
||||||
using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
|
|
||||||
using Class_ = class_<Map, holder_type>;
|
using Class_ = class_<Map, holder_type>;
|
||||||
|
|
||||||
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
||||||
|
@ -718,39 +716,20 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||||
}
|
}
|
||||||
|
|
||||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||||
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
|
|
||||||
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
|
|
||||||
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
|
|
||||||
|
|
||||||
// If key type isn't properly wrapped, fall back to C++ names
|
// Wrap KeysView if it wasn't already wrapped
|
||||||
if (key_type_name == "%") {
|
|
||||||
key_type_name = detail::type_info_description(typeid(KeyType));
|
|
||||||
}
|
|
||||||
// Similarly for value type:
|
|
||||||
if (mapped_type_name == "%") {
|
|
||||||
mapped_type_name = detail::type_info_description(typeid(MappedType));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap KeysView[KeyType] if it wasn't already wrapped
|
|
||||||
if (!detail::get_type_info(typeid(KeysView))) {
|
if (!detail::get_type_info(typeid(KeysView))) {
|
||||||
class_<KeysView> keys_view(
|
class_<KeysView> keys_view(scope, "KeysView", pybind11::module_local(local));
|
||||||
scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
|
|
||||||
keys_view.def("__len__", &KeysView::len);
|
keys_view.def("__len__", &KeysView::len);
|
||||||
keys_view.def("__iter__",
|
keys_view.def("__iter__",
|
||||||
&KeysView::iter,
|
&KeysView::iter,
|
||||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||||
);
|
);
|
||||||
keys_view.def("__contains__",
|
keys_view.def("__contains__", &KeysView::contains);
|
||||||
static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
|
|
||||||
// Fallback for when the object is not of the key type
|
|
||||||
keys_view.def("__contains__",
|
|
||||||
static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
|
|
||||||
}
|
}
|
||||||
// Similarly for ValuesView:
|
// Similarly for ValuesView:
|
||||||
if (!detail::get_type_info(typeid(ValuesView))) {
|
if (!detail::get_type_info(typeid(ValuesView))) {
|
||||||
class_<ValuesView> values_view(scope,
|
class_<ValuesView> values_view(scope, "ValuesView", pybind11::module_local(local));
|
||||||
("ValuesView[" + mapped_type_name + "]").c_str(),
|
|
||||||
pybind11::module_local(local));
|
|
||||||
values_view.def("__len__", &ValuesView::len);
|
values_view.def("__len__", &ValuesView::len);
|
||||||
values_view.def("__iter__",
|
values_view.def("__iter__",
|
||||||
&ValuesView::iter,
|
&ValuesView::iter,
|
||||||
|
@ -759,10 +738,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||||
}
|
}
|
||||||
// Similarly for ItemsView:
|
// Similarly for ItemsView:
|
||||||
if (!detail::get_type_info(typeid(ItemsView))) {
|
if (!detail::get_type_info(typeid(ItemsView))) {
|
||||||
class_<ItemsView> items_view(
|
class_<ItemsView> items_view(scope, "ItemsView", pybind11::module_local(local));
|
||||||
scope,
|
|
||||||
("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
|
|
||||||
pybind11::module_local(local));
|
|
||||||
items_view.def("__len__", &ItemsView::len);
|
items_view.def("__len__", &ItemsView::len);
|
||||||
items_view.def("__iter__",
|
items_view.def("__iter__",
|
||||||
&ItemsView::iter,
|
&ItemsView::iter,
|
||||||
|
@ -788,25 +764,19 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"keys",
|
"keys",
|
||||||
[](Map &m) {
|
[](Map &m) { return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map>(m)); },
|
||||||
return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"values",
|
"values",
|
||||||
[](Map &m) {
|
[](Map &m) { return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map>(m)); },
|
||||||
return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"items",
|
"items",
|
||||||
[](Map &m) {
|
[](Map &m) { return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map>(m)); },
|
||||||
return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -843,7 +813,8 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||||
m.erase(it);
|
m.erase(it);
|
||||||
});
|
});
|
||||||
|
|
||||||
cl.def("__len__", &Map::size);
|
// Always use a lambda in case of `using` declaration
|
||||||
|
cl.def("__len__", [](const Map &m) { return m.size(); });
|
||||||
|
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
pybind11/typing.h: Convenience wrapper classes for basic Python types
|
||||||
|
with more explicit annotations.
|
||||||
|
|
||||||
|
Copyright (c) 2023 Dustin Spicuzza <dustin@virtualroadside.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 "detail/common.h"
|
||||||
|
#include "cast.h"
|
||||||
|
#include "pytypes.h"
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(typing)
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following types can be used to direct pybind11-generated docstrings
|
||||||
|
to have have more explicit types (e.g., `list[str]` instead of `list`).
|
||||||
|
Just use these in place of existing types.
|
||||||
|
|
||||||
|
There is no additional enforcement of types at runtime.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename... Types>
|
||||||
|
class Tuple : public tuple {
|
||||||
|
using tuple::tuple;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V>
|
||||||
|
class Dict : public dict {
|
||||||
|
using dict::dict;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class List : public list {
|
||||||
|
using list::list;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Set : public set {
|
||||||
|
using set::set;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Iterable : public iterable {
|
||||||
|
using iterable::iterable;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Iterator : public iterator {
|
||||||
|
using iterator::iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Signature>
|
||||||
|
class Callable;
|
||||||
|
|
||||||
|
template <typename Return, typename... Args>
|
||||||
|
class Callable<Return(Args...)> : public function {
|
||||||
|
using function::function;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Type : public type {
|
||||||
|
using type::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Types>
|
||||||
|
class Union : public object {
|
||||||
|
PYBIND11_OBJECT_DEFAULT(Union, object, PyObject_Type)
|
||||||
|
using object::object;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Optional : public object {
|
||||||
|
PYBIND11_OBJECT_DEFAULT(Optional, object, PyObject_Type)
|
||||||
|
using object::object;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TypeGuard : public bool_ {
|
||||||
|
using bool_::bool_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TypeIs : public bool_ {
|
||||||
|
using bool_::bool_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NoReturn : public none {
|
||||||
|
using none::none;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Never : public none {
|
||||||
|
using none::none;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cpp_nontype_template_parameter_class)
|
||||||
|
template <size_t N>
|
||||||
|
struct StringLiteral {
|
||||||
|
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, name); }
|
||||||
|
char name[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
template <StringLiteral... StrLits>
|
||||||
|
class Literal : public object {
|
||||||
|
PYBIND11_OBJECT_DEFAULT(Literal, object, PyObject_Type)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Example syntax for creating a TypeVar.
|
||||||
|
// typedef typing::TypeVar<"T"> TypeVarT;
|
||||||
|
template <StringLiteral>
|
||||||
|
class TypeVar : public object {
|
||||||
|
PYBIND11_OBJECT_DEFAULT(TypeVar, object, PyObject_Type)
|
||||||
|
using object::object;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(typing)
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
template <typename... Types>
|
||||||
|
struct handle_type_name<typing::Tuple<Types...>> {
|
||||||
|
static constexpr auto name = const_name("tuple[")
|
||||||
|
+ ::pybind11::detail::concat(make_caster<Types>::name...)
|
||||||
|
+ const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<typing::Tuple<>> {
|
||||||
|
// PEP 484 specifies this syntax for an empty tuple
|
||||||
|
static constexpr auto name = const_name("tuple[()]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Tuple<T, ellipsis>> {
|
||||||
|
// PEP 484 specifies this syntax for a variable-length tuple
|
||||||
|
static constexpr auto name
|
||||||
|
= const_name("tuple[") + make_caster<T>::name + const_name(", ...]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V>
|
||||||
|
struct handle_type_name<typing::Dict<K, V>> {
|
||||||
|
static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ")
|
||||||
|
+ make_caster<V>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::List<T>> {
|
||||||
|
static constexpr auto name = const_name("list[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Set<T>> {
|
||||||
|
static constexpr auto name = const_name("set[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Iterable<T>> {
|
||||||
|
static constexpr auto name = const_name("Iterable[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Iterator<T>> {
|
||||||
|
static constexpr auto name = const_name("Iterator[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Return, typename... Args>
|
||||||
|
struct handle_type_name<typing::Callable<Return(Args...)>> {
|
||||||
|
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||||
|
static constexpr auto name
|
||||||
|
= const_name("Callable[[") + ::pybind11::detail::concat(make_caster<Args>::name...)
|
||||||
|
+ const_name("], ") + make_caster<retval_type>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Return>
|
||||||
|
struct handle_type_name<typing::Callable<Return(ellipsis)>> {
|
||||||
|
// PEP 484 specifies this syntax for defining only return types of callables
|
||||||
|
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||||
|
static constexpr auto name
|
||||||
|
= const_name("Callable[..., ") + make_caster<retval_type>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Type<T>> {
|
||||||
|
static constexpr auto name = const_name("type[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Types>
|
||||||
|
struct handle_type_name<typing::Union<Types...>> {
|
||||||
|
static constexpr auto name = const_name("Union[")
|
||||||
|
+ ::pybind11::detail::concat(make_caster<Types>::name...)
|
||||||
|
+ const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Optional<T>> {
|
||||||
|
static constexpr auto name = const_name("Optional[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::TypeGuard<T>> {
|
||||||
|
static constexpr auto name = const_name("TypeGuard[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::TypeIs<T>> {
|
||||||
|
static constexpr auto name = const_name("TypeIs[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<typing::NoReturn> {
|
||||||
|
static constexpr auto name = const_name("NoReturn");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct handle_type_name<typing::Never> {
|
||||||
|
static constexpr auto name = const_name("Never");
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cpp_nontype_template_parameter_class)
|
||||||
|
template <typing::StringLiteral... Literals>
|
||||||
|
struct handle_type_name<typing::Literal<Literals...>> {
|
||||||
|
static constexpr auto name = const_name("Literal[")
|
||||||
|
+ pybind11::detail::concat(const_name(Literals.name)...)
|
||||||
|
+ const_name("]");
|
||||||
|
};
|
||||||
|
template <typing::StringLiteral StrLit>
|
||||||
|
struct handle_type_name<typing::TypeVar<StrLit>> {
|
||||||
|
static constexpr auto name = const_name(StrLit.name);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -1,24 +1,12 @@
|
||||||
import os
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
import nox
|
import nox
|
||||||
|
|
||||||
nox.needs_version = ">=2022.1.7"
|
nox.needs_version = ">=2024.3.2"
|
||||||
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
||||||
|
nox.options.default_venv_backend = "uv|virtualenv"
|
||||||
PYTHON_VERSIONS = [
|
|
||||||
"3.6",
|
|
||||||
"3.7",
|
|
||||||
"3.8",
|
|
||||||
"3.9",
|
|
||||||
"3.10",
|
|
||||||
"3.11",
|
|
||||||
"pypy3.7",
|
|
||||||
"pypy3.8",
|
|
||||||
"pypy3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
if os.environ.get("CI", None):
|
|
||||||
nox.options.error_on_missing_interpreters = True
|
|
||||||
|
|
||||||
|
|
||||||
@nox.session(reuse_venv=True)
|
@nox.session(reuse_venv=True)
|
||||||
|
@ -30,7 +18,7 @@ def lint(session: nox.Session) -> None:
|
||||||
session.run("pre-commit", "run", "-a", *session.posargs)
|
session.run("pre-commit", "run", "-a", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
@nox.session(python=PYTHON_VERSIONS)
|
@nox.session
|
||||||
def tests(session: nox.Session) -> None:
|
def tests(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Run the tests (requires a compiler).
|
Run the tests (requires a compiler).
|
||||||
|
@ -57,30 +45,42 @@ def tests_packaging(session: nox.Session) -> None:
|
||||||
Run the packaging tests.
|
Run the packaging tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
session.install("-r", "tests/requirements.txt", "--prefer-binary")
|
session.install("-r", "tests/requirements.txt", "pip")
|
||||||
session.run("pytest", "tests/extra_python_package", *session.posargs)
|
session.run("pytest", "tests/extra_python_package", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
@nox.session(reuse_venv=True)
|
@nox.session(reuse_venv=True)
|
||||||
def docs(session: nox.Session) -> None:
|
def docs(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Build the docs. Pass "serve" to serve.
|
Build the docs. Pass --non-interactive to avoid serving.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
session.install("-r", "docs/requirements.txt")
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"-b", dest="builder", default="html", help="Build target (default: html)"
|
||||||
|
)
|
||||||
|
args, posargs = parser.parse_known_args(session.posargs)
|
||||||
|
serve = args.builder == "html" and session.interactive
|
||||||
|
|
||||||
|
extra_installs = ["sphinx-autobuild"] if serve else []
|
||||||
|
session.install("-r", "docs/requirements.txt", *extra_installs)
|
||||||
session.chdir("docs")
|
session.chdir("docs")
|
||||||
|
|
||||||
if "pdf" in session.posargs:
|
shared_args = (
|
||||||
session.run("sphinx-build", "-M", "latexpdf", ".", "_build")
|
"-n", # nitpicky mode
|
||||||
return
|
"-T", # full tracebacks
|
||||||
|
f"-b={args.builder}",
|
||||||
|
".",
|
||||||
|
f"_build/{args.builder}",
|
||||||
|
*posargs,
|
||||||
|
)
|
||||||
|
|
||||||
session.run("sphinx-build", "-M", "html", ".", "_build")
|
if serve:
|
||||||
|
session.run(
|
||||||
if "serve" in session.posargs:
|
"sphinx-autobuild", "--open-browser", "--ignore=.build", *shared_args
|
||||||
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
|
)
|
||||||
session.run("python", "-m", "http.server", "8000", "-d", "_build/html")
|
else:
|
||||||
elif session.posargs:
|
session.run("sphinx-build", "--keep-going", *shared_args)
|
||||||
session.error("Unsupported argument to docs")
|
|
||||||
|
|
||||||
|
|
||||||
@nox.session(reuse_venv=True)
|
@nox.session(reuse_venv=True)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info < (3, 6): # noqa: UP036
|
if sys.version_info < (3, 7): # noqa: UP036
|
||||||
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
|
msg = "pybind11 does not support Python < 3.7. v2.12 was the last release supporting Python 3.6."
|
||||||
raise ImportError(msg)
|
raise ImportError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# pylint: disable=missing-function-docstring
|
# pylint: disable=missing-function-docstring
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
from typing import Union
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
def _to_int(s: str) -> Union[int, str]:
|
def _to_int(s: str) -> int | str:
|
||||||
try:
|
try:
|
||||||
return int(s)
|
return int(s)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
__version__ = "2.11.1"
|
__version__ = "2.13.1"
|
||||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
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,6 +36,7 @@ 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
|
||||||
|
@ -52,7 +53,6 @@ from pathlib import Path
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
Dict,
|
|
||||||
Iterable,
|
Iterable,
|
||||||
Iterator,
|
Iterator,
|
||||||
List,
|
List,
|
||||||
|
@ -66,7 +66,9 @@ try:
|
||||||
from setuptools import Extension as _Extension
|
from setuptools import Extension as _Extension
|
||||||
from setuptools.command.build_ext import build_ext as _build_ext
|
from setuptools.command.build_ext import build_ext as _build_ext
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.command.build_ext import build_ext as _build_ext # type: ignore[assignment]
|
from distutils.command.build_ext import ( # type: ignore[assignment]
|
||||||
|
build_ext as _build_ext,
|
||||||
|
)
|
||||||
from distutils.extension import Extension as _Extension # type: ignore[assignment]
|
from distutils.extension import Extension as _Extension # type: ignore[assignment]
|
||||||
|
|
||||||
import distutils.ccompiler
|
import distutils.ccompiler
|
||||||
|
@ -111,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:
|
||||||
|
@ -248,7 +250,7 @@ cpp_flag_cache = None
|
||||||
|
|
||||||
|
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def auto_cpp_level(compiler: Any) -> Union[str, int]:
|
def auto_cpp_level(compiler: Any) -> 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.
|
||||||
"""
|
"""
|
||||||
|
@ -286,8 +288,8 @@ class build_ext(_build_ext): # noqa: N801
|
||||||
|
|
||||||
|
|
||||||
def intree_extensions(
|
def intree_extensions(
|
||||||
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None
|
paths: Iterable[str], package_dir: dict[str, str] | None = 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.
|
||||||
|
@ -351,7 +353,7 @@ CCompilerMethod = Callable[
|
||||||
distutils.ccompiler.CCompiler,
|
distutils.ccompiler.CCompiler,
|
||||||
List[str],
|
List[str],
|
||||||
Optional[str],
|
Optional[str],
|
||||||
Optional[Union[Tuple[str], Tuple[str, Optional[str]]]],
|
Optional[List[Union[Tuple[str], Tuple[str, Optional[str]]]]],
|
||||||
Optional[List[str]],
|
Optional[List[str]],
|
||||||
bool,
|
bool,
|
||||||
Optional[List[str]],
|
Optional[List[str]],
|
||||||
|
@ -407,7 +409,7 @@ class ParallelCompile:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
envvar: Optional[str] = None,
|
envvar: str | None = 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,
|
||||||
|
@ -416,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:
|
||||||
"""
|
"""
|
||||||
|
@ -425,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: Optional[str] = None,
|
output_dir: str | None = None,
|
||||||
macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None,
|
macros: list[tuple[str] | tuple[str, str | None]] | None = None,
|
||||||
include_dirs: Optional[List[str]] = None,
|
include_dirs: list[str] | None = None,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
extra_preargs: Optional[List[str]] = None,
|
extra_preargs: list[str] | None = None,
|
||||||
extra_postargs: Optional[List[str]] = None,
|
extra_postargs: list[str] | None = None,
|
||||||
depends: Optional[List[str]] = None,
|
depends: list[str] | None = 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]
|
||||||
|
|
|
@ -19,9 +19,8 @@ ignore = [
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
files = ["pybind11"]
|
files = ["pybind11"]
|
||||||
python_version = "3.6"
|
python_version = "3.8"
|
||||||
strict = true
|
strict = true
|
||||||
show_error_codes = true
|
|
||||||
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
|
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
|
||||||
warn_unreachable = true
|
warn_unreachable = true
|
||||||
|
|
||||||
|
@ -30,20 +29,8 @@ module = ["ghapi.*"]
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
minversion = "6.0"
|
|
||||||
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
|
|
||||||
xfail_strict = true
|
|
||||||
filterwarnings = ["error"]
|
|
||||||
log_cli_level = "info"
|
|
||||||
testpaths = [
|
|
||||||
"tests",
|
|
||||||
]
|
|
||||||
timeout=300
|
|
||||||
|
|
||||||
|
|
||||||
[tool.pylint]
|
[tool.pylint]
|
||||||
master.py-version = "3.6"
|
master.py-version = "3.7"
|
||||||
reports.output-format = "colorized"
|
reports.output-format = "colorized"
|
||||||
messages_control.disable = [
|
messages_control.disable = [
|
||||||
"design",
|
"design",
|
||||||
|
@ -57,10 +44,12 @@ messages_control.disable = [
|
||||||
"unused-argument", # covered by Ruff ARG
|
"unused-argument", # covered by Ruff ARG
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
select = [
|
target-version = "py37"
|
||||||
"E", "F", "W", # flake8
|
src = ["src"]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
extend-select = [
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"I", # isort
|
"I", # isort
|
||||||
"N", # pep8-naming
|
"N", # pep8-naming
|
||||||
|
@ -68,7 +57,6 @@ select = [
|
||||||
"C4", # flake8-comprehensions
|
"C4", # flake8-comprehensions
|
||||||
"EM", # flake8-errmsg
|
"EM", # flake8-errmsg
|
||||||
"ICN", # flake8-import-conventions
|
"ICN", # flake8-import-conventions
|
||||||
"ISC", # flake8-implicit-str-concat
|
|
||||||
"PGH", # pygrep-hooks
|
"PGH", # pygrep-hooks
|
||||||
"PIE", # flake8-pie
|
"PIE", # flake8-pie
|
||||||
"PL", # pylint
|
"PL", # pylint
|
||||||
|
@ -86,13 +74,14 @@ ignore = [
|
||||||
"PT004", # Fixture that doesn't return needs underscore (no, it is fine)
|
"PT004", # Fixture that doesn't return needs underscore (no, it is fine)
|
||||||
"SIM118", # iter(x) is not always the same as iter(x.keys())
|
"SIM118", # iter(x) is not always the same as iter(x.keys())
|
||||||
]
|
]
|
||||||
target-version = "py37"
|
|
||||||
src = ["src"]
|
|
||||||
unfixable = ["T20"]
|
unfixable = ["T20"]
|
||||||
exclude = []
|
|
||||||
line-length = 120
|
|
||||||
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.per-file-ignores]
|
|
||||||
"tests/**" = ["EM", "N"]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"tests/**" = ["EM", "N", "E721"]
|
||||||
"tests/test_call_policies.py" = ["PLC1901"]
|
"tests/test_call_policies.py" = ["PLC1901"]
|
||||||
|
|
||||||
|
[tool.repo-review]
|
||||||
|
ignore = ["PP"]
|
||||||
|
|
|
@ -14,13 +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.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
|
||||||
|
@ -39,5 +39,5 @@ project_urls =
|
||||||
Chat = https://gitter.im/pybind/Lobby
|
Chat = https://gitter.im/pybind/Lobby
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
python_requires = >=3.6
|
python_requires = >=3.7
|
||||||
zip_safe = False
|
zip_safe = False
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/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
|
||||||
|
@ -9,9 +10,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
|
||||||
|
|
||||||
|
@ -23,7 +24,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"])
|
||||||
|
@ -64,7 +65,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__"]
|
||||||
|
@ -84,9 +85,7 @@ 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(
|
def get_and_replace(filename: Path, binary: bool = False, **opts: str) -> bytes | str:
|
||||||
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()
|
||||||
|
@ -97,7 +96,7 @@ def get_and_replace(
|
||||||
# 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:
|
||||||
|
@ -112,7 +111,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) -> Iterator[None]:
|
def remove_output(*sources: str) -> Generator[None, None, None]:
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
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.
|
||||||
|
@ -144,6 +144,7 @@ set(PYBIND11_TEST_FILES
|
||||||
test_opaque_types
|
test_opaque_types
|
||||||
test_operator_overloading
|
test_operator_overloading
|
||||||
test_pickling
|
test_pickling
|
||||||
|
test_python_multiple_inheritance
|
||||||
test_pytypes
|
test_pytypes
|
||||||
test_sequences_and_iterators
|
test_sequences_and_iterators
|
||||||
test_smart_ptr
|
test_smart_ptr
|
||||||
|
@ -329,7 +330,7 @@ if(Boost_FOUND)
|
||||||
add_library(Boost::headers IMPORTED INTERFACE)
|
add_library(Boost::headers IMPORTED INTERFACE)
|
||||||
if(TARGET Boost::boost)
|
if(TARGET Boost::boost)
|
||||||
# Classic FindBoost
|
# Classic FindBoost
|
||||||
set_property(TARGET Boost::boost PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost)
|
set_property(TARGET Boost::headers PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost)
|
||||||
else()
|
else()
|
||||||
# Very old FindBoost, or newer Boost than CMake in older CMakes
|
# Very old FindBoost, or newer Boost than CMake in older CMakes
|
||||||
set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
||||||
|
@ -519,11 +520,15 @@ set(PYBIND11_TEST_PREFIX_COMMAND
|
||||||
""
|
""
|
||||||
CACHE STRING "Put this before pytest, use for checkers and such")
|
CACHE STRING "Put this before pytest, use for checkers and such")
|
||||||
|
|
||||||
|
set(PYBIND11_PYTEST_ARGS
|
||||||
|
""
|
||||||
|
CACHE STRING "Extra arguments for pytest")
|
||||||
|
|
||||||
# A single command to compile and run the tests
|
# A single command to compile and run the tests
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
pytest
|
pytest
|
||||||
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
|
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
|
||||||
${PYBIND11_ABS_PYTEST_FILES}
|
${PYBIND11_ABS_PYTEST_FILES} ${PYBIND11_PYTEST_ARGS}
|
||||||
DEPENDS ${test_targets}
|
DEPENDS ${test_targets}
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
USES_TERMINAL)
|
USES_TERMINAL)
|
||||||
|
|
|
@ -4,6 +4,8 @@ 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
|
||||||
|
@ -218,4 +220,5 @@ def pytest_report_header(config):
|
||||||
f" {pybind11_tests.cpp_std}"
|
f" {pybind11_tests.cpp_std}"
|
||||||
f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
|
f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
|
||||||
f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
|
f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
|
||||||
|
f" PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}"
|
||||||
)
|
)
|
||||||
|
|
|
@ -92,6 +92,9 @@ 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",
|
||||||
|
|
|
@ -16,12 +16,12 @@ namespace {
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
|
||||||
void interleaved_error_already_set() {
|
void interleaved_error_already_set() {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "1st error.");
|
py::set_error(PyExc_RuntimeError, "1st error.");
|
||||||
try {
|
try {
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
} catch (const py::error_already_set &) {
|
} catch (const py::error_already_set &) {
|
||||||
// The 2nd error could be conditional in a real application.
|
// The 2nd error could be conditional in a real application.
|
||||||
PyErr_SetString(PyExc_RuntimeError, "2nd error.");
|
py::set_error(PyExc_RuntimeError, "2nd error.");
|
||||||
} // Here the 1st error is destroyed before the 2nd error is fetched.
|
} // Here the 1st error is destroyed before the 2nd error is fetched.
|
||||||
// The error_already_set dtor triggers a pybind11::detail::get_internals()
|
// The error_already_set dtor triggers a pybind11::detail::get_internals()
|
||||||
// call via pybind11::gil_scoped_acquire.
|
// call via pybind11::gil_scoped_acquire.
|
||||||
|
@ -42,6 +42,9 @@ 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",
|
||||||
|
|
|
@ -11,4 +11,6 @@
|
||||||
|
|
||||||
#include "test_eigen_tensor.inl"
|
#include "test_eigen_tensor.inl"
|
||||||
|
|
||||||
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m) { eigen_tensor_test::test_module(m); }
|
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m, pybind11::mod_gil_not_used()) {
|
||||||
|
eigen_tensor_test::test_module(m);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -9,6 +12,7 @@ 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,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
|
@ -35,6 +37,7 @@ main_headers = {
|
||||||
"include/pybind11/eval.h",
|
"include/pybind11/eval.h",
|
||||||
"include/pybind11/functional.h",
|
"include/pybind11/functional.h",
|
||||||
"include/pybind11/gil.h",
|
"include/pybind11/gil.h",
|
||||||
|
"include/pybind11/gil_safe_call_once.h",
|
||||||
"include/pybind11/iostream.h",
|
"include/pybind11/iostream.h",
|
||||||
"include/pybind11/numpy.h",
|
"include/pybind11/numpy.h",
|
||||||
"include/pybind11/operators.h",
|
"include/pybind11/operators.h",
|
||||||
|
@ -44,6 +47,7 @@ main_headers = {
|
||||||
"include/pybind11/stl.h",
|
"include/pybind11/stl.h",
|
||||||
"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",
|
||||||
}
|
}
|
||||||
|
|
||||||
detail_headers = {
|
detail_headers = {
|
||||||
|
@ -71,6 +75,7 @@ cmake_files = {
|
||||||
"share/cmake/pybind11/pybind11Common.cmake",
|
"share/cmake/pybind11/pybind11Common.cmake",
|
||||||
"share/cmake/pybind11/pybind11Config.cmake",
|
"share/cmake/pybind11/pybind11Config.cmake",
|
||||||
"share/cmake/pybind11/pybind11ConfigVersion.cmake",
|
"share/cmake/pybind11/pybind11ConfigVersion.cmake",
|
||||||
|
"share/cmake/pybind11/pybind11GuessPythonExtSuffix.cmake",
|
||||||
"share/cmake/pybind11/pybind11NewTools.cmake",
|
"share/cmake/pybind11/pybind11NewTools.cmake",
|
||||||
"share/cmake/pybind11/pybind11Targets.cmake",
|
"share/cmake/pybind11/pybind11Targets.cmake",
|
||||||
"share/cmake/pybind11/pybind11Tools.cmake",
|
"share/cmake/pybind11/pybind11Tools.cmake",
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
PYBIND11_MODULE(pybind11_cross_module_tests, m, py::mod_gil_not_used()) {
|
||||||
m.doc() = "pybind11 cross-module test module";
|
m.doc() = "pybind11 cross-module test module";
|
||||||
|
|
||||||
// test_local_bindings.py tests:
|
// test_local_bindings.py tests:
|
||||||
|
@ -31,11 +31,11 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||||
// test_exceptions.py
|
// test_exceptions.py
|
||||||
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
|
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
|
||||||
m.def("raise_runtime_error", []() {
|
m.def("raise_runtime_error", []() {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "My runtime error");
|
py::set_error(PyExc_RuntimeError, "My runtime error");
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
});
|
});
|
||||||
m.def("raise_value_error", []() {
|
m.def("raise_value_error", []() {
|
||||||
PyErr_SetString(PyExc_ValueError, "My value error");
|
py::set_error(PyExc_ValueError, "My value error");
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
});
|
});
|
||||||
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
||||||
|
@ -49,7 +49,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||||
std::rethrow_exception(p);
|
std::rethrow_exception(p);
|
||||||
}
|
}
|
||||||
} catch (const shared_exception &e) {
|
} catch (const shared_exception &e) {
|
||||||
PyErr_SetString(PyExc_KeyError, e.what());
|
py::set_error(PyExc_KeyError, e.what());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||||
std::rethrow_exception(p);
|
std::rethrow_exception(p);
|
||||||
}
|
}
|
||||||
} catch (const LocalException &e) {
|
} catch (const LocalException &e) {
|
||||||
PyErr_SetString(PyExc_KeyError, e.what());
|
py::set_error(PyExc_KeyError, e.what());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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::get_internals().registered_instances.size();
|
return py::detail::num_registered_instances();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,26 +75,34 @@ const char *cpp_std() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_MODULE(pybind11_tests, m) {
|
PYBIND11_MODULE(pybind11_tests, m, py::mod_gil_not_used()) {
|
||||||
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
|
||||||
// ("just enough" to be conclusive).
|
// ("just enough" to be conclusive).
|
||||||
#if defined(_MSC_FULL_VER)
|
#if defined(__VERSION__)
|
||||||
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
|
|
||||||
#elif defined(__VERSION__)
|
|
||||||
m.attr("compiler_info") = __VERSION__;
|
m.attr("compiler_info") = __VERSION__;
|
||||||
|
#elif defined(_MSC_FULL_VER)
|
||||||
|
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
|
||||||
#else
|
#else
|
||||||
m.attr("compiler_info") = py::none();
|
m.attr("compiler_info") = py::none();
|
||||||
#endif
|
#endif
|
||||||
m.attr("cpp_std") = cpp_std();
|
m.attr("cpp_std") = cpp_std();
|
||||||
m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
|
m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
|
||||||
|
// Free threaded Python uses UINT32_MAX for immortal objects.
|
||||||
|
m.attr("PYBIND11_REFCNT_IMMORTAL") = UINT32_MAX;
|
||||||
m.attr("PYBIND11_SIMPLE_GIL_MANAGEMENT") =
|
m.attr("PYBIND11_SIMPLE_GIL_MANAGEMENT") =
|
||||||
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||||
true;
|
true;
|
||||||
#else
|
#else
|
||||||
false;
|
false;
|
||||||
#endif
|
#endif
|
||||||
|
m.attr("PYBIND11_NUMPY_1_ONLY") =
|
||||||
|
#if defined(PYBIND11_NUMPY_1_ONLY)
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
bind_ConstructorStats(m);
|
bind_ConstructorStats(m);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#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;
|
||||||
|
|
||||||
|
@ -52,6 +54,17 @@ 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 {};
|
||||||
|
|
|
@ -20,3 +20,4 @@ filterwarnings =
|
||||||
# bogus numpy ABI warning (see numpy/#432)
|
# bogus numpy ABI warning (see numpy/#432)
|
||||||
ignore:.*numpy.dtype size changed.*:RuntimeWarning
|
ignore:.*numpy.dtype size changed.*:RuntimeWarning
|
||||||
ignore:.*numpy.ufunc size changed.*:RuntimeWarning
|
ignore:.*numpy.ufunc size changed.*:RuntimeWarning
|
||||||
|
default:The global interpreter lock:RuntimeWarning
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
build==0.8.0
|
--only-binary=:all:
|
||||||
numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
|
build~=1.0; python_version>="3.7"
|
||||||
numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
|
numpy~=1.20.0; python_version=="3.7" and platform_python_implementation=="PyPy"
|
||||||
numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"
|
numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy"
|
||||||
numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11"
|
numpy~=1.25.0; python_version=="3.9" and platform_python_implementation=='PyPy'
|
||||||
pytest==7.0.0
|
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.26.0; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13"
|
||||||
|
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.10.0; 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.11.1; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13" and sys_platform!='win32'
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
asyncio = pytest.importorskip("asyncio")
|
asyncio = pytest.importorskip("asyncio")
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import io
|
import io
|
||||||
import struct
|
import struct
|
||||||
|
@ -219,3 +221,10 @@ def test_ctypes_from_buffer():
|
||||||
assert cinfo.shape == pyinfo.shape
|
assert cinfo.shape == pyinfo.shape
|
||||||
assert cinfo.strides == pyinfo.strides
|
assert cinfo.strides == pyinfo.strides
|
||||||
assert not cinfo.readonly
|
assert not cinfo.readonly
|
||||||
|
|
||||||
|
|
||||||
|
def test_buffer_docstring():
|
||||||
|
assert (
|
||||||
|
m.get_buffer_info.__doc__.strip()
|
||||||
|
== "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info"
|
||||||
|
)
|
||||||
|
|
|
@ -95,7 +95,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||||
} // 𝐀, utf16
|
} // 𝐀, utf16
|
||||||
else {
|
else {
|
||||||
wstr.push_back((wchar_t) mathbfA32);
|
wstr.push_back((wchar_t) mathbfA32);
|
||||||
} // 𝐀, utf32
|
} // 𝐀, utf32
|
||||||
wstr.push_back(0x7a); // z
|
wstr.push_back(0x7a); // z
|
||||||
|
|
||||||
m.def("good_utf8_string", []() {
|
m.def("good_utf8_string", []() {
|
||||||
|
@ -104,10 +104,9 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||||
m.def("good_utf16_string", [=]() {
|
m.def("good_utf16_string", [=]() {
|
||||||
return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16});
|
return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16});
|
||||||
}); // b‽🎂𝐀z
|
}); // b‽🎂𝐀z
|
||||||
m.def("good_utf32_string", [=]() {
|
m.def("good_utf32_string",
|
||||||
return std::u32string({a32, mathbfA32, cake32, ib32, z32});
|
[=]() { return std::u32string({a32, mathbfA32, cake32, ib32, z32}); }); // a𝐀🎂‽z
|
||||||
}); // a𝐀🎂‽z
|
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
|
||||||
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
|
|
||||||
m.def("bad_utf8_string", []() {
|
m.def("bad_utf8_string", []() {
|
||||||
return std::string("abc\xd0"
|
return std::string("abc\xd0"
|
||||||
"def");
|
"def");
|
||||||
|
@ -117,9 +116,8 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||||
// UnicodeDecodeError
|
// UnicodeDecodeError
|
||||||
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
|
||||||
if (sizeof(wchar_t) == 2) {
|
if (sizeof(wchar_t) == 2) {
|
||||||
m.def("bad_wchar_string", [=]() {
|
m.def("bad_wchar_string",
|
||||||
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
[=]() { return std::wstring({wchar_t(0x61), wchar_t(0xd800)}); });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
m.def("u8_Z", []() -> char { return 'Z'; });
|
m.def("u8_Z", []() -> char { return 'Z'; });
|
||||||
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
m.def("u8_eacute", []() -> char { return '\xe9'; });
|
||||||
|
@ -236,8 +234,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||||
|
|
||||||
// test_int_convert
|
// test_int_convert
|
||||||
m.def("int_passthrough", [](int arg) { return arg; });
|
m.def("int_passthrough", [](int arg) { return arg; });
|
||||||
m.def(
|
m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
|
||||||
"int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
|
|
||||||
|
|
||||||
// test_tuple
|
// test_tuple
|
||||||
m.def(
|
m.def(
|
||||||
|
@ -302,8 +299,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||||
|
|
||||||
// test_bool_caster
|
// test_bool_caster
|
||||||
m.def("bool_passthrough", [](bool arg) { return arg; });
|
m.def("bool_passthrough", [](bool arg) { return arg; });
|
||||||
m.def(
|
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
|
||||||
"bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
|
|
||||||
|
|
||||||
// TODO: This should be disabled and fixed in future Intel compilers
|
// TODO: This should be disabled and fixed in future Intel compilers
|
||||||
#if !defined(__INTEL_COMPILER)
|
#if !defined(__INTEL_COMPILER)
|
||||||
|
@ -311,8 +307,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||||
// When compiled with the Intel compiler, this results in segmentation faults when importing
|
// When compiled with the Intel compiler, this results in segmentation faults when importing
|
||||||
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
|
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
|
||||||
// a newer version of icc is available.
|
// a newer version of icc is available.
|
||||||
m.def(
|
m.def("bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
|
||||||
"bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// test_reference_wrapper
|
// test_reference_wrapper
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -352,7 +354,7 @@ def test_tuple(doc):
|
||||||
assert (
|
assert (
|
||||||
doc(m.pair_passthrough)
|
doc(m.pair_passthrough)
|
||||||
== """
|
== """
|
||||||
pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
|
pair_passthrough(arg0: tuple[bool, str]) -> tuple[str, bool]
|
||||||
|
|
||||||
Return a pair in reversed order
|
Return a pair in reversed order
|
||||||
"""
|
"""
|
||||||
|
@ -360,7 +362,7 @@ def test_tuple(doc):
|
||||||
assert (
|
assert (
|
||||||
doc(m.tuple_passthrough)
|
doc(m.tuple_passthrough)
|
||||||
== """
|
== """
|
||||||
tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
|
tuple_passthrough(arg0: tuple[bool, str, int]) -> tuple[int, str, bool]
|
||||||
|
|
||||||
Return a triple in reversed order
|
Return a triple in reversed order
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -63,10 +63,8 @@ TEST_SUBMODULE(call_policies, m) {
|
||||||
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
|
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
|
||||||
.def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
|
.def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
|
||||||
|
|
||||||
m.def(
|
m.def("free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
|
||||||
"free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
|
m.def("invalid_arg_index", [] {}, py::keep_alive<0, 1>());
|
||||||
m.def(
|
|
||||||
"invalid_arg_index", [] {}, py::keep_alive<0, 1>());
|
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
// test_alive_gc
|
// test_alive_gc
|
||||||
|
@ -97,7 +95,7 @@ TEST_SUBMODULE(call_policies, m) {
|
||||||
},
|
},
|
||||||
py::call_guard<DependentGuard, CustomGuard>());
|
py::call_guard<DependentGuard, CustomGuard>());
|
||||||
|
|
||||||
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
|
// `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,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
|
@ -216,3 +218,10 @@ def test_custom_func():
|
||||||
def test_custom_func2():
|
def test_custom_func2():
|
||||||
assert m.custom_function2(3) == 27
|
assert m.custom_function2(3) == 27
|
||||||
assert m.roundtrip(m.custom_function2)(3) == 27
|
assert m.roundtrip(m.custom_function2)(3) == 27
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_docstring():
|
||||||
|
assert (
|
||||||
|
m.test_tuple_unpacking.__doc__.strip()
|
||||||
|
== "test_tuple_unpacking(arg0: Callable) -> object"
|
||||||
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
@ -403,7 +403,7 @@ TEST_SUBMODULE(class_, m) {
|
||||||
// [workaround(intel)] = default does not work here
|
// [workaround(intel)] = default does not work here
|
||||||
// Removing or defaulting this destructor results in linking errors with the Intel compiler
|
// Removing or defaulting this destructor results in linking errors with the Intel compiler
|
||||||
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
|
||||||
~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
|
~PublicistB() override {}; // NOLINT(modernize-use-equals-default)
|
||||||
using ProtectedB::foo;
|
using ProtectedB::foo;
|
||||||
using ProtectedB::get_self;
|
using ProtectedB::get_self;
|
||||||
using ProtectedB::void_foo;
|
using ProtectedB::void_foo;
|
||||||
|
@ -461,8 +461,7 @@ TEST_SUBMODULE(class_, m) {
|
||||||
py::class_<Nested>(base, "Nested")
|
py::class_<Nested>(base, "Nested")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
|
.def("fn", [](Nested &, int, NestBase &, Nested &) {})
|
||||||
.def(
|
.def("fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
|
||||||
"fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
|
|
||||||
base.def("g", [](NestBase &, Nested &) {});
|
base.def("g", [](NestBase &, Nested &) {});
|
||||||
base.def("h", []() { return NestBase(); });
|
base.def("h", []() { return NestBase(); });
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
import env
|
||||||
from pybind11_tests import ConstructorStats, UserType
|
from pybind11_tests import PYBIND11_REFCNT_IMMORTAL, ConstructorStats, UserType
|
||||||
from pybind11_tests import class_ as m
|
from pybind11_tests import class_ as m
|
||||||
|
|
||||||
|
|
||||||
|
@ -203,6 +207,18 @@ def test_inheritance_init(msg):
|
||||||
assert msg(exc_info.value) == expected
|
assert msg(exc_info.value) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"mock_return_value", [None, (1, 2, 3), m.Pet("Polly", "parrot"), m.Dog("Molly")]
|
||||||
|
)
|
||||||
|
def test_mock_new(mock_return_value):
|
||||||
|
with mock.patch.object(
|
||||||
|
m.Pet, "__new__", return_value=mock_return_value
|
||||||
|
) as mock_new:
|
||||||
|
obj = m.Pet("Noname", "Nospecies")
|
||||||
|
assert obj is mock_return_value
|
||||||
|
mock_new.assert_called_once_with(m.Pet, "Noname", "Nospecies")
|
||||||
|
|
||||||
|
|
||||||
def test_automatic_upcasting():
|
def test_automatic_upcasting():
|
||||||
assert type(m.return_class_1()).__name__ == "DerivedClass1"
|
assert type(m.return_class_1()).__name__ == "DerivedClass1"
|
||||||
assert type(m.return_class_2()).__name__ == "DerivedClass2"
|
assert type(m.return_class_2()).__name__ == "DerivedClass2"
|
||||||
|
@ -363,7 +379,9 @@ def test_class_refcount():
|
||||||
refcount_3 = getrefcount(cls)
|
refcount_3 = getrefcount(cls)
|
||||||
|
|
||||||
assert refcount_1 == refcount_3
|
assert refcount_1 == refcount_3
|
||||||
assert refcount_2 > refcount_1
|
assert (refcount_2 > refcount_1) or (
|
||||||
|
refcount_2 == refcount_1 == PYBIND11_REFCNT_IMMORTAL
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_reentrant_implicit_conversion_failure(msg):
|
def test_reentrant_implicit_conversion_failure(msg):
|
||||||
|
|
|
@ -5,9 +5,8 @@ function(pybind11_add_build_test name)
|
||||||
|
|
||||||
set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
|
set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
|
||||||
|
|
||||||
|
list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}")
|
||||||
if(PYBIND11_FINDPYTHON)
|
if(PYBIND11_FINDPYTHON)
|
||||||
list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}")
|
|
||||||
|
|
||||||
if(DEFINED Python_ROOT_DIR)
|
if(DEFINED Python_ROOT_DIR)
|
||||||
list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}")
|
list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(test_installed_embed CXX)
|
project(test_installed_embed CXX)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(test_installed_module CXX)
|
project(test_installed_module CXX)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(test_installed_function CXX)
|
project(test_installed_function CXX)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
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) {
|
PYBIND11_MODULE(test_cmake_build, m, py::mod_gil_not_used()) {
|
||||||
m.def("add", [](int i, int j) { return i + j; });
|
m.def("add", [](int i, int j) { return i + j; });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(test_subdirectory_embed CXX)
|
project(test_subdirectory_embed CXX)
|
||||||
|
@ -16,6 +16,12 @@ set(PYBIND11_INSTALL
|
||||||
CACHE BOOL "")
|
CACHE BOOL "")
|
||||||
set(PYBIND11_EXPORT_NAME test_export)
|
set(PYBIND11_EXPORT_NAME test_export)
|
||||||
|
|
||||||
|
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
|
||||||
|
# (makes transition easier while we support both modes).
|
||||||
|
if(DEFINED PYTHON_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE)
|
||||||
|
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
||||||
|
|
||||||
# Test basic target functionality
|
# Test basic target functionality
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(test_subdirectory_function CXX)
|
project(test_subdirectory_function CXX)
|
||||||
|
|
||||||
|
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
|
||||||
|
# (makes transition easier while we support both modes).
|
||||||
|
if(DEFINED PYTHON_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE)
|
||||||
|
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
||||||
pybind11_add_module(test_subdirectory_function ../main.cpp)
|
pybind11_add_module(test_subdirectory_function ../main.cpp)
|
||||||
set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build)
|
set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
|
if(${CMAKE_VERSION} VERSION_LESS 3.29)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.26)
|
cmake_policy(VERSION 3.29)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(test_subdirectory_target CXX)
|
project(test_subdirectory_target CXX)
|
||||||
|
|
||||||
|
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
|
||||||
|
# (makes transition easier while we support both modes).
|
||||||
|
if(DEFINED PYTHON_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE)
|
||||||
|
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
|
||||||
|
|
||||||
add_library(test_subdirectory_target MODULE ../main.cpp)
|
add_library(test_subdirectory_target MODULE ../main.cpp)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import test_cmake_build
|
import test_cmake_build
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import const_name as m
|
from pybind11_tests import const_name as m
|
||||||
|
|
|
@ -54,7 +54,11 @@ int f2(int x) noexcept(true) { return x + 2; }
|
||||||
int f3(int x) noexcept(false) { return x + 3; }
|
int f3(int x) noexcept(false) { return x + 3; }
|
||||||
PYBIND11_WARNING_PUSH
|
PYBIND11_WARNING_PUSH
|
||||||
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
|
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
|
||||||
|
#if defined(__clang_major__) && __clang_major__ >= 5
|
||||||
|
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-dynamic-exception-spec")
|
||||||
|
#else
|
||||||
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
|
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
|
||||||
|
#endif
|
||||||
// NOLINTNEXTLINE(modernize-use-noexcept)
|
// NOLINTNEXTLINE(modernize-use-noexcept)
|
||||||
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
|
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
|
||||||
PYBIND11_WARNING_POP
|
PYBIND11_WARNING_POP
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
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,6 +157,13 @@ 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")
|
||||||
|
@ -289,11 +296,15 @@ TEST_SUBMODULE(copy_move_policies, m) {
|
||||||
"get_moveissue1",
|
"get_moveissue1",
|
||||||
[](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
|
[](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
|
||||||
py::return_value_policy::move);
|
py::return_value_policy::move);
|
||||||
m.def(
|
m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
||||||
"get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
|
|
||||||
|
|
||||||
// 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,3 +1,5 @@
|
||||||
|
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
|
||||||
|
@ -130,3 +132,9 @@ 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"
|
||||||
|
|
|
@ -134,6 +134,16 @@ struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace PYBIND11_NAMESPACE
|
} // namespace PYBIND11_NAMESPACE
|
||||||
|
|
||||||
|
// This simply is required to compile
|
||||||
|
namespace ADL_issue {
|
||||||
|
template <typename OutStringType = std::string, typename... Args>
|
||||||
|
OutStringType concat(Args &&...) {
|
||||||
|
return OutStringType();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct test {};
|
||||||
|
} // namespace ADL_issue
|
||||||
|
|
||||||
TEST_SUBMODULE(custom_type_casters, m) {
|
TEST_SUBMODULE(custom_type_casters, m) {
|
||||||
// test_custom_type_casters
|
// test_custom_type_casters
|
||||||
|
|
||||||
|
@ -175,14 +185,10 @@ TEST_SUBMODULE(custom_type_casters, m) {
|
||||||
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
|
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
|
||||||
py::arg() = ArgAlwaysConverts());
|
py::arg() = ArgAlwaysConverts());
|
||||||
|
|
||||||
m.def(
|
m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
|
||||||
"floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
|
m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
|
||||||
m.def(
|
m.def("ints_preferred", [](int i) { return i / 2; }, "i"_a);
|
||||||
"floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
|
m.def("ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
|
||||||
m.def(
|
|
||||||
"ints_preferred", [](int i) { return i / 2; }, "i"_a);
|
|
||||||
m.def(
|
|
||||||
"ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
|
|
||||||
|
|
||||||
// test_custom_caster_destruction
|
// test_custom_caster_destruction
|
||||||
// Test that `take_ownership` works on types with a custom type caster when given a pointer
|
// Test that `take_ownership` works on types with a custom type caster when given a pointer
|
||||||
|
@ -206,4 +212,6 @@ TEST_SUBMODULE(custom_type_casters, m) {
|
||||||
py::return_value_policy::reference);
|
py::return_value_policy::reference);
|
||||||
|
|
||||||
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
|
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
|
||||||
|
|
||||||
|
m.def("_adl_issue", [](const ADL_issue::test &) {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import custom_type_casters as m
|
from pybind11_tests import custom_type_casters as m
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import gc
|
import gc
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
|
|
|
@ -15,37 +15,26 @@ TEST_SUBMODULE(docstring_options, m) {
|
||||||
py::options options;
|
py::options options;
|
||||||
options.disable_function_signatures();
|
options.disable_function_signatures();
|
||||||
|
|
||||||
m.def(
|
m.def("test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
|
||||||
"test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
|
m.def("test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
||||||
m.def(
|
|
||||||
"test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
|
||||||
|
|
||||||
m.def(
|
m.def("test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
|
||||||
"test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
|
m.def("test_overloaded1", [](double) {}, py::arg("d"));
|
||||||
m.def(
|
|
||||||
"test_overloaded1", [](double) {}, py::arg("d"));
|
|
||||||
|
|
||||||
m.def(
|
m.def("test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
|
||||||
"test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
|
m.def("test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
|
||||||
m.def(
|
|
||||||
"test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
|
|
||||||
|
|
||||||
m.def(
|
m.def("test_overloaded3", [](int) {}, py::arg("i"));
|
||||||
"test_overloaded3", [](int) {}, py::arg("i"));
|
m.def("test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
|
||||||
m.def(
|
|
||||||
"test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
|
|
||||||
|
|
||||||
options.enable_function_signatures();
|
options.enable_function_signatures();
|
||||||
|
|
||||||
m.def(
|
m.def("test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
|
||||||
"test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
|
m.def("test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
||||||
m.def(
|
|
||||||
"test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
|
||||||
|
|
||||||
options.disable_function_signatures().disable_user_defined_docstrings();
|
options.disable_function_signatures().disable_user_defined_docstrings();
|
||||||
|
|
||||||
m.def(
|
m.def("test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
||||||
"test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
|
||||||
|
|
||||||
{
|
{
|
||||||
py::options nested_options;
|
py::options nested_options;
|
||||||
|
@ -59,8 +48,7 @@ TEST_SUBMODULE(docstring_options, m) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.def(
|
m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
||||||
"test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
|
|
||||||
|
|
||||||
{
|
{
|
||||||
py::options options;
|
py::options options;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue