mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-29 16:37:13 +00:00
Merge branch 'master' into stable
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
This commit is contained in:
commit
0ba639d617
@ -1,6 +1,6 @@
|
|||||||
version: 1.0.{build}
|
version: 1.0.{build}
|
||||||
image:
|
image:
|
||||||
- Visual Studio 2015
|
- Visual Studio 2017
|
||||||
test: off
|
test: off
|
||||||
skip_branch_with_pr: true
|
skip_branch_with_pr: true
|
||||||
build:
|
build:
|
||||||
@ -11,11 +11,9 @@ environment:
|
|||||||
matrix:
|
matrix:
|
||||||
- PYTHON: 36
|
- PYTHON: 36
|
||||||
CONFIG: Debug
|
CONFIG: Debug
|
||||||
- PYTHON: 27
|
|
||||||
CONFIG: Debug
|
|
||||||
install:
|
install:
|
||||||
- ps: |
|
- ps: |
|
||||||
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
$env:CMAKE_GENERATOR = "Visual Studio 15 2017"
|
||||||
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
||||||
$env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH"
|
$env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH"
|
||||||
python -W ignore -m pip install --upgrade pip wheel
|
python -W ignore -m pip install --upgrade pip wheel
|
||||||
|
123
.clang-tidy
123
.clang-tidy
@ -1,72 +1,75 @@
|
|||||||
FormatStyle: file
|
FormatStyle: file
|
||||||
|
|
||||||
Checks: '
|
Checks: |
|
||||||
*bugprone*,
|
*bugprone*,
|
||||||
clang-analyzer-optin.performance.Padding,
|
*performance*,
|
||||||
clang-analyzer-optin.cplusplus.VirtualCall,
|
clang-analyzer-optin.cplusplus.VirtualCall,
|
||||||
cppcoreguidelines-init-variables,
|
clang-analyzer-optin.performance.Padding,
|
||||||
cppcoreguidelines-prefer-member-initializer,
|
cppcoreguidelines-init-variables,
|
||||||
cppcoreguidelines-pro-type-static-cast-downcast,
|
cppcoreguidelines-prefer-member-initializer,
|
||||||
cppcoreguidelines-slicing,
|
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
google-explicit-constructor,
|
cppcoreguidelines-slicing,
|
||||||
llvm-namespace-comment,
|
google-explicit-constructor,
|
||||||
misc-misplaced-const,
|
llvm-namespace-comment,
|
||||||
misc-non-copyable-objects,
|
misc-definitions-in-headers,
|
||||||
misc-static-assert,
|
misc-misplaced-const,
|
||||||
misc-throw-by-value-catch-by-reference,
|
misc-non-copyable-objects,
|
||||||
misc-uniqueptr-reset-release,
|
misc-static-assert,
|
||||||
misc-unused-parameters,
|
misc-throw-by-value-catch-by-reference,
|
||||||
modernize-avoid-bind,
|
misc-uniqueptr-reset-release,
|
||||||
modernize-make-shared,
|
misc-unused-parameters,
|
||||||
modernize-redundant-void-arg,
|
modernize-avoid-bind,
|
||||||
modernize-replace-auto-ptr,
|
modernize-loop-convert,
|
||||||
modernize-replace-disallow-copy-and-assign-macro,
|
modernize-make-shared,
|
||||||
modernize-replace-random-shuffle,
|
modernize-redundant-void-arg,
|
||||||
modernize-shrink-to-fit,
|
modernize-replace-auto-ptr,
|
||||||
modernize-use-auto,
|
modernize-replace-disallow-copy-and-assign-macro,
|
||||||
modernize-use-bool-literals,
|
modernize-replace-random-shuffle,
|
||||||
modernize-use-equals-default,
|
modernize-shrink-to-fit,
|
||||||
modernize-use-equals-delete,
|
modernize-use-auto,
|
||||||
modernize-use-default-member-init,
|
modernize-use-bool-literals,
|
||||||
modernize-use-noexcept,
|
modernize-use-default-member-init,
|
||||||
modernize-use-emplace,
|
modernize-use-emplace,
|
||||||
modernize-use-override,
|
modernize-use-equals-default,
|
||||||
modernize-use-using,
|
modernize-use-equals-delete,
|
||||||
*performance*,
|
modernize-use-noexcept,
|
||||||
readability-avoid-const-params-in-decls,
|
modernize-use-nullptr,
|
||||||
readability-braces-around-statements,
|
modernize-use-override,
|
||||||
readability-const-return-type,
|
modernize-use-using,
|
||||||
readability-container-size-empty,
|
readability-avoid-const-params-in-decls,
|
||||||
readability-delete-null-pointer,
|
readability-braces-around-statements,
|
||||||
readability-else-after-return,
|
readability-const-return-type,
|
||||||
readability-implicit-bool-conversion,
|
readability-container-size-empty,
|
||||||
readability-inconsistent-declaration-parameter-name,
|
readability-delete-null-pointer,
|
||||||
readability-make-member-function-const,
|
readability-else-after-return,
|
||||||
readability-misplaced-array-index,
|
readability-implicit-bool-conversion,
|
||||||
readability-non-const-parameter,
|
readability-inconsistent-declaration-parameter-name,
|
||||||
readability-qualified-auto,
|
readability-make-member-function-const,
|
||||||
readability-redundant-function-ptr-dereference,
|
readability-misplaced-array-index,
|
||||||
readability-redundant-smartptr-get,
|
readability-non-const-parameter,
|
||||||
readability-redundant-string-cstr,
|
readability-qualified-auto,
|
||||||
readability-simplify-subscript-expr,
|
readability-redundant-function-ptr-dereference,
|
||||||
readability-static-accessed-through-instance,
|
readability-redundant-smartptr-get,
|
||||||
readability-static-definition-in-anonymous-namespace,
|
readability-redundant-string-cstr,
|
||||||
readability-string-compare,
|
readability-simplify-subscript-expr,
|
||||||
readability-suspicious-call-argument,
|
readability-static-accessed-through-instance,
|
||||||
readability-uniqueptr-delete-release,
|
readability-static-definition-in-anonymous-namespace,
|
||||||
-bugprone-exception-escape,
|
readability-string-compare,
|
||||||
-bugprone-reserved-identifier,
|
readability-suspicious-call-argument,
|
||||||
-bugprone-unused-raii,
|
readability-uniqueptr-delete-release,
|
||||||
'
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-exception-escape,
|
||||||
|
-bugprone-reserved-identifier,
|
||||||
|
-bugprone-unused-raii,
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
||||||
value: true
|
value: true
|
||||||
|
- key: performance-inefficient-string-concatenation.StrictMode
|
||||||
|
value: true
|
||||||
- key: performance-unnecessary-value-param.AllowedTypes
|
- key: performance-unnecessary-value-param.AllowedTypes
|
||||||
value: 'exception_ptr$;'
|
value: 'exception_ptr$;'
|
||||||
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||||
value: true
|
value: true
|
||||||
|
|
||||||
HeaderFilterRegex: 'pybind11/.*h'
|
HeaderFilterRegex: 'pybind11/.*h'
|
||||||
|
|
||||||
WarningsAsErrors: '*'
|
|
||||||
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
docs/*.svg binary
|
19
.github/CONTRIBUTING.md
vendored
19
.github/CONTRIBUTING.md
vendored
@ -93,11 +93,10 @@ cmake --build build -j4
|
|||||||
|
|
||||||
Tips:
|
Tips:
|
||||||
|
|
||||||
* You can use `virtualenv` (from PyPI) instead of `venv` (which is Python 3
|
* You can use `virtualenv` (faster, from PyPI) instead of `venv`.
|
||||||
only).
|
|
||||||
* You can select any name for your environment folder; if it contains "env" it
|
* You can select any name for your environment folder; if it contains "env" it
|
||||||
will be ignored by git.
|
will be ignored by git.
|
||||||
* If you don’t have CMake 3.14+, just add “cmake” to the pip install command.
|
* If you don't have CMake 3.14+, just add "cmake" to the pip install command.
|
||||||
* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+
|
* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+
|
||||||
* In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`.
|
* In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`.
|
||||||
FindPython uses `-DPython_ROOT_DIR=/path/to` or
|
FindPython uses `-DPython_ROOT_DIR=/path/to` or
|
||||||
@ -105,7 +104,7 @@ Tips:
|
|||||||
|
|
||||||
### Configuration options
|
### Configuration options
|
||||||
|
|
||||||
In CMake, configuration options are given with “-D”. Options are stored in the
|
In CMake, configuration options are given with "-D". Options are stored in the
|
||||||
build directory, in the `CMakeCache.txt` file, so they are remembered for each
|
build directory, in the `CMakeCache.txt` file, so they are remembered for each
|
||||||
build directory. Two selections are special - the generator, given with `-G`,
|
build directory. Two selections are special - the generator, given with `-G`,
|
||||||
and the compiler, which is selected based on environment variables `CXX` and
|
and the compiler, which is selected based on environment variables `CXX` and
|
||||||
@ -115,7 +114,7 @@ after the initial run.
|
|||||||
The valid options are:
|
The valid options are:
|
||||||
|
|
||||||
* `-DCMAKE_BUILD_TYPE`: Release, Debug, MinSizeRel, RelWithDebInfo
|
* `-DCMAKE_BUILD_TYPE`: Release, Debug, MinSizeRel, RelWithDebInfo
|
||||||
* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+’s FindPython instead of the
|
* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+'s FindPython instead of the
|
||||||
classic, deprecated, custom FindPythonLibs
|
classic, deprecated, custom FindPythonLibs
|
||||||
* `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests)
|
* `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests)
|
||||||
* `-DBUILD_TESTING=ON`: Enable the tests
|
* `-DBUILD_TESTING=ON`: Enable the tests
|
||||||
@ -236,12 +235,14 @@ directory inside your pybind11 git clone. Files will be modified in place,
|
|||||||
so you can use git to monitor the changes.
|
so you can use git to monitor the changes.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:12
|
docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:13
|
||||||
apt-get update && apt-get install -y python3-dev python3-pytest
|
apt-get update && apt-get install -y python3-dev python3-pytest
|
||||||
cmake -S /mounted_pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);-fix" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17
|
cmake -S /mounted_pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17
|
||||||
cmake --build build -j 2 -- --keep-going
|
cmake --build build -j 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can add `--fix` to the options list if you want.
|
||||||
|
|
||||||
### Include what you use
|
### Include what you use
|
||||||
|
|
||||||
To run include what you use, install (`brew install include-what-you-use` on
|
To run include what you use, install (`brew install include-what-you-use` on
|
||||||
@ -257,7 +258,7 @@ The report is sent to stderr; you can pipe it into a file if you wish.
|
|||||||
### Build recipes
|
### Build recipes
|
||||||
|
|
||||||
This builds with the Intel compiler (assuming it is in your path, along with a
|
This builds with the Intel compiler (assuming it is in your path, along with a
|
||||||
recent CMake and Python 3):
|
recent CMake and Python):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
|
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@ -5,12 +5,3 @@ updates:
|
|||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
ignore:
|
|
||||||
# Official actions have moving tags like v1
|
|
||||||
# that are used, so they don't need updates here
|
|
||||||
- dependency-name: "actions/checkout"
|
|
||||||
- dependency-name: "actions/setup-python"
|
|
||||||
- dependency-name: "actions/cache"
|
|
||||||
- dependency-name: "actions/upload-artifact"
|
|
||||||
- dependency-name: "actions/download-artifact"
|
|
||||||
- dependency-name: "actions/labeler"
|
|
||||||
|
32
.github/matchers/pylint.json
vendored
Normal file
32
.github/matchers/pylint.json
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"severity": "warning",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^([^:]+):(\\d+):(\\d+): ([A-DF-Z]\\d+): \\033\\[[\\d;]+m([^\\033]+).*$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"column": 3,
|
||||||
|
"code": 4,
|
||||||
|
"message": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"owner": "pylint-warning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"severity": "error",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^([^:]+):(\\d+):(\\d+): (E\\d+): \\033\\[[\\d;]+m([^\\033]+).*$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"column": 3,
|
||||||
|
"code": 4,
|
||||||
|
"message": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"owner": "pylint-error"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
219
.github/workflows/ci.yml
vendored
219
.github/workflows/ci.yml
vendored
@ -15,6 +15,8 @@ concurrency:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
PIP_ONLY_BINARY: numpy
|
PIP_ONLY_BINARY: numpy
|
||||||
|
FORCE_COLOR: 3
|
||||||
|
PYTEST_TIMEOUT: 300
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# This is the "main" test suite, which tests a large number of different
|
# This is the "main" test suite, which tests a large number of different
|
||||||
@ -25,13 +27,13 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-latest, windows-2022, macos-latest]
|
runs-on: [ubuntu-latest, windows-2022, macos-latest]
|
||||||
python:
|
python:
|
||||||
- '2.7'
|
|
||||||
- '3.5'
|
|
||||||
- '3.6'
|
- '3.6'
|
||||||
- '3.9'
|
- '3.9'
|
||||||
- '3.10'
|
- '3.10'
|
||||||
|
- '3.11-dev'
|
||||||
- 'pypy-3.7'
|
- 'pypy-3.7'
|
||||||
- 'pypy-3.8'
|
- 'pypy-3.8'
|
||||||
|
- 'pypy-3.9'
|
||||||
|
|
||||||
# Items in here will either be added to the build matrix (if not
|
# Items in here will either be added to the build matrix (if not
|
||||||
# present), or add new keys to an existing matrix element if all the
|
# present), or add new keys to an existing matrix element if all the
|
||||||
@ -45,26 +47,26 @@ jobs:
|
|||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
-DCMAKE_CXX_FLAGS="-D_=1"
|
-DCMAKE_CXX_FLAGS="-D_=1"
|
||||||
- runs-on: windows-latest
|
- runs-on: ubuntu-latest
|
||||||
|
python: 'pypy-3.8'
|
||||||
|
args: >
|
||||||
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
|
- runs-on: windows-2019
|
||||||
python: '3.6'
|
python: '3.6'
|
||||||
args: >
|
args: >
|
||||||
-DPYBIND11_FINDPYTHON=ON
|
-DPYBIND11_FINDPYTHON=ON
|
||||||
- runs-on: macos-latest
|
|
||||||
python: 'pypy-2.7'
|
|
||||||
# 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'
|
||||||
- runs-on: windows-2019
|
|
||||||
python: '2.7'
|
|
||||||
|
|
||||||
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@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
|
|
||||||
@ -82,7 +84,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache wheels
|
- name: Cache wheels
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
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
|
||||||
@ -168,27 +170,11 @@ jobs:
|
|||||||
- name: Interface test
|
- name: Interface test
|
||||||
run: cmake --build build2 --target test_cmake_build
|
run: cmake --build build2 --target test_cmake_build
|
||||||
|
|
||||||
# Eventually Microsoft might have an action for setting up
|
|
||||||
# MSVC, but for now, this action works:
|
|
||||||
- name: Prepare compiler environment for Windows 🐍 2.7
|
|
||||||
if: matrix.python == 2.7 && runner.os == 'Windows'
|
|
||||||
uses: ilammy/msvc-dev-cmd@v1.10.0
|
|
||||||
with:
|
|
||||||
arch: x64
|
|
||||||
|
|
||||||
# This makes two environment variables available in the following step(s)
|
|
||||||
- name: Set Windows 🐍 2.7 environment variables
|
|
||||||
if: matrix.python == 2.7 && runner.os == 'Windows'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "DISTUTILS_USE_SDK=1" >> $GITHUB_ENV
|
|
||||||
echo "MSSdk=1" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# This makes sure the setup_helpers module can build packages using
|
# This makes sure the setup_helpers module can build packages using
|
||||||
# setuptools
|
# setuptools
|
||||||
- name: Setuptools helpers test
|
- name: Setuptools helpers test
|
||||||
run: pytest tests/extra_setuptools
|
run: pytest tests/extra_setuptools
|
||||||
if: "!(matrix.python == '3.5' && matrix.runs-on == 'windows-2022')"
|
if: "!(matrix.runs-on == 'windows-2022')"
|
||||||
|
|
||||||
|
|
||||||
deadsnakes:
|
deadsnakes:
|
||||||
@ -200,14 +186,14 @@ jobs:
|
|||||||
- python-version: "3.9"
|
- python-version: "3.9"
|
||||||
python-debug: true
|
python-debug: true
|
||||||
valgrind: true
|
valgrind: true
|
||||||
# - python-version: "3.11-dev"
|
- python-version: "3.11-dev"
|
||||||
# python-debug: false
|
python-debug: false
|
||||||
|
|
||||||
name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64"
|
name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
|
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
|
||||||
uses: deadsnakes/action@v2.1.1
|
uses: deadsnakes/action@v2.1.1
|
||||||
@ -220,7 +206,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Valgrind cache
|
- name: Valgrind cache
|
||||||
if: matrix.valgrind
|
if: matrix.valgrind
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
id: cache-valgrind
|
id: cache-valgrind
|
||||||
with:
|
with:
|
||||||
path: valgrind
|
path: valgrind
|
||||||
@ -295,12 +281,14 @@ jobs:
|
|||||||
std: 20
|
std: 20
|
||||||
- clang: 10
|
- clang: 10
|
||||||
std: 17
|
std: 17
|
||||||
|
- clang: 14
|
||||||
|
std: 20
|
||||||
|
|
||||||
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
|
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
|
||||||
container: "silkeh/clang:${{ matrix.clang }}"
|
container: "silkeh/clang:${{ matrix.clang }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- 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
|
||||||
@ -330,11 +318,11 @@ jobs:
|
|||||||
# Testing NVCC; forces sources to behave like .cu files
|
# Testing NVCC; forces sources to behave like .cu files
|
||||||
cuda:
|
cuda:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: "🐍 3.8 • CUDA 11 • Ubuntu 20.04"
|
name: "🐍 3.8 • CUDA 11.2 • Ubuntu 20.04"
|
||||||
container: nvidia/cuda:11.0-devel-ubuntu20.04
|
container: nvidia/cuda:11.2.2-devel-ubuntu20.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
# 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
|
||||||
@ -358,7 +346,7 @@ jobs:
|
|||||||
# container: centos:8
|
# container: centos:8
|
||||||
#
|
#
|
||||||
# steps:
|
# steps:
|
||||||
# - uses: actions/checkout@v2
|
# - uses: actions/checkout@v3
|
||||||
#
|
#
|
||||||
# - 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
|
||||||
@ -397,17 +385,17 @@ jobs:
|
|||||||
# Testing on CentOS 7 + PGI compilers, which seems to require more workarounds
|
# Testing on CentOS 7 + PGI compilers, which seems to require more workarounds
|
||||||
centos-nvhpc7:
|
centos-nvhpc7:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: "🐍 3 • CentOS7 / PGI 20.9 • x64"
|
name: "🐍 3 • CentOS7 / PGI 22.3 • x64"
|
||||||
container: centos:7
|
container: centos:7
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Add Python 3 and a few requirements
|
- name: Add Python 3 and a few requirements
|
||||||
run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3
|
run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 yum-utils
|
||||||
|
|
||||||
- name: Install NVidia HPC SDK
|
- name: Install NVidia HPC SDK
|
||||||
run: yum -y install https://developer.download.nvidia.com/hpc-sdk/20.9/nvhpc-20-9-20.9-1.x86_64.rpm https://developer.download.nvidia.com/hpc-sdk/20.9/nvhpc-2020-20.9-1.x86_64.rpm
|
run: yum-config-manager --add-repo https://developer.download.nvidia.com/hpc-sdk/rhel/nvhpc.repo && yum -y install nvhpc-22.3
|
||||||
|
|
||||||
# On CentOS 7, we have to filter a few tests (compiler internal error)
|
# On CentOS 7, we have to filter a few tests (compiler internal error)
|
||||||
# and allow deeper template recursion (not needed on CentOS 8 with a newer
|
# and allow deeper template recursion (not needed on CentOS 8 with a newer
|
||||||
@ -417,7 +405,7 @@ jobs:
|
|||||||
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/20.9
|
module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.3
|
||||||
cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \
|
cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \
|
||||||
-DCMAKE_CXX_STANDARD=11 \
|
-DCMAKE_CXX_STANDARD=11 \
|
||||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
|
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
|
||||||
@ -462,7 +450,7 @@ jobs:
|
|||||||
container: "gcc:${{ matrix.gcc }}"
|
container: "gcc:${{ matrix.gcc }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- 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
|
||||||
@ -504,7 +492,7 @@ jobs:
|
|||||||
name: "🐍 3 • ICC latest • x64"
|
name: "🐍 3 • ICC latest • x64"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Add apt repo
|
- name: Add apt repo
|
||||||
run: |
|
run: |
|
||||||
@ -599,19 +587,25 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
centos:
|
container:
|
||||||
- centos7 # GCC 4.8
|
- "centos:7" # GCC 4.8
|
||||||
- stream8
|
- "almalinux:8"
|
||||||
|
- "almalinux:9"
|
||||||
|
|
||||||
name: "🐍 3 • CentOS ${{ matrix.centos }} • x64"
|
name: "🐍 3 • ${{ matrix.container }} • x64"
|
||||||
container: "quay.io/centos/centos:${{ matrix.centos }}"
|
container: "${{ matrix.container }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Add Python 3
|
- name: Add Python 3 (RHEL 7)
|
||||||
|
if: matrix.container == 'centos:7'
|
||||||
run: yum update -y && yum install -y python3-devel gcc-c++ make git
|
run: yum update -y && yum install -y python3-devel gcc-c++ make git
|
||||||
|
|
||||||
|
- name: Add Python 3 (RHEL 8+)
|
||||||
|
if: matrix.container != 'centos:7'
|
||||||
|
run: dnf update -y && dnf install -y python3-devel gcc-c++ make git
|
||||||
|
|
||||||
- name: Update pip
|
- name: Update pip
|
||||||
run: python3 -m pip install --upgrade pip
|
run: python3 -m pip install --upgrade pip
|
||||||
|
|
||||||
@ -645,18 +639,18 @@ jobs:
|
|||||||
|
|
||||||
# This tests an "install" with the CMake tools
|
# This tests an "install" with the CMake tools
|
||||||
install-classic:
|
install-classic:
|
||||||
name: "🐍 3.5 • Debian • x86 • Install"
|
name: "🐍 3.7 • Debian • x86 • Install"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: i386/debian:stretch
|
container: i386/debian:buster
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1 # Required to run inside docker
|
||||||
|
|
||||||
- name: Install requirements
|
- name: Install requirements
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y git make cmake g++ libeigen3-dev python3-dev python3-pip
|
apt-get install -y git make cmake g++ libeigen3-dev python3-dev python3-pip
|
||||||
pip3 install "pytest==3.1.*"
|
pip3 install "pytest==6.*"
|
||||||
|
|
||||||
- name: Configure for install
|
- name: Configure for install
|
||||||
run: >
|
run: >
|
||||||
@ -687,15 +681,17 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
# This verifies that the documentation is not horribly broken, and does a
|
# This verifies that the documentation is not horribly broken, and does a
|
||||||
# basic sanity check on the SDist.
|
# basic validation check on the SDist.
|
||||||
doxygen:
|
doxygen:
|
||||||
name: "Documentation build test"
|
name: "Documentation build test"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
|
||||||
- name: Install Doxygen
|
- name: Install Doxygen
|
||||||
run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04
|
run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04
|
||||||
@ -725,27 +721,25 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- 3.5
|
|
||||||
- 3.6
|
- 3.6
|
||||||
- 3.7
|
- 3.7
|
||||||
- 3.8
|
- 3.8
|
||||||
- 3.9
|
- 3.9
|
||||||
- pypy-3.6
|
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- python: 3.9
|
- python: 3.9
|
||||||
args: -DCMAKE_CXX_STANDARD=20 -DDOWNLOAD_EIGEN=OFF
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
- python: 3.8
|
- python: 3.8
|
||||||
args: -DCMAKE_CXX_STANDARD=17
|
args: -DCMAKE_CXX_STANDARD=17
|
||||||
|
|
||||||
name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}"
|
name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}"
|
||||||
runs-on: windows-latest
|
runs-on: windows-2019
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Python ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
architecture: x86
|
architecture: x86
|
||||||
@ -777,25 +771,31 @@ jobs:
|
|||||||
- name: Python tests
|
- name: Python tests
|
||||||
run: cmake --build build -t pytest
|
run: cmake --build build -t pytest
|
||||||
|
|
||||||
win32-msvc2015:
|
win32-debug:
|
||||||
name: "🐍 ${{ matrix.python }} • MSVC 2015 • x64"
|
|
||||||
runs-on: windows-latest
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- 2.7
|
- 3.8
|
||||||
- 3.6
|
- 3.9
|
||||||
- 3.7
|
|
||||||
# todo: check/cpptest does not support 3.8+ yet
|
include:
|
||||||
|
- python: 3.9
|
||||||
|
args: -DCMAKE_CXX_STANDARD=20
|
||||||
|
- python: 3.8
|
||||||
|
args: -DCMAKE_CXX_STANDARD=17
|
||||||
|
|
||||||
|
name: "🐍 ${{ matrix.python }} • MSVC 2019 (Debug) • x86 ${{ matrix.args }}"
|
||||||
|
runs-on: windows-2019
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup 🐍 ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
|
architecture: x86
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.12
|
uses: jwlawson/actions-setup-cmake@v1.12
|
||||||
@ -803,82 +803,73 @@ jobs:
|
|||||||
- name: Prepare MSVC
|
- name: Prepare MSVC
|
||||||
uses: ilammy/msvc-dev-cmd@v1.10.0
|
uses: ilammy/msvc-dev-cmd@v1.10.0
|
||||||
with:
|
with:
|
||||||
toolset: 14.0
|
arch: x86
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
run: |
|
run: |
|
||||||
python -m pip install -r tests/requirements.txt
|
python -m pip install -r tests/requirements.txt
|
||||||
|
|
||||||
# First build - C++11 mode and inplace
|
# First build - C++11 mode and inplace
|
||||||
- name: Configure
|
- name: Configure ${{ matrix.args }}
|
||||||
run: >
|
run: >
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
-G "Visual Studio 14 2015" -A x64
|
-G "Visual Studio 16 2019" -A Win32
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug
|
||||||
-DPYBIND11_WERROR=ON
|
-DPYBIND11_WERROR=ON
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
|
${{ matrix.args }}
|
||||||
|
- name: Build C++11
|
||||||
|
run: cmake --build build --config Debug -j 2
|
||||||
|
|
||||||
- name: Build C++14
|
- name: Python tests
|
||||||
run: cmake --build build -j 2
|
run: cmake --build build --config Debug -t pytest
|
||||||
|
|
||||||
- name: Run all checks
|
|
||||||
run: cmake --build build -t check
|
|
||||||
|
|
||||||
|
|
||||||
win32-msvc2017:
|
windows-2022:
|
||||||
name: "🐍 ${{ matrix.python }} • MSVC 2017 • x64"
|
|
||||||
runs-on: windows-2016
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python:
|
python:
|
||||||
- 2.7
|
- 3.9
|
||||||
- 3.5
|
|
||||||
- 3.7
|
|
||||||
std:
|
|
||||||
- 14
|
|
||||||
|
|
||||||
include:
|
name: "🐍 ${{ matrix.python }} • MSVC 2022 C++20 • x64"
|
||||||
- python: 2.7
|
runs-on: windows-2022
|
||||||
std: 17
|
|
||||||
args: >
|
|
||||||
-DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR"
|
|
||||||
- python: 3.7
|
|
||||||
std: 17
|
|
||||||
args: >
|
|
||||||
-DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR"
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup 🐍 ${{ matrix.python }}
|
- name: Setup Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
|
|
||||||
|
- name: Prepare env
|
||||||
|
run: |
|
||||||
|
python3 -m pip install -r tests/requirements.txt
|
||||||
|
|
||||||
- name: Update CMake
|
- name: Update CMake
|
||||||
uses: jwlawson/actions-setup-cmake@v1.12
|
uses: jwlawson/actions-setup-cmake@v1.12
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Configure C++20
|
||||||
run: |
|
|
||||||
python -m pip install -r tests/requirements.txt
|
|
||||||
|
|
||||||
# First build - C++11 mode and inplace
|
|
||||||
- name: Configure
|
|
||||||
run: >
|
run: >
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
-G "Visual Studio 15 2017" -A x64
|
|
||||||
-DPYBIND11_WERROR=ON
|
-DPYBIND11_WERROR=ON
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DCMAKE_CXX_STANDARD=${{ matrix.std }}
|
-DCMAKE_CXX_STANDARD=20
|
||||||
${{ matrix.args }}
|
|
||||||
|
|
||||||
- name: Build ${{ matrix.std }}
|
- name: Build C++20
|
||||||
run: cmake --build build -j 2
|
run: cmake --build build -j 2
|
||||||
|
|
||||||
- name: Run all checks
|
- name: Python tests
|
||||||
run: cmake --build build -t check
|
run: cmake --build build --target pytest
|
||||||
|
|
||||||
|
- name: C++20 tests
|
||||||
|
run: cmake --build build --target cpptest -j 2
|
||||||
|
|
||||||
|
- name: Interface test C++20
|
||||||
|
run: cmake --build build --target test_cmake_build
|
||||||
|
|
||||||
mingw:
|
mingw:
|
||||||
name: "🐍 3 • windows-latest • ${{ matrix.sys }}"
|
name: "🐍 3 • windows-latest • ${{ matrix.sys }}"
|
||||||
@ -909,7 +900,7 @@ jobs:
|
|||||||
mingw-w64-${{matrix.env}}-boost
|
mingw-w64-${{matrix.env}}-boost
|
||||||
mingw-w64-${{matrix.env}}-catch
|
mingw-w64-${{matrix.env}}-catch
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Configure C++11
|
- name: Configure C++11
|
||||||
# LTO leads to many undefined reference like
|
# LTO leads to many undefined reference like
|
||||||
|
14
.github/workflows/configure.yml
vendored
14
.github/workflows/configure.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
runs-on: [ubuntu-latest, macos-latest, windows-latest]
|
runs-on: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
arch: [x64]
|
arch: [x64]
|
||||||
cmake: ["3.21"]
|
cmake: ["3.23"]
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- runs-on: ubuntu-latest
|
- runs-on: ubuntu-latest
|
||||||
@ -29,22 +29,18 @@ jobs:
|
|||||||
arch: x64
|
arch: x64
|
||||||
cmake: 3.7
|
cmake: 3.7
|
||||||
|
|
||||||
- runs-on: windows-2016
|
- runs-on: windows-2019
|
||||||
arch: x86
|
arch: x64 # x86 compilers seem to be missing on 2019 image
|
||||||
cmake: 3.8
|
|
||||||
|
|
||||||
- runs-on: windows-2016
|
|
||||||
arch: x86
|
|
||||||
cmake: 3.18
|
cmake: 3.18
|
||||||
|
|
||||||
name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
|
name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Python 3.7
|
- name: Setup Python 3.7
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
architecture: ${{ matrix.arch }}
|
architecture: ${{ matrix.arch }}
|
||||||
|
19
.github/workflows/format.yml
vendored
19
.github/workflows/format.yml
vendored
@ -12,14 +12,21 @@ on:
|
|||||||
- stable
|
- stable
|
||||||
- "v*"
|
- "v*"
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_COLOR: 3
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pre-commit:
|
pre-commit:
|
||||||
name: Format
|
name: Format
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v4
|
||||||
- uses: pre-commit/action@v2.0.3
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
- name: Add matchers
|
||||||
|
run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
|
||||||
|
- uses: pre-commit/action@v3.0.0
|
||||||
with:
|
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
|
||||||
@ -29,9 +36,9 @@ jobs:
|
|||||||
# in .github/CONTRIBUTING.md and update as needed.
|
# in .github/CONTRIBUTING.md and update as needed.
|
||||||
name: Clang-Tidy
|
name: Clang-Tidy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: silkeh/clang:12
|
container: silkeh/clang:13
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install requirements
|
- name: Install requirements
|
||||||
run: apt-get update && apt-get install -y python3-dev python3-pytest
|
run: apt-get update && apt-get install -y python3-dev python3-pytest
|
||||||
@ -39,7 +46,7 @@ jobs:
|
|||||||
- name: Configure
|
- name: Configure
|
||||||
run: >
|
run: >
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
-DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy)"
|
-DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color;--warnings-as-errors=*"
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DCMAKE_CXX_STANDARD=17
|
-DCMAKE_CXX_STANDARD=17
|
||||||
|
26
.github/workflows/pip.yml
vendored
26
.github/workflows/pip.yml
vendored
@ -17,19 +17,19 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# This builds the sdists and wheels and makes sure the files are exactly as
|
# This builds the sdists and wheels and makes sure the files are exactly as
|
||||||
# expected. Using Windows and Python 2.7, since that is often the most
|
# expected. Using Windows and Python 3.6, since that is often the most
|
||||||
# challenging matrix element.
|
# challenging matrix element.
|
||||||
test-packaging:
|
test-packaging:
|
||||||
name: 🐍 2.7 • 📦 tests • windows-latest
|
name: 🐍 3.6 • 📦 tests • windows-latest
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup 🐍 2.7
|
- name: Setup 🐍 3.6
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 2.7
|
python-version: 3.6
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
run: |
|
run: |
|
||||||
@ -46,10 +46,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup 🐍 3.8
|
- name: Setup 🐍 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
@ -69,13 +69,13 @@ jobs:
|
|||||||
run: twine check dist/*
|
run: twine check dist/*
|
||||||
|
|
||||||
- name: Save standard package
|
- name: Save standard package
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: standard
|
name: standard
|
||||||
path: dist/pybind11-*
|
path: dist/pybind11-*
|
||||||
|
|
||||||
- name: Save global package
|
- name: Save global package
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: global
|
name: global
|
||||||
path: dist/pybind11_global-*
|
path: dist/pybind11_global-*
|
||||||
@ -90,10 +90,12 @@ jobs:
|
|||||||
needs: [packaging]
|
needs: [packaging]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-python@v2
|
- 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@v2
|
- uses: actions/download-artifact@v3
|
||||||
|
|
||||||
- name: Publish standard package
|
- name: Publish standard package
|
||||||
uses: pypa/gh-action-pypi-publish@v1.5.0
|
uses: pypa/gh-action-pypi-publish@v1.5.0
|
||||||
|
6
.github/workflows/upstream.yml
vendored
6
.github/workflows/upstream.yml
vendored
@ -14,15 +14,15 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
standard:
|
standard:
|
||||||
name: "🐍 3.11 dev • ubuntu-latest • x64"
|
name: "🐍 3.11 latest internals • ubuntu-latest • x64"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
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@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Python 3.11
|
- name: Setup Python 3.11
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.11-dev"
|
python-version: "3.11-dev"
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
repos:
|
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.1.0
|
rev: "v4.3.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
@ -29,73 +29,92 @@ repos:
|
|||||||
- id: mixed-line-ending
|
- id: mixed-line-ending
|
||||||
- id: requirements-txt-fixer
|
- id: requirements-txt-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: fix-encoding-pragma
|
|
||||||
exclude: ^noxfile.py$
|
|
||||||
|
|
||||||
|
# Upgrade old Python syntax
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.31.0
|
rev: "v2.37.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
|
args: [--py36-plus]
|
||||||
|
|
||||||
|
# Nicely sort includes
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.10.1
|
rev: "5.10.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
# Black, the code formatter, natively supports pre-commit
|
# Black, the code formatter, natively supports pre-commit
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 21.12b0 # Keep in sync with blacken-docs
|
rev: "22.6.0" # Keep in sync with blacken-docs
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
|
# Also code format the docs
|
||||||
- repo: https://github.com/asottile/blacken-docs
|
- repo: https://github.com/asottile/blacken-docs
|
||||||
rev: v1.12.0
|
rev: "v1.12.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- black==21.12b0 # keep in sync with black hook
|
- black==22.6.0 # keep in sync with black hook
|
||||||
|
|
||||||
# Changes tabs to spaces
|
# Changes tabs to spaces
|
||||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||||
rev: v1.1.10
|
rev: "v1.3.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: remove-tabs
|
- id: remove-tabs
|
||||||
|
|
||||||
|
- repo: https://github.com/sirosen/texthooks
|
||||||
|
rev: "0.3.1"
|
||||||
|
hooks:
|
||||||
|
- id: fix-ligatures
|
||||||
|
- id: fix-smartquotes
|
||||||
|
|
||||||
# Autoremoves unused imports
|
# Autoremoves unused imports
|
||||||
- repo: https://github.com/hadialqattan/pycln
|
- repo: https://github.com/hadialqattan/pycln
|
||||||
rev: v1.1.0
|
rev: "v2.0.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pycln
|
- id: pycln
|
||||||
|
stages: [manual]
|
||||||
|
|
||||||
|
# Checking for common mistakes
|
||||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||||
rev: v1.9.0
|
rev: "v1.9.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: python-check-blanket-noqa
|
- id: python-check-blanket-noqa
|
||||||
- id: python-check-blanket-type-ignore
|
- id: python-check-blanket-type-ignore
|
||||||
- id: python-no-log-warn
|
- id: python-no-log-warn
|
||||||
|
- id: python-use-type-annotations
|
||||||
- id: rst-backticks
|
- id: rst-backticks
|
||||||
- id: rst-directive-colons
|
- id: rst-directive-colons
|
||||||
- id: rst-inline-touching-normal
|
- id: rst-inline-touching-normal
|
||||||
|
|
||||||
# Flake8 also supports pre-commit natively (same author)
|
# Automatically remove noqa that are not used
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/asottile/yesqa
|
||||||
rev: 4.0.1
|
rev: "v1.3.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: yesqa
|
||||||
additional_dependencies: &flake8_dependencies
|
additional_dependencies: &flake8_dependencies
|
||||||
- flake8-bugbear
|
- flake8-bugbear
|
||||||
- pep8-naming
|
- pep8-naming
|
||||||
exclude: ^(docs/.*|tools/.*)$
|
|
||||||
|
|
||||||
- repo: https://github.com/asottile/yesqa
|
# Flake8 also supports pre-commit natively (same author)
|
||||||
rev: v1.3.0
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: "4.0.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: yesqa
|
- id: flake8
|
||||||
|
exclude: ^(docs/.*|tools/.*)$
|
||||||
additional_dependencies: *flake8_dependencies
|
additional_dependencies: *flake8_dependencies
|
||||||
|
|
||||||
|
# PyLint has native support - not always usable, but works for us
|
||||||
|
- repo: https://github.com/PyCQA/pylint
|
||||||
|
rev: "v2.14.4"
|
||||||
|
hooks:
|
||||||
|
- id: pylint
|
||||||
|
files: ^pybind11
|
||||||
|
|
||||||
# CMake formatting
|
# CMake formatting
|
||||||
- repo: https://github.com/cheshirekow/cmake-format-precommit
|
- repo: https://github.com/cheshirekow/cmake-format-precommit
|
||||||
rev: v0.6.13
|
rev: "v0.6.13"
|
||||||
hooks:
|
hooks:
|
||||||
- id: cmake-format
|
- id: cmake-format
|
||||||
additional_dependencies: [pyyaml]
|
additional_dependencies: [pyyaml]
|
||||||
@ -104,44 +123,48 @@ repos:
|
|||||||
|
|
||||||
# Check static types with mypy
|
# Check static types with mypy
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v0.931
|
rev: "v0.961"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
# Running per-file misbehaves a bit, so just run on all files, it's fast
|
args: []
|
||||||
pass_filenames: false
|
exclude: ^(tests|docs)/
|
||||||
additional_dependencies: [typed_ast]
|
additional_dependencies: [nox, rich]
|
||||||
|
|
||||||
# Checks the manifest for missing files (native support)
|
# Checks the manifest for missing files (native support)
|
||||||
- repo: https://github.com/mgedmin/check-manifest
|
- repo: https://github.com/mgedmin/check-manifest
|
||||||
rev: "0.47"
|
rev: "0.48"
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-manifest
|
- id: check-manifest
|
||||||
# This is a slow hook, so only run this if --hook-stage manual is passed
|
# This is a slow hook, so only run this if --hook-stage manual is passed
|
||||||
stages: [manual]
|
stages: [manual]
|
||||||
additional_dependencies: [cmake, ninja]
|
additional_dependencies: [cmake, ninja]
|
||||||
|
|
||||||
|
# Check for spelling
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/codespell-project/codespell
|
||||||
rev: v2.1.0
|
rev: "v2.1.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell
|
- id: codespell
|
||||||
exclude: ".supp$"
|
exclude: ".supp$"
|
||||||
args: ["-L", "nd,ot,thist"]
|
args: ["-L", "nd,ot,thist"]
|
||||||
|
|
||||||
|
# Check for common shell mistakes
|
||||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||||
rev: v0.8.0.3
|
rev: "v0.8.0.4"
|
||||||
hooks:
|
hooks:
|
||||||
- id: shellcheck
|
- id: shellcheck
|
||||||
|
|
||||||
# The original pybind11 checks for a few C++ style items
|
# Disallow some common capitalization mistakes
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
- 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|Numpy|Cmake|CCache|PyTest
|
||||||
exclude: .pre-commit-config.yaml
|
exclude: ^\.pre-commit-config.yaml$
|
||||||
|
|
||||||
|
# Clang format the codebase automatically
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: "v13.0.0"
|
rev: "v14.0.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
|
types_or: [c++, c, cuda]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
recursive-include pybind11/include/pybind11 *.h
|
recursive-include pybind11/include/pybind11 *.h
|
||||||
recursive-include pybind11 *.py
|
recursive-include pybind11 *.py
|
||||||
recursive-include pybind11 py.typed
|
recursive-include pybind11 py.typed
|
||||||
recursive-include pybind11 *.pyi
|
|
||||||
include pybind11/share/cmake/pybind11/*.cmake
|
include pybind11/share/cmake/pybind11/*.cmake
|
||||||
include LICENSE README.rst pyproject.toml setup.py setup.cfg
|
include LICENSE README.rst pyproject.toml setup.py setup.cfg
|
||||||
|
16
README.rst
16
README.rst
@ -32,9 +32,9 @@ this heavy machinery has become an excessively large and unnecessary
|
|||||||
dependency.
|
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 (2.7 or 3.5+, or PyPy) and the C++
|
lines of code and depend on Python (3.6+, or PyPy) and the C++
|
||||||
standard library. This compact implementation was possible thanks to
|
standard library. This compact implementation was possible thanks to
|
||||||
some of the new C++11 language features (specifically: tuples, lambda
|
some of the new C++11 language features (specifically: tuples, lambda
|
||||||
functions and variadic templates). Since its creation, this library has
|
functions and variadic templates). Since its creation, this library has
|
||||||
@ -78,8 +78,8 @@ Goodies
|
|||||||
In addition to the core functionality, pybind11 provides some extra
|
In addition to the core functionality, pybind11 provides some extra
|
||||||
goodies:
|
goodies:
|
||||||
|
|
||||||
- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an
|
- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic
|
||||||
implementation-agnostic interface.
|
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
|
||||||
variables. The lambda capture data is stored inside the resulting
|
variables. The lambda capture data is stored inside the resulting
|
||||||
@ -88,8 +88,8 @@ goodies:
|
|||||||
- pybind11 uses C++11 move constructors and move assignment operators
|
- pybind11 uses C++11 move constructors and move assignment operators
|
||||||
whenever possible to efficiently transfer custom data types.
|
whenever possible to efficiently transfer custom data types.
|
||||||
|
|
||||||
- It’s easy to expose the internal storage of custom data types through
|
- It's easy to expose the internal storage of custom data types through
|
||||||
Pythons’ buffer protocols. This is handy e.g. for fast conversion
|
Pythons' buffer protocols. This is handy e.g. for fast conversion
|
||||||
between C++ matrix classes like Eigen and NumPy without expensive
|
between C++ matrix classes like Eigen and NumPy without expensive
|
||||||
copy operations.
|
copy operations.
|
||||||
|
|
||||||
@ -119,10 +119,10 @@ goodies:
|
|||||||
Supported compilers
|
Supported compilers
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
1. Clang/LLVM 3.3 or newer (for Apple Xcode’s clang, this is 5.0.0 or
|
1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or
|
||||||
newer)
|
newer)
|
||||||
2. GCC 4.8 or newer
|
2. GCC 4.8 or newer
|
||||||
3. Microsoft Visual Studio 2015 Update 3 or newer
|
3. Microsoft Visual Studio 2017 or newer
|
||||||
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
|
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
|
||||||
5. Cygwin/GCC (previously tested on 2.5.1)
|
5. Cygwin/GCC (previously tested on 2.5.1)
|
||||||
6. NVCC (CUDA 11.0 tested in CI)
|
6. NVCC (CUDA 11.0 tested in CI)
|
||||||
|
@ -18,5 +18,4 @@ ALIASES += "endrst=\endverbatim"
|
|||||||
QUIET = YES
|
QUIET = YES
|
||||||
WARNINGS = YES
|
WARNINGS = YES
|
||||||
WARN_IF_UNDOCUMENTED = NO
|
WARN_IF_UNDOCUMENTED = NO
|
||||||
PREDEFINED = PY_MAJOR_VERSION=3 \
|
PREDEFINED = PYBIND11_NOINLINE
|
||||||
PYBIND11_NOINLINE
|
|
||||||
|
3
docs/_static/css/custom.css
vendored
Normal file
3
docs/_static/css/custom.css
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.highlight .go {
|
||||||
|
color: #707070;
|
||||||
|
}
|
11
docs/_static/theme_overrides.css
vendored
11
docs/_static/theme_overrides.css
vendored
@ -1,11 +0,0 @@
|
|||||||
.wy-table-responsive table td,
|
|
||||||
.wy-table-responsive table th {
|
|
||||||
white-space: initial !important;
|
|
||||||
}
|
|
||||||
.rst-content table.docutils td {
|
|
||||||
vertical-align: top !important;
|
|
||||||
}
|
|
||||||
div[class^='highlight'] pre {
|
|
||||||
white-space: pre;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
@ -167,5 +167,4 @@ as arguments and return values, refer to the section on binding :ref:`classes`.
|
|||||||
+------------------------------------+---------------------------+-----------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
|
|
||||||
.. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and
|
.. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and
|
||||||
``os.PathLike`` is converted to ``std::filesystem::path``, but this requires
|
``os.PathLike`` is converted to ``std::filesystem::path``.
|
||||||
Python 3.6 (for ``__fspath__`` support).
|
|
||||||
|
@ -87,8 +87,6 @@ included to tell pybind11 how to visit the variant.
|
|||||||
|
|
||||||
pybind11 only supports the modern implementation of ``boost::variant``
|
pybind11 only supports the modern implementation of ``boost::variant``
|
||||||
which makes use of variadic templates. This requires Boost 1.56 or newer.
|
which makes use of variadic templates. This requires Boost 1.56 or newer.
|
||||||
Additionally, on Windows, MSVC 2017 is required because ``boost::variant``
|
|
||||||
falls back to the old non-variadic implementation on MSVC 2015.
|
|
||||||
|
|
||||||
.. _opaque:
|
.. _opaque:
|
||||||
|
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
Strings, bytes and Unicode conversions
|
Strings, bytes and Unicode conversions
|
||||||
######################################
|
######################################
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This section discusses string handling in terms of Python 3 strings. For
|
|
||||||
Python 2.7, replace all occurrences of ``str`` with ``unicode`` and
|
|
||||||
``bytes`` with ``str``. Python 2.7 users may find it best to use ``from
|
|
||||||
__future__ import unicode_literals`` to avoid unintentionally using ``str``
|
|
||||||
instead of ``unicode``.
|
|
||||||
|
|
||||||
Passing Python strings to C++
|
Passing Python strings to C++
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@ -58,9 +50,9 @@ Passing bytes to C++
|
|||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
A Python ``bytes`` object will be passed to C++ functions that accept
|
A Python ``bytes`` object will be passed to C++ functions that accept
|
||||||
``std::string`` or ``char*`` *without* conversion. On Python 3, in order to
|
``std::string`` or ``char*`` *without* conversion. In order to make a function
|
||||||
make a function *only* accept ``bytes`` (and not ``str``), declare it as taking
|
*only* accept ``bytes`` (and not ``str``), declare it as taking a ``py::bytes``
|
||||||
a ``py::bytes`` argument.
|
argument.
|
||||||
|
|
||||||
|
|
||||||
Returning C++ strings to Python
|
Returning C++ strings to Python
|
||||||
@ -204,11 +196,6 @@ decoded to Python ``str``.
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
Wide character strings may not work as described on Python 2.7 or Python
|
|
||||||
3.3 compiled with ``--enable-unicode=ucs2``.
|
|
||||||
|
|
||||||
Strings in multibyte encodings such as Shift-JIS must transcoded to a
|
Strings in multibyte encodings such as Shift-JIS must transcoded to a
|
||||||
UTF-8/16/32 before being returned to Python.
|
UTF-8/16/32 before being returned to Python.
|
||||||
|
|
||||||
|
@ -133,14 +133,14 @@ a virtual method call.
|
|||||||
>>> from example import *
|
>>> from example import *
|
||||||
>>> d = Dog()
|
>>> d = Dog()
|
||||||
>>> call_go(d)
|
>>> call_go(d)
|
||||||
u'woof! woof! woof! '
|
'woof! woof! woof! '
|
||||||
>>> class Cat(Animal):
|
>>> class Cat(Animal):
|
||||||
... def go(self, n_times):
|
... def go(self, n_times):
|
||||||
... return "meow! " * n_times
|
... return "meow! " * n_times
|
||||||
...
|
...
|
||||||
>>> c = Cat()
|
>>> c = Cat()
|
||||||
>>> call_go(c)
|
>>> call_go(c)
|
||||||
u'meow! meow! meow! '
|
'meow! meow! meow! '
|
||||||
|
|
||||||
If you are defining a custom constructor in a derived Python class, you *must*
|
If you are defining a custom constructor in a derived Python class, you *must*
|
||||||
ensure that you explicitly call the bound C++ constructor using ``__init__``,
|
ensure that you explicitly call the bound C++ constructor using ``__init__``,
|
||||||
@ -813,26 +813,21 @@ An instance can now be pickled as follows:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
try:
|
import pickle
|
||||||
import cPickle as pickle # Use cPickle on Python 2.7
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
p = Pickleable("test_value")
|
p = Pickleable("test_value")
|
||||||
p.setExtra(15)
|
p.setExtra(15)
|
||||||
data = pickle.dumps(p, 2)
|
data = pickle.dumps(p)
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Note that only the cPickle module is supported on Python 2.7.
|
If given, the second argument to ``dumps`` must be 2 or larger - 0 and 1 are
|
||||||
|
not supported. Newer versions are also fine; for instance, specify ``-1`` to
|
||||||
The second argument to ``dumps`` is also crucial: it selects the pickle
|
always use the latest available version. Beware: failure to follow these
|
||||||
protocol version 2, since the older version 1 is not supported. Newer
|
instructions will cause important pybind11 memory allocation routines to be
|
||||||
versions are also fine—for instance, specify ``-1`` to always use the
|
skipped during unpickling, which will likely lead to memory corruption
|
||||||
latest available version. Beware: failure to follow these instructions
|
and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and
|
||||||
will cause important pybind11 memory allocation routines to be skipped
|
version 4 for Python 3.8+.
|
||||||
during unpickling, which will likely lead to memory corruption and/or
|
|
||||||
segmentation faults.
|
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
@ -849,11 +844,9 @@ Python normally uses references in assignments. Sometimes a real copy is needed
|
|||||||
to prevent changing all copies. The ``copy`` module [#f5]_ provides these
|
to prevent changing all copies. The ``copy`` module [#f5]_ provides these
|
||||||
capabilities.
|
capabilities.
|
||||||
|
|
||||||
On Python 3, a class with pickle support is automatically also (deep)copy
|
A class with pickle support is automatically also (deep)copy
|
||||||
compatible. However, performance can be improved by adding custom
|
compatible. However, performance can be improved by adding custom
|
||||||
``__copy__`` and ``__deepcopy__`` methods. With Python 2.7, these custom methods
|
``__copy__`` and ``__deepcopy__`` methods.
|
||||||
are mandatory for (deep)copy compatibility, because pybind11 only supports
|
|
||||||
cPickle.
|
|
||||||
|
|
||||||
For simple classes (deep)copy can be enabled by using the copy constructor,
|
For simple classes (deep)copy can be enabled by using the copy constructor,
|
||||||
which should look as follows:
|
which should look as follows:
|
||||||
@ -1125,13 +1118,6 @@ described trampoline:
|
|||||||
py::class_<A, Trampoline>(m, "A") // <-- `Trampoline` here
|
py::class_<A, Trampoline>(m, "A") // <-- `Trampoline` here
|
||||||
.def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`!
|
.def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`!
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
MSVC 2015 has a compiler bug (fixed in version 2017) which
|
|
||||||
requires a more explicit function binding in the form of
|
|
||||||
``.def("foo", static_cast<int (A::*)() const>(&Publicist::foo));``
|
|
||||||
where ``int (A::*)() const`` is the type of ``A::foo``.
|
|
||||||
|
|
||||||
Binding final classes
|
Binding final classes
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
@ -328,8 +328,8 @@ an invalid state.
|
|||||||
Chaining exceptions ('raise from')
|
Chaining exceptions ('raise from')
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
In Python 3.3 a mechanism for indicating that exceptions were caused by other
|
Python has a mechanism for indicating that exceptions were caused by other
|
||||||
exceptions was introduced:
|
exceptions:
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ exceptions was introduced:
|
|||||||
|
|
||||||
To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It
|
To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It
|
||||||
sets the current python error indicator, so to continue propagating the exception
|
sets the current python error indicator, so to continue propagating the exception
|
||||||
you should ``throw py::error_already_set()`` (Python 3 only).
|
you should ``throw py::error_already_set()``.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ like so:
|
|||||||
Keyword-only arguments
|
Keyword-only arguments
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Python 3 introduced keyword-only arguments by specifying an unnamed ``*``
|
Python implements keyword-only arguments by specifying an unnamed ``*``
|
||||||
argument in a function definition:
|
argument in a function definition:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@ -395,19 +395,18 @@ argument annotations when registering the function:
|
|||||||
m.def("f", [](int a, int b) { /* ... */ },
|
m.def("f", [](int a, int b) { /* ... */ },
|
||||||
py::arg("a"), py::kw_only(), py::arg("b"));
|
py::arg("a"), py::kw_only(), py::arg("b"));
|
||||||
|
|
||||||
Note that you currently cannot combine this with a ``py::args`` argument. This
|
|
||||||
feature does *not* require Python 3 to work.
|
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
As of pybind11 2.9, a ``py::args`` argument implies that any following arguments
|
A ``py::args`` argument implies that any following arguments are keyword-only,
|
||||||
are keyword-only, as if ``py::kw_only()`` had been specified in the same
|
as if ``py::kw_only()`` had been specified in the same relative location of the
|
||||||
relative location of the argument list as the ``py::args`` argument. The
|
argument list as the ``py::args`` argument. The ``py::kw_only()`` may be
|
||||||
``py::kw_only()`` may be included to be explicit about this, but is not
|
included to be explicit about this, but is not required.
|
||||||
required. (Prior to 2.9 ``py::args`` may only occur at the end of the argument
|
|
||||||
list, or immediately before a ``py::kwargs`` argument at the end).
|
.. versionchanged:: 2.9
|
||||||
|
This can now be combined with ``py::args``. Before, ``py::args`` could only
|
||||||
|
occur at the end of the argument list, or immediately before a ``py::kwargs``
|
||||||
|
argument at the end.
|
||||||
|
|
||||||
.. versionadded:: 2.9
|
|
||||||
|
|
||||||
Positional-only arguments
|
Positional-only arguments
|
||||||
=========================
|
=========================
|
||||||
|
@ -87,7 +87,7 @@ buffer objects (e.g. a NumPy matrix).
|
|||||||
/* Request a buffer descriptor from Python */
|
/* Request a buffer descriptor from Python */
|
||||||
py::buffer_info info = b.request();
|
py::buffer_info info = b.request();
|
||||||
|
|
||||||
/* Some sanity checks ... */
|
/* Some basic validation checks ... */
|
||||||
if (info.format != py::format_descriptor<Scalar>::format())
|
if (info.format != py::format_descriptor<Scalar>::format())
|
||||||
throw std::runtime_error("Incompatible format: expected a double array!");
|
throw std::runtime_error("Incompatible format: expected a double array!");
|
||||||
|
|
||||||
@ -395,11 +395,9 @@ uses of ``py::array``:
|
|||||||
Ellipsis
|
Ellipsis
|
||||||
========
|
========
|
||||||
|
|
||||||
Python 3 provides a convenient ``...`` ellipsis notation that is often used to
|
Python provides a convenient ``...`` ellipsis notation that is often used to
|
||||||
slice multidimensional arrays. For instance, the following snippet extracts the
|
slice multidimensional arrays. For instance, the following snippet extracts the
|
||||||
middle dimensions of a tensor with the first and last index set to zero.
|
middle dimensions of a tensor with the first and last index set to zero.
|
||||||
In Python 2, the syntactic sugar ``...`` is not available, but the singleton
|
|
||||||
``Ellipsis`` (of type ``ellipsis``) can still be used directly.
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -414,8 +412,6 @@ operation on the C++ side:
|
|||||||
py::array a = /* A NumPy array */;
|
py::array a = /* A NumPy array */;
|
||||||
py::array b = a[py::make_tuple(0, py::ellipsis(), 0)];
|
py::array b = a[py::make_tuple(0, py::ellipsis(), 0)];
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
|
||||||
``py::ellipsis()`` is now also available in Python 2.
|
|
||||||
|
|
||||||
Memory view
|
Memory view
|
||||||
===========
|
===========
|
||||||
@ -455,9 +451,5 @@ We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer:
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
``memoryview::from_memory`` is not available in Python 2.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
.. versionchanged:: 2.6
|
||||||
``memoryview::from_memory`` added.
|
``memoryview::from_memory`` added.
|
||||||
|
@ -32,8 +32,7 @@ The last line will both compile and run the tests.
|
|||||||
Windows
|
Windows
|
||||||
-------
|
-------
|
||||||
|
|
||||||
On Windows, only **Visual Studio 2015** and newer are supported since pybind11 relies
|
On Windows, only **Visual Studio 2017** and newer are supported.
|
||||||
on various C++11 language features that break older versions of Visual Studio.
|
|
||||||
|
|
||||||
.. Note::
|
.. Note::
|
||||||
|
|
||||||
@ -166,12 +165,12 @@ load and execute the example:
|
|||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
$ python
|
$ python
|
||||||
Python 2.7.10 (default, Aug 22 2015, 20:33:39)
|
Python 3.9.10 (main, Jan 15 2022, 11:48:04)
|
||||||
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin
|
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> import example
|
>>> import example
|
||||||
>>> example.add(1, 2)
|
>>> example.add(1, 2)
|
||||||
3L
|
3
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
.. _keyword_args:
|
.. _keyword_args:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
@ -12,20 +11,20 @@ def generate_dummy_code_pybind11(nclasses=10):
|
|||||||
bindings = ""
|
bindings = ""
|
||||||
|
|
||||||
for cl in range(nclasses):
|
for cl in range(nclasses):
|
||||||
decl += "class cl%03i;\n" % cl
|
decl += f"class cl{cl:03};\n"
|
||||||
decl += "\n"
|
decl += "\n"
|
||||||
|
|
||||||
for cl in range(nclasses):
|
for cl in range(nclasses):
|
||||||
decl += "class cl%03i {\n" % cl
|
decl += f"class {cl:03} {{\n"
|
||||||
decl += "public:\n"
|
decl += "public:\n"
|
||||||
bindings += ' py::class_<cl%03i>(m, "cl%03i")\n' % (cl, cl)
|
bindings += f' py::class_<cl{cl:03}>(m, "cl{cl:03}")\n'
|
||||||
for fn in range(nfns):
|
for fn in range(nfns):
|
||||||
ret = random.randint(0, nclasses - 1)
|
ret = random.randint(0, nclasses - 1)
|
||||||
params = [random.randint(0, nclasses - 1) for i in range(nargs)]
|
params = [random.randint(0, nclasses - 1) for i in range(nargs)]
|
||||||
decl += " cl%03i *fn_%03i(" % (ret, fn)
|
decl += f" cl{ret:03} *fn_{fn:03}("
|
||||||
decl += ", ".join("cl%03i *" % p for p in params)
|
decl += ", ".join(f"cl{p:03} *" for p in params)
|
||||||
decl += ");\n"
|
decl += ");\n"
|
||||||
bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % (fn, cl, fn)
|
bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03})\n'
|
||||||
decl += "};\n\n"
|
decl += "};\n\n"
|
||||||
bindings += " ;\n"
|
bindings += " ;\n"
|
||||||
|
|
||||||
@ -43,23 +42,20 @@ def generate_dummy_code_boost(nclasses=10):
|
|||||||
bindings = ""
|
bindings = ""
|
||||||
|
|
||||||
for cl in range(nclasses):
|
for cl in range(nclasses):
|
||||||
decl += "class cl%03i;\n" % cl
|
decl += f"class cl{cl:03};\n"
|
||||||
decl += "\n"
|
decl += "\n"
|
||||||
|
|
||||||
for cl in range(nclasses):
|
for cl in range(nclasses):
|
||||||
decl += "class cl%03i {\n" % cl
|
decl += "class cl%03i {\n" % cl
|
||||||
decl += "public:\n"
|
decl += "public:\n"
|
||||||
bindings += ' py::class_<cl%03i>("cl%03i")\n' % (cl, cl)
|
bindings += f' py::class_<cl{cl:03}>("cl{cl:03}")\n'
|
||||||
for fn in range(nfns):
|
for fn in range(nfns):
|
||||||
ret = random.randint(0, nclasses - 1)
|
ret = random.randint(0, nclasses - 1)
|
||||||
params = [random.randint(0, nclasses - 1) for i in range(nargs)]
|
params = [random.randint(0, nclasses - 1) for i in range(nargs)]
|
||||||
decl += " cl%03i *fn_%03i(" % (ret, fn)
|
decl += f" cl{ret:03} *fn_{fn:03}("
|
||||||
decl += ", ".join("cl%03i *" % p for p in params)
|
decl += ", ".join(f"cl{p:03} *" for p in params)
|
||||||
decl += ");\n"
|
decl += ");\n"
|
||||||
bindings += (
|
bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03}, py::return_value_policy<py::manage_new_object>())\n'
|
||||||
' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy<py::manage_new_object>())\n'
|
|
||||||
% (fn, cl, fn)
|
|
||||||
)
|
|
||||||
decl += "};\n\n"
|
decl += "};\n\n"
|
||||||
bindings += " ;\n"
|
bindings += " ;\n"
|
||||||
|
|
||||||
@ -75,7 +71,7 @@ def generate_dummy_code_boost(nclasses=10):
|
|||||||
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
|
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
|
||||||
print("{")
|
print("{")
|
||||||
for i in range(0, 10):
|
for i in range(0, 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))
|
||||||
n1 = dt.datetime.now()
|
n1 = dt.datetime.now()
|
||||||
|
@ -9,49 +9,182 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning
|
|||||||
Changes will be added here periodically from the "Suggested changelog entry"
|
Changes will be added here periodically from the "Suggested changelog entry"
|
||||||
block in pull request descriptions.
|
block in pull request descriptions.
|
||||||
|
|
||||||
IN DEVELOPMENT
|
Version 2.10.0 (Jul 15, 2022)
|
||||||
--------------
|
-----------------------------
|
||||||
|
|
||||||
Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC
|
Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC
|
||||||
2017 is limited due to availability of CI runners; we highly recommend MSVC
|
2017 is limited due to availability of CI runners; we highly recommend MSVC
|
||||||
2019 or 2022 be used.
|
2019 or 2022 be used. Initial support added for Python 3.11.
|
||||||
|
|
||||||
New features:
|
New features:
|
||||||
|
|
||||||
|
* ``py::anyset`` & ``py::frozenset`` were added, with copying (cast) to
|
||||||
|
``std::set`` (similar to ``set``).
|
||||||
|
`#3901 <https://github.com/pybind/pybind11/pull/3901>`_
|
||||||
|
|
||||||
|
* Support bytearray casting to string.
|
||||||
|
`#3707 <https://github.com/pybind/pybind11/pull/3707>`_
|
||||||
|
|
||||||
* ``type_caster<std::monostate>`` was added. ``std::monostate`` is a tag type
|
* ``type_caster<std::monostate>`` was added. ``std::monostate`` is a tag type
|
||||||
that allows ``std::variant`` to act as an optional, or allows default
|
that allows ``std::variant`` to act as an optional, or allows default
|
||||||
construction of a ``std::variant`` holding a non-default constructible type.
|
construction of a ``std::variant`` holding a non-default constructible type.
|
||||||
`#3818 <https://github.com/pybind/pybind11/pull/3818>`_
|
`#3818 <https://github.com/pybind/pybind11/pull/3818>`_
|
||||||
|
|
||||||
* Support bytearray casting to string.
|
* ``pybind11::capsule::set_name`` added to mutate the name of the capsule instance.
|
||||||
`#3707 <https://github.com/pybind/pybind11/pull/3707>`_
|
`#3866 <https://github.com/pybind/pybind11/pull/3866>`_
|
||||||
|
|
||||||
|
* NumPy: dtype constructor from type number added, accessors corresponding to
|
||||||
|
Python API ``dtype.num``, ``dtype.byteorder``, ``dtype.flags`` and
|
||||||
|
``dtype.alignment`` added.
|
||||||
|
`#3868 <https://github.com/pybind/pybind11/pull/3868>`_
|
||||||
|
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
|
|
||||||
* Python 2 support was removed completely.
|
* Python 3.6 is now the minimum supported version.
|
||||||
`#3688 <https://github.com/pybind/pybind11/pull/3688>`_
|
`#3688 <https://github.com/pybind/pybind11/pull/3688>`_
|
||||||
|
`#3719 <https://github.com/pybind/pybind11/pull/3719>`_
|
||||||
|
|
||||||
* The minimum version for MSVC is now 2017.
|
* The minimum version for MSVC is now 2017.
|
||||||
`#3722 <https://github.com/pybind/pybind11/pull/3722>`_
|
`#3722 <https://github.com/pybind/pybind11/pull/3722>`_
|
||||||
|
|
||||||
|
* Fix issues with CPython 3.11 betas and add to supported test matrix.
|
||||||
|
`#3923 <https://github.com/pybind/pybind11/pull/3923>`_
|
||||||
|
|
||||||
|
* ``error_already_set`` is now safer and more performant, especially for
|
||||||
|
exceptions with long tracebacks, by delaying computation.
|
||||||
|
`#1895 <https://github.com/pybind/pybind11/pull/1895>`_
|
||||||
|
|
||||||
* Improve exception handling in python ``str`` bindings.
|
* Improve exception handling in python ``str`` bindings.
|
||||||
`#3826 <https://github.com/pybind/pybind11/pull/3826>`_
|
`#3826 <https://github.com/pybind/pybind11/pull/3826>`_
|
||||||
|
|
||||||
* The bindings for capsules now have more consistent exception handling.
|
* The bindings for capsules now have more consistent exception handling.
|
||||||
`#3825 <https://github.com/pybind/pybind11/pull/3825>`_
|
`#3825 <https://github.com/pybind/pybind11/pull/3825>`_
|
||||||
|
|
||||||
* Fix exception handling when ``pybind11::weakref()`` fails.
|
* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can now be
|
||||||
`#3739 <https://github.com/pybind/pybind11/pull/3739>`_
|
used to define classes in namespaces other than pybind11.
|
||||||
|
`#3797 <https://github.com/pybind/pybind11/pull/3797>`_
|
||||||
|
|
||||||
|
* Error printing code now uses ``PYBIND11_DETAILED_ERROR_MESSAGES`` instead of
|
||||||
|
requiring ``NDEBUG``, allowing use with release builds if desired.
|
||||||
|
`#3913 <https://github.com/pybind/pybind11/pull/3913>`_
|
||||||
|
|
||||||
|
* Implicit conversion of the literal ``0`` to ``pybind11::handle`` is now disabled.
|
||||||
|
`#4008 <https://github.com/pybind/pybind11/pull/4008>`_
|
||||||
|
|
||||||
|
|
||||||
Bug fixes:
|
Bug fixes:
|
||||||
|
|
||||||
* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can be used
|
* Fix exception handling when ``pybind11::weakref()`` fails.
|
||||||
to define classes in namespaces other than pybind11.
|
`#3739 <https://github.com/pybind/pybind11/pull/3739>`_
|
||||||
`#3797 <https://github.com/pybind/pybind11/pull/3797>`_
|
|
||||||
|
* ``module_::def_submodule`` was missing proper error handling. This is fixed now.
|
||||||
|
`#3973 <https://github.com/pybind/pybind11/pull/3973>`_
|
||||||
|
|
||||||
|
* The behavior or ``error_already_set`` was made safer and the highly opaque
|
||||||
|
"Unknown internal error occurred" message was replaced with a more helpful
|
||||||
|
message.
|
||||||
|
`#3982 <https://github.com/pybind/pybind11/pull/3982>`_
|
||||||
|
|
||||||
|
* ``error_already_set::what()`` now handles non-normalized exceptions correctly.
|
||||||
|
`#3971 <https://github.com/pybind/pybind11/pull/3971>`_
|
||||||
|
|
||||||
|
* Support older C++ compilers where filesystem is not yet part of the standard
|
||||||
|
library and is instead included in ``std::experimental::filesystem``.
|
||||||
|
`#3840 <https://github.com/pybind/pybind11/pull/3840>`_
|
||||||
|
|
||||||
|
* Fix ``-Wfree-nonheap-object`` warnings produced by GCC by avoiding returning
|
||||||
|
pointers to static objects with ``return_value_policy::take_ownership``.
|
||||||
|
`#3946 <https://github.com/pybind/pybind11/pull/3946>`_
|
||||||
|
|
||||||
|
* Fix cast from pytype rvalue to another pytype.
|
||||||
|
`#3949 <https://github.com/pybind/pybind11/pull/3949>`_
|
||||||
|
|
||||||
|
* Ensure proper behavior when garbage collecting classes with dynamic attributes in Python >=3.9.
|
||||||
|
`#4051 <https://github.com/pybind/pybind11/pull/4051>`_
|
||||||
|
|
||||||
|
* A couple long-standing ``PYBIND11_NAMESPACE``
|
||||||
|
``__attribute__((visibility("hidden")))`` inconsistencies are now fixed
|
||||||
|
(affects only unusual environments).
|
||||||
|
`#4043 <https://github.com/pybind/pybind11/pull/4043>`_
|
||||||
|
|
||||||
|
* ``pybind11::detail::get_internals()`` is now resilient to in-flight Python
|
||||||
|
exceptions.
|
||||||
|
`#3981 <https://github.com/pybind/pybind11/pull/3981>`_
|
||||||
|
|
||||||
|
* Arrays with a dimension of size 0 are now properly converted to dynamic Eigen
|
||||||
|
matrices (more common in NumPy 1.23).
|
||||||
|
`#4038 <https://github.com/pybind/pybind11/pull/4038>`_
|
||||||
|
|
||||||
|
* Avoid catching unrelated errors when importing NumPy.
|
||||||
|
`#3974 <https://github.com/pybind/pybind11/pull/3974>`_
|
||||||
|
|
||||||
|
Performance and style:
|
||||||
|
|
||||||
|
* Added an accessor overload of ``(object &&key)`` to reference steal the
|
||||||
|
object when using python types as keys. This prevents unnecessary reference
|
||||||
|
count overhead for attr, dictionary, tuple, and sequence look ups. Added
|
||||||
|
additional regression tests. Fixed a performance bug the caused accessor
|
||||||
|
assignments to potentially perform unnecessary copies.
|
||||||
|
`#3970 <https://github.com/pybind/pybind11/pull/3970>`_
|
||||||
|
|
||||||
|
* Perfect forward all args of ``make_iterator``.
|
||||||
|
`#3980 <https://github.com/pybind/pybind11/pull/3980>`_
|
||||||
|
|
||||||
|
* Avoid potential bug in pycapsule destructor by adding an ``error_guard`` to
|
||||||
|
one of the dtors.
|
||||||
|
`#3958 <https://github.com/pybind/pybind11/pull/3958>`_
|
||||||
|
|
||||||
|
* Optimize dictionary access in ``strip_padding`` for numpy.
|
||||||
|
`#3994 <https://github.com/pybind/pybind11/pull/3994>`_
|
||||||
|
|
||||||
|
* ``stl_bind.h`` bindings now take slice args as a const-ref.
|
||||||
|
`#3852 <https://github.com/pybind/pybind11/pull/3852>`_
|
||||||
|
|
||||||
|
* Made slice constructor more consistent, and improve performance of some
|
||||||
|
casters by allowing reference stealing.
|
||||||
|
`#3845 <https://github.com/pybind/pybind11/pull/3845>`_
|
||||||
|
|
||||||
|
* Change numpy dtype from_args method to use const ref.
|
||||||
|
`#3878 <https://github.com/pybind/pybind11/pull/3878>`_
|
||||||
|
|
||||||
|
* Follow rule of three to ensure ``PyErr_Restore`` is called only once.
|
||||||
|
`#3872 <https://github.com/pybind/pybind11/pull/3872>`_
|
||||||
|
|
||||||
|
* Added missing perfect forwarding for ``make_iterator`` functions.
|
||||||
|
`#3860 <https://github.com/pybind/pybind11/pull/3860>`_
|
||||||
|
|
||||||
|
* Optimize c++ to python function casting by using the rvalue caster.
|
||||||
|
`#3966 <https://github.com/pybind/pybind11/pull/3966>`_
|
||||||
|
|
||||||
|
* Optimize Eigen sparse matrix casting by removing unnecessary temporary.
|
||||||
|
`#4064 <https://github.com/pybind/pybind11/pull/4064>`_
|
||||||
|
|
||||||
|
* Avoid potential implicit copy/assignment constructors causing double free in
|
||||||
|
``strdup_gaurd``.
|
||||||
|
`#3905 <https://github.com/pybind/pybind11/pull/3905>`_
|
||||||
|
|
||||||
|
* Enable clang-tidy checks ``misc-definitions-in-headers``,
|
||||||
|
``modernize-loop-convert``, and ``modernize-use-nullptr``.
|
||||||
|
`#3881 <https://github.com/pybind/pybind11/pull/3881>`_
|
||||||
|
`#3988 <https://github.com/pybind/pybind11/pull/3988>`_
|
||||||
|
|
||||||
|
|
||||||
Build system improvements:
|
Build system improvements:
|
||||||
|
|
||||||
|
* CMake: Fix file extension on Windows with cp36 and cp37 using FindPython.
|
||||||
|
`#3919 <https://github.com/pybind/pybind11/pull/3919>`_
|
||||||
|
|
||||||
|
* CMake: Support multiple Python targets (such as on vcpkg).
|
||||||
|
`#3948 <https://github.com/pybind/pybind11/pull/3948>`_
|
||||||
|
|
||||||
|
* CMake: Fix issue with NVCC on Windows.
|
||||||
|
`#3947 <https://github.com/pybind/pybind11/pull/3947>`_
|
||||||
|
|
||||||
|
* CMake: Drop the bitness check on cross compiles (like targeting WebAssembly
|
||||||
|
via Emscripten).
|
||||||
|
`#3959 <https://github.com/pybind/pybind11/pull/3959>`_
|
||||||
|
|
||||||
* Add MSVC builds in debug mode to CI.
|
* Add MSVC builds in debug mode to CI.
|
||||||
`#3784 <https://github.com/pybind/pybind11/pull/3784>`_
|
`#3784 <https://github.com/pybind/pybind11/pull/3784>`_
|
||||||
|
|
||||||
@ -59,15 +192,23 @@ Build system improvements:
|
|||||||
`#3732 <https://github.com/pybind/pybind11/pull/3732>`_,
|
`#3732 <https://github.com/pybind/pybind11/pull/3732>`_,
|
||||||
`#3741 <https://github.com/pybind/pybind11/pull/3741>`_
|
`#3741 <https://github.com/pybind/pybind11/pull/3741>`_
|
||||||
|
|
||||||
* Avoid ``setup.py <command>`` usage in internal tests.
|
|
||||||
`#3734 <https://github.com/pybind/pybind11/pull/3734>`_
|
|
||||||
|
|
||||||
|
|
||||||
Backend and tidying up:
|
Backend and tidying up:
|
||||||
|
|
||||||
* Remove idioms in code comments. Use inclusive language.
|
* New theme for the documentation.
|
||||||
|
`#3109 <https://github.com/pybind/pybind11/pull/3109>`_
|
||||||
|
|
||||||
|
* Remove idioms in code comments. Use more inclusive language.
|
||||||
`#3809 <https://github.com/pybind/pybind11/pull/3809>`_
|
`#3809 <https://github.com/pybind/pybind11/pull/3809>`_
|
||||||
|
|
||||||
|
* ``#include <iostream>`` was removed from the ``pybind11/stl.h`` header. Your
|
||||||
|
project may break if it has a transitive dependency on this include. The fix
|
||||||
|
is to "Include What You Use".
|
||||||
|
`#3928 <https://github.com/pybind/pybind11/pull/3928>`_
|
||||||
|
|
||||||
|
* Avoid ``setup.py <command>`` usage in internal tests.
|
||||||
|
`#3734 <https://github.com/pybind/pybind11/pull/3734>`_
|
||||||
|
|
||||||
|
|
||||||
Version 2.9.2 (Mar 29, 2022)
|
Version 2.9.2 (Mar 29, 2022)
|
||||||
----------------------------
|
----------------------------
|
||||||
@ -919,7 +1060,7 @@ Packaging / building improvements:
|
|||||||
`#2338 <https://github.com/pybind/pybind11/pull/2338>`_ and
|
`#2338 <https://github.com/pybind/pybind11/pull/2338>`_ and
|
||||||
`#2370 <https://github.com/pybind/pybind11/pull/2370>`_
|
`#2370 <https://github.com/pybind/pybind11/pull/2370>`_
|
||||||
|
|
||||||
* Full integration with CMake’s C++ standard system and compile features
|
* Full integration with CMake's C++ standard system and compile features
|
||||||
replaces ``PYBIND11_CPP_STANDARD``.
|
replaces ``PYBIND11_CPP_STANDARD``.
|
||||||
|
|
||||||
* Generated config file is now portable to different Python/compiler/CMake
|
* Generated config file is now portable to different Python/compiler/CMake
|
||||||
|
@ -48,10 +48,10 @@ interactive Python session demonstrating this example is shown below:
|
|||||||
>>> print(p)
|
>>> print(p)
|
||||||
<example.Pet object at 0x10cd98060>
|
<example.Pet object at 0x10cd98060>
|
||||||
>>> p.getName()
|
>>> p.getName()
|
||||||
u'Molly'
|
'Molly'
|
||||||
>>> p.setName("Charly")
|
>>> p.setName("Charly")
|
||||||
>>> p.getName()
|
>>> p.getName()
|
||||||
u'Charly'
|
'Charly'
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
@ -124,10 +124,10 @@ This makes it possible to write
|
|||||||
|
|
||||||
>>> p = example.Pet("Molly")
|
>>> p = example.Pet("Molly")
|
||||||
>>> p.name
|
>>> p.name
|
||||||
u'Molly'
|
'Molly'
|
||||||
>>> p.name = "Charly"
|
>>> p.name = "Charly"
|
||||||
>>> p.name
|
>>> p.name
|
||||||
u'Charly'
|
'Charly'
|
||||||
|
|
||||||
Now suppose that ``Pet::name`` was a private internal variable
|
Now suppose that ``Pet::name`` was a private internal variable
|
||||||
that can only be accessed via setters and getters.
|
that can only be accessed via setters and getters.
|
||||||
@ -282,9 +282,9 @@ expose fields and methods of both types:
|
|||||||
|
|
||||||
>>> p = example.Dog("Molly")
|
>>> p = example.Dog("Molly")
|
||||||
>>> p.name
|
>>> p.name
|
||||||
u'Molly'
|
'Molly'
|
||||||
>>> p.bark()
|
>>> p.bark()
|
||||||
u'woof!'
|
'woof!'
|
||||||
|
|
||||||
The C++ classes defined above are regular non-polymorphic types with an
|
The C++ classes defined above are regular non-polymorphic types with an
|
||||||
inheritance relationship. This is reflected in Python:
|
inheritance relationship. This is reflected in Python:
|
||||||
@ -332,7 +332,7 @@ will automatically recognize this:
|
|||||||
>>> type(p)
|
>>> type(p)
|
||||||
PolymorphicDog # automatically downcast
|
PolymorphicDog # automatically downcast
|
||||||
>>> p.bark()
|
>>> p.bark()
|
||||||
u'woof!'
|
'woof!'
|
||||||
|
|
||||||
Given a pointer to a polymorphic base, pybind11 performs automatic downcasting
|
Given a pointer to a polymorphic base, pybind11 performs automatic downcasting
|
||||||
to the actual derived type. Note that this goes beyond the usual situation in
|
to the actual derived type. Note that this goes beyond the usual situation in
|
||||||
@ -434,8 +434,7 @@ you can use ``py::detail::overload_cast_impl`` with an additional set of parenth
|
|||||||
.def("set", overload_cast_<int>()(&Pet::set), "Set the pet's age")
|
.def("set", overload_cast_<int>()(&Pet::set), "Set the pet's age")
|
||||||
.def("set", overload_cast_<const std::string &>()(&Pet::set), "Set the pet's name");
|
.def("set", overload_cast_<const std::string &>()(&Pet::set), "Set the pet's name");
|
||||||
|
|
||||||
.. [#cpp14] A compiler which supports the ``-std=c++14`` flag
|
.. [#cpp14] A compiler which supports the ``-std=c++14`` flag.
|
||||||
or Visual Studio 2015 Update 2 and newer.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@ -483,7 +482,7 @@ The binding code for this example looks as follows:
|
|||||||
.value("Cat", Pet::Kind::Cat)
|
.value("Cat", Pet::Kind::Cat)
|
||||||
.export_values();
|
.export_values();
|
||||||
|
|
||||||
py::class_<Pet::Attributes> attributes(pet, "Attributes")
|
py::class_<Pet::Attributes>(pet, "Attributes")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_readwrite("age", &Pet::Attributes::age);
|
.def_readwrite("age", &Pet::Attributes::age);
|
||||||
|
|
||||||
|
@ -417,10 +417,10 @@ existing targets instead:
|
|||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15...3.19)
|
cmake_minimum_required(VERSION 3.15...3.22)
|
||||||
project(example LANGUAGES CXX)
|
project(example LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(Python COMPONENTS Interpreter Development REQUIRED)
|
find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED)
|
||||||
find_package(pybind11 CONFIG REQUIRED)
|
find_package(pybind11 CONFIG REQUIRED)
|
||||||
# or add_subdirectory(pybind11)
|
# or add_subdirectory(pybind11)
|
||||||
|
|
||||||
@ -433,9 +433,8 @@ algorithms from the CMake invocation, with ``-DPYBIND11_FINDPYTHON=ON``.
|
|||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
If you use FindPython2 and FindPython3 to dual-target Python, use the
|
If you use FindPython to multi-target Python versions, use the individual
|
||||||
individual targets listed below, and avoid targets that directly include
|
targets listed below, and avoid targets that directly include Python parts.
|
||||||
Python parts.
|
|
||||||
|
|
||||||
There are `many ways to hint or force a discovery of a specific Python
|
There are `many ways to hint or force a discovery of a specific Python
|
||||||
installation <https://cmake.org/cmake/help/latest/module/FindPython.html>`_),
|
installation <https://cmake.org/cmake/help/latest/module/FindPython.html>`_),
|
||||||
@ -462,11 +461,8 @@ available in all modes. The targets provided are:
|
|||||||
``pybind11::headers``
|
``pybind11::headers``
|
||||||
Just the pybind11 headers and minimum compile requirements
|
Just the pybind11 headers and minimum compile requirements
|
||||||
|
|
||||||
``pybind11::python2_no_register``
|
|
||||||
Quiets the warning/error when mixing C++14 or higher and Python 2
|
|
||||||
|
|
||||||
``pybind11::pybind11``
|
``pybind11::pybind11``
|
||||||
Python headers + ``pybind11::headers`` + ``pybind11::python2_no_register`` (Python 2 only)
|
Python headers + ``pybind11::headers``
|
||||||
|
|
||||||
``pybind11::python_link_helper``
|
``pybind11::python_link_helper``
|
||||||
Just the "linking" part of pybind11:module
|
Just the "linking" part of pybind11:module
|
||||||
@ -509,7 +505,10 @@ You can use these targets to build complex applications. For example, the
|
|||||||
target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras)
|
target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras)
|
||||||
|
|
||||||
pybind11_extension(example)
|
pybind11_extension(example)
|
||||||
pybind11_strip(example)
|
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
|
||||||
|
# Strip unnecessary sections of the binary on Linux/macOS
|
||||||
|
pybind11_strip(example)
|
||||||
|
endif()
|
||||||
|
|
||||||
set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden"
|
set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden"
|
||||||
CUDA_VISIBILITY_PRESET "hidden")
|
CUDA_VISIBILITY_PRESET "hidden")
|
||||||
@ -577,21 +576,12 @@ On Linux, you can compile an example such as the one given in
|
|||||||
|
|
||||||
$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
|
$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
|
||||||
|
|
||||||
The flags given here assume that you're using Python 3. For Python 2, just
|
|
||||||
change the executable appropriately (to ``python`` or ``python2``).
|
|
||||||
|
|
||||||
The ``python3 -m pybind11 --includes`` command fetches the include paths for
|
The ``python3 -m pybind11 --includes`` command fetches the include paths for
|
||||||
both pybind11 and Python headers. This assumes that pybind11 has been installed
|
both pybind11 and Python headers. This assumes that pybind11 has been installed
|
||||||
using ``pip`` or ``conda``. If it hasn't, you can also manually specify
|
using ``pip`` or ``conda``. If it hasn't, you can also manually specify
|
||||||
``-I <path-to-pybind11>/include`` together with the Python includes path
|
``-I <path-to-pybind11>/include`` together with the Python includes path
|
||||||
``python3-config --includes``.
|
``python3-config --includes``.
|
||||||
|
|
||||||
Note that Python 2.7 modules don't use a special suffix, so you should simply
|
|
||||||
use ``example.so`` instead of ``example$(python3-config --extension-suffix)``.
|
|
||||||
Besides, the ``--extension-suffix`` option may or may not be available, depending
|
|
||||||
on the distribution; in the latter case, the module extension can be manually
|
|
||||||
set to ``.so``.
|
|
||||||
|
|
||||||
On macOS: the build command is almost the same but it also requires passing
|
On macOS: the build command is almost the same but it also requires passing
|
||||||
the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when
|
the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when
|
||||||
building the module:
|
building the module:
|
||||||
|
28
docs/conf.py
28
docs/conf.py
@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# pybind11 documentation build configuration file, created by
|
# pybind11 documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Sun Oct 11 19:23:48 2015.
|
# sphinx-quickstart on Sun Oct 11 19:23:48 2015.
|
||||||
@ -36,6 +35,7 @@ DIR = Path(__file__).parent.resolve()
|
|||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
"breathe",
|
"breathe",
|
||||||
|
"sphinx_copybutton",
|
||||||
"sphinxcontrib.rsvgconverter",
|
"sphinxcontrib.rsvgconverter",
|
||||||
"sphinxcontrib.moderncmakedomain",
|
"sphinxcontrib.moderncmakedomain",
|
||||||
]
|
]
|
||||||
@ -126,23 +126,7 @@ todo_include_todos = False
|
|||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
|
|
||||||
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
|
html_theme = "furo"
|
||||||
|
|
||||||
if not on_rtd: # only import and set the theme if we're building docs locally
|
|
||||||
import sphinx_rtd_theme
|
|
||||||
|
|
||||||
html_theme = "sphinx_rtd_theme"
|
|
||||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
|
||||||
|
|
||||||
html_context = {"css_files": ["_static/theme_overrides.css"]}
|
|
||||||
else:
|
|
||||||
html_context = {
|
|
||||||
"css_files": [
|
|
||||||
"//media.readthedocs.org/css/sphinx_rtd_theme.css",
|
|
||||||
"//media.readthedocs.org/css/readthedocs-doc-embed.css",
|
|
||||||
"_static/theme_overrides.css",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
@ -173,6 +157,10 @@ else:
|
|||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ["_static"]
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
|
html_css_files = [
|
||||||
|
"css/custom.css",
|
||||||
|
]
|
||||||
|
|
||||||
# Add any extra paths that contain custom files (such as robots.txt or
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
# .htaccess) here, relative to this directory. These files are copied
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
# directly to the root of the documentation.
|
# directly to the root of the documentation.
|
||||||
@ -345,9 +333,9 @@ def generate_doxygen_xml(app):
|
|||||||
subprocess.call(["doxygen", "--version"])
|
subprocess.call(["doxygen", "--version"])
|
||||||
retcode = subprocess.call(["doxygen"], cwd=app.confdir)
|
retcode = subprocess.call(["doxygen"], cwd=app.confdir)
|
||||||
if retcode < 0:
|
if retcode < 0:
|
||||||
sys.stderr.write("doxygen error code: {}\n".format(-retcode))
|
sys.stderr.write(f"doxygen error code: {-retcode}\n")
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
sys.stderr.write("doxygen execution failed: {}\n".format(e))
|
sys.stderr.write(f"doxygen execution failed: {e}\n")
|
||||||
|
|
||||||
|
|
||||||
def prepare(app):
|
def prepare(app):
|
||||||
|
42
docs/faq.rst
42
docs/faq.rst
@ -8,9 +8,7 @@ Frequently asked questions
|
|||||||
filename of the extension library (without suffixes such as ``.so``).
|
filename of the extension library (without suffixes such as ``.so``).
|
||||||
|
|
||||||
2. If the above did not fix the issue, you are likely using an incompatible
|
2. If the above did not fix the issue, you are likely using an incompatible
|
||||||
version of Python (for instance, the extension library was compiled against
|
version of Python that does not match what you compiled with.
|
||||||
Python 2, while the interpreter is running on top of some version of Python
|
|
||||||
3, or vice versa).
|
|
||||||
|
|
||||||
"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``"
|
"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``"
|
||||||
========================================================================
|
========================================================================
|
||||||
@ -147,7 +145,7 @@ using C++14 template metaprogramming.
|
|||||||
|
|
||||||
.. _`faq:hidden_visibility`:
|
.. _`faq:hidden_visibility`:
|
||||||
|
|
||||||
"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]"
|
"'SomeClass' declared with greater visibility than the type of its field 'SomeClass::member' [-Wattributes]"
|
||||||
============================================================================================================
|
============================================================================================================
|
||||||
|
|
||||||
This error typically indicates that you are compiling without the required
|
This error typically indicates that you are compiling without the required
|
||||||
@ -222,20 +220,6 @@ In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids
|
|||||||
potential serious issues when loading multiple modules and is required for
|
potential serious issues when loading multiple modules and is required for
|
||||||
proper pybind operation. See the previous FAQ entry for more details.
|
proper pybind operation. See the previous FAQ entry for more details.
|
||||||
|
|
||||||
Working with ancient Visual Studio 2008 builds on Windows
|
|
||||||
=========================================================
|
|
||||||
|
|
||||||
The official Windows distributions of Python are compiled using truly
|
|
||||||
ancient versions of Visual Studio that lack good C++11 support. Some users
|
|
||||||
implicitly assume that it would be impossible to load a plugin built with
|
|
||||||
Visual Studio 2015 into a Python distribution that was compiled using Visual
|
|
||||||
Studio 2008. However, no such issue exists: it's perfectly legitimate to
|
|
||||||
interface DLLs that are built with different compilers and/or C libraries.
|
|
||||||
Common gotchas to watch out for involve not ``free()``-ing memory region
|
|
||||||
that that were ``malloc()``-ed in another shared library, using data
|
|
||||||
structures with incompatible ABIs, and so on. pybind11 is very careful not
|
|
||||||
to make these types of mistakes.
|
|
||||||
|
|
||||||
How can I properly handle Ctrl-C in long-running functions?
|
How can I properly handle Ctrl-C in long-running functions?
|
||||||
===========================================================
|
===========================================================
|
||||||
|
|
||||||
@ -289,27 +273,7 @@ Conflicts can arise, however, when using pybind11 in a project that *also* uses
|
|||||||
the CMake Python detection in a system with several Python versions installed.
|
the CMake Python detection in a system with several Python versions installed.
|
||||||
|
|
||||||
This difference may cause inconsistencies and errors if *both* mechanisms are
|
This difference may cause inconsistencies and errors if *both* mechanisms are
|
||||||
used in the same project. Consider the following CMake code executed in a
|
used in the same project.
|
||||||
system with Python 2.7 and 3.x installed:
|
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
find_package(PythonInterp)
|
|
||||||
find_package(PythonLibs)
|
|
||||||
find_package(pybind11)
|
|
||||||
|
|
||||||
It will detect Python 2.7 and pybind11 will pick it as well.
|
|
||||||
|
|
||||||
In contrast this code:
|
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
find_package(pybind11)
|
|
||||||
find_package(PythonInterp)
|
|
||||||
find_package(PythonLibs)
|
|
||||||
|
|
||||||
will detect Python 3.x for pybind11 and may crash on
|
|
||||||
``find_package(PythonLibs)`` afterwards.
|
|
||||||
|
|
||||||
There are three possible solutions:
|
There are three possible solutions:
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 60 KiB |
@ -1,5 +1,6 @@
|
|||||||
breathe==4.31.0
|
breathe==4.34.0
|
||||||
sphinx==3.5.4
|
furo==2022.6.21
|
||||||
sphinx_rtd_theme==1.0.0
|
sphinx==5.0.2
|
||||||
sphinxcontrib-moderncmakedomain==3.19
|
sphinx-copybutton==0.5.0
|
||||||
sphinxcontrib-svg2pdfconverter==1.1.1
|
sphinxcontrib-moderncmakedomain==3.21.4
|
||||||
|
sphinxcontrib-svg2pdfconverter==1.2.0
|
||||||
|
@ -524,7 +524,7 @@ include a declaration of the form:
|
|||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
|
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
|
||||||
|
|
||||||
Continuing to do so won’t cause an error or even a deprecation warning,
|
Continuing to do so won't cause an error or even a deprecation warning,
|
||||||
but it's completely redundant.
|
but it's completely redundant.
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
#include "cast.h"
|
#include "cast.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -61,7 +62,7 @@ struct base {
|
|||||||
|
|
||||||
PYBIND11_DEPRECATED(
|
PYBIND11_DEPRECATED(
|
||||||
"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
||||||
base() {} // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
|
base() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Keep patient alive while nurse lives
|
/// Keep patient alive while nurse lives
|
||||||
@ -82,8 +83,7 @@ struct metaclass {
|
|||||||
handle value;
|
handle value;
|
||||||
|
|
||||||
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
|
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
|
||||||
// NOLINTNEXTLINE(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
|
metaclass() = default;
|
||||||
metaclass() {}
|
|
||||||
|
|
||||||
/// Override pybind11's default metaclass
|
/// Override pybind11's default metaclass
|
||||||
explicit metaclass(handle value) : value(value) {}
|
explicit metaclass(handle value) : value(value) {}
|
||||||
@ -345,9 +345,11 @@ struct type_record {
|
|||||||
|
|
||||||
bases.append((PyObject *) base_info->type);
|
bases.append((PyObject *) base_info->type);
|
||||||
|
|
||||||
if (base_info->type->tp_dictoffset != 0) {
|
#if PY_VERSION_HEX < 0x030B0000
|
||||||
dynamic_attr = true;
|
dynamic_attr |= base_info->type->tp_dictoffset != 0;
|
||||||
}
|
#else
|
||||||
|
dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (caster) {
|
if (caster) {
|
||||||
base_info->implicit_casts.emplace_back(type, caster);
|
base_info->implicit_casts.emplace_back(type, caster);
|
||||||
@ -478,7 +480,7 @@ struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!a.value) {
|
if (!a.value) {
|
||||||
#if !defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
std::string descr("'");
|
std::string descr("'");
|
||||||
if (a.name) {
|
if (a.name) {
|
||||||
descr += std::string(a.name) + ": ";
|
descr += std::string(a.name) + ": ";
|
||||||
@ -499,7 +501,8 @@ struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
|||||||
#else
|
#else
|
||||||
pybind11_fail("arg(): could not convert default argument "
|
pybind11_fail("arg(): could not convert default argument "
|
||||||
"into a Python object (type not registered yet?). "
|
"into a Python object (type not registered yet?). "
|
||||||
"Compile in debug mode for more information.");
|
"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
|
||||||
|
"more information.");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
||||||
|
@ -329,7 +329,7 @@ public:
|
|||||||
res = 0; // None is implicitly converted to False
|
res = 0; // None is implicitly converted to False
|
||||||
}
|
}
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
// On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists
|
// On PyPy, check that "__bool__" attr exists
|
||||||
else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
|
else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
|
||||||
res = PyObject_IsTrue(src.ptr());
|
res = PyObject_IsTrue(src.ptr());
|
||||||
}
|
}
|
||||||
@ -379,37 +379,16 @@ struct string_caster {
|
|||||||
static constexpr size_t UTF_N = 8 * sizeof(CharT);
|
static constexpr size_t UTF_N = 8 * sizeof(CharT);
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool) {
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
object temp;
|
|
||||||
#endif
|
|
||||||
handle load_src = src;
|
handle load_src = src;
|
||||||
if (!src) {
|
if (!src) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!PyUnicode_Check(load_src.ptr())) {
|
if (!PyUnicode_Check(load_src.ptr())) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
return load_raw(load_src);
|
||||||
return load_bytes(load_src);
|
|
||||||
#else
|
|
||||||
if (std::is_same<CharT, char>::value) {
|
|
||||||
return load_bytes(load_src);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false
|
|
||||||
if (!PYBIND11_BYTES_CHECK(load_src.ptr()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr()));
|
|
||||||
if (!temp) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
load_src = temp;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
// For UTF-8 we avoid the need for a temporary `bytes` object by using
|
||||||
// On Python >= 3.3, for UTF-8 we avoid the need for a temporary `bytes`
|
// `PyUnicode_AsUTF8AndSize`.
|
||||||
// object by using `PyUnicode_AsUTF8AndSize`.
|
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) {
|
if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) {
|
||||||
Py_ssize_t size = -1;
|
Py_ssize_t size = -1;
|
||||||
const auto *buffer
|
const auto *buffer
|
||||||
@ -421,7 +400,6 @@ struct string_caster {
|
|||||||
value = StringType(buffer, static_cast<size_t>(size));
|
value = StringType(buffer, static_cast<size_t>(size));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
auto utfNbytes
|
auto utfNbytes
|
||||||
= reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),
|
= reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),
|
||||||
@ -484,26 +462,37 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// When loading into a std::string or char*, accept a bytes object as-is (i.e.
|
// When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e.
|
||||||
// without any encoding/decoding attempt). For other C++ char sizes this is a no-op.
|
// without any encoding/decoding attempt). For other C++ char sizes this is a no-op.
|
||||||
// which supports loading a unicode from a str, doesn't take this path.
|
// which supports loading a unicode from a str, doesn't take this path.
|
||||||
template <typename C = CharT>
|
template <typename C = CharT>
|
||||||
bool load_bytes(enable_if_t<std::is_same<C, char>::value, handle> src) {
|
bool load_raw(enable_if_t<std::is_same<C, char>::value, handle> src) {
|
||||||
if (PYBIND11_BYTES_CHECK(src.ptr())) {
|
if (PYBIND11_BYTES_CHECK(src.ptr())) {
|
||||||
// We were passed a Python 3 raw bytes; accept it into a std::string or char*
|
// We were passed raw bytes; accept it into a std::string or char*
|
||||||
// without any encoding attempt.
|
// without any encoding attempt.
|
||||||
const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
|
const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
|
||||||
if (bytes) {
|
if (!bytes) {
|
||||||
value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr()));
|
pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure.");
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (PyByteArray_Check(src.ptr())) {
|
||||||
|
// We were passed a bytearray; accept it into a std::string or char*
|
||||||
|
// without any encoding attempt.
|
||||||
|
const char *bytearray = PyByteArray_AsString(src.ptr());
|
||||||
|
if (!bytearray) {
|
||||||
|
pybind11_fail("Unexpected PyByteArray_AsString() failure.");
|
||||||
|
}
|
||||||
|
value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr()));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C = CharT>
|
template <typename C = CharT>
|
||||||
bool load_bytes(enable_if_t<!std::is_same<C, char>::value, handle>) {
|
bool load_raw(enable_if_t<!std::is_same<C, char>::value, handle>) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -525,7 +514,7 @@ struct type_caster<std::basic_string_view<CharT, Traits>,
|
|||||||
template <typename CharT>
|
template <typename CharT>
|
||||||
struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
|
struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
|
||||||
using StringType = std::basic_string<CharT>;
|
using StringType = std::basic_string<CharT>;
|
||||||
using StringCaster = type_caster<StringType>;
|
using StringCaster = make_caster<StringType>;
|
||||||
StringCaster str_caster;
|
StringCaster str_caster;
|
||||||
bool none = false;
|
bool none = false;
|
||||||
CharT one_char = 0;
|
CharT one_char = 0;
|
||||||
@ -788,8 +777,9 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
"(compile in debug mode for type information)");
|
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
|
||||||
|
"type information)");
|
||||||
#else
|
#else
|
||||||
"of type '"
|
"of type '"
|
||||||
+ type_id<holder_type>() + "''");
|
+ type_id<holder_type>() + "''");
|
||||||
@ -856,7 +846,7 @@ struct always_construct_holder {
|
|||||||
|
|
||||||
/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
|
/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
|
||||||
#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \
|
#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \
|
||||||
namespace pybind11 { \
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \
|
||||||
namespace detail { \
|
namespace detail { \
|
||||||
template <typename type> \
|
template <typename type> \
|
||||||
struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { \
|
struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { \
|
||||||
@ -865,7 +855,7 @@ struct always_construct_holder {
|
|||||||
class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
|
class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
|
||||||
: public type_caster_holder<type, holder_type> {}; \
|
: public type_caster_holder<type, holder_type> {}; \
|
||||||
} \
|
} \
|
||||||
}
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
|
||||||
template <typename base, typename holder>
|
template <typename base, typename holder>
|
||||||
@ -918,6 +908,14 @@ struct handle_type_name<kwargs> {
|
|||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
struct pyobject_caster {
|
struct pyobject_caster {
|
||||||
|
template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
|
||||||
|
pyobject_caster() : value() {}
|
||||||
|
|
||||||
|
// `type` may not be default constructible (e.g. frozenset, anyset). Initializing `value`
|
||||||
|
// to a nil handle is safe since it will only be accessed if `load` succeeds.
|
||||||
|
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
||||||
|
pyobject_caster() : value(reinterpret_steal<type>(handle())) {}
|
||||||
|
|
||||||
template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
|
template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
|
||||||
bool load(handle src, bool /* convert */) {
|
bool load(handle src, bool /* convert */) {
|
||||||
value = src;
|
value = src;
|
||||||
@ -926,18 +924,6 @@ struct pyobject_caster {
|
|||||||
|
|
||||||
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
||||||
bool load(handle src, bool /* convert */) {
|
bool load(handle src, bool /* convert */) {
|
||||||
#if PY_MAJOR_VERSION < 3 && !defined(PYBIND11_STR_LEGACY_PERMISSIVE)
|
|
||||||
// For Python 2, without this implicit conversion, Python code would
|
|
||||||
// need to be cluttered with six.ensure_text() or similar, only to be
|
|
||||||
// un-cluttered later after Python 2 support is dropped.
|
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(std::is_same<T, str>::value) && isinstance<bytes>(src)) {
|
|
||||||
PyObject *str_from_bytes = PyUnicode_FromEncodedObject(src.ptr(), "utf-8", nullptr);
|
|
||||||
if (!str_from_bytes)
|
|
||||||
throw error_already_set();
|
|
||||||
value = reinterpret_steal<type>(str_from_bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!isinstance<type>(src)) {
|
if (!isinstance<type>(src)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1023,10 +1009,12 @@ struct return_value_policy_override<
|
|||||||
// Basic python -> C++ casting; throws if casting fails
|
// Basic python -> C++ casting; throws if casting fails
|
||||||
template <typename T, typename SFINAE>
|
template <typename T, typename SFINAE>
|
||||||
type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
|
type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
|
||||||
|
static_assert(!detail::is_pyobject<T>::value,
|
||||||
|
"Internal error: type_caster should only be used for C++ types");
|
||||||
if (!conv.load(handle, true)) {
|
if (!conv.load(handle, true)) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error(
|
throw cast_error("Unable to cast Python instance to C++ type (#define "
|
||||||
"Unable to cast Python instance to C++ type (compile in debug mode for details)");
|
"PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
|
||||||
#else
|
#else
|
||||||
throw cast_error("Unable to cast Python instance of type "
|
throw cast_error("Unable to cast Python instance of type "
|
||||||
+ (std::string) str(type::handle_of(handle)) + " to C++ type '"
|
+ (std::string) str(type::handle_of(handle)) + " to C++ type '"
|
||||||
@ -1091,10 +1079,10 @@ inline void handle::cast() const {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
|
detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
|
||||||
if (obj.ref_count() > 1) {
|
if (obj.ref_count() > 1) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error(
|
throw cast_error(
|
||||||
"Unable to cast Python instance to C++ rvalue: instance has multiple references"
|
"Unable to cast Python instance to C++ rvalue: instance has multiple references"
|
||||||
" (compile in debug mode for details)");
|
" (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
|
||||||
#else
|
#else
|
||||||
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj))
|
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj))
|
||||||
+ " instance to C++ " + type_id<T>()
|
+ " instance to C++ " + type_id<T>()
|
||||||
@ -1113,21 +1101,30 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
|
|||||||
// - If both movable and copyable, check ref count: if 1, move; otherwise copy
|
// - If both movable and copyable, check ref count: if 1, move; otherwise copy
|
||||||
// - Otherwise (not movable), copy.
|
// - Otherwise (not movable), copy.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
detail::enable_if_t<detail::move_always<T>::value, T> cast(object &&object) {
|
detail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_always<T>::value, T>
|
||||||
|
cast(object &&object) {
|
||||||
return move<T>(std::move(object));
|
return move<T>(std::move(object));
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) {
|
detail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_if_unreferenced<T>::value, T>
|
||||||
|
cast(object &&object) {
|
||||||
if (object.ref_count() > 1) {
|
if (object.ref_count() > 1) {
|
||||||
return cast<T>(object);
|
return cast<T>(object);
|
||||||
}
|
}
|
||||||
return move<T>(std::move(object));
|
return move<T>(std::move(object));
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) {
|
detail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_never<T>::value, T>
|
||||||
|
cast(object &&object) {
|
||||||
return cast<T>(object);
|
return cast<T>(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pytype rvalue -> pytype (calls converting constructor)
|
||||||
|
template <typename T>
|
||||||
|
detail::enable_if_t<detail::is_pyobject<T>::value, T> cast(object &&object) {
|
||||||
|
return T(std::move(object));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T object::cast() const & {
|
T object::cast() const & {
|
||||||
return pybind11::cast<T>(*this);
|
return pybind11::cast<T>(*this);
|
||||||
@ -1178,24 +1175,27 @@ 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 &&o) {
|
|
||||||
return pybind11::cast<T>(std::move(o));
|
|
||||||
}
|
|
||||||
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, T> cast_safe(object &&) {
|
||||||
pybind11_fail("Internal error: cast_safe fallback invoked");
|
pybind11_fail("Internal error: cast_safe fallback invoked");
|
||||||
}
|
}
|
||||||
template <>
|
template <typename T>
|
||||||
inline void cast_safe<void>(object &&) {}
|
enable_if_t<std::is_same<void, intrinsic_t<T>>::value, void> cast_safe(object &&) {}
|
||||||
|
template <typename T>
|
||||||
|
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>,
|
||||||
|
std::is_same<void, intrinsic_t<T>>>::value,
|
||||||
|
T>
|
||||||
|
cast_safe(object &&o) {
|
||||||
|
return pybind11::cast<T>(std::move(o));
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
// The overloads could coexist, i.e. the #if is not strictly speaking needed,
|
// The overloads could coexist, i.e. the #if is not strictly speaking needed,
|
||||||
// but it is an easy minor optimization.
|
// but it is an easy minor optimization.
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
inline cast_error cast_error_unable_to_convert_call_arg() {
|
inline cast_error cast_error_unable_to_convert_call_arg() {
|
||||||
return cast_error(
|
return cast_error("Unable to convert call argument to Python object (#define "
|
||||||
"Unable to convert call argument to Python object (compile in debug mode for details)");
|
"PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,
|
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,
|
||||||
@ -1217,7 +1217,7 @@ tuple make_tuple(Args &&...args_) {
|
|||||||
detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}};
|
detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}};
|
||||||
for (size_t i = 0; i < args.size(); i++) {
|
for (size_t i = 0; i < args.size(); i++) {
|
||||||
if (!args[i]) {
|
if (!args[i]) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error_unable_to_convert_call_arg();
|
throw cast_error_unable_to_convert_call_arg();
|
||||||
#else
|
#else
|
||||||
std::array<std::string, size> argtypes{{type_id<Args>()...}};
|
std::array<std::string, size> argtypes{{type_id<Args>()...}};
|
||||||
@ -1266,10 +1266,10 @@ struct arg_v : arg {
|
|||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
arg_v(arg &&base, T &&x, const char *descr = nullptr)
|
arg_v(arg &&base, T &&x, const char *descr = nullptr)
|
||||||
: arg(base), value(reinterpret_steal<object>(
|
: arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast(
|
||||||
detail::make_caster<T>::cast(x, return_value_policy::automatic, {}))),
|
std::forward<T>(x), return_value_policy::automatic, {}))),
|
||||||
descr(descr)
|
descr(descr)
|
||||||
#if !defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
,
|
,
|
||||||
type(type_id<T>())
|
type(type_id<T>())
|
||||||
#endif
|
#endif
|
||||||
@ -1309,7 +1309,7 @@ public:
|
|||||||
object value;
|
object value;
|
||||||
/// The (optional) description of the default value
|
/// The (optional) description of the default value
|
||||||
const char *descr;
|
const char *descr;
|
||||||
#if !defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
/// The C++ type name of the default value (only available when compiled in debug mode)
|
/// The C++ type name of the default value (only available when compiled in debug mode)
|
||||||
std::string type;
|
std::string type;
|
||||||
#endif
|
#endif
|
||||||
@ -1317,7 +1317,7 @@ public:
|
|||||||
|
|
||||||
/// \ingroup annotations
|
/// \ingroup annotations
|
||||||
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of
|
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of
|
||||||
/// an unnamed '*' argument (in Python 3)
|
/// an unnamed '*' argument
|
||||||
struct kw_only {};
|
struct kw_only {};
|
||||||
|
|
||||||
/// \ingroup annotations
|
/// \ingroup annotations
|
||||||
@ -1507,14 +1507,14 @@ private:
|
|||||||
auto o = reinterpret_steal<object>(
|
auto o = reinterpret_steal<object>(
|
||||||
detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
|
detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
|
||||||
if (!o) {
|
if (!o) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error_unable_to_convert_call_arg();
|
throw cast_error_unable_to_convert_call_arg();
|
||||||
#else
|
#else
|
||||||
throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),
|
throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),
|
||||||
type_id<T>());
|
type_id<T>());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
args_list.append(o);
|
args_list.append(std::move(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
void process(list &args_list, detail::args_proxy ap) {
|
void process(list &args_list, detail::args_proxy ap) {
|
||||||
@ -1525,21 +1525,21 @@ private:
|
|||||||
|
|
||||||
void process(list & /*args_list*/, arg_v a) {
|
void process(list & /*args_list*/, arg_v a) {
|
||||||
if (!a.name) {
|
if (!a.name) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
nameless_argument_error();
|
nameless_argument_error();
|
||||||
#else
|
#else
|
||||||
nameless_argument_error(a.type);
|
nameless_argument_error(a.type);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (m_kwargs.contains(a.name)) {
|
if (m_kwargs.contains(a.name)) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
multiple_values_error();
|
multiple_values_error();
|
||||||
#else
|
#else
|
||||||
multiple_values_error(a.name);
|
multiple_values_error(a.name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!a.value) {
|
if (!a.value) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error_unable_to_convert_call_arg();
|
throw cast_error_unable_to_convert_call_arg();
|
||||||
#else
|
#else
|
||||||
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
|
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
|
||||||
@ -1554,7 +1554,7 @@ private:
|
|||||||
}
|
}
|
||||||
for (auto k : reinterpret_borrow<dict>(kp)) {
|
for (auto k : reinterpret_borrow<dict>(kp)) {
|
||||||
if (m_kwargs.contains(k.first)) {
|
if (m_kwargs.contains(k.first)) {
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
multiple_values_error();
|
multiple_values_error();
|
||||||
#else
|
#else
|
||||||
multiple_values_error(str(k.first));
|
multiple_values_error(str(k.first));
|
||||||
@ -1565,9 +1565,10 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] static void nameless_argument_error() {
|
[[noreturn]] static void nameless_argument_error() {
|
||||||
throw type_error("Got kwargs without a name; only named arguments "
|
throw type_error(
|
||||||
"may be passed via py::arg() to a python function call. "
|
"Got kwargs without a name; only named arguments "
|
||||||
"(compile in debug mode for details)");
|
"may be passed via py::arg() to a python function call. "
|
||||||
|
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
|
||||||
}
|
}
|
||||||
[[noreturn]] static void nameless_argument_error(const std::string &type) {
|
[[noreturn]] static void nameless_argument_error(const std::string &type) {
|
||||||
throw type_error("Got kwargs without a name of type '" + type
|
throw type_error("Got kwargs without a name of type '" + type
|
||||||
@ -1575,8 +1576,9 @@ private:
|
|||||||
"arguments may be passed via py::arg() to a python function call. ");
|
"arguments may be passed via py::arg() to a python function call. ");
|
||||||
}
|
}
|
||||||
[[noreturn]] static void multiple_values_error() {
|
[[noreturn]] static void multiple_values_error() {
|
||||||
throw type_error("Got multiple values for keyword argument "
|
throw type_error(
|
||||||
"(compile in debug mode for details)");
|
"Got multiple values for keyword argument "
|
||||||
|
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] static void multiple_values_error(const std::string &name) {
|
[[noreturn]] static void multiple_values_error(const std::string &name) {
|
||||||
@ -1623,7 +1625,7 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
|
|||||||
template <typename Derived>
|
template <typename Derived>
|
||||||
template <return_value_policy policy, typename... Args>
|
template <return_value_policy policy, typename... Args>
|
||||||
object object_api<Derived>::operator()(Args &&...args) const {
|
object object_api<Derived>::operator()(Args &&...args) const {
|
||||||
#if !defined(NDEBUG) && PY_VERSION_HEX >= 0x03060000
|
#ifndef NDEBUG
|
||||||
if (!PyGILState_Check()) {
|
if (!PyGILState_Check()) {
|
||||||
pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure.");
|
pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure.");
|
||||||
}
|
}
|
||||||
@ -1648,12 +1650,12 @@ handle type::handle_of() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define PYBIND11_MAKE_OPAQUE(...) \
|
#define PYBIND11_MAKE_OPAQUE(...) \
|
||||||
namespace pybind11 { \
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \
|
||||||
namespace detail { \
|
namespace detail { \
|
||||||
template <> \
|
template <> \
|
||||||
class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \
|
class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \
|
||||||
} \
|
} \
|
||||||
}
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate
|
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate
|
||||||
/// typedef, e.g.:
|
/// typedef, e.g.:
|
||||||
|
@ -18,17 +18,6 @@
|
|||||||
#include <datetime.h>
|
#include <datetime.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
// Backport the PyDateTime_DELTA functions from Python3.3 if required
|
|
||||||
#ifndef PyDateTime_DELTA_GET_DAYS
|
|
||||||
# define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta *) o)->days)
|
|
||||||
#endif
|
|
||||||
#ifndef PyDateTime_DELTA_GET_SECONDS
|
|
||||||
# define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta *) o)->seconds)
|
|
||||||
#endif
|
|
||||||
#ifndef PyDateTime_DELTA_GET_MICROSECONDS
|
|
||||||
# define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta *) o)->microseconds)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
# define PYBIND11_BUILTIN_QUALNAME
|
# define PYBIND11_BUILTIN_QUALNAME
|
||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
||||||
#else
|
#else
|
||||||
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
|
// In PyPy, we still set __qualname__ so that we can produce reliable function type
|
||||||
// signatures; in 3.3+ this macro expands to nothing:
|
// signatures; in CPython this macro expands to nothing:
|
||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
||||||
setattr((PyObject *) obj, "__qualname__", nameobj)
|
setattr((PyObject *) obj, "__qualname__", nameobj)
|
||||||
#endif
|
#endif
|
||||||
@ -155,7 +155,6 @@ extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyOb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
/**
|
/**
|
||||||
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
|
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
|
||||||
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
|
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
|
||||||
@ -170,7 +169,6 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
|
|||||||
}
|
}
|
||||||
return PyType_Type.tp_getattro(obj, name);
|
return PyType_Type.tp_getattro(obj, name);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
||||||
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
||||||
@ -266,9 +264,7 @@ inline PyTypeObject *make_default_metaclass() {
|
|||||||
type->tp_call = pybind11_meta_call;
|
type->tp_call = pybind11_meta_call;
|
||||||
|
|
||||||
type->tp_setattro = pybind11_meta_setattro;
|
type->tp_setattro = pybind11_meta_setattro;
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
type->tp_getattro = pybind11_meta_getattro;
|
type->tp_getattro = pybind11_meta_getattro;
|
||||||
#endif
|
|
||||||
|
|
||||||
type->tp_dealloc = pybind11_meta_dealloc;
|
type->tp_dealloc = pybind11_meta_dealloc;
|
||||||
|
|
||||||
@ -459,6 +455,8 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string error_string();
|
||||||
|
|
||||||
/** Create the type which can be used as a common base for all classes. This is
|
/** Create the type which can be used as a common base for all classes. This is
|
||||||
needed in order to satisfy Python's requirements for multiple inheritance.
|
needed in order to satisfy Python's requirements for multiple inheritance.
|
||||||
Return value: New reference. */
|
Return value: New reference. */
|
||||||
@ -494,7 +492,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
|||||||
type->tp_weaklistoffset = offsetof(instance, weakrefs);
|
type->tp_weaklistoffset = offsetof(instance, weakrefs);
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
if (PyType_Ready(type) < 0) {
|
||||||
pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string());
|
pybind11_fail("PyType_Ready failed in make_object_base_type(): " + error_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
@ -533,6 +531,10 @@ extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void
|
|||||||
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
Py_VISIT(dict);
|
Py_VISIT(dict);
|
||||||
|
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
|
||||||
|
#if PY_VERSION_HEX >= 0x03090000
|
||||||
|
Py_VISIT(Py_TYPE(self));
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,8 +549,12 @@ extern "C" inline int pybind11_clear(PyObject *self) {
|
|||||||
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
||||||
auto *type = &heap_type->ht_type;
|
auto *type = &heap_type->ht_type;
|
||||||
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||||
|
#if PY_VERSION_HEX < 0x030B0000
|
||||||
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
||||||
type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
|
type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
|
||||||
|
#else
|
||||||
|
type->tp_flags |= Py_TPFLAGS_MANAGED_DICT;
|
||||||
|
#endif
|
||||||
type->tp_traverse = pybind11_traverse;
|
type->tp_traverse = pybind11_traverse;
|
||||||
type->tp_clear = pybind11_clear;
|
type->tp_clear = pybind11_clear;
|
||||||
|
|
||||||
@ -613,9 +619,6 @@ extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
|
|||||||
/// Give this type a buffer interface.
|
/// Give this type a buffer interface.
|
||||||
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
||||||
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
|
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
|
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
|
||||||
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
|
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
|
||||||
@ -628,12 +631,8 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
|||||||
|
|
||||||
auto qualname = name;
|
auto qualname = name;
|
||||||
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
qualname = reinterpret_steal<object>(
|
qualname = reinterpret_steal<object>(
|
||||||
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
|
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
|
||||||
#else
|
|
||||||
qualname = str(rec.scope.attr("__qualname__").cast<std::string>() + "." + rec.name);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object module_;
|
object module_;
|
||||||
@ -697,15 +696,10 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
|||||||
type->tp_as_number = &heap_type->as_number;
|
type->tp_as_number = &heap_type->as_number;
|
||||||
type->tp_as_sequence = &heap_type->as_sequence;
|
type->tp_as_sequence = &heap_type->as_sequence;
|
||||||
type->tp_as_mapping = &heap_type->as_mapping;
|
type->tp_as_mapping = &heap_type->as_mapping;
|
||||||
#if PY_VERSION_HEX >= 0x03050000
|
|
||||||
type->tp_as_async = &heap_type->as_async;
|
type->tp_as_async = &heap_type->as_async;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
|
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
|
|
||||||
#endif
|
|
||||||
if (!rec.is_final) {
|
if (!rec.is_final) {
|
||||||
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
||||||
}
|
}
|
||||||
@ -723,7 +717,7 @@ inline PyObject *make_new_python_type(const type_record &rec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
if (PyType_Ready(type) < 0) {
|
||||||
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!");
|
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed: " + error_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PYBIND11_VERSION_MAJOR 2
|
#define PYBIND11_VERSION_MAJOR 2
|
||||||
#define PYBIND11_VERSION_MINOR 9
|
#define PYBIND11_VERSION_MINOR 10
|
||||||
#define PYBIND11_VERSION_PATCH 2
|
#define PYBIND11_VERSION_PATCH 0
|
||||||
|
|
||||||
// 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 0x02090200
|
#define PYBIND11_VERSION_HEX 0x020A0000
|
||||||
|
|
||||||
#define PYBIND11_NAMESPACE_BEGIN(name) namespace name {
|
#define PYBIND11_NAMESPACE_BEGIN(name) namespace name {
|
||||||
#define PYBIND11_NAMESPACE_END(name) }
|
#define PYBIND11_NAMESPACE_END(name) }
|
||||||
@ -38,6 +38,7 @@
|
|||||||
# define PYBIND11_CPP17
|
# define PYBIND11_CPP17
|
||||||
# if __cplusplus >= 202002L
|
# if __cplusplus >= 202002L
|
||||||
# define PYBIND11_CPP20
|
# define PYBIND11_CPP20
|
||||||
|
// Please update tests/pybind11_tests.cpp `cpp_std()` when adding a macro here.
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
@ -47,7 +48,7 @@
|
|||||||
// or newer.
|
// or newer.
|
||||||
# if _MSVC_LANG >= 201402L
|
# if _MSVC_LANG >= 201402L
|
||||||
# define PYBIND11_CPP14
|
# define PYBIND11_CPP14
|
||||||
# if _MSVC_LANG > 201402L && _MSC_VER >= 1910
|
# if _MSVC_LANG > 201402L
|
||||||
# define PYBIND11_CPP17
|
# define PYBIND11_CPP17
|
||||||
# if _MSVC_LANG >= 202002L
|
# if _MSVC_LANG >= 202002L
|
||||||
# define PYBIND11_CPP20
|
# define PYBIND11_CPP20
|
||||||
@ -81,10 +82,8 @@
|
|||||||
# error pybind11 requires gcc 4.8 or newer
|
# error pybind11 requires gcc 4.8 or newer
|
||||||
# endif
|
# endif
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features
|
# if _MSC_VER < 1910
|
||||||
// (e.g. std::negation) added in 2015u3:
|
# error pybind11 2.10+ requires MSVC 2017 or newer
|
||||||
# if _MSC_FULL_VER < 190024210
|
|
||||||
# error pybind11 requires MSVC 2015 update 3 or newer
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -149,7 +148,7 @@
|
|||||||
|
|
||||||
/* Don't let Python.h #define (v)snprintf as macro because they are implemented
|
/* Don't let Python.h #define (v)snprintf as macro because they are implemented
|
||||||
properly in Visual Studio since 2015. */
|
properly in Visual Studio since 2015. */
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
#if defined(_MSC_VER)
|
||||||
# define HAVE_SNPRINTF 1
|
# define HAVE_SNPRINTF 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -211,6 +210,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
#if PY_VERSION_HEX < 0x03060000
|
||||||
|
# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5."
|
||||||
|
#endif
|
||||||
#include <frameobject.h>
|
#include <frameobject.h>
|
||||||
#include <pythread.h>
|
#include <pythread.h>
|
||||||
|
|
||||||
@ -266,78 +268,37 @@
|
|||||||
// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and
|
// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and
|
||||||
// pybind11::isinstance<str>() is true only for pybind11::str.
|
// pybind11::isinstance<str>() is true only for pybind11::str.
|
||||||
// However, for Python 2 only (!), the pybind11::str caster
|
// However, for Python 2 only (!), the pybind11::str caster
|
||||||
// implicitly decodes bytes to PyUnicodeObject. This is to ease
|
// implicitly decoded bytes to PyUnicodeObject. This was to ease
|
||||||
// the transition from the legacy behavior to the non-permissive
|
// the transition from the legacy behavior to the non-permissive
|
||||||
// behavior.
|
// behavior.
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
/// Compatibility macros for Python 2 / Python 3 versions TODO: remove
|
||||||
# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
||||||
# define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
|
#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
|
||||||
# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
|
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
|
||||||
# define PYBIND11_BYTES_CHECK PyBytes_Check
|
#define PYBIND11_BYTES_CHECK PyBytes_Check
|
||||||
# define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
||||||
# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
||||||
# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
|
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
|
||||||
# define PYBIND11_BYTES_AS_STRING PyBytes_AsString
|
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
|
||||||
# define PYBIND11_BYTES_SIZE PyBytes_Size
|
#define PYBIND11_BYTES_SIZE PyBytes_Size
|
||||||
# define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
|
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
|
||||||
# define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
|
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
|
||||||
# define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
|
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
|
||||||
# define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
|
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
|
||||||
# define PYBIND11_BYTES_NAME "bytes"
|
#define PYBIND11_BYTES_NAME "bytes"
|
||||||
# define PYBIND11_STRING_NAME "str"
|
#define PYBIND11_STRING_NAME "str"
|
||||||
# define PYBIND11_SLICE_OBJECT PyObject
|
#define PYBIND11_SLICE_OBJECT PyObject
|
||||||
# define PYBIND11_FROM_STRING PyUnicode_FromString
|
#define PYBIND11_FROM_STRING PyUnicode_FromString
|
||||||
# define PYBIND11_STR_TYPE ::pybind11::str
|
#define PYBIND11_STR_TYPE ::pybind11::str
|
||||||
# define PYBIND11_BOOL_ATTR "__bool__"
|
#define PYBIND11_BOOL_ATTR "__bool__"
|
||||||
# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
|
#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
|
||||||
# define PYBIND11_BUILTINS_MODULE "builtins"
|
#define PYBIND11_BUILTINS_MODULE "builtins"
|
||||||
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
|
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
|
||||||
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
|
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
|
||||||
# define PYBIND11_PLUGIN_IMPL(name) \
|
#define PYBIND11_PLUGIN_IMPL(name) \
|
||||||
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \
|
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \
|
||||||
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
||||||
|
|
||||||
#else
|
|
||||||
# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
|
|
||||||
# define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check
|
|
||||||
# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION
|
|
||||||
# define PYBIND11_BYTES_CHECK PyString_Check
|
|
||||||
# define PYBIND11_BYTES_FROM_STRING PyString_FromString
|
|
||||||
# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
|
|
||||||
# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
|
|
||||||
# define PYBIND11_BYTES_AS_STRING PyString_AsString
|
|
||||||
# define PYBIND11_BYTES_SIZE PyString_Size
|
|
||||||
# define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
|
|
||||||
# define PYBIND11_LONG_AS_LONGLONG(o) \
|
|
||||||
(PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
|
|
||||||
# define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
|
|
||||||
# define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
|
|
||||||
# define PYBIND11_BYTES_NAME "str"
|
|
||||||
# define PYBIND11_STRING_NAME "unicode"
|
|
||||||
# define PYBIND11_SLICE_OBJECT PySliceObject
|
|
||||||
# define PYBIND11_FROM_STRING PyString_FromString
|
|
||||||
# define PYBIND11_STR_TYPE ::pybind11::bytes
|
|
||||||
# define PYBIND11_BOOL_ATTR "__nonzero__"
|
|
||||||
# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero)
|
|
||||||
# define PYBIND11_BUILTINS_MODULE "__builtin__"
|
|
||||||
// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy.
|
|
||||||
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
|
|
||||||
# define PYBIND11_PLUGIN_IMPL(name) \
|
|
||||||
static PyObject *pybind11_init_wrapper(); \
|
|
||||||
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT void init##name(); \
|
|
||||||
extern "C" PYBIND11_EXPORT void init##name() { (void) pybind11_init_wrapper(); } \
|
|
||||||
PyObject *pybind11_init_wrapper()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
|
|
||||||
extern "C" {
|
|
||||||
struct _Py_atomic_address {
|
|
||||||
void *value;
|
|
||||||
};
|
|
||||||
PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code
|
#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code
|
||||||
#define PYBIND11_STRINGIFY(x) #x
|
#define PYBIND11_STRINGIFY(x) #x
|
||||||
@ -362,31 +323,15 @@ PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
|
catch (pybind11::error_already_set & e) { \
|
||||||
# define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
|
||||||
catch (pybind11::error_already_set & e) { \
|
return nullptr; \
|
||||||
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
|
} \
|
||||||
return nullptr; \
|
catch (const std::exception &e) { \
|
||||||
} \
|
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||||
catch (const std::exception &e) { \
|
return nullptr; \
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
}
|
||||||
return nullptr; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
# define PYBIND11_CATCH_INIT_EXCEPTIONS \
|
|
||||||
catch (pybind11::error_already_set & e) { \
|
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
|
||||||
return nullptr; \
|
|
||||||
} \
|
|
||||||
catch (const std::exception &e) { \
|
|
||||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
|
||||||
return nullptr; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
***Deprecated in favor of PYBIND11_MODULE***
|
***Deprecated in favor of PYBIND11_MODULE***
|
||||||
@ -483,7 +428,7 @@ enum class return_value_policy : uint8_t {
|
|||||||
|
|
||||||
/** Reference an existing object (i.e. do not create a new copy) and take
|
/** Reference an existing object (i.e. do not create a new copy) and take
|
||||||
ownership. Python will call the destructor and delete operator when the
|
ownership. Python will call the destructor and delete operator when the
|
||||||
object’s reference count reaches zero. Undefined behavior ensues when
|
object's reference count reaches zero. Undefined behavior ensues when
|
||||||
the C++ side does the same.. */
|
the C++ side does the same.. */
|
||||||
take_ownership,
|
take_ownership,
|
||||||
|
|
||||||
@ -499,7 +444,7 @@ enum class return_value_policy : uint8_t {
|
|||||||
move,
|
move,
|
||||||
|
|
||||||
/** Reference an existing object, but do not take ownership. The C++ side
|
/** Reference an existing object, but do not take ownership. The C++ side
|
||||||
is responsible for managing the object’s lifetime and deallocating it
|
is responsible for managing the object's lifetime and deallocating it
|
||||||
when it is no longer used. Warning: undefined behavior will ensue when
|
when it is no longer used. Warning: undefined behavior will ensue when
|
||||||
the C++ side deletes an object that is still referenced and used by
|
the C++ side deletes an object that is still referenced and used by
|
||||||
Python. */
|
Python. */
|
||||||
@ -508,7 +453,7 @@ enum class return_value_policy : uint8_t {
|
|||||||
/** This policy only applies to methods and properties. It references the
|
/** This policy only applies to methods and properties. It references the
|
||||||
object without taking ownership similar to the above
|
object without taking ownership similar to the above
|
||||||
return_value_policy::reference policy. In contrast to that policy, the
|
return_value_policy::reference policy. In contrast to that policy, the
|
||||||
function or property’s implicit this argument (called the parent) is
|
function or property's implicit this argument (called the parent) is
|
||||||
considered to be the the owner of the return value (the child).
|
considered to be the the owner of the return value (the child).
|
||||||
pybind11 then couples the lifetime of the parent to the child via a
|
pybind11 then couples the lifetime of the parent to the child via a
|
||||||
reference relationship that ensures that the parent cannot be garbage
|
reference relationship that ensures that the parent cannot be garbage
|
||||||
@ -615,7 +560,7 @@ static_assert(std::is_standard_layout<instance>::value,
|
|||||||
"Internal error: `pybind11::detail::instance` is not standard layout!");
|
"Internal error: `pybind11::detail::instance` is not standard layout!");
|
||||||
|
|
||||||
/// from __cpp_future__ import (convenient aliases from C++14/17)
|
/// from __cpp_future__ import (convenient aliases from C++14/17)
|
||||||
#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
|
#if defined(PYBIND11_CPP14)
|
||||||
using std::conditional_t;
|
using std::conditional_t;
|
||||||
using std::enable_if_t;
|
using std::enable_if_t;
|
||||||
using std::remove_cv_t;
|
using std::remove_cv_t;
|
||||||
@ -878,10 +823,12 @@ struct is_template_base_of_impl {
|
|||||||
/// Check if a template is the base of a type. For example:
|
/// Check if a template is the base of a type. For example:
|
||||||
/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything
|
/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything
|
||||||
template <template <typename...> class Base, typename T>
|
template <template <typename...> class Base, typename T>
|
||||||
|
// Sadly, all MSVC versions incl. 2022 need the workaround, even in C++20 mode.
|
||||||
|
// See also: https://github.com/pybind/pybind11/pull/3741
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
using is_template_base_of
|
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 // MSVC2015 has trouble with decltype in template aliases
|
#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)) {
|
||||||
};
|
};
|
||||||
@ -990,9 +937,11 @@ PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybin
|
|||||||
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
|
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
|
||||||
|
|
||||||
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) {
|
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) {
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
throw std::runtime_error(reason);
|
throw std::runtime_error(reason);
|
||||||
}
|
}
|
||||||
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) {
|
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) {
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
throw std::runtime_error(reason);
|
throw std::runtime_error(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1044,6 +993,8 @@ constexpr const char
|
|||||||
struct error_scope {
|
struct error_scope {
|
||||||
PyObject *type, *value, *trace;
|
PyObject *type, *value, *trace;
|
||||||
error_scope() { PyErr_Fetch(&type, &value, &trace); }
|
error_scope() { PyErr_Fetch(&type, &value, &trace); }
|
||||||
|
error_scope(const error_scope &) = delete;
|
||||||
|
error_scope &operator=(const error_scope &) = delete;
|
||||||
~error_scope() { PyErr_Restore(type, value, trace); }
|
~error_scope() { PyErr_Restore(type, value, trace); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1056,9 +1007,6 @@ struct nodelete {
|
|||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
struct overload_cast_impl {
|
struct overload_cast_impl {
|
||||||
// NOLINTNEXTLINE(modernize-use-equals-default): MSVC 2015 needs this
|
|
||||||
constexpr overload_cast_impl() {}
|
|
||||||
|
|
||||||
template <typename Return>
|
template <typename Return>
|
||||||
constexpr auto operator()(Return (*pf)(Args...)) const noexcept -> decltype(pf) {
|
constexpr auto operator()(Return (*pf)(Args...)) const noexcept -> decltype(pf) {
|
||||||
return pf;
|
return pf;
|
||||||
@ -1085,8 +1033,12 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
|
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
|
||||||
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
|
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
# if (defined(_MSC_VER) && _MSC_VER < 1920) /* MSVC 2017 */ \
|
||||||
|
|| (defined(__clang__) && __clang_major__ == 5)
|
||||||
static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
|
static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
|
||||||
// MSVC 2015 only accepts this particular initialization syntax for this variable template.
|
# else
|
||||||
|
static constexpr detail::overload_cast_impl<Args...> overload_cast;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Const member function selector for overload_cast
|
/// Const member function selector for overload_cast
|
||||||
@ -1172,7 +1124,7 @@ try_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) {
|
|||||||
|
|
||||||
// For silencing "unused" compiler warnings in special situations.
|
// For silencing "unused" compiler warnings in special situations.
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER < 1920 // MSVC 2017
|
#if defined(_MSC_VER) && _MSC_VER < 1920 // MSVC 2017
|
||||||
constexpr
|
constexpr
|
||||||
#endif
|
#endif
|
||||||
inline void
|
inline void
|
||||||
@ -1206,5 +1158,12 @@ constexpr inline bool silence_msvc_c4127(bool cond) { return cond; }
|
|||||||
# define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__
|
# define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Pybind offers detailed error messages by default for all builts that are debug (through the
|
||||||
|
// negation of ndebug). This can also be manually enabled by users, for any builds, through
|
||||||
|
// defining PYBIND11_DETAILED_ERROR_MESSAGES.
|
||||||
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG)
|
||||||
|
# define PYBIND11_DETAILED_ERROR_MESSAGES
|
||||||
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -425,4 +425,4 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
|||||||
|
|
||||||
PYBIND11_NAMESPACE_END(initimpl)
|
PYBIND11_NAMESPACE_END(initimpl)
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(pybind11)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -82,7 +82,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
|||||||
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||||
# if PY_MAJOR_VERSION < 3 || defined(PYPY_VERSION)
|
# if defined(PYPY_VERSION)
|
||||||
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
||||||
// the value if it has already been set. Instead, it must first be deleted and
|
// the value if it has already been set. Instead, it must first be deleted and
|
||||||
// then set again.
|
// then set again.
|
||||||
@ -294,7 +294,6 @@ inline internals **&get_internals_pp() {
|
|||||||
return internals_pp;
|
return internals_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// forward decl
|
// forward decl
|
||||||
inline void translate_exception(std::exception_ptr);
|
inline void translate_exception(std::exception_ptr);
|
||||||
|
|
||||||
@ -318,21 +317,11 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
bool handle_nested_exception(const T &, std::exception_ptr &) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline bool raise_err(PyObject *exc_type, const char *msg) {
|
inline bool raise_err(PyObject *exc_type, const char *msg) {
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
raise_from(exc_type, msg);
|
raise_from(exc_type, msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyErr_SetString(exc_type, msg);
|
PyErr_SetString(exc_type, msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -426,6 +415,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
||||||
const PyGILState_STATE state;
|
const PyGILState_STATE state;
|
||||||
} gil;
|
} gil;
|
||||||
|
error_scope err_scope;
|
||||||
|
|
||||||
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
|
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
|
||||||
auto builtins = handle(PyEval_GetBuiltins());
|
auto builtins = handle(PyEval_GetBuiltins());
|
||||||
|
@ -225,8 +225,8 @@ PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,
|
|||||||
if (throw_if_missing) {
|
if (throw_if_missing) {
|
||||||
std::string tname = tp.name();
|
std::string tname = tp.name();
|
||||||
detail::clean_type_id(tname);
|
detail::clean_type_id(tname);
|
||||||
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname
|
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \""
|
||||||
+ "\"");
|
+ std::move(tname) + '"');
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -394,15 +394,16 @@ instance::get_value_and_holder(const type_info *find_type /*= nullptr default in
|
|||||||
return value_and_holder();
|
return value_and_holder();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
|
|
||||||
"type is not a pybind11 base of the given instance "
|
|
||||||
"(compile in debug mode for type details)");
|
|
||||||
#else
|
|
||||||
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `"
|
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `"
|
||||||
+ get_fully_qualified_tp_name(find_type->type)
|
+ get_fully_qualified_tp_name(find_type->type)
|
||||||
+ "' is not a pybind11 base of the given `"
|
+ "' is not a pybind11 base of the given `"
|
||||||
+ get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
|
+ get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
|
||||||
|
#else
|
||||||
|
pybind11_fail(
|
||||||
|
"pybind11::detail::instance::get_value_and_holder: "
|
||||||
|
"type is not a pybind11 base of the given instance "
|
||||||
|
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for type details)");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,21 +440,15 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
|
|||||||
// instance_registered)
|
// instance_registered)
|
||||||
|
|
||||||
// Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,
|
// Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,
|
||||||
// in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6
|
// in particular, need to be 0). Use Python's memory allocation
|
||||||
// they default to using pymalloc, which is designed to be efficient for small allocations
|
// functions: Python is using pymalloc, which is designed to be
|
||||||
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
// efficient for small allocations like the one we're doing here;
|
||||||
// just wrappers around malloc.
|
// for larger allocations they are just wrappers around malloc.
|
||||||
#if PY_VERSION_HEX >= 0x03050000
|
// TODO: is this still true for pure Python 3.6?
|
||||||
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
||||||
if (!nonsimple.values_and_holders) {
|
if (!nonsimple.values_and_holders) {
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
|
|
||||||
if (!nonsimple.values_and_holders)
|
|
||||||
throw std::bad_alloc();
|
|
||||||
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
|
|
||||||
#endif
|
|
||||||
nonsimple.status
|
nonsimple.status
|
||||||
= reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
= reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
||||||
}
|
}
|
||||||
@ -475,70 +470,6 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp)
|
|||||||
return isinstance(obj, type);
|
return isinstance(obj, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE std::string error_string() {
|
|
||||||
if (!PyErr_Occurred()) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
|
|
||||||
return "Unknown internal error occurred";
|
|
||||||
}
|
|
||||||
|
|
||||||
error_scope scope; // Preserve error state
|
|
||||||
|
|
||||||
std::string errorString;
|
|
||||||
if (scope.type) {
|
|
||||||
errorString += handle(scope.type).attr("__name__").cast<std::string>();
|
|
||||||
errorString += ": ";
|
|
||||||
}
|
|
||||||
if (scope.value) {
|
|
||||||
errorString += (std::string) str(scope.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
if (scope.trace != nullptr) {
|
|
||||||
PyException_SetTraceback(scope.value, scope.trace);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
if (scope.trace) {
|
|
||||||
auto *trace = (PyTracebackObject *) scope.trace;
|
|
||||||
|
|
||||||
/* Get the deepest trace possible */
|
|
||||||
while (trace->tb_next) {
|
|
||||||
trace = trace->tb_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyFrameObject *frame = trace->tb_frame;
|
|
||||||
Py_XINCREF(frame);
|
|
||||||
errorString += "\n\nAt:\n";
|
|
||||||
while (frame) {
|
|
||||||
# if PY_VERSION_HEX >= 0x030900B1
|
|
||||||
PyCodeObject *f_code = PyFrame_GetCode(frame);
|
|
||||||
# else
|
|
||||||
PyCodeObject *f_code = frame->f_code;
|
|
||||||
Py_INCREF(f_code);
|
|
||||||
# endif
|
|
||||||
int lineno = PyFrame_GetLineNumber(frame);
|
|
||||||
errorString += " " + handle(f_code->co_filename).cast<std::string>() + "("
|
|
||||||
+ std::to_string(lineno)
|
|
||||||
+ "): " + handle(f_code->co_name).cast<std::string>() + "\n";
|
|
||||||
Py_DECREF(f_code);
|
|
||||||
# if PY_VERSION_HEX >= 0x030900B1
|
|
||||||
auto *b_frame = PyFrame_GetBack(frame);
|
|
||||||
# else
|
|
||||||
auto *b_frame = frame->f_back;
|
|
||||||
Py_XINCREF(b_frame);
|
|
||||||
# endif
|
|
||||||
Py_DECREF(frame);
|
|
||||||
frame = b_frame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return errorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
auto &instances = get_internals().registered_instances;
|
||||||
auto range = instances.equal_range(ptr);
|
auto range = instances.equal_range(ptr);
|
||||||
@ -555,12 +486,6 @@ PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_i
|
|||||||
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();
|
||||||
#elif PY_VERSION_HEX < 0x03000000
|
|
||||||
return _PyThreadState_Current;
|
|
||||||
#elif PY_VERSION_HEX < 0x03050000
|
|
||||||
return (PyThreadState *) _Py_atomic_load_relaxed(&_PyThreadState_Current);
|
|
||||||
#elif PY_VERSION_HEX < 0x03050200
|
|
||||||
return (PyThreadState *) _PyThreadState_Current.value;
|
|
||||||
#else
|
#else
|
||||||
return _PyThreadState_UncheckedGet();
|
return _PyThreadState_UncheckedGet();
|
||||||
#endif
|
#endif
|
||||||
@ -622,14 +547,15 @@ public:
|
|||||||
if (copy_constructor) {
|
if (copy_constructor) {
|
||||||
valueptr = copy_constructor(src);
|
valueptr = copy_constructor(src);
|
||||||
} else {
|
} else {
|
||||||
#if defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error("return_value_policy = copy, but type is "
|
|
||||||
"non-copyable! (compile in debug mode for details)");
|
|
||||||
#else
|
|
||||||
std::string type_name(tinfo->cpptype->name());
|
std::string type_name(tinfo->cpptype->name());
|
||||||
detail::clean_type_id(type_name);
|
detail::clean_type_id(type_name);
|
||||||
throw cast_error("return_value_policy = copy, but type " + type_name
|
throw cast_error("return_value_policy = copy, but type " + type_name
|
||||||
+ " is non-copyable!");
|
+ " is non-copyable!");
|
||||||
|
#else
|
||||||
|
throw cast_error("return_value_policy = copy, but type is "
|
||||||
|
"non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or "
|
||||||
|
"compile in debug mode for details)");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
wrapper->owned = true;
|
wrapper->owned = true;
|
||||||
@ -641,15 +567,16 @@ public:
|
|||||||
} else if (copy_constructor) {
|
} else if (copy_constructor) {
|
||||||
valueptr = copy_constructor(src);
|
valueptr = copy_constructor(src);
|
||||||
} else {
|
} else {
|
||||||
#if defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
throw cast_error("return_value_policy = move, but type is neither "
|
|
||||||
"movable nor copyable! "
|
|
||||||
"(compile in debug mode for details)");
|
|
||||||
#else
|
|
||||||
std::string type_name(tinfo->cpptype->name());
|
std::string type_name(tinfo->cpptype->name());
|
||||||
detail::clean_type_id(type_name);
|
detail::clean_type_id(type_name);
|
||||||
throw cast_error("return_value_policy = move, but type " + type_name
|
throw cast_error("return_value_policy = move, but type " + type_name
|
||||||
+ " is neither movable nor copyable!");
|
+ " is neither movable nor copyable!");
|
||||||
|
#else
|
||||||
|
throw cast_error("return_value_policy = move, but type is neither "
|
||||||
|
"movable nor copyable! "
|
||||||
|
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in "
|
||||||
|
"debug mode for details)");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
wrapper->owned = true;
|
wrapper->owned = true;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
/// Erase all occurrences of a substring
|
/// Erase all occurrences of a substring
|
||||||
inline void erase_all(std::string &string, const std::string &search) {
|
inline void erase_all(std::string &string, const std::string &search) {
|
||||||
for (size_t pos = 0;;) {
|
for (size_t pos = 0;;) {
|
||||||
@ -46,14 +47,19 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
|
|||||||
#endif
|
#endif
|
||||||
detail::erase_all(name, "pybind11::");
|
detail::erase_all(name, "pybind11::");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string clean_type_id(const char *typeid_name) {
|
||||||
|
std::string name(typeid_name);
|
||||||
|
detail::clean_type_id(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
/// Return a string representation of a C++ type
|
/// Return a string representation of a C++ type
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static std::string type_id() {
|
static std::string type_id() {
|
||||||
std::string name(typeid(T).name());
|
return detail::clean_type_id(typeid(T).name());
|
||||||
detail::clean_type_id(name);
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -21,10 +21,12 @@
|
|||||||
// make it version specific, or even remove it later, but considering that
|
// make it version specific, or even remove it later, but considering that
|
||||||
// 1. C4127 is generally far more distracting than useful for modern template code, and
|
// 1. C4127 is generally far more distracting than useful for modern template code, and
|
||||||
// 2. we definitely want to ignore any MSVC warnings originating from Eigen code,
|
// 2. we definitely want to ignore any MSVC warnings originating from Eigen code,
|
||||||
// it is probably best to keep this around indefinitely.
|
// it is probably best to keep this around indefinitely.
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable : 4127) // C4127: conditional expression is constant
|
# pragma warning(disable : 4127) // C4127: conditional expression is constant
|
||||||
|
# pragma warning(disable : 5054) // https://github.com/pybind/pybind11/pull/3741
|
||||||
|
// C5054: operator '&': deprecated between enumerations of different types
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
@ -109,10 +111,16 @@ struct EigenConformable {
|
|||||||
bool stride_compatible() const {
|
bool stride_compatible() const {
|
||||||
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
|
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
|
||||||
// matching strides, or a dimension size of 1 (in which case the stride value is
|
// matching strides, or a dimension size of 1 (in which case the stride value is
|
||||||
// irrelevant)
|
// irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
|
||||||
return !negativestrides
|
// (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
|
||||||
&& (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|
if (negativestrides) {
|
||||||
|| (EigenRowMajor ? cols : rows) == 1)
|
return false;
|
||||||
|
}
|
||||||
|
if (rows == 0 || cols == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|
||||||
|
|| (EigenRowMajor ? cols : rows) == 1)
|
||||||
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|
||||||
|| (EigenRowMajor ? rows : cols) == 1);
|
|| (EigenRowMajor ? rows : cols) == 1);
|
||||||
}
|
}
|
||||||
@ -666,7 +674,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
|
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
|
||||||
StorageIndex>(shape[0].cast<Index>(),
|
StorageIndex>(shape[0].cast<Index>(),
|
||||||
shape[1].cast<Index>(),
|
shape[1].cast<Index>(),
|
||||||
nnz,
|
std::move(nnz),
|
||||||
outerIndices.mutable_data(),
|
outerIndices.mutable_data(),
|
||||||
innerIndices.mutable_data(),
|
innerIndices.mutable_data(),
|
||||||
values.mutable_data());
|
values.mutable_data());
|
||||||
@ -684,8 +692,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
||||||
array innerIndices(src.nonZeros(), src.innerIndexPtr());
|
array innerIndices(src.nonZeros(), src.innerIndexPtr());
|
||||||
|
|
||||||
return matrix_type(std::make_tuple(data, innerIndices, outerIndices),
|
return matrix_type(pybind11::make_tuple(
|
||||||
std::make_pair(src.rows(), src.cols()))
|
std::move(data), std::move(innerIndices), std::move(outerIndices)),
|
||||||
|
pybind11::make_tuple(src.rows(), src.cols()))
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,15 +19,9 @@
|
|||||||
# error Embedding the interpreter is not supported with PyPy
|
# error Embedding the interpreter is not supported with PyPy
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
extern "C" PyObject *pybind11_init_impl_##name(); \
|
||||||
extern "C" PyObject *pybind11_init_impl_##name(); \
|
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
|
||||||
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
|
|
||||||
#else
|
|
||||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
|
||||||
extern "C" void pybind11_init_impl_##name(); \
|
|
||||||
extern "C" void pybind11_init_impl_##name() { pybind11_init_wrapper_##name(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Add a new module to the table of builtins for the interpreter. Must be
|
Add a new module to the table of builtins for the interpreter. Must be
|
||||||
@ -67,11 +61,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
|
|
||||||
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
||||||
struct embedded_module {
|
struct embedded_module {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
using init_t = PyObject *(*) ();
|
using init_t = PyObject *(*) ();
|
||||||
#else
|
|
||||||
using init_t = void (*)();
|
|
||||||
#endif
|
|
||||||
embedded_module(const char *name, init_t init) {
|
embedded_module(const char *name, init_t init) {
|
||||||
if (Py_IsInitialized() != 0) {
|
if (Py_IsInitialized() != 0) {
|
||||||
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
||||||
@ -86,86 +76,16 @@ struct embedded_module {
|
|||||||
|
|
||||||
struct wide_char_arg_deleter {
|
struct wide_char_arg_deleter {
|
||||||
void operator()(wchar_t *ptr) const {
|
void operator()(wchar_t *ptr) const {
|
||||||
#if PY_VERSION_HEX >= 0x030500f0
|
|
||||||
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
||||||
PyMem_RawFree(ptr);
|
PyMem_RawFree(ptr);
|
||||||
#else
|
|
||||||
delete[] ptr;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline wchar_t *widen_chars(const char *safe_arg) {
|
inline wchar_t *widen_chars(const char *safe_arg) {
|
||||||
#if PY_VERSION_HEX >= 0x030500f0
|
|
||||||
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
||||||
#else
|
|
||||||
wchar_t *widened_arg = nullptr;
|
|
||||||
|
|
||||||
// warning C4996: 'mbstowcs': This function or variable may be unsafe.
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable : 4996)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS
|
|
||||||
size_t count = std::strlen(safe_arg);
|
|
||||||
# else
|
|
||||||
size_t count = std::mbstowcs(nullptr, safe_arg, 0);
|
|
||||||
# endif
|
|
||||||
if (count != static_cast<size_t>(-1)) {
|
|
||||||
widened_arg = new wchar_t[count + 1];
|
|
||||||
std::mbstowcs(widened_arg, safe_arg, count + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
return widened_arg;
|
return widened_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Python 2.x/3.x-compatible version of `PySys_SetArgv`
|
|
||||||
inline void set_interpreter_argv(int argc, const char *const *argv, bool add_program_dir_to_path) {
|
|
||||||
// Before it was special-cased in python 3.8, passing an empty or null argv
|
|
||||||
// caused a segfault, so we have to reimplement the special case ourselves.
|
|
||||||
bool special_case = (argv == nullptr || argc <= 0);
|
|
||||||
|
|
||||||
const char *const empty_argv[]{"\0"};
|
|
||||||
const char *const *safe_argv = special_case ? empty_argv : argv;
|
|
||||||
if (special_case) {
|
|
||||||
argc = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto argv_size = static_cast<size_t>(argc);
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
|
||||||
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
|
|
||||||
std::vector<std::unique_ptr<wchar_t[], wide_char_arg_deleter>> widened_argv_entries;
|
|
||||||
widened_argv_entries.reserve(argv_size);
|
|
||||||
for (size_t ii = 0; ii < argv_size; ++ii) {
|
|
||||||
widened_argv_entries.emplace_back(widen_chars(safe_argv[ii]));
|
|
||||||
if (!widened_argv_entries.back()) {
|
|
||||||
// A null here indicates a character-encoding failure or the python
|
|
||||||
// interpreter out of memory. Give up.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
widened_argv[ii] = widened_argv_entries.back().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *pysys_argv = widened_argv.get();
|
|
||||||
#else
|
|
||||||
// python 2.x
|
|
||||||
std::vector<std::string> strings{safe_argv, safe_argv + argv_size};
|
|
||||||
std::vector<char *> char_strings{argv_size};
|
|
||||||
for (std::size_t i = 0; i < argv_size; ++i)
|
|
||||||
char_strings[i] = &strings[i][0];
|
|
||||||
char **pysys_argv = char_strings.data();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
@ -195,9 +115,64 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
|
|||||||
pybind11_fail("The interpreter is already running");
|
pybind11_fail("The interpreter is already running");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX < 0x030B0000
|
||||||
|
|
||||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
||||||
|
|
||||||
detail::set_interpreter_argv(argc, argv, add_program_dir_to_path);
|
// Before it was special-cased in python 3.8, passing an empty or null argv
|
||||||
|
// caused a segfault, so we have to reimplement the special case ourselves.
|
||||||
|
bool special_case = (argv == nullptr || argc <= 0);
|
||||||
|
|
||||||
|
const char *const empty_argv[]{"\0"};
|
||||||
|
const char *const *safe_argv = special_case ? empty_argv : argv;
|
||||||
|
if (special_case) {
|
||||||
|
argc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto argv_size = static_cast<size_t>(argc);
|
||||||
|
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
||||||
|
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
|
||||||
|
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
|
||||||
|
widened_argv_entries.reserve(argv_size);
|
||||||
|
for (size_t ii = 0; ii < argv_size; ++ii) {
|
||||||
|
widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));
|
||||||
|
if (!widened_argv_entries.back()) {
|
||||||
|
// A null here indicates a character-encoding failure or the python
|
||||||
|
// interpreter out of memory. Give up.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
widened_argv[ii] = widened_argv_entries.back().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *pysys_argv = widened_argv.get();
|
||||||
|
|
||||||
|
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
|
||||||
|
#else
|
||||||
|
PyConfig config;
|
||||||
|
PyConfig_InitIsolatedConfig(&config);
|
||||||
|
config.install_signal_handlers = init_signal_handlers ? 1 : 0;
|
||||||
|
|
||||||
|
PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast<char *const *>(argv));
|
||||||
|
if (PyStatus_Exception(status)) {
|
||||||
|
// A failure here indicates a character-encoding failure or the python
|
||||||
|
// interpreter out of memory. Give up.
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
|
||||||
|
: "Failed to prepare CPython");
|
||||||
|
}
|
||||||
|
status = Py_InitializeFromConfig(&config);
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
if (PyStatus_Exception(status)) {
|
||||||
|
throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
|
||||||
|
: "Failed to init CPython");
|
||||||
|
}
|
||||||
|
if (add_program_dir_to_path) {
|
||||||
|
PyRun_SimpleString("import sys, os.path; "
|
||||||
|
"sys.path.insert(0, "
|
||||||
|
"os.path.abspath(os.path.dirname(sys.argv[0])) "
|
||||||
|
"if sys.argv and os.path.exists(sys.argv[0]) else '')");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
|
@ -20,10 +20,10 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
|
|
||||||
inline void ensure_builtins_in_globals(object &global) {
|
inline void ensure_builtins_in_globals(object &global) {
|
||||||
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
||||||
// Running exec and eval on Python 2 and 3 adds `builtins` module under
|
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
||||||
// `__builtins__` key to globals if not yet present.
|
// globals if not yet present. Python 3.8 made PyRun_String behave
|
||||||
// Python 3.8 made PyRun_String behave similarly. Let's also do that for
|
// similarly. Let's also do that for older versions, for consistency. This
|
||||||
// older versions, for consistency. This was missing from PyPy3.8 7.3.7.
|
// was missing from PyPy3.8 7.3.7.
|
||||||
if (!global.contains("__builtins__"))
|
if (!global.contains("__builtins__"))
|
||||||
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
||||||
#else
|
#else
|
||||||
@ -94,7 +94,7 @@ void exec(const char (&s)[N], object global = globals(), object local = object()
|
|||||||
eval<eval_statements>(s, std::move(global), std::move(local));
|
eval<eval_statements>(s, std::move(global), std::move(local));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03000000
|
#if defined(PYPY_VERSION)
|
||||||
template <eval_mode mode = eval_statements>
|
template <eval_mode mode = eval_statements>
|
||||||
object eval_file(str, object, object) {
|
object eval_file(str, object, object) {
|
||||||
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
||||||
@ -133,40 +133,18 @@ object eval_file(str fname, object global = globals(), object local = object())
|
|||||||
|
|
||||||
int closeFile = 1;
|
int closeFile = 1;
|
||||||
std::string fname_str = (std::string) fname;
|
std::string fname_str = (std::string) fname;
|
||||||
# if PY_VERSION_HEX >= 0x03040000
|
|
||||||
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
||||||
# elif PY_VERSION_HEX >= 0x03000000
|
|
||||||
FILE *f = _Py_fopen(fname.ptr(), "r");
|
|
||||||
# else
|
|
||||||
/* No unicode support in open() :( */
|
|
||||||
auto fobj = reinterpret_steal<object>(
|
|
||||||
PyFile_FromString(const_cast<char *>(fname_str.c_str()), const_cast<char *>("r")));
|
|
||||||
FILE *f = nullptr;
|
|
||||||
if (fobj)
|
|
||||||
f = PyFile_AsFile(fobj.ptr());
|
|
||||||
closeFile = 0;
|
|
||||||
# endif
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Python2, this should be encoded by getfilesystemencoding.
|
|
||||||
// We don't boher setting it since Python2 is past EOL anyway.
|
|
||||||
// See PR#3233
|
|
||||||
# if PY_VERSION_HEX >= 0x03000000
|
|
||||||
if (!global.contains("__file__")) {
|
if (!global.contains("__file__")) {
|
||||||
global["__file__"] = std::move(fname);
|
global["__file__"] = std::move(fname);
|
||||||
}
|
}
|
||||||
# endif
|
|
||||||
|
|
||||||
# if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
|
||||||
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), local.ptr());
|
|
||||||
(void) closeFile;
|
|
||||||
# else
|
|
||||||
PyObject *result
|
PyObject *result
|
||||||
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
||||||
# endif
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
|
@ -98,9 +98,8 @@ public:
|
|||||||
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
||||||
Return operator()(Args... args) const {
|
Return operator()(Args... args) const {
|
||||||
gil_scoped_acquire acq;
|
gil_scoped_acquire acq;
|
||||||
object retval(hfunc.f(std::forward<Args>(args)...));
|
// casts the returned object as a rvalue to the return type
|
||||||
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
||||||
return (retval.template cast<Return>());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public:
|
|||||||
|
|
||||||
if (!tstate) {
|
if (!tstate) {
|
||||||
tstate = PyThreadState_New(internals.istate);
|
tstate = PyThreadState_New(internals.istate);
|
||||||
# if !defined(NDEBUG)
|
# 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!");
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ public:
|
|||||||
|
|
||||||
PYBIND11_NOINLINE void dec_ref() {
|
PYBIND11_NOINLINE void dec_ref() {
|
||||||
--tstate->gilstate_counter;
|
--tstate->gilstate_counter;
|
||||||
# if !defined(NDEBUG)
|
# 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!");
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ public:
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
if (tstate->gilstate_counter == 0) {
|
if (tstate->gilstate_counter == 0) {
|
||||||
# if !defined(NDEBUG)
|
# 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!");
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ private:
|
|||||||
|
|
||||||
if (size > remainder) {
|
if (size > remainder) {
|
||||||
str line(pbase(), size - remainder);
|
str line(pbase(), size - remainder);
|
||||||
pywrite(line);
|
pywrite(std::move(line));
|
||||||
pyflush();
|
pyflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,11 +263,7 @@ private:
|
|||||||
static npy_api lookup() {
|
static npy_api lookup() {
|
||||||
module_ m = module_::import("numpy.core.multiarray");
|
module_ m = module_::import("numpy.core.multiarray");
|
||||||
auto c = m.attr("_ARRAY_API");
|
auto c = m.attr("_ARRAY_API");
|
||||||
#if PY_MAJOR_VERSION >= 3
|
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr);
|
||||||
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
|
||||||
#else
|
|
||||||
void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr());
|
|
||||||
#endif
|
|
||||||
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);
|
||||||
@ -544,18 +540,18 @@ public:
|
|||||||
PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
|
PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
|
||||||
|
|
||||||
explicit dtype(const buffer_info &info) {
|
explicit dtype(const buffer_info &info) {
|
||||||
dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
|
dtype descr(_dtype_from_pep3118()(pybind11::str(info.format)));
|
||||||
// If info.itemsize == 0, use the value calculated from the format string
|
// If info.itemsize == 0, use the value calculated from the format string
|
||||||
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
|
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
|
||||||
.release()
|
.release()
|
||||||
.ptr();
|
.ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit dtype(const std::string &format) {
|
explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {}
|
||||||
m_ptr = from_args(pybind11::str(format)).release().ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit dtype(const char *format) : dtype(std::string(format)) {}
|
explicit dtype(const std::string &format) : dtype(pybind11::str(format)) {}
|
||||||
|
|
||||||
|
explicit dtype(const char *format) : dtype(pybind11::str(format)) {}
|
||||||
|
|
||||||
dtype(list names, list formats, list offsets, ssize_t itemsize) {
|
dtype(list names, list formats, list offsets, ssize_t itemsize) {
|
||||||
dict args;
|
dict args;
|
||||||
@ -563,11 +559,18 @@ public:
|
|||||||
args["formats"] = std::move(formats);
|
args["formats"] = std::move(formats);
|
||||||
args["offsets"] = std::move(offsets);
|
args["offsets"] = std::move(offsets);
|
||||||
args["itemsize"] = pybind11::int_(itemsize);
|
args["itemsize"] = pybind11::int_(itemsize);
|
||||||
m_ptr = from_args(std::move(args)).release().ptr();
|
m_ptr = from_args(args).release().ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit dtype(int typenum)
|
||||||
|
: object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) {
|
||||||
|
if (m_ptr == nullptr) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is essentially the same as calling numpy.dtype(args) in Python.
|
/// This is essentially the same as calling numpy.dtype(args) in Python.
|
||||||
static dtype from_args(object args) {
|
static dtype from_args(const object &args) {
|
||||||
PyObject *ptr = nullptr;
|
PyObject *ptr = nullptr;
|
||||||
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {
|
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
@ -600,6 +603,23 @@ public:
|
|||||||
return detail::array_descriptor_proxy(m_ptr)->type;
|
return detail::array_descriptor_proxy(m_ptr)->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// type number of dtype.
|
||||||
|
int num() const {
|
||||||
|
// Note: The signature, `dtype::num` follows the naming of NumPy's public
|
||||||
|
// Python API (i.e., ``dtype.num``), rather than its internal
|
||||||
|
// C API (``PyArray_Descr::type_num``).
|
||||||
|
return detail::array_descriptor_proxy(m_ptr)->type_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Single character for byteorder
|
||||||
|
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
|
||||||
|
|
||||||
|
/// Alignment of the data type
|
||||||
|
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
|
||||||
|
|
||||||
|
/// Flags for the array descriptor
|
||||||
|
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static object _dtype_from_pep3118() {
|
static object _dtype_from_pep3118() {
|
||||||
static PyObject *obj = module_::import("numpy.core._internal")
|
static PyObject *obj = module_::import("numpy.core._internal")
|
||||||
@ -618,22 +638,27 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct field_descr {
|
struct field_descr {
|
||||||
PYBIND11_STR_TYPE name;
|
pybind11::str name;
|
||||||
object format;
|
object format;
|
||||||
pybind11::int_ offset;
|
pybind11::int_ offset;
|
||||||
|
field_descr(pybind11::str &&name, object &&format, pybind11::int_ &&offset)
|
||||||
|
: name{std::move(name)}, format{std::move(format)}, offset{std::move(offset)} {};
|
||||||
};
|
};
|
||||||
|
auto field_dict = attr("fields").cast<dict>();
|
||||||
std::vector<field_descr> field_descriptors;
|
std::vector<field_descr> field_descriptors;
|
||||||
|
field_descriptors.reserve(field_dict.size());
|
||||||
|
|
||||||
for (auto field : attr("fields").attr("items")()) {
|
for (auto field : field_dict.attr("items")()) {
|
||||||
auto spec = field.cast<tuple>();
|
auto spec = field.cast<tuple>();
|
||||||
auto name = spec[0].cast<pybind11::str>();
|
auto name = spec[0].cast<pybind11::str>();
|
||||||
auto format = spec[1].cast<tuple>()[0].cast<dtype>();
|
auto spec_fo = spec[1].cast<tuple>();
|
||||||
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
|
auto format = spec_fo[0].cast<dtype>();
|
||||||
|
auto offset = spec_fo[1].cast<pybind11::int_>();
|
||||||
if ((len(name) == 0u) && format.kind() == 'V') {
|
if ((len(name) == 0u) && format.kind() == 'V') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
field_descriptors.push_back(
|
field_descriptors.emplace_back(
|
||||||
{(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
|
std::move(name), format.strip_padding(format.itemsize()), std::move(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(field_descriptors.begin(),
|
std::sort(field_descriptors.begin(),
|
||||||
@ -644,9 +669,9 @@ private:
|
|||||||
|
|
||||||
list names, formats, offsets;
|
list names, formats, offsets;
|
||||||
for (auto &descr : field_descriptors) {
|
for (auto &descr : field_descriptors) {
|
||||||
names.append(descr.name);
|
names.append(std::move(descr.name));
|
||||||
formats.append(descr.format);
|
formats.append(std::move(descr.format));
|
||||||
offsets.append(descr.offset);
|
offsets.append(std::move(descr.offset));
|
||||||
}
|
}
|
||||||
return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize);
|
return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize);
|
||||||
}
|
}
|
||||||
@ -944,7 +969,7 @@ protected:
|
|||||||
|
|
||||||
void fail_dim_check(ssize_t dim, const std::string &msg) const {
|
void fail_dim_check(ssize_t dim, const std::string &msg) const {
|
||||||
throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim())
|
throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim())
|
||||||
+ ")");
|
+ ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Ix>
|
template <typename... Ix>
|
||||||
@ -1148,11 +1173,11 @@ struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>
|
|||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
struct format_descriptor<char[N]> {
|
struct format_descriptor<char[N]> {
|
||||||
static std::string format() { return std::to_string(N) + "s"; }
|
static std::string format() { return std::to_string(N) + 's'; }
|
||||||
};
|
};
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
struct format_descriptor<std::array<char, N>> {
|
struct format_descriptor<std::array<char, N>> {
|
||||||
static std::string format() { return std::to_string(N) + "s"; }
|
static std::string format() { return std::to_string(N) + 's'; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1292,7 +1317,8 @@ public:
|
|||||||
static pybind11::dtype dtype() {
|
static pybind11::dtype dtype() {
|
||||||
list shape;
|
list shape;
|
||||||
array_info<T>::append_extents(shape);
|
array_info<T>::append_extents(shape);
|
||||||
return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape));
|
return pybind11::dtype::from_args(
|
||||||
|
pybind11::make_tuple(base_descr::dtype(), std::move(shape)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1338,7 +1364,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor>
|
|||||||
pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
|
pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
|
||||||
+ tinfo.name());
|
+ tinfo.name());
|
||||||
}
|
}
|
||||||
names.append(PYBIND11_STR_TYPE(field.name));
|
names.append(pybind11::str(field.name));
|
||||||
formats.append(field.descr);
|
formats.append(field.descr);
|
||||||
offsets.append(pybind11::int_(field.offset));
|
offsets.append(pybind11::int_(field.offset));
|
||||||
}
|
}
|
||||||
@ -1383,7 +1409,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor>
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto tindex = std::type_index(tinfo);
|
auto tindex = std::type_index(tinfo);
|
||||||
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, format_str};
|
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)};
|
||||||
get_internals().direct_conversions[tindex].push_back(direct_converter);
|
get_internals().direct_conversions[tindex].push_back(direct_converter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1530,7 +1556,7 @@ public:
|
|||||||
void *data() const { return p_ptr; }
|
void *data() const { return p_ptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *p_ptr{0};
|
char *p_ptr{nullptr};
|
||||||
container_type m_strides;
|
container_type m_strides;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,16 +91,6 @@ struct op_ {
|
|||||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(id == op_truediv)
|
|
||||||
|| PYBIND11_SILENCE_MSVC_C4127(id == op_itruediv))
|
|
||||||
cl.def(id == op_itruediv ? "__idiv__"
|
|
||||||
: ot == op_l ? "__div__"
|
|
||||||
: "__rdiv__",
|
|
||||||
&op::execute,
|
|
||||||
is_operator(),
|
|
||||||
extra...);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
template <typename Class, typename... Extra>
|
template <typename Class, typename... Extra>
|
||||||
void execute_cast(Class &cl, const Extra &...extra) const {
|
void execute_cast(Class &cl, const Extra &...extra) const {
|
||||||
@ -109,15 +99,6 @@ struct op_ {
|
|||||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (id == op_truediv || id == op_itruediv)
|
|
||||||
cl.def(id == op_itruediv ? "__idiv__"
|
|
||||||
: ot == op_l ? "__div__"
|
|
||||||
: "__rdiv__",
|
|
||||||
&op::execute,
|
|
||||||
is_operator(),
|
|
||||||
extra...);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -312,6 +312,10 @@ protected:
|
|||||||
// along the way.
|
// along the way.
|
||||||
class strdup_guard {
|
class strdup_guard {
|
||||||
public:
|
public:
|
||||||
|
strdup_guard() = default;
|
||||||
|
strdup_guard(const strdup_guard &) = delete;
|
||||||
|
strdup_guard &operator=(const strdup_guard &) = delete;
|
||||||
|
|
||||||
~strdup_guard() {
|
~strdup_guard() {
|
||||||
for (auto *s : strings) {
|
for (auto *s : strings) {
|
||||||
std::free(s);
|
std::free(s);
|
||||||
@ -366,7 +370,7 @@ protected:
|
|||||||
rec->is_constructor = (std::strcmp(rec->name, "__init__") == 0)
|
rec->is_constructor = (std::strcmp(rec->name, "__init__") == 0)
|
||||||
|| (std::strcmp(rec->name, "__setstate__") == 0);
|
|| (std::strcmp(rec->name, "__setstate__") == 0);
|
||||||
|
|
||||||
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
|
||||||
if (rec->is_constructor && !rec->is_new_style_constructor) {
|
if (rec->is_constructor && !rec->is_new_style_constructor) {
|
||||||
const auto class_name
|
const auto class_name
|
||||||
= detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());
|
= detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());
|
||||||
@ -431,9 +435,8 @@ protected:
|
|||||||
}
|
}
|
||||||
if (auto *tinfo = detail::get_type_info(*t)) {
|
if (auto *tinfo = detail::get_type_info(*t)) {
|
||||||
handle th((PyObject *) tinfo->type);
|
handle th((PyObject *) tinfo->type);
|
||||||
signature += th.attr("__module__").cast<std::string>() + "." +
|
signature += th.attr("__module__").cast<std::string>() + "."
|
||||||
// Python 3.3+, but we backport it to earlier versions
|
+ th.attr("__qualname__").cast<std::string>();
|
||||||
th.attr("__qualname__").cast<std::string>();
|
|
||||||
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
||||||
// A new-style `__init__` takes `self` as `value_and_holder`.
|
// A new-style `__init__` takes `self` as `value_and_holder`.
|
||||||
// Rewrite it to the proper class type.
|
// Rewrite it to the proper class type.
|
||||||
@ -453,15 +456,6 @@ protected:
|
|||||||
pybind11_fail("Internal error while parsing type signature (2)");
|
pybind11_fail("Internal error while parsing type signature (2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (std::strcmp(rec->name, "__next__") == 0) {
|
|
||||||
std::free(rec->name);
|
|
||||||
rec->name = guarded_strdup("next");
|
|
||||||
} else if (std::strcmp(rec->name, "__bool__") == 0) {
|
|
||||||
std::free(rec->name);
|
|
||||||
rec->name = guarded_strdup("__nonzero__");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
rec->signature = guarded_strdup(signature.c_str());
|
rec->signature = guarded_strdup(signature.c_str());
|
||||||
rec->args.shrink_to_fit();
|
rec->args.shrink_to_fit();
|
||||||
rec->nargs = (std::uint16_t) args;
|
rec->nargs = (std::uint16_t) args;
|
||||||
@ -524,8 +518,9 @@ protected:
|
|||||||
if (chain->is_method != rec->is_method) {
|
if (chain->is_method != rec->is_method) {
|
||||||
pybind11_fail(
|
pybind11_fail(
|
||||||
"overloading a method with both static and instance methods is not supported; "
|
"overloading a method with both static and instance methods is not supported; "
|
||||||
#if defined(NDEBUG)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
"compile in debug mode for more details"
|
"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more "
|
||||||
|
"details"
|
||||||
#else
|
#else
|
||||||
"error while attempting to bind "
|
"error while attempting to bind "
|
||||||
+ std::string(rec->is_method ? "instance" : "static") + " method "
|
+ std::string(rec->is_method ? "instance" : "static") + " method "
|
||||||
@ -571,14 +566,14 @@ protected:
|
|||||||
for (auto *it = chain_start; it != nullptr; it = it->next) {
|
for (auto *it = chain_start; it != nullptr; it = it->next) {
|
||||||
if (options::show_function_signatures()) {
|
if (options::show_function_signatures()) {
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
signatures += "\n";
|
signatures += '\n';
|
||||||
}
|
}
|
||||||
if (chain) {
|
if (chain) {
|
||||||
signatures += std::to_string(++index) + ". ";
|
signatures += std::to_string(++index) + ". ";
|
||||||
}
|
}
|
||||||
signatures += rec->name;
|
signatures += rec->name;
|
||||||
signatures += it->signature;
|
signatures += it->signature;
|
||||||
signatures += "\n";
|
signatures += '\n';
|
||||||
}
|
}
|
||||||
if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) {
|
if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) {
|
||||||
// If we're appending another docstring, and aren't printing function signatures,
|
// If we're appending another docstring, and aren't printing function signatures,
|
||||||
@ -587,15 +582,15 @@ protected:
|
|||||||
if (first_user_def) {
|
if (first_user_def) {
|
||||||
first_user_def = false;
|
first_user_def = false;
|
||||||
} else {
|
} else {
|
||||||
signatures += "\n";
|
signatures += '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options::show_function_signatures()) {
|
if (options::show_function_signatures()) {
|
||||||
signatures += "\n";
|
signatures += '\n';
|
||||||
}
|
}
|
||||||
signatures += it->doc;
|
signatures += it->doc;
|
||||||
if (options::show_function_signatures()) {
|
if (options::show_function_signatures()) {
|
||||||
signatures += "\n";
|
signatures += '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -912,7 +907,7 @@ protected:
|
|||||||
|
|
||||||
// 5. Put everything in a vector. Not technically step 5, we've been building it
|
// 5. Put everything in a vector. Not technically step 5, we've been building it
|
||||||
// in `call.args` all along.
|
// in `call.args` all along.
|
||||||
#if !defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) {
|
if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) {
|
||||||
pybind11_fail("Internal error: function call dispatcher inserted wrong number "
|
pybind11_fail("Internal error: function call dispatcher inserted wrong number "
|
||||||
"of arguments!");
|
"of arguments!");
|
||||||
@ -1065,7 +1060,7 @@ protected:
|
|||||||
msg += it2->signature;
|
msg += it2->signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg += "\n";
|
msg += '\n';
|
||||||
}
|
}
|
||||||
msg += "\nInvoked with: ";
|
msg += "\nInvoked with: ";
|
||||||
auto args_ = reinterpret_borrow<tuple>(args_in);
|
auto args_ = reinterpret_borrow<tuple>(args_in);
|
||||||
@ -1107,14 +1102,12 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_note_if_missing_header_is_suspected(msg);
|
append_note_if_missing_header_is_suspected(msg);
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// Attach additional error info to the exception if supported
|
// Attach additional error info to the exception if supported
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
// #HelpAppreciated: unit test coverage for this branch.
|
// #HelpAppreciated: unit test coverage for this branch.
|
||||||
raise_from(PyExc_TypeError, msg.c_str());
|
raise_from(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1123,13 +1116,11 @@ protected:
|
|||||||
"Python type! The signature was\n\t";
|
"Python type! The signature was\n\t";
|
||||||
msg += it->signature;
|
msg += it->signature;
|
||||||
append_note_if_missing_header_is_suspected(msg);
|
append_note_if_missing_header_is_suspected(msg);
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1149,11 +1140,7 @@ public:
|
|||||||
/// Create a new top-level Python module with the given name and docstring
|
/// Create a new top-level Python module with the given name and docstring
|
||||||
PYBIND11_DEPRECATED("Use PYBIND11_MODULE or module_::create_extension_module instead")
|
PYBIND11_DEPRECATED("Use PYBIND11_MODULE or module_::create_extension_module instead")
|
||||||
explicit module_(const char *name, const char *doc = nullptr) {
|
explicit module_(const char *name, const char *doc = nullptr) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
*this = create_extension_module(name, doc, new PyModuleDef());
|
*this = create_extension_module(name, doc, new PyModuleDef());
|
||||||
#else
|
|
||||||
*this = create_extension_module(name, doc, nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
@ -1186,9 +1173,16 @@ public:
|
|||||||
py::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
|
py::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
|
||||||
\endrst */
|
\endrst */
|
||||||
module_ def_submodule(const char *name, const char *doc = nullptr) {
|
module_ def_submodule(const char *name, const char *doc = nullptr) {
|
||||||
std::string full_name
|
const char *this_name = PyModule_GetName(m_ptr);
|
||||||
= std::string(PyModule_GetName(m_ptr)) + std::string(".") + std::string(name);
|
if (this_name == nullptr) {
|
||||||
auto result = reinterpret_borrow<module_>(PyImport_AddModule(full_name.c_str()));
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
std::string full_name = std::string(this_name) + '.' + name;
|
||||||
|
handle submodule = PyImport_AddModule(full_name.c_str());
|
||||||
|
if (!submodule) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
auto result = reinterpret_borrow<module_>(submodule);
|
||||||
if (doc && options::show_user_defined_docstrings()) {
|
if (doc && options::show_user_defined_docstrings()) {
|
||||||
result.attr("__doc__") = pybind11::str(doc);
|
result.attr("__doc__") = pybind11::str(doc);
|
||||||
}
|
}
|
||||||
@ -1231,20 +1225,14 @@ public:
|
|||||||
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
|
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)?
|
||||||
using module_def = PyModuleDef;
|
|
||||||
#else
|
|
||||||
struct module_def {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Create a new top-level module that can be used as the main module of a C extension.
|
Create a new top-level module that can be used as the main module of a C extension.
|
||||||
|
|
||||||
For Python 3, ``def`` should point to a statically allocated module_def.
|
``def`` should point to a statically allocated module_def.
|
||||||
For Python 2, ``def`` can be a nullptr and is completely ignored.
|
|
||||||
\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) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
// module_def is PyModuleDef
|
// module_def is PyModuleDef
|
||||||
// Placement new (not an allocation).
|
// Placement new (not an allocation).
|
||||||
def = new (def)
|
def = new (def)
|
||||||
@ -1258,12 +1246,6 @@ public:
|
|||||||
/* m_clear */ nullptr,
|
/* m_clear */ nullptr,
|
||||||
/* m_free */ nullptr};
|
/* m_free */ nullptr};
|
||||||
auto *m = PyModule_Create(def);
|
auto *m = PyModule_Create(def);
|
||||||
#else
|
|
||||||
// Ignore module_def *def; only necessary for Python 3
|
|
||||||
(void) def;
|
|
||||||
auto m = Py_InitModule3(
|
|
||||||
name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr);
|
|
||||||
#endif
|
|
||||||
if (m == nullptr) {
|
if (m == nullptr) {
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
@ -1271,8 +1253,8 @@ public:
|
|||||||
pybind11_fail("Internal error in module_::create_extension_module()");
|
pybind11_fail("Internal error in module_::create_extension_module()");
|
||||||
}
|
}
|
||||||
// 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 is correct.
|
// For Python 2, reinterpret_borrow was correct.
|
||||||
return reinterpret_borrow<module_>(m);
|
return reinterpret_borrow<module_>(m);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1290,14 +1272,12 @@ inline dict globals() {
|
|||||||
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
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...>()>>
|
||||||
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
|
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
|
||||||
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
|
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
|
||||||
object make_simple_namespace(Args &&...args_) {
|
object make_simple_namespace(Args &&...args_) {
|
||||||
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
|
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
/// Generic support for creating new Python heap types
|
/// Generic support for creating new Python heap types
|
||||||
@ -1593,7 +1573,8 @@ public:
|
|||||||
scope(*this),
|
scope(*this),
|
||||||
sibling(getattr(*this, name_, none())),
|
sibling(getattr(*this, name_, none())),
|
||||||
extra...);
|
extra...);
|
||||||
attr(cf.name()) = staticmethod(cf);
|
auto cf_name = cf.name();
|
||||||
|
attr(std::move(cf_name)) = staticmethod(std::move(cf));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1647,7 +1628,7 @@ public:
|
|||||||
if (!caster.load(obj, false)) {
|
if (!caster.load(obj, false)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return new buffer_info(((capture *) ptr)->func(caster));
|
return new buffer_info(((capture *) ptr)->func(std::move(caster)));
|
||||||
},
|
},
|
||||||
ptr);
|
ptr);
|
||||||
weakref(m_ptr, cpp_function([ptr](handle wr) {
|
weakref(m_ptr, cpp_function([ptr](handle wr) {
|
||||||
@ -1849,7 +1830,8 @@ private:
|
|||||||
if (holder_ptr) {
|
if (holder_ptr) {
|
||||||
init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
|
init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
|
||||||
v_h.set_holder_constructed();
|
v_h.set_holder_constructed();
|
||||||
} else if (inst->owned || detail::always_construct_holder<holder_type>::value) {
|
} else if (PYBIND11_SILENCE_MSVC_C4127(detail::always_construct_holder<holder_type>::value)
|
||||||
|
|| inst->owned) {
|
||||||
new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
|
new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
|
||||||
v_h.set_holder_constructed();
|
v_h.set_holder_constructed();
|
||||||
}
|
}
|
||||||
@ -1952,7 +1934,8 @@ struct enum_base {
|
|||||||
[](const object &arg) -> str {
|
[](const object &arg) -> str {
|
||||||
handle type = type::handle_of(arg);
|
handle type = type::handle_of(arg);
|
||||||
object type_name = type.attr("__name__");
|
object type_name = type.attr("__name__");
|
||||||
return pybind11::str("<{}.{}: {}>").format(type_name, enum_name(arg), int_(arg));
|
return pybind11::str("<{}.{}: {}>")
|
||||||
|
.format(std::move(type_name), enum_name(arg), int_(arg));
|
||||||
},
|
},
|
||||||
name("__repr__"),
|
name("__repr__"),
|
||||||
is_method(m_base));
|
is_method(m_base));
|
||||||
@ -1962,7 +1945,7 @@ struct enum_base {
|
|||||||
m_base.attr("__str__") = cpp_function(
|
m_base.attr("__str__") = cpp_function(
|
||||||
[](handle arg) -> str {
|
[](handle arg) -> str {
|
||||||
object type_name = type::handle_of(arg).attr("__name__");
|
object type_name = type::handle_of(arg).attr("__name__");
|
||||||
return pybind11::str("{}.{}").format(type_name, enum_name(arg));
|
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
|
||||||
},
|
},
|
||||||
name("name"),
|
name("name"),
|
||||||
is_method(m_base));
|
is_method(m_base));
|
||||||
@ -2086,12 +2069,12 @@ struct enum_base {
|
|||||||
str name(name_);
|
str name(name_);
|
||||||
if (entries.contains(name)) {
|
if (entries.contains(name)) {
|
||||||
std::string type_name = (std::string) str(m_base.attr("__name__"));
|
std::string type_name = (std::string) str(m_base.attr("__name__"));
|
||||||
throw value_error(type_name + ": element \"" + std::string(name_)
|
throw value_error(std::move(type_name) + ": element \"" + std::string(name_)
|
||||||
+ "\" already exists!");
|
+ "\" already exists!");
|
||||||
}
|
}
|
||||||
|
|
||||||
entries[name] = std::make_pair(value, doc);
|
entries[name] = std::make_pair(value, doc);
|
||||||
m_base.attr(name) = value;
|
m_base.attr(std::move(name)) = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE void export_values() {
|
PYBIND11_NOINLINE void export_values() {
|
||||||
@ -2173,9 +2156,6 @@ public:
|
|||||||
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
||||||
def("__int__", [](Type value) { return (Scalar) value; });
|
def("__int__", [](Type value) { return (Scalar) value; });
|
||||||
def("__index__", [](Type value) { return (Scalar) value; });
|
def("__index__", [](Type value) { return (Scalar) value; });
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
def("__long__", [](Type value) { return (Scalar) value; });
|
|
||||||
#endif
|
|
||||||
attr("__setstate__") = cpp_function(
|
attr("__setstate__") = cpp_function(
|
||||||
[](detail::value_and_holder &v_h, Scalar arg) {
|
[](detail::value_and_holder &v_h, Scalar arg) {
|
||||||
detail::initimpl::setstate<Base>(
|
detail::initimpl::setstate<Base>(
|
||||||
@ -2353,7 +2333,7 @@ template <typename Access,
|
|||||||
typename Sentinel,
|
typename Sentinel,
|
||||||
typename ValueType,
|
typename ValueType,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
iterator make_iterator_impl(Iterator &&first, Sentinel &&last, Extra &&...extra) {
|
||||||
using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
|
using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
|
||||||
// TODO: state captures only the types of Extra, not the values
|
// TODO: state captures only the types of Extra, not the values
|
||||||
|
|
||||||
@ -2379,7 +2359,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)
|
||||||
@ -2390,13 +2370,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) {
|
iterator 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
|
||||||
@ -2406,13 +2388,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) {
|
iterator 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
|
||||||
@ -2422,13 +2406,15 @@ 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) {
|
iterator 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
|
||||||
@ -2437,7 +2423,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|||||||
typename Type,
|
typename Type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_iterator(Type &value, Extra &&...extra) {
|
iterator make_iterator(Type &value, Extra &&...extra) {
|
||||||
return make_iterator<Policy>(std::begin(value), std::end(value), extra...);
|
return make_iterator<Policy>(
|
||||||
|
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting
|
/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting
|
||||||
@ -2446,7 +2433,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|||||||
typename Type,
|
typename Type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_key_iterator(Type &value, Extra &&...extra) {
|
iterator make_key_iterator(Type &value, Extra &&...extra) {
|
||||||
return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
|
return make_key_iterator<Policy>(
|
||||||
|
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes an iterator over the values (`.second`) of a stl map-like container supporting
|
/// Makes an iterator over the values (`.second`) of a stl map-like container supporting
|
||||||
@ -2455,7 +2443,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|||||||
typename Type,
|
typename Type,
|
||||||
typename... Extra>
|
typename... Extra>
|
||||||
iterator make_value_iterator(Type &value, Extra &&...extra) {
|
iterator make_value_iterator(Type &value, Extra &&...extra) {
|
||||||
return make_value_iterator<Policy>(std::begin(value), std::end(value), extra...);
|
return make_value_iterator<Policy>(
|
||||||
|
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputType, typename OutputType>
|
template <typename InputType, typename OutputType>
|
||||||
@ -2484,7 +2473,7 @@ void implicitly_convertible() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (auto *tinfo = detail::get_type_info(typeid(OutputType))) {
|
if (auto *tinfo = detail::get_type_info(typeid(OutputType))) {
|
||||||
tinfo->implicit_conversions.push_back(implicit_caster);
|
tinfo->implicit_conversions.emplace_back(std::move(implicit_caster));
|
||||||
} else {
|
} else {
|
||||||
pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
|
pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
|
||||||
}
|
}
|
||||||
@ -2520,7 +2509,7 @@ public:
|
|||||||
exception(handle scope, const char *name, handle base = PyExc_Exception) {
|
exception(handle scope, const char *name, handle base = PyExc_Exception) {
|
||||||
std::string full_name
|
std::string full_name
|
||||||
= scope.attr("__name__").cast<std::string>() + std::string(".") + name;
|
= scope.attr("__name__").cast<std::string>() + std::string(".") + name;
|
||||||
m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), NULL);
|
m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), nullptr);
|
||||||
if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) {
|
if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) {
|
||||||
pybind11_fail("Error during initialization: multiple incompatible "
|
pybind11_fail("Error during initialization: multiple incompatible "
|
||||||
"definitions with name \""
|
"definitions with name \""
|
||||||
@ -2602,8 +2591,8 @@ PYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) {
|
|||||||
for (size_t i = 0; i < args.size(); ++i) {
|
for (size_t i = 0; i < args.size(); ++i) {
|
||||||
strings[i] = str(args[i]);
|
strings[i] = str(args[i]);
|
||||||
}
|
}
|
||||||
auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" ");
|
auto sep = kwargs.contains("sep") ? kwargs["sep"] : str(" ");
|
||||||
auto line = sep.attr("join")(strings);
|
auto line = sep.attr("join")(std::move(strings));
|
||||||
|
|
||||||
object file;
|
object file;
|
||||||
if (kwargs.contains("file")) {
|
if (kwargs.contains("file")) {
|
||||||
@ -2621,8 +2610,8 @@ PYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto write = file.attr("write");
|
auto write = file.attr("write");
|
||||||
write(line);
|
write(std::move(line));
|
||||||
write(kwargs.contains("end") ? kwargs["end"] : cast("\n"));
|
write(kwargs.contains("end") ? kwargs["end"] : str("\n"));
|
||||||
|
|
||||||
if (kwargs.contains("flush") && kwargs["flush"].cast<bool>()) {
|
if (kwargs.contains("flush") && kwargs["flush"].cast<bool>()) {
|
||||||
file.attr("flush")();
|
file.attr("flush")();
|
||||||
@ -2636,17 +2625,21 @@ void print(Args &&...args) {
|
|||||||
detail::print(c.args(), c.kwargs());
|
detail::print(c.args(), c.kwargs());
|
||||||
}
|
}
|
||||||
|
|
||||||
error_already_set::~error_already_set() {
|
inline void
|
||||||
if (m_type) {
|
error_already_set::m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr) {
|
||||||
gil_scoped_acquire gil;
|
gil_scoped_acquire gil;
|
||||||
error_scope scope;
|
error_scope scope;
|
||||||
m_type.release().dec_ref();
|
delete raw_ptr;
|
||||||
m_value.release().dec_ref();
|
}
|
||||||
m_trace.release().dec_ref();
|
|
||||||
}
|
inline const char *error_already_set::what() const noexcept {
|
||||||
|
gil_scoped_acquire gil;
|
||||||
|
error_scope scope;
|
||||||
|
return m_fetched_error->error_string().c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
inline function
|
inline function
|
||||||
get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
|
get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
|
||||||
handle self = get_object_handle(this_ptr, this_type);
|
handle self = get_object_handle(this_ptr, this_type);
|
||||||
@ -2665,7 +2658,7 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
|
|||||||
|
|
||||||
function override = getattr(self, name, function());
|
function override = getattr(self, name, function());
|
||||||
if (override.is_cpp_function()) {
|
if (override.is_cpp_function()) {
|
||||||
cache.insert(key);
|
cache.insert(std::move(key));
|
||||||
return function();
|
return function();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,15 @@
|
|||||||
#include "detail/common.h"
|
#include "detail/common.h"
|
||||||
#include "buffer_info.h"
|
#include "buffer_info.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <exception>
|
||||||
|
#include <frameobject.h>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_OPTIONAL)
|
#if defined(PYBIND11_HAS_OPTIONAL)
|
||||||
@ -85,7 +93,9 @@ public:
|
|||||||
or `object` subclass causes a call to ``__setitem__``.
|
or `object` subclass causes a call to ``__setitem__``.
|
||||||
\endrst */
|
\endrst */
|
||||||
item_accessor operator[](handle key) const;
|
item_accessor operator[](handle key) const;
|
||||||
/// See above (the only difference is that they key is provided as a string literal)
|
/// See above (the only difference is that the key's reference is stolen)
|
||||||
|
item_accessor operator[](object &&key) const;
|
||||||
|
/// See above (the only difference is that the key is provided as a string literal)
|
||||||
item_accessor operator[](const char *key) const;
|
item_accessor operator[](const char *key) const;
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
@ -95,7 +105,9 @@ public:
|
|||||||
or `object` subclass causes a call to ``setattr``.
|
or `object` subclass causes a call to ``setattr``.
|
||||||
\endrst */
|
\endrst */
|
||||||
obj_attr_accessor attr(handle key) const;
|
obj_attr_accessor attr(handle key) const;
|
||||||
/// See above (the only difference is that they key is provided as a string literal)
|
/// See above (the only difference is that the key's reference is stolen)
|
||||||
|
obj_attr_accessor attr(object &&key) const;
|
||||||
|
/// See above (the only difference is that the key is provided as a string literal)
|
||||||
str_attr_accessor attr(const char *key) const;
|
str_attr_accessor attr(const char *key) const;
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
@ -178,8 +190,17 @@ private:
|
|||||||
bool rich_compare(object_api const &other, int value) const;
|
bool rich_compare(object_api const &other, int value) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using is_pyobj_ptr_or_nullptr_t = detail::any_of<std::is_same<T, PyObject *>,
|
||||||
|
std::is_same<T, PyObject *const>,
|
||||||
|
std::is_same<T, std::nullptr_t>>;
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
#if !defined(PYBIND11_HANDLE_REF_DEBUG) && !defined(NDEBUG)
|
||||||
|
# define PYBIND11_HANDLE_REF_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Holds a reference to a Python object (no reference counting)
|
Holds a reference to a Python object (no reference counting)
|
||||||
|
|
||||||
@ -195,9 +216,23 @@ class handle : public detail::object_api<handle> {
|
|||||||
public:
|
public:
|
||||||
/// The default constructor creates a handle with a ``nullptr``-valued pointer
|
/// The default constructor creates a handle with a ``nullptr``-valued pointer
|
||||||
handle() = default;
|
handle() = default;
|
||||||
/// Creates a ``handle`` from the given raw Python object pointer
|
|
||||||
|
/// Enable implicit conversion from ``PyObject *`` and ``nullptr``.
|
||||||
|
/// Not using ``handle(PyObject *ptr)`` to avoid implicit conversion from ``0``.
|
||||||
|
template <typename T,
|
||||||
|
detail::enable_if_t<detail::is_pyobj_ptr_or_nullptr_t<T>::value, int> = 0>
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
handle(PyObject *ptr) : m_ptr(ptr) {} // Allow implicit conversion from PyObject*
|
handle(T ptr) : m_ptr(ptr) {}
|
||||||
|
|
||||||
|
/// Enable implicit conversion through ``T::operator PyObject *()``.
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
detail::enable_if_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,
|
||||||
|
detail::is_pyobj_ptr_or_nullptr_t<T>>,
|
||||||
|
std::is_convertible<T, PyObject *>>::value,
|
||||||
|
int> = 0>
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
handle(T &obj) : m_ptr(obj) {}
|
||||||
|
|
||||||
/// Return the underlying ``PyObject *`` pointer
|
/// Return the underlying ``PyObject *`` pointer
|
||||||
PyObject *ptr() const { return m_ptr; }
|
PyObject *ptr() const { return m_ptr; }
|
||||||
@ -209,6 +244,9 @@ public:
|
|||||||
this function automatically. Returns a reference to itself.
|
this function automatically. Returns a reference to itself.
|
||||||
\endrst */
|
\endrst */
|
||||||
const handle &inc_ref() const & {
|
const handle &inc_ref() const & {
|
||||||
|
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
||||||
|
inc_ref_counter(1);
|
||||||
|
#endif
|
||||||
Py_XINCREF(m_ptr);
|
Py_XINCREF(m_ptr);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -244,6 +282,18 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
PyObject *m_ptr = nullptr;
|
PyObject *m_ptr = nullptr;
|
||||||
|
|
||||||
|
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
||||||
|
private:
|
||||||
|
static std::size_t inc_ref_counter(std::size_t add) {
|
||||||
|
thread_local std::size_t counter = 0;
|
||||||
|
counter += add;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::size_t inc_ref_counter() { return inc_ref_counter(0); }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
@ -268,10 +318,7 @@ public:
|
|||||||
/// Copy constructor; always increases the reference count
|
/// Copy constructor; always increases the reference count
|
||||||
object(const object &o) : handle(o) { inc_ref(); }
|
object(const object &o) : handle(o) { inc_ref(); }
|
||||||
/// Move constructor; steals the object from ``other`` and preserves its reference count
|
/// Move constructor; steals the object from ``other`` and preserves its reference count
|
||||||
object(object &&other) noexcept {
|
object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }
|
||||||
m_ptr = other.m_ptr;
|
|
||||||
other.m_ptr = nullptr;
|
|
||||||
}
|
|
||||||
/// Destructor; automatically calls `handle::dec_ref()`
|
/// Destructor; automatically calls `handle::dec_ref()`
|
||||||
~object() { dec_ref(); }
|
~object() { dec_ref(); }
|
||||||
|
|
||||||
@ -363,7 +410,175 @@ T reinterpret_steal(handle h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
// Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class).
|
||||||
|
inline const char *obj_class_name(PyObject *obj) {
|
||||||
|
if (Py_TYPE(obj) == &PyType_Type) {
|
||||||
|
return reinterpret_cast<PyTypeObject *>(obj)->tp_name;
|
||||||
|
}
|
||||||
|
return Py_TYPE(obj)->tp_name;
|
||||||
|
}
|
||||||
|
|
||||||
std::string error_string();
|
std::string error_string();
|
||||||
|
|
||||||
|
struct error_fetch_and_normalize {
|
||||||
|
// Immediate normalization is long-established behavior (starting with
|
||||||
|
// https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011
|
||||||
|
// from Sep 2016) and safest. Normalization could be deferred, but this could mask
|
||||||
|
// errors elsewhere, the performance gain is very minor in typical situations
|
||||||
|
// (usually the dominant bottleneck is EH unwinding), and the implementation here
|
||||||
|
// would be more complex.
|
||||||
|
explicit error_fetch_and_normalize(const char *called) {
|
||||||
|
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
||||||
|
if (!m_type) {
|
||||||
|
pybind11_fail("Internal error: " + std::string(called)
|
||||||
|
+ " called while "
|
||||||
|
"Python error indicator not set.");
|
||||||
|
}
|
||||||
|
const char *exc_type_name_orig = detail::obj_class_name(m_type.ptr());
|
||||||
|
if (exc_type_name_orig == nullptr) {
|
||||||
|
pybind11_fail("Internal error: " + std::string(called)
|
||||||
|
+ " failed to obtain the name "
|
||||||
|
"of the original active exception type.");
|
||||||
|
}
|
||||||
|
m_lazy_error_string = exc_type_name_orig;
|
||||||
|
// PyErr_NormalizeException() may change the exception type if there are cascading
|
||||||
|
// failures. This can potentially be extremely confusing.
|
||||||
|
PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
||||||
|
if (m_type.ptr() == nullptr) {
|
||||||
|
pybind11_fail("Internal error: " + std::string(called)
|
||||||
|
+ " failed to normalize the "
|
||||||
|
"active exception.");
|
||||||
|
}
|
||||||
|
const char *exc_type_name_norm = detail::obj_class_name(m_type.ptr());
|
||||||
|
if (exc_type_name_orig == nullptr) {
|
||||||
|
pybind11_fail("Internal error: " + std::string(called)
|
||||||
|
+ " failed to obtain the name "
|
||||||
|
"of the normalized active exception type.");
|
||||||
|
}
|
||||||
|
if (exc_type_name_norm != m_lazy_error_string) {
|
||||||
|
std::string msg = std::string(called)
|
||||||
|
+ ": MISMATCH of original and normalized "
|
||||||
|
"active exception types: ";
|
||||||
|
msg += "ORIGINAL ";
|
||||||
|
msg += m_lazy_error_string;
|
||||||
|
msg += " REPLACED BY ";
|
||||||
|
msg += exc_type_name_norm;
|
||||||
|
msg += ": " + format_value_and_trace();
|
||||||
|
pybind11_fail(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_fetch_and_normalize(const error_fetch_and_normalize &) = delete;
|
||||||
|
error_fetch_and_normalize(error_fetch_and_normalize &&) = delete;
|
||||||
|
|
||||||
|
std::string format_value_and_trace() const {
|
||||||
|
std::string result;
|
||||||
|
std::string message_error_string;
|
||||||
|
if (m_value) {
|
||||||
|
auto value_str = reinterpret_steal<object>(PyObject_Str(m_value.ptr()));
|
||||||
|
if (!value_str) {
|
||||||
|
message_error_string = detail::error_string();
|
||||||
|
result = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
|
||||||
|
} else {
|
||||||
|
result = value_str.cast<std::string>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = "<MESSAGE UNAVAILABLE>";
|
||||||
|
}
|
||||||
|
if (result.empty()) {
|
||||||
|
result = "<EMPTY MESSAGE>";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool have_trace = false;
|
||||||
|
if (m_trace) {
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
auto *tb = reinterpret_cast<PyTracebackObject *>(m_trace.ptr());
|
||||||
|
|
||||||
|
// Get the deepest trace possible.
|
||||||
|
while (tb->tb_next) {
|
||||||
|
tb = tb->tb_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyFrameObject *frame = tb->tb_frame;
|
||||||
|
Py_XINCREF(frame);
|
||||||
|
result += "\n\nAt:\n";
|
||||||
|
while (frame) {
|
||||||
|
# if PY_VERSION_HEX >= 0x030900B1
|
||||||
|
PyCodeObject *f_code = PyFrame_GetCode(frame);
|
||||||
|
# else
|
||||||
|
PyCodeObject *f_code = frame->f_code;
|
||||||
|
Py_INCREF(f_code);
|
||||||
|
# endif
|
||||||
|
int lineno = PyFrame_GetLineNumber(frame);
|
||||||
|
result += " ";
|
||||||
|
result += handle(f_code->co_filename).cast<std::string>();
|
||||||
|
result += '(';
|
||||||
|
result += std::to_string(lineno);
|
||||||
|
result += "): ";
|
||||||
|
result += handle(f_code->co_name).cast<std::string>();
|
||||||
|
result += '\n';
|
||||||
|
Py_DECREF(f_code);
|
||||||
|
# if PY_VERSION_HEX >= 0x030900B1
|
||||||
|
auto *b_frame = PyFrame_GetBack(frame);
|
||||||
|
# else
|
||||||
|
auto *b_frame = frame->f_back;
|
||||||
|
Py_XINCREF(b_frame);
|
||||||
|
# endif
|
||||||
|
Py_DECREF(frame);
|
||||||
|
frame = b_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
have_trace = true;
|
||||||
|
#endif //! defined(PYPY_VERSION)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message_error_string.empty()) {
|
||||||
|
if (!have_trace) {
|
||||||
|
result += '\n';
|
||||||
|
}
|
||||||
|
result += "\nMESSAGE UNAVAILABLE DUE TO EXCEPTION: " + message_error_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const &error_string() const {
|
||||||
|
if (!m_lazy_error_string_completed) {
|
||||||
|
m_lazy_error_string += ": " + format_value_and_trace();
|
||||||
|
m_lazy_error_string_completed = true;
|
||||||
|
}
|
||||||
|
return m_lazy_error_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore() {
|
||||||
|
if (m_restore_called) {
|
||||||
|
pybind11_fail("Internal error: pybind11::detail::error_fetch_and_normalize::restore() "
|
||||||
|
"called a second time. ORIGINAL ERROR: "
|
||||||
|
+ error_string());
|
||||||
|
}
|
||||||
|
PyErr_Restore(m_type.inc_ref().ptr(), m_value.inc_ref().ptr(), m_trace.inc_ref().ptr());
|
||||||
|
m_restore_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(handle exc) const {
|
||||||
|
return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not protecting these for simplicity.
|
||||||
|
object m_type, m_value, m_trace;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Only protecting invariants.
|
||||||
|
mutable std::string m_lazy_error_string;
|
||||||
|
mutable bool m_lazy_error_string_completed = false;
|
||||||
|
mutable bool m_restore_called = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string error_string() {
|
||||||
|
return error_fetch_and_normalize("pybind11::detail::error_string").error_string();
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
@ -376,38 +591,37 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
|
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
|
||||||
/// else falls back to the function dispatcher (which then raises the captured error back to
|
/// else falls back to the function dispatcher (which then raises the captured error back to
|
||||||
/// python).
|
/// python).
|
||||||
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
|
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::exception {
|
||||||
public:
|
public:
|
||||||
/// Constructs a new exception from the current Python error indicator, if any. The current
|
/// Fetches the current Python exception (using PyErr_Fetch()), which will clear the
|
||||||
/// Python error indicator will be cleared.
|
/// current Python error indicator.
|
||||||
error_already_set() : std::runtime_error(detail::error_string()) {
|
error_already_set()
|
||||||
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
: m_fetched_error{new detail::error_fetch_and_normalize("pybind11::error_already_set"),
|
||||||
}
|
m_fetched_error_deleter} {}
|
||||||
|
|
||||||
error_already_set(const error_already_set &) = default;
|
/// The what() result is built lazily on demand.
|
||||||
error_already_set(error_already_set &&) = default;
|
/// WARNING: This member function needs to acquire the Python GIL. This can lead to
|
||||||
|
/// crashes (undefined behavior) if the Python interpreter is finalizing.
|
||||||
|
const char *what() const noexcept override;
|
||||||
|
|
||||||
inline ~error_already_set() override;
|
/// Restores the currently-held Python error (which will clear the Python error indicator first
|
||||||
|
/// if already set).
|
||||||
/// Give the currently-held error back to Python, if any. If there is currently a Python error
|
/// NOTE: This member function will always restore the normalized exception, which may or may
|
||||||
/// already set it is cleared first. After this call, the current object no longer stores the
|
/// not be the original Python exception.
|
||||||
/// error variables (but the `.what()` string is still available).
|
/// WARNING: The GIL must be held when this member function is called!
|
||||||
void restore() {
|
void restore() { m_fetched_error->restore(); }
|
||||||
PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If it is impossible to raise the currently-held error, such as in a destructor, we can
|
/// If it is impossible to raise the currently-held error, such as in a destructor, we can
|
||||||
/// write it out using Python's unraisable hook (`sys.unraisablehook`). The error context
|
/// write it out using Python's unraisable hook (`sys.unraisablehook`). The error context
|
||||||
/// should be some object whose `repr()` helps identify the location of the error. Python
|
/// should be some object whose `repr()` helps identify the location of the error. Python
|
||||||
/// already knows the type and value of the error, so there is no need to repeat that. After
|
/// already knows the type and value of the error, so there is no need to repeat that.
|
||||||
/// this call, the current object no longer stores the error variables, and neither does
|
|
||||||
/// Python.
|
|
||||||
void discard_as_unraisable(object err_context) {
|
void discard_as_unraisable(object err_context) {
|
||||||
restore();
|
restore();
|
||||||
PyErr_WriteUnraisable(err_context.ptr());
|
PyErr_WriteUnraisable(err_context.ptr());
|
||||||
}
|
}
|
||||||
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
|
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
|
||||||
/// the location of the error. For example, `__func__` could be helpful.
|
/// the location of the error. For example, `__func__` could be helpful.
|
||||||
|
/// WARNING: The GIL must be held when this member function is called!
|
||||||
void discard_as_unraisable(const char *err_context) {
|
void discard_as_unraisable(const char *err_context) {
|
||||||
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
|
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
|
||||||
}
|
}
|
||||||
@ -419,23 +633,23 @@ public:
|
|||||||
/// Check if the currently trapped error type matches the given Python exception class (or a
|
/// Check if the currently trapped error type matches the given Python exception class (or a
|
||||||
/// subclass thereof). May also be passed a tuple to search for any exception class matches in
|
/// subclass thereof). May also be passed a tuple to search for any exception class matches in
|
||||||
/// the given tuple.
|
/// the given tuple.
|
||||||
bool matches(handle exc) const {
|
bool matches(handle exc) const { return m_fetched_error->matches(exc); }
|
||||||
return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const object &type() const { return m_type; }
|
const object &type() const { return m_fetched_error->m_type; }
|
||||||
const object &value() const { return m_value; }
|
const object &value() const { return m_fetched_error->m_value; }
|
||||||
const object &trace() const { return m_trace; }
|
const object &trace() const { return m_fetched_error->m_trace; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
object m_type, m_value, m_trace;
|
std::shared_ptr<detail::error_fetch_and_normalize> m_fetched_error;
|
||||||
|
|
||||||
|
/// WARNING: This custom deleter needs to acquire the Python GIL. This can lead to
|
||||||
|
/// crashes (undefined behavior) if the Python interpreter is finalizing.
|
||||||
|
static void m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr);
|
||||||
};
|
};
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03030000
|
|
||||||
|
|
||||||
/// Replaces the current Python error indicator with the chosen error, performing a
|
/// Replaces the current Python error indicator with the chosen error, performing a
|
||||||
/// 'raise from' to indicate that the chosen error was caused by the original error.
|
/// 'raise from' to indicate that the chosen error was caused by the original error.
|
||||||
inline void raise_from(PyObject *type, const char *message) {
|
inline void raise_from(PyObject *type, const char *message) {
|
||||||
@ -466,15 +680,12 @@ inline void raise_from(PyObject *type, const char *message) {
|
|||||||
|
|
||||||
/// Sets the current Python error indicator with the chosen error, performing a 'raise from'
|
/// Sets the current Python error indicator with the chosen error, performing a 'raise from'
|
||||||
/// from the error contained in error_already_set to indicate that the chosen error was
|
/// from the error contained in error_already_set to indicate that the chosen error was
|
||||||
/// caused by the original error. After this function is called error_already_set will
|
/// caused by the original error.
|
||||||
/// no longer contain an error.
|
|
||||||
inline void raise_from(error_already_set &err, PyObject *type, const char *message) {
|
inline void raise_from(error_already_set &err, PyObject *type, const char *message) {
|
||||||
err.restore();
|
err.restore();
|
||||||
raise_from(type, message);
|
raise_from(type, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \defgroup python_builtins const_name
|
/** \defgroup python_builtins const_name
|
||||||
Unless stated otherwise, the following C++ functions behave the same
|
Unless stated otherwise, the following C++ functions behave the same
|
||||||
as their Python counterparts.
|
as their Python counterparts.
|
||||||
@ -591,12 +802,9 @@ inline ssize_t hash(handle obj) {
|
|||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
inline handle get_function(handle value) {
|
inline handle get_function(handle value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
if (PyInstanceMethod_Check(value.ptr())) {
|
if (PyInstanceMethod_Check(value.ptr())) {
|
||||||
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
||||||
} else
|
} else if (PyMethod_Check(value.ptr())) {
|
||||||
#endif
|
|
||||||
if (PyMethod_Check(value.ptr())) {
|
|
||||||
value = PyMethod_GET_FUNCTION(value.ptr());
|
value = PyMethod_GET_FUNCTION(value.ptr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -608,34 +816,26 @@ inline handle get_function(handle value) {
|
|||||||
|
|
||||||
// copied from cpython _PyDict_GetItemStringWithError
|
// copied from cpython _PyDict_GetItemStringWithError
|
||||||
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyObject *kv = nullptr, *rv = nullptr;
|
PyObject *kv = nullptr, *rv = nullptr;
|
||||||
kv = PyUnicode_FromString(key);
|
kv = PyUnicode_FromString(key);
|
||||||
if (kv == NULL) {
|
if (kv == nullptr) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = PyDict_GetItemWithError(v, kv);
|
rv = PyDict_GetItemWithError(v, kv);
|
||||||
Py_DECREF(kv);
|
Py_DECREF(kv);
|
||||||
if (rv == NULL && PyErr_Occurred()) {
|
if (rv == nullptr && PyErr_Occurred()) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
#else
|
|
||||||
return PyDict_GetItemString(v, key);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyObject *rv = PyDict_GetItemWithError(v, key);
|
PyObject *rv = PyDict_GetItemWithError(v, key);
|
||||||
if (rv == NULL && PyErr_Occurred()) {
|
if (rv == nullptr && PyErr_Occurred()) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
#else
|
|
||||||
return PyDict_GetItem(v, key);
|
|
||||||
#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
|
||||||
@ -675,7 +875,7 @@ public:
|
|||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void operator=(T &&value) & {
|
void operator=(T &&value) & {
|
||||||
get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value)));
|
get_cache() = ensure_object(object_or_cast(std::forward<T>(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = Policy>
|
template <typename T = Policy>
|
||||||
@ -703,6 +903,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static object ensure_object(object &&o) { return std::move(o); }
|
||||||
|
static object ensure_object(handle h) { return reinterpret_borrow<object>(h); }
|
||||||
|
|
||||||
object &get_cache() const {
|
object &get_cache() const {
|
||||||
if (!cache) {
|
if (!cache) {
|
||||||
cache = Policy::get(obj, key);
|
cache = Policy::get(obj, key);
|
||||||
@ -1053,12 +1256,12 @@ public:
|
|||||||
Name(const object &o) \
|
Name(const object &o) \
|
||||||
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
|
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
|
||||||
if (!m_ptr) \
|
if (!m_ptr) \
|
||||||
throw error_already_set(); \
|
throw ::pybind11::error_already_set(); \
|
||||||
} \
|
} \
|
||||||
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
|
||||||
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
|
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
|
||||||
if (!m_ptr) \
|
if (!m_ptr) \
|
||||||
throw error_already_set(); \
|
throw ::pybind11::error_already_set(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
|
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
|
||||||
@ -1258,8 +1461,8 @@ public:
|
|||||||
}
|
}
|
||||||
char *buffer = nullptr;
|
char *buffer = nullptr;
|
||||||
ssize_t length = 0;
|
ssize_t length = 0;
|
||||||
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) {
|
if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
|
||||||
pybind11_fail("Unable to extract string contents! (invalid type)");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return std::string(buffer, (size_t) length);
|
return std::string(buffer, (size_t) length);
|
||||||
}
|
}
|
||||||
@ -1273,13 +1476,6 @@ private:
|
|||||||
/// Return string representation -- always returns a new reference, even if already a str
|
/// Return string representation -- always returns a new reference, even if already a str
|
||||||
static PyObject *raw_str(PyObject *op) {
|
static PyObject *raw_str(PyObject *op) {
|
||||||
PyObject *str_value = PyObject_Str(op);
|
PyObject *str_value = PyObject_Str(op);
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
if (!str_value)
|
|
||||||
throw error_already_set();
|
|
||||||
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
|
||||||
Py_XDECREF(str_value);
|
|
||||||
str_value = unicode;
|
|
||||||
#endif
|
|
||||||
return str_value;
|
return str_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1321,14 +1517,7 @@ public:
|
|||||||
explicit bytes(const pybind11::str &s);
|
explicit bytes(const pybind11::str &s);
|
||||||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
operator std::string() const {
|
operator std::string() const { return string_op<std::string>(); }
|
||||||
char *buffer = nullptr;
|
|
||||||
ssize_t length = 0;
|
|
||||||
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) {
|
|
||||||
pybind11_fail("Unable to extract bytes contents!");
|
|
||||||
}
|
|
||||||
return std::string(buffer, (size_t) length);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PYBIND11_HAS_STRING_VIEW
|
#ifdef PYBIND11_HAS_STRING_VIEW
|
||||||
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
|
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
|
||||||
@ -1340,15 +1529,18 @@ public:
|
|||||||
// valid so long as the `bytes` instance remains alive and so generally should not outlive the
|
// valid so long as the `bytes` instance remains alive and so generally should not outlive the
|
||||||
// lifetime of the `bytes` instance.
|
// lifetime of the `bytes` instance.
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
operator std::string_view() const {
|
operator std::string_view() const { return string_op<std::string_view>(); }
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
T string_op() const {
|
||||||
char *buffer = nullptr;
|
char *buffer = nullptr;
|
||||||
ssize_t length = 0;
|
ssize_t length = 0;
|
||||||
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) {
|
if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) {
|
||||||
pybind11_fail("Unable to extract bytes contents!");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
return {buffer, static_cast<size_t>(length)};
|
return {buffer, static_cast<size_t>(length)};
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
||||||
// are included in the doxygen group; close here and reopen after as a workaround
|
// are included in the doxygen group; close here and reopen after as a workaround
|
||||||
@ -1359,13 +1551,13 @@ inline bytes::bytes(const pybind11::str &s) {
|
|||||||
if (PyUnicode_Check(s.ptr())) {
|
if (PyUnicode_Check(s.ptr())) {
|
||||||
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
|
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
|
||||||
if (!temp) {
|
if (!temp) {
|
||||||
pybind11_fail("Unable to extract string contents! (encoding issue)");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char *buffer = nullptr;
|
char *buffer = nullptr;
|
||||||
ssize_t length = 0;
|
ssize_t length = 0;
|
||||||
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) {
|
if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
|
||||||
pybind11_fail("Unable to extract string contents! (invalid type)");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
|
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
@ -1377,8 +1569,8 @@ inline bytes::bytes(const pybind11::str &s) {
|
|||||||
inline str::str(const bytes &b) {
|
inline str::str(const bytes &b) {
|
||||||
char *buffer = nullptr;
|
char *buffer = nullptr;
|
||||||
ssize_t length = 0;
|
ssize_t length = 0;
|
||||||
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) {
|
if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) {
|
||||||
pybind11_fail("Unable to extract bytes contents!");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
|
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
@ -1459,11 +1651,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
||||||
template <typename Unsigned>
|
template <typename Unsigned>
|
||||||
Unsigned as_unsigned(PyObject *o) {
|
Unsigned as_unsigned(PyObject *o) {
|
||||||
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))
|
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))) {
|
||||||
#if PY_VERSION_HEX < 0x03000000
|
|
||||||
|| PyInt_Check(o)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
unsigned long v = PyLong_AsUnsignedLong(o);
|
unsigned long v = PyLong_AsUnsignedLong(o);
|
||||||
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
|
||||||
}
|
}
|
||||||
@ -1535,6 +1723,9 @@ public:
|
|||||||
explicit weakref(handle obj, handle callback = {})
|
explicit weakref(handle obj, handle callback = {})
|
||||||
: object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
|
: object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
|
||||||
if (!m_ptr) {
|
if (!m_ptr) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
pybind11_fail("Could not allocate weak reference!");
|
pybind11_fail("Could not allocate weak reference!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1546,8 +1737,8 @@ private:
|
|||||||
class slice : public object {
|
class slice : public object {
|
||||||
public:
|
public:
|
||||||
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
|
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
|
||||||
slice(handle start, handle stop, handle step) {
|
slice(handle start, handle stop, handle step)
|
||||||
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
|
: object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) {
|
||||||
if (!m_ptr) {
|
if (!m_ptr) {
|
||||||
pybind11_fail("Could not allocate slice object!");
|
pybind11_fail("Could not allocate slice object!");
|
||||||
}
|
}
|
||||||
@ -1597,7 +1788,7 @@ public:
|
|||||||
void (*destructor)(PyObject *) = nullptr)
|
void (*destructor)(PyObject *) = nullptr)
|
||||||
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
|
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
|
||||||
if (!m_ptr) {
|
if (!m_ptr) {
|
||||||
pybind11_fail("Could not allocate capsule object!");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1605,34 +1796,46 @@ public:
|
|||||||
capsule(const void *value, void (*destruct)(PyObject *))
|
capsule(const void *value, void (*destruct)(PyObject *))
|
||||||
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
|
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
|
||||||
if (!m_ptr) {
|
if (!m_ptr) {
|
||||||
pybind11_fail("Could not allocate capsule object!");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
capsule(const void *value, void (*destructor)(void *)) {
|
capsule(const void *value, void (*destructor)(void *)) {
|
||||||
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
|
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
|
||||||
|
// guard if destructor called while err indicator is set
|
||||||
|
error_scope error_guard;
|
||||||
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
||||||
void *ptr = PyCapsule_GetPointer(o, nullptr);
|
if (destructor == nullptr) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
pybind11_fail("Unable to get capsule context");
|
||||||
|
}
|
||||||
|
const char *name = get_name_in_error_scope(o);
|
||||||
|
void *ptr = PyCapsule_GetPointer(o, name);
|
||||||
|
if (ptr == nullptr) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
destructor(ptr);
|
destructor(ptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!m_ptr) {
|
if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
|
||||||
pybind11_fail("Could not allocate capsule object!");
|
throw error_already_set();
|
||||||
}
|
|
||||||
|
|
||||||
if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
|
|
||||||
pybind11_fail("Could not set capsule context!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit capsule(void (*destructor)()) {
|
explicit capsule(void (*destructor)()) {
|
||||||
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
|
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
|
||||||
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr));
|
const char *name = get_name_in_error_scope(o);
|
||||||
|
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, name));
|
||||||
|
if (destructor == nullptr) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
destructor();
|
destructor();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!m_ptr) {
|
if (!m_ptr) {
|
||||||
pybind11_fail("Could not allocate capsule object!");
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1647,8 +1850,7 @@ public:
|
|||||||
const auto *name = this->name();
|
const auto *name = this->name();
|
||||||
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
|
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
PyErr_Clear();
|
throw error_already_set();
|
||||||
pybind11_fail("Unable to extract capsule contents!");
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1656,12 +1858,37 @@ public:
|
|||||||
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
|
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
|
||||||
void set_pointer(const void *value) {
|
void set_pointer(const void *value) {
|
||||||
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {
|
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {
|
||||||
PyErr_Clear();
|
throw error_already_set();
|
||||||
pybind11_fail("Could not set capsule pointer");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *name() const { return PyCapsule_GetName(m_ptr); }
|
const char *name() const {
|
||||||
|
const char *name = PyCapsule_GetName(m_ptr);
|
||||||
|
if ((name == nullptr) && PyErr_Occurred()) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces a capsule's name *without* calling the destructor on the existing one.
|
||||||
|
void set_name(const char *new_name) {
|
||||||
|
if (PyCapsule_SetName(m_ptr, new_name) != 0) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char *get_name_in_error_scope(PyObject *o) {
|
||||||
|
error_scope error_guard;
|
||||||
|
|
||||||
|
const char *name = PyCapsule_GetName(o);
|
||||||
|
if ((name == nullptr) && PyErr_Occurred()) {
|
||||||
|
// write out and consume error raised by call to PyCapsule_GetName
|
||||||
|
PyErr_WriteUnraisable(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class tuple : public object {
|
class tuple : public object {
|
||||||
@ -1678,7 +1905,10 @@ public:
|
|||||||
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
||||||
bool empty() const { return size() == 0; }
|
bool empty() const { return size() == 0; }
|
||||||
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
||||||
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
||||||
|
detail::item_accessor operator[](T &&o) const {
|
||||||
|
return object::operator[](std::forward<T>(o));
|
||||||
|
}
|
||||||
detail::tuple_iterator begin() const { return {*this, 0}; }
|
detail::tuple_iterator begin() const { return {*this, 0}; }
|
||||||
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
|
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
|
||||||
};
|
};
|
||||||
@ -1738,7 +1968,10 @@ public:
|
|||||||
}
|
}
|
||||||
bool empty() const { return size() == 0; }
|
bool empty() const { return size() == 0; }
|
||||||
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
|
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
|
||||||
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
||||||
|
detail::item_accessor operator[](T &&o) const {
|
||||||
|
return object::operator[](std::forward<T>(o));
|
||||||
|
}
|
||||||
detail::sequence_iterator begin() const { return {*this, 0}; }
|
detail::sequence_iterator begin() const { return {*this, 0}; }
|
||||||
detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
|
detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
|
||||||
};
|
};
|
||||||
@ -1757,7 +1990,10 @@ public:
|
|||||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
||||||
bool empty() const { return size() == 0; }
|
bool empty() const { return size() == 0; }
|
||||||
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
||||||
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
||||||
|
detail::item_accessor operator[](T &&o) const {
|
||||||
|
return object::operator[](std::forward<T>(o));
|
||||||
|
}
|
||||||
detail::list_iterator begin() const { return {*this, 0}; }
|
detail::list_iterator begin() const { return {*this, 0}; }
|
||||||
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
|
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1780,25 +2016,35 @@ class kwargs : public dict {
|
|||||||
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
|
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
|
||||||
};
|
};
|
||||||
|
|
||||||
class set : public object {
|
class anyset : public object {
|
||||||
public:
|
public:
|
||||||
PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New)
|
PYBIND11_OBJECT(anyset, object, PyAnySet_Check)
|
||||||
set() : object(PySet_New(nullptr), stolen_t{}) {
|
size_t size() const { return static_cast<size_t>(PySet_Size(m_ptr)); }
|
||||||
|
bool empty() const { return size() == 0; }
|
||||||
|
template <typename T>
|
||||||
|
bool contains(T &&val) const {
|
||||||
|
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class set : public anyset {
|
||||||
|
public:
|
||||||
|
PYBIND11_OBJECT_CVT(set, anyset, PySet_Check, PySet_New)
|
||||||
|
set() : anyset(PySet_New(nullptr), stolen_t{}) {
|
||||||
if (!m_ptr) {
|
if (!m_ptr) {
|
||||||
pybind11_fail("Could not allocate set object!");
|
pybind11_fail("Could not allocate set object!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PySet_Size(m_ptr); }
|
|
||||||
bool empty() const { return size() == 0; }
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool add(T &&val) /* py-non-const */ {
|
bool add(T &&val) /* py-non-const */ {
|
||||||
return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
|
return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
|
||||||
}
|
}
|
||||||
void clear() /* py-non-const */ { PySet_Clear(m_ptr); }
|
void clear() /* py-non-const */ { PySet_Clear(m_ptr); }
|
||||||
template <typename T>
|
};
|
||||||
bool contains(T &&val) const {
|
|
||||||
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
|
class frozenset : public anyset {
|
||||||
}
|
public:
|
||||||
|
PYBIND11_OBJECT_CVT(frozenset, anyset, PyFrozenSet_Check, PyFrozenSet_New)
|
||||||
};
|
};
|
||||||
|
|
||||||
class function : public object {
|
class function : public object {
|
||||||
@ -1910,8 +2156,8 @@ public:
|
|||||||
return memoryview::from_buffer(reinterpret_cast<void *>(ptr),
|
return memoryview::from_buffer(reinterpret_cast<void *>(ptr),
|
||||||
sizeof(T),
|
sizeof(T),
|
||||||
format_descriptor<T>::value,
|
format_descriptor<T>::value,
|
||||||
shape,
|
std::move(shape),
|
||||||
strides,
|
std::move(strides),
|
||||||
readonly);
|
readonly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1919,10 +2165,10 @@ public:
|
|||||||
static memoryview from_buffer(const T *ptr,
|
static memoryview from_buffer(const T *ptr,
|
||||||
detail::any_container<ssize_t> shape,
|
detail::any_container<ssize_t> shape,
|
||||||
detail::any_container<ssize_t> strides) {
|
detail::any_container<ssize_t> strides) {
|
||||||
return memoryview::from_buffer(const_cast<T *>(ptr), shape, strides, true);
|
return memoryview::from_buffer(
|
||||||
|
const_cast<T *>(ptr), std::move(shape), std::move(strides), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Creates ``memoryview`` from static memory.
|
Creates ``memoryview`` from static memory.
|
||||||
|
|
||||||
@ -1930,8 +2176,6 @@ public:
|
|||||||
managed by Python. The caller is responsible for managing the lifetime
|
managed by Python. The caller is responsible for managing the lifetime
|
||||||
of ``mem``, which MUST outlive the memoryview constructed here.
|
of ``mem``, which MUST outlive the memoryview constructed here.
|
||||||
|
|
||||||
This method is not available in Python 2.
|
|
||||||
|
|
||||||
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
See also: Python C API documentation for `PyMemoryView_FromBuffer`_.
|
||||||
|
|
||||||
.. _PyMemoryView_FromMemory:
|
.. _PyMemoryView_FromMemory:
|
||||||
@ -1950,12 +2194,10 @@ public:
|
|||||||
return memoryview::from_memory(const_cast<void *>(mem), size, true);
|
return memoryview::from_memory(const_cast<void *>(mem), size, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef PYBIND11_HAS_STRING_VIEW
|
#ifdef PYBIND11_HAS_STRING_VIEW
|
||||||
static memoryview from_memory(std::string_view mem) {
|
static memoryview from_memory(std::string_view mem) {
|
||||||
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
|
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
|
||||||
}
|
}
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2010,11 +2252,7 @@ inline size_t len(handle h) {
|
|||||||
/// Get the length hint of a Python object.
|
/// Get the length hint of a Python object.
|
||||||
/// Returns 0 when this cannot be determined.
|
/// Returns 0 when this cannot be determined.
|
||||||
inline size_t len_hint(handle h) {
|
inline size_t len_hint(handle h) {
|
||||||
#if PY_VERSION_HEX >= 0x03040000
|
|
||||||
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
||||||
#else
|
|
||||||
ssize_t result = PyObject_Length(h.ptr());
|
|
||||||
#endif
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
// Sometimes a length can't be determined at all (eg generators)
|
// Sometimes a length can't be determined at all (eg generators)
|
||||||
// In which case simply return 0
|
// In which case simply return 0
|
||||||
@ -2029,13 +2267,6 @@ inline str repr(handle h) {
|
|||||||
if (!str_value) {
|
if (!str_value) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
|
||||||
Py_XDECREF(str_value);
|
|
||||||
str_value = unicode;
|
|
||||||
if (!str_value)
|
|
||||||
throw error_already_set();
|
|
||||||
#endif
|
|
||||||
return reinterpret_steal<str>(str_value);
|
return reinterpret_steal<str>(str_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2062,6 +2293,10 @@ item_accessor object_api<D>::operator[](handle key) const {
|
|||||||
return {derived(), reinterpret_borrow<object>(key)};
|
return {derived(), reinterpret_borrow<object>(key)};
|
||||||
}
|
}
|
||||||
template <typename D>
|
template <typename D>
|
||||||
|
item_accessor object_api<D>::operator[](object &&key) const {
|
||||||
|
return {derived(), std::move(key)};
|
||||||
|
}
|
||||||
|
template <typename D>
|
||||||
item_accessor object_api<D>::operator[](const char *key) const {
|
item_accessor object_api<D>::operator[](const char *key) const {
|
||||||
return {derived(), pybind11::str(key)};
|
return {derived(), pybind11::str(key)};
|
||||||
}
|
}
|
||||||
@ -2070,6 +2305,10 @@ obj_attr_accessor object_api<D>::attr(handle key) const {
|
|||||||
return {derived(), reinterpret_borrow<object>(key)};
|
return {derived(), reinterpret_borrow<object>(key)};
|
||||||
}
|
}
|
||||||
template <typename D>
|
template <typename D>
|
||||||
|
obj_attr_accessor object_api<D>::attr(object &&key) const {
|
||||||
|
return {derived(), std::move(key)};
|
||||||
|
}
|
||||||
|
template <typename D>
|
||||||
str_attr_accessor object_api<D>::attr(const char *key) const {
|
str_attr_accessor object_api<D>::attr(const char *key) const {
|
||||||
return {derived(), key};
|
return {derived(), key};
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
#include "detail/common.h"
|
#include "detail/common.h"
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <iostream>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <ostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -55,10 +55,10 @@ struct set_caster {
|
|||||||
using key_conv = make_caster<Key>;
|
using key_conv = make_caster<Key>;
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!isinstance<pybind11::set>(src)) {
|
if (!isinstance<anyset>(src)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto s = reinterpret_borrow<pybind11::set>(src);
|
auto s = reinterpret_borrow<anyset>(src);
|
||||||
value.clear();
|
value.clear();
|
||||||
for (auto entry : s) {
|
for (auto entry : s) {
|
||||||
key_conv conv;
|
key_conv conv;
|
||||||
@ -79,7 +79,7 @@ struct set_caster {
|
|||||||
for (auto &&value : src) {
|
for (auto &&value : src) {
|
||||||
auto value_ = reinterpret_steal<object>(
|
auto value_ = reinterpret_steal<object>(
|
||||||
key_conv::cast(forward_like<T>(value), policy, parent));
|
key_conv::cast(forward_like<T>(value), policy, parent));
|
||||||
if (!value_ || !s.add(value_)) {
|
if (!value_ || !s.add(std::move(value_))) {
|
||||||
return handle();
|
return handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ struct map_caster {
|
|||||||
if (!key || !value) {
|
if (!key || !value) {
|
||||||
return handle();
|
return handle();
|
||||||
}
|
}
|
||||||
d[key] = value;
|
d[std::move(key)] = std::move(value);
|
||||||
}
|
}
|
||||||
return d.release();
|
return d.release();
|
||||||
}
|
}
|
||||||
@ -372,7 +372,7 @@ struct variant_caster<V<Ts...>> {
|
|||||||
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
||||||
auto caster = make_caster<U>();
|
auto caster = make_caster<U>();
|
||||||
if (caster.load(src, convert)) {
|
if (caster.load(src, convert)) {
|
||||||
value = cast_op<U>(caster);
|
value = cast_op<U>(std::move(caster));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return load_alternative(src, convert, type_list<Us...>{});
|
return load_alternative(src, convert, type_list<Us...>{});
|
||||||
@ -406,6 +406,9 @@ struct variant_caster<V<Ts...>> {
|
|||||||
#if defined(PYBIND11_HAS_VARIANT)
|
#if defined(PYBIND11_HAS_VARIANT)
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
|
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct type_caster<std::monostate> : public void_caster<std::monostate> {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
@ -13,22 +13,28 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef __has_include
|
#ifdef __has_include
|
||||||
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
|
# if defined(PYBIND11_CPP17)
|
||||||
PY_VERSION_HEX >= 0x03060000
|
# if __has_include(<filesystem>) && \
|
||||||
# include <filesystem>
|
PY_VERSION_HEX >= 0x03060000
|
||||||
# define PYBIND11_HAS_FILESYSTEM 1
|
# include <filesystem>
|
||||||
|
# define PYBIND11_HAS_FILESYSTEM 1
|
||||||
|
# elif __has_include(<experimental/filesystem>)
|
||||||
|
# include <experimental/filesystem>
|
||||||
|
# define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \
|
||||||
|
&& !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
||||||
# error \
|
# error \
|
||||||
"#include <filesystem> is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
"Neither #include <filesystem> nor #include <experimental/filesystem is available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_FILESYSTEM)
|
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct path_caster {
|
struct path_caster {
|
||||||
|
|
||||||
@ -95,9 +101,16 @@ public:
|
|||||||
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
|
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
|
|
||||||
|
#if defined(PYBIND11_HAS_FILESYSTEM)
|
||||||
template <>
|
template <>
|
||||||
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
|
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
|
||||||
#endif // PYBIND11_HAS_FILESYSTEM
|
#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
|
template <>
|
||||||
|
struct type_caster<std::experimental::filesystem::path>
|
||||||
|
: public path_caster<std::experimental::filesystem::path> {};
|
||||||
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
@ -232,7 +232,7 @@ void vector_modifiers(
|
|||||||
/// Slicing protocol
|
/// Slicing protocol
|
||||||
cl.def(
|
cl.def(
|
||||||
"__getitem__",
|
"__getitem__",
|
||||||
[](const Vector &v, slice slice) -> Vector * {
|
[](const Vector &v, const slice &slice) -> Vector * {
|
||||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||||
|
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
||||||
@ -253,7 +253,7 @@ void vector_modifiers(
|
|||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"__setitem__",
|
"__setitem__",
|
||||||
[](Vector &v, slice slice, const Vector &value) {
|
[](Vector &v, const slice &slice, const Vector &value) {
|
||||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
@ -281,7 +281,7 @@ void vector_modifiers(
|
|||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"__delitem__",
|
"__delitem__",
|
||||||
[](Vector &v, slice slice) {
|
[](Vector &v, const slice &slice) {
|
||||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||||
|
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
||||||
|
13
noxfile.py
13
noxfile.py
@ -1,9 +1,14 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
import nox
|
import nox
|
||||||
|
|
||||||
nox.needs_version = ">=2022.1.7"
|
nox.needs_version = ">=2022.1.7"
|
||||||
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
||||||
|
|
||||||
PYTHON_VERSIONS = ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
|
PYTHON_VERISONS = ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3.7", "pypy3.8"]
|
||||||
|
|
||||||
|
if os.environ.get("CI", None):
|
||||||
|
nox.options.error_on_missing_interpreters = True
|
||||||
|
|
||||||
|
|
||||||
@nox.session(reuse_venv=True)
|
@nox.session(reuse_venv=True)
|
||||||
@ -15,7 +20,7 @@ def lint(session: nox.Session) -> None:
|
|||||||
session.run("pre-commit", "run", "-a")
|
session.run("pre-commit", "run", "-a")
|
||||||
|
|
||||||
|
|
||||||
@nox.session(python=PYTHON_VERSIONS)
|
@nox.session(python=PYTHON_VERISONS)
|
||||||
def tests(session: nox.Session) -> None:
|
def tests(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Run the tests (requires a compiler).
|
Run the tests (requires a compiler).
|
||||||
@ -56,10 +61,10 @@ def docs(session: nox.Session) -> None:
|
|||||||
session.chdir("docs")
|
session.chdir("docs")
|
||||||
|
|
||||||
if "pdf" in session.posargs:
|
if "pdf" in session.posargs:
|
||||||
session.run("sphinx-build", "-b", "latexpdf", ".", "_build")
|
session.run("sphinx-build", "-M", "latexpdf", ".", "_build")
|
||||||
return
|
return
|
||||||
|
|
||||||
session.run("sphinx-build", "-b", "html", ".", "_build")
|
session.run("sphinx-build", "-M", "html", ".", "_build")
|
||||||
|
|
||||||
if "serve" in session.posargs:
|
if "serve" in session.posargs:
|
||||||
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
|
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info < (3, 6):
|
||||||
|
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
|
||||||
|
raise ImportError(msg)
|
||||||
|
|
||||||
|
|
||||||
from ._version import __version__, version_info
|
from ._version import __version__, version_info
|
||||||
from .commands import get_cmake_dir, get_include
|
from .commands import get_cmake_dir, get_include
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# pylint: disable=missing-function-docstring
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
@ -8,8 +7,7 @@ import sysconfig
|
|||||||
from .commands import get_cmake_dir, get_include
|
from .commands import get_cmake_dir, get_include
|
||||||
|
|
||||||
|
|
||||||
def print_includes():
|
def print_includes() -> None:
|
||||||
# type: () -> None
|
|
||||||
dirs = [
|
dirs = [
|
||||||
sysconfig.get_path("include"),
|
sysconfig.get_path("include"),
|
||||||
sysconfig.get_path("platinclude"),
|
sysconfig.get_path("platinclude"),
|
||||||
@ -25,8 +23,7 @@ def print_includes():
|
|||||||
print(" ".join("-I" + d for d in unique_dirs))
|
print(" ".join("-I" + d for d in unique_dirs))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
# type: () -> None
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
def _to_int(s):
|
def _to_int(s: str) -> Union[int, str]:
|
||||||
try:
|
try:
|
||||||
return int(s)
|
return int(s)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
__version__ = "2.9.2"
|
__version__ = "2.10.0"
|
||||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
from typing import Tuple, Union
|
|
||||||
|
|
||||||
def _to_int(s: str) -> Union[int, str]: ...
|
|
||||||
|
|
||||||
__version__: str
|
|
||||||
version_info: Tuple[Union[int, str], ...]
|
|
@ -1,21 +1,25 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
def get_include(user=False):
|
def get_include(user: bool = False) -> str: # pylint: disable=unused-argument
|
||||||
# type: (bool) -> str
|
"""
|
||||||
|
Return the path to the pybind11 include directory. The historical "user"
|
||||||
|
argument is unused, and may be removed.
|
||||||
|
"""
|
||||||
installed_path = os.path.join(DIR, "include")
|
installed_path = os.path.join(DIR, "include")
|
||||||
source_path = os.path.join(os.path.dirname(DIR), "include")
|
source_path = os.path.join(os.path.dirname(DIR), "include")
|
||||||
return installed_path if os.path.exists(installed_path) else source_path
|
return installed_path if os.path.exists(installed_path) else source_path
|
||||||
|
|
||||||
|
|
||||||
def get_cmake_dir():
|
def get_cmake_dir() -> str:
|
||||||
# type: () -> str
|
"""
|
||||||
|
Return the path to the pybind11 CMake module directory.
|
||||||
|
"""
|
||||||
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
||||||
if os.path.exists(cmake_installed_path):
|
if os.path.exists(cmake_installed_path):
|
||||||
return cmake_installed_path
|
return cmake_installed_path
|
||||||
else:
|
|
||||||
msg = "pybind11 not installed, installation required to access the CMake files"
|
msg = "pybind11 not installed, installation required to access the CMake files"
|
||||||
raise ImportError(msg)
|
raise ImportError(msg)
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module provides helpers for C++11+ projects using pybind11.
|
This module provides helpers for C++11+ projects using pybind11.
|
||||||
|
|
||||||
@ -49,6 +47,20 @@ import sysconfig
|
|||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import warnings
|
import warnings
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
Iterable,
|
||||||
|
Iterator,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
TypeVar,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from setuptools import Extension as _Extension
|
from setuptools import Extension as _Extension
|
||||||
@ -61,7 +73,6 @@ import distutils.ccompiler
|
|||||||
import distutils.errors
|
import distutils.errors
|
||||||
|
|
||||||
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
||||||
PY2 = sys.version_info[0] < 3
|
|
||||||
MACOS = sys.platform.startswith("darwin")
|
MACOS = sys.platform.startswith("darwin")
|
||||||
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
||||||
|
|
||||||
@ -73,7 +84,7 @@ STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
|||||||
# directory into your path if it sits beside your setup.py.
|
# directory into your path if it sits beside your setup.py.
|
||||||
|
|
||||||
|
|
||||||
class Pybind11Extension(_Extension):
|
class Pybind11Extension(_Extension): # type: ignore[misc]
|
||||||
"""
|
"""
|
||||||
Build a C++11+ Extension module with pybind11. This automatically adds the
|
Build a C++11+ Extension module with pybind11. This automatically adds the
|
||||||
recommended flags when you init the extension and assumes C++ sources - you
|
recommended flags when you init the extension and assumes C++ sources - you
|
||||||
@ -95,21 +106,18 @@ class Pybind11Extension(_Extension):
|
|||||||
|
|
||||||
If you want to add pybind11 headers manually, for example for an exact
|
If you want to add pybind11 headers manually, for example for an exact
|
||||||
git checkout, then set ``include_pybind11=False``.
|
git checkout, then set ``include_pybind11=False``.
|
||||||
|
|
||||||
Warning: do not use property-based access to the instance on Python 2 -
|
|
||||||
this is an ugly old-style class due to Distutils.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 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):
|
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):
|
def _add_ldflags(self, flags: List[str]) -> None:
|
||||||
self.extra_link_args[:0] = flags
|
self.extra_link_args[:0] = flags
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
|
||||||
self._cxx_level = 0
|
self._cxx_level = 0
|
||||||
cxx_std = kwargs.pop("cxx_std", 0)
|
cxx_std = kwargs.pop("cxx_std", 0)
|
||||||
@ -119,9 +127,7 @@ class Pybind11Extension(_Extension):
|
|||||||
|
|
||||||
include_pybind11 = kwargs.pop("include_pybind11", True)
|
include_pybind11 = kwargs.pop("include_pybind11", True)
|
||||||
|
|
||||||
# Can't use super here because distutils has old-style classes in
|
super().__init__(*args, **kwargs)
|
||||||
# Python 2!
|
|
||||||
_Extension.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
# Include the installed package pybind11 headers
|
# Include the installed package pybind11 headers
|
||||||
if include_pybind11:
|
if include_pybind11:
|
||||||
@ -133,11 +139,10 @@ class Pybind11Extension(_Extension):
|
|||||||
|
|
||||||
if pyinc not in self.include_dirs:
|
if pyinc not in self.include_dirs:
|
||||||
self.include_dirs.append(pyinc)
|
self.include_dirs.append(pyinc)
|
||||||
except ImportError:
|
except ModuleNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Have to use the accessor manually to support Python 2 distutils
|
self.cxx_std = cxx_std
|
||||||
Pybind11Extension.cxx_std.__set__(self, cxx_std)
|
|
||||||
|
|
||||||
cflags = []
|
cflags = []
|
||||||
ldflags = []
|
ldflags = []
|
||||||
@ -157,18 +162,18 @@ class Pybind11Extension(_Extension):
|
|||||||
self._add_ldflags(ldflags)
|
self._add_ldflags(ldflags)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cxx_std(self):
|
def cxx_std(self) -> int:
|
||||||
"""
|
"""
|
||||||
The CXX standard level. If set, will add the required flags. If left
|
The CXX standard level. If set, will add the required flags. If left at
|
||||||
at 0, it will trigger an automatic search when pybind11's build_ext
|
0, it will trigger an automatic search when pybind11's build_ext is
|
||||||
is used. If None, will have no effect. Besides just the flags, this
|
used. If None, will have no effect. Besides just the flags, this may
|
||||||
may add a register warning/error fix for Python 2 or macos-min 10.9
|
add a macos-min 10.9 or 10.14 flag if MACOSX_DEPLOYMENT_TARGET is
|
||||||
or 10.14.
|
unset.
|
||||||
"""
|
"""
|
||||||
return self._cxx_level
|
return self._cxx_level
|
||||||
|
|
||||||
@cxx_std.setter
|
@cxx_std.setter
|
||||||
def cxx_std(self, level):
|
def cxx_std(self, level: int) -> None:
|
||||||
|
|
||||||
if self._cxx_level:
|
if self._cxx_level:
|
||||||
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
||||||
@ -195,31 +200,20 @@ class Pybind11Extension(_Extension):
|
|||||||
current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2])
|
current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2])
|
||||||
desired_macos = (10, 9) if level < 17 else (10, 14)
|
desired_macos = (10, 9) if level < 17 else (10, 14)
|
||||||
macos_string = ".".join(str(x) for x in min(current_macos, desired_macos))
|
macos_string = ".".join(str(x) for x in min(current_macos, desired_macos))
|
||||||
macosx_min = "-mmacosx-version-min=" + macos_string
|
macosx_min = f"-mmacosx-version-min={macos_string}"
|
||||||
cflags += [macosx_min]
|
cflags += [macosx_min]
|
||||||
ldflags += [macosx_min]
|
ldflags += [macosx_min]
|
||||||
|
|
||||||
if PY2:
|
|
||||||
if WIN:
|
|
||||||
# Will be ignored on MSVC 2015, where C++17 is not supported so
|
|
||||||
# this flag is not valid.
|
|
||||||
cflags += ["/wd5033"]
|
|
||||||
elif level >= 17:
|
|
||||||
cflags += ["-Wno-register"]
|
|
||||||
elif level >= 14:
|
|
||||||
cflags += ["-Wno-deprecated-register"]
|
|
||||||
|
|
||||||
self._add_cflags(cflags)
|
self._add_cflags(cflags)
|
||||||
self._add_ldflags(ldflags)
|
self._add_ldflags(ldflags)
|
||||||
|
|
||||||
|
|
||||||
# Just in case someone clever tries to multithread
|
# Just in case someone clever tries to multithread
|
||||||
tmp_chdir_lock = threading.Lock()
|
tmp_chdir_lock = threading.Lock()
|
||||||
cpp_cache_lock = threading.Lock()
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def tmp_chdir():
|
def tmp_chdir() -> Iterator[str]:
|
||||||
"Prepare and enter a temporary directory, cleanup when done"
|
"Prepare and enter a temporary directory, cleanup when done"
|
||||||
|
|
||||||
# Threadsafe
|
# Threadsafe
|
||||||
@ -235,7 +229,7 @@ def tmp_chdir():
|
|||||||
|
|
||||||
|
|
||||||
# cf http://bugs.python.org/issue26689
|
# cf http://bugs.python.org/issue26689
|
||||||
def has_flag(compiler, flag):
|
def has_flag(compiler: Any, flag: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Return the flag if a flag name is supported on the
|
Return the flag if a flag name is supported on the
|
||||||
specified compiler, otherwise None (can be used as a boolean).
|
specified compiler, otherwise None (can be used as a boolean).
|
||||||
@ -243,13 +237,12 @@ def has_flag(compiler, flag):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
with tmp_chdir():
|
with tmp_chdir():
|
||||||
fname = "flagcheck.cpp"
|
fname = Path("flagcheck.cpp")
|
||||||
with open(fname, "w") as f:
|
# Don't trigger -Wunused-parameter.
|
||||||
# Don't trigger -Wunused-parameter.
|
fname.write_text("int main (int, char **) { return 0; }", encoding="utf-8")
|
||||||
f.write("int main (int, char **) { return 0; }")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
compiler.compile([fname], extra_postargs=[flag])
|
compiler.compile([str(fname)], extra_postargs=[flag])
|
||||||
except distutils.errors.CompileError:
|
except distutils.errors.CompileError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@ -259,7 +252,8 @@ def has_flag(compiler, flag):
|
|||||||
cpp_flag_cache = None
|
cpp_flag_cache = None
|
||||||
|
|
||||||
|
|
||||||
def auto_cpp_level(compiler):
|
@lru_cache()
|
||||||
|
def auto_cpp_level(compiler: Any) -> Union[str, int]:
|
||||||
"""
|
"""
|
||||||
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
|
Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
|
||||||
"""
|
"""
|
||||||
@ -267,48 +261,38 @@ def auto_cpp_level(compiler):
|
|||||||
if WIN:
|
if WIN:
|
||||||
return "latest"
|
return "latest"
|
||||||
|
|
||||||
global cpp_flag_cache
|
|
||||||
|
|
||||||
# If this has been previously calculated with the same args, return that
|
|
||||||
with cpp_cache_lock:
|
|
||||||
if cpp_flag_cache:
|
|
||||||
return cpp_flag_cache
|
|
||||||
|
|
||||||
levels = [17, 14, 11]
|
levels = [17, 14, 11]
|
||||||
|
|
||||||
for level in levels:
|
for level in levels:
|
||||||
if has_flag(compiler, STD_TMPL.format(level)):
|
if has_flag(compiler, STD_TMPL.format(level)):
|
||||||
with cpp_cache_lock:
|
|
||||||
cpp_flag_cache = level
|
|
||||||
return level
|
return level
|
||||||
|
|
||||||
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
class build_ext(_build_ext): # noqa: N801
|
class build_ext(_build_ext): # type: ignore[misc] # noqa: N801
|
||||||
"""
|
"""
|
||||||
Customized build_ext that allows an auto-search for the highest supported
|
Customized build_ext that allows an auto-search for the highest supported
|
||||||
C++ level for Pybind11Extension. This is only needed for the auto-search
|
C++ level for Pybind11Extension. This is only needed for the auto-search
|
||||||
for now, and is completely optional otherwise.
|
for now, and is completely optional otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def build_extensions(self):
|
def build_extensions(self) -> None:
|
||||||
"""
|
"""
|
||||||
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for ext in self.extensions:
|
for ext in self.extensions:
|
||||||
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
||||||
# Python 2 syntax - old-style distutils class
|
ext.cxx_std = auto_cpp_level(self.compiler)
|
||||||
ext.__class__.cxx_std.__set__(ext, auto_cpp_level(self.compiler))
|
|
||||||
|
|
||||||
# Python 2 doesn't allow super here, since distutils uses old-style
|
super().build_extensions()
|
||||||
# classes!
|
|
||||||
_build_ext.build_extensions(self)
|
|
||||||
|
|
||||||
|
|
||||||
def intree_extensions(paths, package_dir=None):
|
def intree_extensions(
|
||||||
|
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None
|
||||||
|
) -> 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.
|
||||||
@ -318,33 +302,37 @@ def intree_extensions(paths, package_dir=None):
|
|||||||
not contain an ``__init__.py`` file.
|
not contain an ``__init__.py`` file.
|
||||||
"""
|
"""
|
||||||
exts = []
|
exts = []
|
||||||
for path in paths:
|
|
||||||
if package_dir is None:
|
if package_dir is None:
|
||||||
|
for path in paths:
|
||||||
parent, _ = os.path.split(path)
|
parent, _ = os.path.split(path)
|
||||||
while os.path.exists(os.path.join(parent, "__init__.py")):
|
while os.path.exists(os.path.join(parent, "__init__.py")):
|
||||||
parent, _ = os.path.split(parent)
|
parent, _ = os.path.split(parent)
|
||||||
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
||||||
qualified_name = relname.replace(os.path.sep, ".")
|
qualified_name = relname.replace(os.path.sep, ".")
|
||||||
exts.append(Pybind11Extension(qualified_name, [path]))
|
exts.append(Pybind11Extension(qualified_name, [path]))
|
||||||
|
return exts
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
for prefix, parent in package_dir.items():
|
||||||
|
if path.startswith(parent):
|
||||||
|
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
||||||
|
qualified_name = relname.replace(os.path.sep, ".")
|
||||||
|
if prefix:
|
||||||
|
qualified_name = prefix + "." + qualified_name
|
||||||
|
exts.append(Pybind11Extension(qualified_name, [path]))
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
found = False
|
msg = (
|
||||||
for prefix, parent in package_dir.items():
|
f"path {path} is not a child of any of the directories listed "
|
||||||
if path.startswith(parent):
|
f"in 'package_dir' ({package_dir})"
|
||||||
found = True
|
)
|
||||||
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
raise ValueError(msg)
|
||||||
qualified_name = relname.replace(os.path.sep, ".")
|
|
||||||
if prefix:
|
|
||||||
qualified_name = prefix + "." + qualified_name
|
|
||||||
exts.append(Pybind11Extension(qualified_name, [path]))
|
|
||||||
if not found:
|
|
||||||
raise ValueError(
|
|
||||||
"path {} is not a child of any of the directories listed "
|
|
||||||
"in 'package_dir' ({})".format(path, package_dir)
|
|
||||||
)
|
|
||||||
return exts
|
return exts
|
||||||
|
|
||||||
|
|
||||||
def naive_recompile(obj, src):
|
def naive_recompile(obj: str, src: str) -> bool:
|
||||||
"""
|
"""
|
||||||
This will recompile only if the source file changes. It does not check
|
This will recompile only if the source file changes. It does not check
|
||||||
header files, so a more advanced function or Ccache is better if you have
|
header files, so a more advanced function or Ccache is better if you have
|
||||||
@ -353,7 +341,7 @@ def naive_recompile(obj, src):
|
|||||||
return os.stat(obj).st_mtime < os.stat(src).st_mtime
|
return os.stat(obj).st_mtime < os.stat(src).st_mtime
|
||||||
|
|
||||||
|
|
||||||
def no_recompile(obg, src):
|
def no_recompile(obg: str, src: str) -> bool: # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
This is the safest but slowest choice (and is the default) - will always
|
This is the safest but slowest choice (and is the default) - will always
|
||||||
recompile sources.
|
recompile sources.
|
||||||
@ -361,15 +349,33 @@ def no_recompile(obg, src):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
S = TypeVar("S", bound="ParallelCompile")
|
||||||
|
|
||||||
|
CCompilerMethod = Callable[
|
||||||
|
[
|
||||||
|
distutils.ccompiler.CCompiler,
|
||||||
|
List[str],
|
||||||
|
Optional[str],
|
||||||
|
Optional[Union[Tuple[str], Tuple[str, Optional[str]]]],
|
||||||
|
Optional[List[str]],
|
||||||
|
bool,
|
||||||
|
Optional[List[str]],
|
||||||
|
Optional[List[str]],
|
||||||
|
Optional[List[str]],
|
||||||
|
],
|
||||||
|
List[str],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# Optional parallel compile utility
|
# Optional parallel compile utility
|
||||||
# inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
|
# inspired by: http://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
|
||||||
# and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py
|
# and: https://github.com/tbenthompson/cppimport/blob/stable/cppimport/build_module.py
|
||||||
# and NumPy's parallel distutils module:
|
# and NumPy's parallel distutils module:
|
||||||
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
# https://github.com/numpy/numpy/blob/master/numpy/distutils/ccompiler.py
|
||||||
class ParallelCompile(object):
|
class ParallelCompile:
|
||||||
"""
|
"""
|
||||||
Make a parallel compile function. Inspired by
|
Make a parallel compile function. Inspired by
|
||||||
numpy.distutils.ccompiler.CCompiler_compile and cppimport.
|
numpy.distutils.ccompiler.CCompiler.compile and cppimport.
|
||||||
|
|
||||||
This takes several arguments that allow you to customize the compile
|
This takes several arguments that allow you to customize the compile
|
||||||
function created:
|
function created:
|
||||||
@ -404,35 +410,41 @@ class ParallelCompile(object):
|
|||||||
|
|
||||||
__slots__ = ("envvar", "default", "max", "_old", "needs_recompile")
|
__slots__ = ("envvar", "default", "max", "_old", "needs_recompile")
|
||||||
|
|
||||||
def __init__(self, envvar=None, default=0, max=0, needs_recompile=no_recompile):
|
def __init__(
|
||||||
|
self,
|
||||||
|
envvar: Optional[str] = None,
|
||||||
|
default: int = 0,
|
||||||
|
max: int = 0, # pylint: disable=redefined-builtin
|
||||||
|
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
||||||
|
) -> None:
|
||||||
self.envvar = envvar
|
self.envvar = envvar
|
||||||
self.default = default
|
self.default = default
|
||||||
self.max = max
|
self.max = max
|
||||||
self.needs_recompile = needs_recompile
|
self.needs_recompile = needs_recompile
|
||||||
self._old = []
|
self._old: List[CCompilerMethod] = []
|
||||||
|
|
||||||
def function(self):
|
def function(self) -> CCompilerMethod:
|
||||||
"""
|
"""
|
||||||
Builds a function object usable as distutils.ccompiler.CCompiler.compile.
|
Builds a function object usable as distutils.ccompiler.CCompiler.compile.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def compile_function(
|
def compile_function(
|
||||||
compiler,
|
compiler: distutils.ccompiler.CCompiler,
|
||||||
sources,
|
sources: List[str],
|
||||||
output_dir=None,
|
output_dir: Optional[str] = None,
|
||||||
macros=None,
|
macros: Optional[Union[Tuple[str], Tuple[str, Optional[str]]]] = None,
|
||||||
include_dirs=None,
|
include_dirs: Optional[List[str]] = None,
|
||||||
debug=0,
|
debug: bool = False,
|
||||||
extra_preargs=None,
|
extra_preargs: Optional[List[str]] = None,
|
||||||
extra_postargs=None,
|
extra_postargs: Optional[List[str]] = None,
|
||||||
depends=None,
|
depends: Optional[List[str]] = None,
|
||||||
):
|
) -> 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(
|
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]
|
||||||
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
||||||
)
|
)
|
||||||
cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs)
|
cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs) # type: ignore[attr-defined]
|
||||||
|
|
||||||
# The number of threads; start with default.
|
# The number of threads; start with default.
|
||||||
threads = self.default
|
threads = self.default
|
||||||
@ -441,14 +453,14 @@ class ParallelCompile(object):
|
|||||||
if self.envvar is not None:
|
if self.envvar is not None:
|
||||||
threads = int(os.environ.get(self.envvar, self.default))
|
threads = int(os.environ.get(self.envvar, self.default))
|
||||||
|
|
||||||
def _single_compile(obj):
|
def _single_compile(obj: Any) -> None:
|
||||||
try:
|
try:
|
||||||
src, ext = build[obj]
|
src, ext = build[obj]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not os.path.exists(obj) or self.needs_recompile(obj, src):
|
if not os.path.exists(obj) or self.needs_recompile(obj, src):
|
||||||
compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) # type: ignore[attr-defined]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Importing .synchronize checks for platforms that have some multiprocessing
|
# Importing .synchronize checks for platforms that have some multiprocessing
|
||||||
@ -466,14 +478,9 @@ class ParallelCompile(object):
|
|||||||
threads = 1
|
threads = 1
|
||||||
|
|
||||||
if threads > 1:
|
if threads > 1:
|
||||||
pool = ThreadPool(threads)
|
with ThreadPool(threads) as pool:
|
||||||
# In Python 2, ThreadPool can't be used as a context manager.
|
|
||||||
# Once we are no longer supporting it, this can be 'with pool:'
|
|
||||||
try:
|
|
||||||
for _ in pool.imap_unordered(_single_compile, objects):
|
for _ in pool.imap_unordered(_single_compile, objects):
|
||||||
pass
|
pass
|
||||||
finally:
|
|
||||||
pool.terminate()
|
|
||||||
else:
|
else:
|
||||||
for ob in objects:
|
for ob in objects:
|
||||||
_single_compile(ob)
|
_single_compile(ob)
|
||||||
@ -482,13 +489,16 @@ class ParallelCompile(object):
|
|||||||
|
|
||||||
return compile_function
|
return compile_function
|
||||||
|
|
||||||
def install(self):
|
def install(self: S) -> S:
|
||||||
distutils.ccompiler.CCompiler.compile = self.function()
|
"""
|
||||||
|
Installs the compile function into distutils.ccompiler.CCompiler.compile.
|
||||||
|
"""
|
||||||
|
distutils.ccompiler.CCompiler.compile = self.function() # type: ignore[assignment]
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self: S) -> S:
|
||||||
self._old.append(distutils.ccompiler.CCompiler.compile)
|
self._old.append(distutils.ccompiler.CCompiler.compile)
|
||||||
return self.install()
|
return self.install()
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args: Any) -> None:
|
||||||
distutils.ccompiler.CCompiler.compile = self._old.pop()
|
distutils.ccompiler.CCompiler.compile = self._old.pop() # type: ignore[assignment]
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
# IMPORTANT: Should stay in sync with setup_helpers.py (mostly checked by CI /
|
|
||||||
# pre-commit).
|
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import distutils.ccompiler
|
|
||||||
from distutils.command.build_ext import build_ext as _build_ext # type: ignore
|
|
||||||
from distutils.extension import Extension as _Extension
|
|
||||||
from types import TracebackType
|
|
||||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, TypeVar, Union
|
|
||||||
|
|
||||||
WIN: bool
|
|
||||||
PY2: bool
|
|
||||||
MACOS: bool
|
|
||||||
STD_TMPL: str
|
|
||||||
|
|
||||||
class Pybind11Extension(_Extension):
|
|
||||||
def _add_cflags(self, *flags: str) -> None: ...
|
|
||||||
def _add_lflags(self, *flags: str) -> None: ...
|
|
||||||
def __init__(
|
|
||||||
self, *args: Any, cxx_std: int = 0, language: str = "c++", **kwargs: Any
|
|
||||||
) -> None: ...
|
|
||||||
@property
|
|
||||||
def cxx_std(self) -> int: ...
|
|
||||||
@cxx_std.setter
|
|
||||||
def cxx_std(self, level: int) -> None: ...
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def tmp_chdir() -> Iterator[str]: ...
|
|
||||||
def has_flag(compiler: distutils.ccompiler.CCompiler, flag: str) -> bool: ...
|
|
||||||
def auto_cpp_level(compiler: distutils.ccompiler.CCompiler) -> Union[int, str]: ...
|
|
||||||
|
|
||||||
class build_ext(_build_ext): # type: ignore
|
|
||||||
def build_extensions(self) -> None: ...
|
|
||||||
|
|
||||||
def intree_extensions(
|
|
||||||
paths: Iterator[str], package_dir: Optional[Dict[str, str]] = None
|
|
||||||
) -> List[Pybind11Extension]: ...
|
|
||||||
def no_recompile(obj: str, src: str) -> bool: ...
|
|
||||||
def naive_recompile(obj: str, src: str) -> bool: ...
|
|
||||||
|
|
||||||
T = TypeVar("T", bound="ParallelCompile")
|
|
||||||
|
|
||||||
class ParallelCompile:
|
|
||||||
envvar: Optional[str]
|
|
||||||
default: int
|
|
||||||
max: int
|
|
||||||
needs_recompile: Callable[[str, str], bool]
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
envvar: Optional[str] = None,
|
|
||||||
default: int = 0,
|
|
||||||
max: int = 0,
|
|
||||||
needs_recompile: Callable[[str, str], bool] = no_recompile,
|
|
||||||
) -> None: ...
|
|
||||||
def function(self) -> Any: ...
|
|
||||||
def install(self: T) -> T: ...
|
|
||||||
def __enter__(self: T) -> T: ...
|
|
||||||
def __exit__(
|
|
||||||
self,
|
|
||||||
exc_type: Optional[Type[BaseException]],
|
|
||||||
exc_value: Optional[BaseException],
|
|
||||||
traceback: Optional[TracebackType],
|
|
||||||
) -> None: ...
|
|
@ -1,5 +1,5 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools>=42", "wheel", "cmake>=3.18", "ninja"]
|
requires = ["setuptools>=42", "cmake>=3.18", "ninja"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[tool.check-manifest]
|
[tool.check-manifest]
|
||||||
@ -22,20 +22,40 @@ known_first_party = "env,pybind11_cross_module_tests,pybind11_tests,"
|
|||||||
profile = "black"
|
profile = "black"
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
files = "pybind11"
|
files = ["pybind11"]
|
||||||
python_version = "2.7"
|
python_version = "3.6"
|
||||||
warn_unused_configs = true
|
strict = true
|
||||||
|
show_error_codes = true
|
||||||
|
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
|
||||||
|
warn_unreachable = true
|
||||||
|
|
||||||
disallow_any_generics = true
|
[[tool.mypy.overrides]]
|
||||||
disallow_subclassing_any = true
|
module = ["ghapi.*", "setuptools.*"]
|
||||||
disallow_untyped_calls = true
|
ignore_missing_imports = true
|
||||||
disallow_untyped_defs = true
|
|
||||||
disallow_incomplete_defs = true
|
|
||||||
check_untyped_defs = true
|
[tool.pytest.ini_options]
|
||||||
disallow_untyped_decorators = true
|
minversion = "6.0"
|
||||||
no_implicit_optional = true
|
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
|
||||||
warn_redundant_casts = true
|
xfail_strict = true
|
||||||
warn_unused_ignores = true
|
filterwarnings = ["error"]
|
||||||
warn_return_any = true
|
log_cli_level = "info"
|
||||||
no_implicit_reexport = true
|
testpaths = [
|
||||||
strict_equality = true
|
"tests",
|
||||||
|
]
|
||||||
|
timeout=300
|
||||||
|
|
||||||
|
|
||||||
|
[tool.pylint]
|
||||||
|
master.py-version = "3.6"
|
||||||
|
reports.output-format = "colorized"
|
||||||
|
messages_control.disable = [
|
||||||
|
"design",
|
||||||
|
"fixme",
|
||||||
|
"imports",
|
||||||
|
"line-too-long",
|
||||||
|
"imports",
|
||||||
|
"invalid-name",
|
||||||
|
"protected-access",
|
||||||
|
"missing-module-docstring",
|
||||||
|
]
|
||||||
|
25
setup.cfg
25
setup.cfg
@ -13,14 +13,13 @@ classifiers =
|
|||||||
Topic :: Software Development :: Libraries :: Python Modules
|
Topic :: Software Development :: Libraries :: Python Modules
|
||||||
Topic :: Utilities
|
Topic :: Utilities
|
||||||
Programming Language :: C++
|
Programming Language :: C++
|
||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 3 :: Only
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.5
|
|
||||||
Programming Language :: Python :: 3.6
|
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
|
||||||
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,25 +38,13 @@ project_urls =
|
|||||||
Chat = https://gitter.im/pybind/Lobby
|
Chat = https://gitter.im/pybind/Lobby
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
python_requires = >=3.6
|
||||||
zip_safe = False
|
zip_safe = False
|
||||||
|
|
||||||
[bdist_wheel]
|
|
||||||
universal=1
|
|
||||||
|
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 99
|
max-line-length = 120
|
||||||
show_source = True
|
show_source = True
|
||||||
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
exclude = .git, __pycache__, build, dist, docs, tools, venv
|
||||||
ignore =
|
extend-ignore = E203, E722, B950
|
||||||
# required for pretty matrix formatting: multiple spaces after `,` and `[`
|
extend-select = B9
|
||||||
E201, E241, W504,
|
|
||||||
# camelcase 'cPickle' imported as lowercase 'pickle'
|
|
||||||
N813
|
|
||||||
# Black conflict
|
|
||||||
W503, E203
|
|
||||||
|
|
||||||
|
|
||||||
[tool:pytest]
|
|
||||||
timeout = 300
|
|
||||||
|
136
setup.py
136
setup.py
@ -1,56 +1,50 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import io
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
from pathlib import Path
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import Dict, Iterator, List, Union
|
||||||
|
|
||||||
import setuptools.command.sdist
|
import setuptools.command.sdist
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = Path(__file__).parent.absolute()
|
||||||
VERSION_REGEX = re.compile(
|
VERSION_REGEX = re.compile(
|
||||||
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
||||||
)
|
)
|
||||||
|
VERSION_FILE = Path("pybind11/_version.py")
|
||||||
|
COMMON_FILE = Path("include/pybind11/detail/common.h")
|
||||||
|
|
||||||
|
|
||||||
def build_expected_version_hex(matches):
|
def build_expected_version_hex(matches: Dict[str, str]) -> str:
|
||||||
patch_level_serial = matches["PATCH"]
|
patch_level_serial = matches["PATCH"]
|
||||||
serial = None
|
serial = None
|
||||||
try:
|
major = int(matches["MAJOR"])
|
||||||
major = int(matches["MAJOR"])
|
minor = int(matches["MINOR"])
|
||||||
minor = int(matches["MINOR"])
|
flds = patch_level_serial.split(".")
|
||||||
flds = patch_level_serial.split(".")
|
if flds:
|
||||||
if flds:
|
patch = int(flds[0])
|
||||||
patch = int(flds[0])
|
if len(flds) == 1:
|
||||||
level = None
|
level = "0"
|
||||||
if len(flds) == 1:
|
serial = 0
|
||||||
level = "0"
|
elif len(flds) == 2:
|
||||||
serial = 0
|
level_serial = flds[1]
|
||||||
elif len(flds) == 2:
|
for level in ("a", "b", "c", "dev"):
|
||||||
level_serial = flds[1]
|
if level_serial.startswith(level):
|
||||||
for level in ("a", "b", "c", "dev"):
|
serial = int(level_serial[len(level) :])
|
||||||
if level_serial.startswith(level):
|
break
|
||||||
serial = int(level_serial[len(level) :])
|
|
||||||
break
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
if serial is None:
|
if serial is None:
|
||||||
msg = 'Invalid PYBIND11_VERSION_PATCH: "{}"'.format(patch_level_serial)
|
msg = f'Invalid PYBIND11_VERSION_PATCH: "{patch_level_serial}"'
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
return (
|
version_hex_str = f"{major:02x}{minor:02x}{patch:02x}{level[:1]}{serial:x}"
|
||||||
"0x"
|
return f"0x{version_hex_str.upper()}"
|
||||||
+ "{:02x}{:02x}{:02x}{}{:x}".format(
|
|
||||||
major, minor, patch, level[:1], serial
|
|
||||||
).upper()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
||||||
@ -58,82 +52,67 @@ def build_expected_version_hex(matches):
|
|||||||
|
|
||||||
global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False)
|
global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False)
|
||||||
|
|
||||||
setup_py = "tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in"
|
setup_py = Path(
|
||||||
|
"tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in"
|
||||||
|
)
|
||||||
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
||||||
|
|
||||||
to_src = (
|
to_src = (
|
||||||
("pyproject.toml", "tools/pyproject.toml"),
|
(Path("pyproject.toml"), Path("tools/pyproject.toml")),
|
||||||
("setup.py", setup_py),
|
(Path("setup.py"), setup_py),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Read the listed version
|
# Read the listed version
|
||||||
with open("pybind11/_version.py") as f:
|
loc: Dict[str, str] = {}
|
||||||
code = compile(f.read(), "pybind11/_version.py", "exec")
|
code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
|
||||||
loc = {}
|
|
||||||
exec(code, loc)
|
exec(code, loc)
|
||||||
version = loc["__version__"]
|
version = loc["__version__"]
|
||||||
|
|
||||||
# Verify that the version matches the one in C++
|
# Verify that the version matches the one in C++
|
||||||
with io.open("include/pybind11/detail/common.h", encoding="utf8") as f:
|
matches = dict(VERSION_REGEX.findall(COMMON_FILE.read_text(encoding="utf8")))
|
||||||
matches = dict(VERSION_REGEX.findall(f.read()))
|
|
||||||
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
||||||
if version != cpp_version:
|
if version != cpp_version:
|
||||||
msg = "Python version {} does not match C++ version {}!".format(
|
msg = f"Python version {version} does not match C++ version {cpp_version}!"
|
||||||
version, cpp_version
|
|
||||||
)
|
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
version_hex = matches.get("HEX", "MISSING")
|
version_hex = matches.get("HEX", "MISSING")
|
||||||
expected_version_hex = build_expected_version_hex(matches)
|
exp_version_hex = build_expected_version_hex(matches)
|
||||||
if version_hex != expected_version_hex:
|
if version_hex != exp_version_hex:
|
||||||
msg = "PYBIND11_VERSION_HEX {} does not match expected value {}!".format(
|
msg = f"PYBIND11_VERSION_HEX {version_hex} does not match expected value {exp_version_hex}!"
|
||||||
version_hex,
|
|
||||||
expected_version_hex,
|
|
||||||
)
|
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
def get_and_replace(filename, binary=False, **opts):
|
# TODO: use literals & overload (typing extensions or Python 3.8)
|
||||||
with open(filename, "rb" if binary else "r") as f:
|
def get_and_replace(
|
||||||
contents = f.read()
|
filename: Path, binary: bool = False, **opts: str
|
||||||
# Replacement has to be done on text in Python 3 (both work in Python 2)
|
) -> Union[bytes, str]:
|
||||||
if binary:
|
if binary:
|
||||||
|
contents = filename.read_bytes()
|
||||||
return string.Template(contents.decode()).substitute(opts).encode()
|
return string.Template(contents.decode()).substitute(opts).encode()
|
||||||
else:
|
|
||||||
return string.Template(contents).substitute(opts)
|
return string.Template(filename.read_text()).substitute(opts)
|
||||||
|
|
||||||
|
|
||||||
# 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): # type: ignore[misc]
|
||||||
def make_release_tree(self, base_dir, files):
|
def make_release_tree(self, base_dir: str, files: List[str]) -> None:
|
||||||
setuptools.command.sdist.sdist.make_release_tree(self, base_dir, files)
|
super().make_release_tree(base_dir, files)
|
||||||
|
|
||||||
for to, src in to_src:
|
for to, src in to_src:
|
||||||
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
||||||
|
|
||||||
dest = os.path.join(base_dir, to)
|
dest = Path(base_dir) / to
|
||||||
|
|
||||||
# This is normally linked, so unlink before writing!
|
# This is normally linked, so unlink before writing!
|
||||||
os.unlink(dest)
|
dest.unlink()
|
||||||
with open(dest, "wb") as f:
|
dest.write_bytes(txt) # type: ignore[arg-type]
|
||||||
f.write(txt)
|
|
||||||
|
|
||||||
|
|
||||||
# Backport from Python 3
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def TemporaryDirectory(): # noqa: N802
|
|
||||||
"Prepare a temporary directory, cleanup when done"
|
|
||||||
try:
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
|
||||||
yield tmpdir
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(tmpdir)
|
|
||||||
|
|
||||||
|
|
||||||
# Remove the CMake install directory when done
|
# Remove the CMake install directory when done
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def remove_output(*sources):
|
def remove_output(*sources: str) -> Iterator[None]:
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
@ -156,9 +135,14 @@ with remove_output("pybind11/include", "pybind11/share"):
|
|||||||
if "DCMAKE_INSTALL_PREFIX" not in c
|
if "DCMAKE_INSTALL_PREFIX" not in c
|
||||||
]
|
]
|
||||||
cmd += fcommand
|
cmd += fcommand
|
||||||
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
subprocess.run(cmd, check=True, cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||||
subprocess.check_call(cmd, **cmake_opts)
|
subprocess.run(
|
||||||
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
["cmake", "--install", tmpdir],
|
||||||
|
check=True,
|
||||||
|
cwd=DIR,
|
||||||
|
stdout=sys.stdout,
|
||||||
|
stderr=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
||||||
code = compile(txt, setup_py, "exec")
|
code = compile(txt, setup_py, "exec")
|
||||||
|
@ -179,11 +179,6 @@ if(PYBIND11_TEST_FILTER)
|
|||||||
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PYTHON_VERSION VERSION_LESS 3.5)
|
|
||||||
pybind11_filter_tests(PYBIND11_TEST_FILES test_async.cpp MESSAGE
|
|
||||||
"Skipping test_async on Python 2")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Skip tests for CUDA check:
|
# Skip tests for CUDA check:
|
||||||
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
||||||
# error: incompatible exception specifications
|
# error: incompatible exception specifications
|
||||||
@ -220,6 +215,7 @@ tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_
|
|||||||
"pybind11_cross_module_tests")
|
"pybind11_cross_module_tests")
|
||||||
|
|
||||||
# And add additional targets for other tests.
|
# And add additional targets for other tests.
|
||||||
|
tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set")
|
||||||
tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
|
tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
|
||||||
|
|
||||||
set(PYBIND11_EIGEN_REPO
|
set(PYBIND11_EIGEN_REPO
|
||||||
@ -356,7 +352,7 @@ endif()
|
|||||||
# Compile with compiler warnings turned on
|
# Compile with compiler warnings turned on
|
||||||
function(pybind11_enable_warnings target_name)
|
function(pybind11_enable_warnings target_name)
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_compile_options(${target_name} PRIVATE /W4)
|
target_compile_options(${target_name} PRIVATE /W4 /wd4189)
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
|
||||||
target_compile_options(
|
target_compile_options(
|
||||||
${target_name}
|
${target_name}
|
||||||
@ -388,17 +384,6 @@ function(pybind11_enable_warnings target_name)
|
|||||||
-diag-disable 11074,11076)
|
-diag-disable 11074,11076)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Needs to be re-added since the ordering requires these to be after the ones above
|
|
||||||
if(CMAKE_CXX_STANDARD
|
|
||||||
AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
|
||||||
AND PYTHON_VERSION VERSION_LESS 3.0)
|
|
||||||
if(CMAKE_CXX_STANDARD LESS 17)
|
|
||||||
target_compile_options(${target_name} PUBLIC -Wno-deprecated-register)
|
|
||||||
else()
|
|
||||||
target_compile_options(${target_name} PUBLIC -Wno-register)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
set(test_targets pybind11_tests)
|
set(test_targets pybind11_tests)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""pytest configuration
|
"""pytest configuration
|
||||||
|
|
||||||
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
|
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
|
||||||
Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
|
Adds docstring and exceptions message sanitizers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
@ -13,19 +12,14 @@ import textwrap
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
|
||||||
|
|
||||||
# Early diagnostic for failed imports
|
# Early diagnostic for failed imports
|
||||||
import pybind11_tests # noqa: F401
|
import pybind11_tests
|
||||||
|
|
||||||
_unicode_marker = re.compile(r"u(\'[^\']*\')")
|
|
||||||
_long_marker = re.compile(r"([0-9])L")
|
_long_marker = re.compile(r"([0-9])L")
|
||||||
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
|
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
|
||||||
|
|
||||||
# Avoid collecting Python3 only files
|
# Avoid collecting Python3 only files
|
||||||
collect_ignore = []
|
collect_ignore = []
|
||||||
if env.PY2:
|
|
||||||
collect_ignore.append("test_async.py")
|
|
||||||
|
|
||||||
|
|
||||||
def _strip_and_dedent(s):
|
def _strip_and_dedent(s):
|
||||||
@ -45,7 +39,7 @@ def _make_explanation(a, b):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Output(object):
|
class Output:
|
||||||
"""Basic output post-processing and comparison"""
|
"""Basic output post-processing and comparison"""
|
||||||
|
|
||||||
def __init__(self, string):
|
def __init__(self, string):
|
||||||
@ -83,7 +77,7 @@ class Unordered(Output):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Capture(object):
|
class Capture:
|
||||||
def __init__(self, capfd):
|
def __init__(self, capfd):
|
||||||
self.capfd = capfd
|
self.capfd = capfd
|
||||||
self.out = ""
|
self.out = ""
|
||||||
@ -126,7 +120,7 @@ def capture(capsys):
|
|||||||
return Capture(capsys)
|
return Capture(capsys)
|
||||||
|
|
||||||
|
|
||||||
class SanitizedString(object):
|
class SanitizedString:
|
||||||
def __init__(self, sanitizer):
|
def __init__(self, sanitizer):
|
||||||
self.sanitizer = sanitizer
|
self.sanitizer = sanitizer
|
||||||
self.string = ""
|
self.string = ""
|
||||||
@ -149,9 +143,7 @@ class SanitizedString(object):
|
|||||||
def _sanitize_general(s):
|
def _sanitize_general(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
s = s.replace("pybind11_tests.", "m.")
|
s = s.replace("pybind11_tests.", "m.")
|
||||||
s = s.replace("unicode", "str")
|
|
||||||
s = _long_marker.sub(r"\1", s)
|
s = _long_marker.sub(r"\1", s)
|
||||||
s = _unicode_marker.sub(r"\1", s)
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
@ -206,3 +198,16 @@ def gc_collect():
|
|||||||
def pytest_configure():
|
def pytest_configure():
|
||||||
pytest.suppress = suppress
|
pytest.suppress = suppress
|
||||||
pytest.gc_collect = gc_collect
|
pytest.gc_collect = gc_collect
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_report_header(config):
|
||||||
|
del config # Unused.
|
||||||
|
assert (
|
||||||
|
pybind11_tests.compiler_info is not None
|
||||||
|
), "Please update pybind11_tests.cpp if this assert fails."
|
||||||
|
return (
|
||||||
|
"C++ Info:"
|
||||||
|
f" {pybind11_tests.compiler_info}"
|
||||||
|
f" {pybind11_tests.cpp_std}"
|
||||||
|
f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
|
||||||
|
)
|
||||||
|
@ -25,40 +25,21 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
|
|||||||
|
|
||||||
constexpr char kModuleName[] = "cross_module_gil_utils";
|
constexpr char kModuleName[] = "cross_module_gil_utils";
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
struct PyModuleDef moduledef = {
|
||||||
struct PyModuleDef moduledef
|
PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||||
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
|
|
||||||
#else
|
|
||||||
PyMethodDef module_methods[] = {{NULL, NULL, 0, NULL}};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" PYBIND11_EXPORT
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyObject *
|
|
||||||
PyInit_cross_module_gil_utils()
|
|
||||||
#else
|
|
||||||
void
|
|
||||||
initcross_module_gil_utils()
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
|
|
||||||
PyObject *m =
|
PyObject *m = PyModule_Create(&moduledef);
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyModule_Create(&moduledef);
|
|
||||||
#else
|
|
||||||
Py_InitModule(kModuleName, module_methods);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m != NULL) {
|
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*");
|
||||||
PyModule_AddObject(
|
PyModule_AddObject(
|
||||||
m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
|
m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return m;
|
return m;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
51
tests/cross_module_interleaved_error_already_set.cpp
Normal file
51
tests/cross_module_interleaved_error_already_set.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2022 Google LLC
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
|
// This file mimics a DSO that makes pybind11 calls but does not define a PYBIND11_MODULE,
|
||||||
|
// so that the first call of cross_module_error_already_set() triggers the first call of
|
||||||
|
// pybind11::detail::get_internals().
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
void interleaved_error_already_set() {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "1st error.");
|
||||||
|
try {
|
||||||
|
throw py::error_already_set();
|
||||||
|
} catch (const py::error_already_set &) {
|
||||||
|
// The 2nd error could be conditional in a real application.
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "2nd error.");
|
||||||
|
} // Here the 1st error is destroyed before the 2nd error is fetched.
|
||||||
|
// The error_already_set dtor triggers a pybind11::detail::get_internals()
|
||||||
|
// call via pybind11::gil_scoped_acquire.
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
throw py::error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char kModuleName[] = "cross_module_interleaved_error_already_set";
|
||||||
|
|
||||||
|
struct PyModuleDef moduledef = {
|
||||||
|
PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_interleaved_error_already_set() {
|
||||||
|
PyObject *m = PyModule_Create(&moduledef);
|
||||||
|
if (m != nullptr) {
|
||||||
|
static_assert(sizeof(&interleaved_error_already_set) == sizeof(void *),
|
||||||
|
"Function pointer must have the same size as void *");
|
||||||
|
PyModule_AddObject(
|
||||||
|
m,
|
||||||
|
"funcaddr",
|
||||||
|
PyLong_FromVoidPtr(reinterpret_cast<void *>(&interleaved_error_already_set)));
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -11,10 +10,6 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
|||||||
CPYTHON = platform.python_implementation() == "CPython"
|
CPYTHON = platform.python_implementation() == "CPython"
|
||||||
PYPY = platform.python_implementation() == "PyPy"
|
PYPY = platform.python_implementation() == "PyPy"
|
||||||
|
|
||||||
PY2 = sys.version_info.major == 2
|
|
||||||
|
|
||||||
PY = sys.version_info
|
|
||||||
|
|
||||||
|
|
||||||
def deprecated_call():
|
def deprecated_call():
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
@ -64,11 +63,9 @@ py_files = {
|
|||||||
"__init__.py",
|
"__init__.py",
|
||||||
"__main__.py",
|
"__main__.py",
|
||||||
"_version.py",
|
"_version.py",
|
||||||
"_version.pyi",
|
|
||||||
"commands.py",
|
"commands.py",
|
||||||
"py.typed",
|
"py.typed",
|
||||||
"setup_helpers.py",
|
"setup_helpers.py",
|
||||||
"setup_helpers.pyi",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = main_headers | detail_headers | stl_headers
|
headers = main_headers | detail_headers | stl_headers
|
||||||
@ -111,19 +108,19 @@ def test_build_sdist(monkeypatch, tmpdir):
|
|||||||
out = subprocess.check_output(
|
out = subprocess.check_output(
|
||||||
[
|
[
|
||||||
sys.executable,
|
sys.executable,
|
||||||
"setup.py",
|
"-m",
|
||||||
"sdist",
|
"build",
|
||||||
"--formats=tar",
|
"--sdist",
|
||||||
"--dist-dir",
|
"--outdir",
|
||||||
str(tmpdir),
|
str(tmpdir),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if hasattr(out, "decode"):
|
if hasattr(out, "decode"):
|
||||||
out = out.decode()
|
out = out.decode()
|
||||||
|
|
||||||
(sdist,) = tmpdir.visit("*.tar")
|
(sdist,) = tmpdir.visit("*.tar.gz")
|
||||||
|
|
||||||
with tarfile.open(str(sdist)) as tar:
|
with tarfile.open(str(sdist), "r:gz") as tar:
|
||||||
start = tar.getnames()[0] + "/"
|
start = tar.getnames()[0] + "/"
|
||||||
version = start[9:-1]
|
version = start[9:-1]
|
||||||
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
||||||
@ -148,9 +145,9 @@ def test_build_sdist(monkeypatch, tmpdir):
|
|||||||
contents = f.read().decode("utf8")
|
contents = f.read().decode("utf8")
|
||||||
assert 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in contents
|
assert 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in contents
|
||||||
|
|
||||||
files = {"pybind11/{}".format(n) for n in all_files}
|
files = {f"pybind11/{n}" for n in all_files}
|
||||||
files |= sdist_files
|
files |= sdist_files
|
||||||
files |= {"pybind11{}".format(n) for n in local_sdist_files}
|
files |= {f"pybind11{n}" for n in local_sdist_files}
|
||||||
files.add("pybind11.egg-info/entry_points.txt")
|
files.add("pybind11.egg-info/entry_points.txt")
|
||||||
files.add("pybind11.egg-info/requires.txt")
|
files.add("pybind11.egg-info/requires.txt")
|
||||||
assert simpler == files
|
assert simpler == files
|
||||||
@ -172,23 +169,23 @@ def test_build_global_dist(monkeypatch, tmpdir):
|
|||||||
|
|
||||||
monkeypatch.chdir(MAIN_DIR)
|
monkeypatch.chdir(MAIN_DIR)
|
||||||
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
||||||
|
|
||||||
out = subprocess.check_output(
|
out = subprocess.check_output(
|
||||||
[
|
[
|
||||||
sys.executable,
|
sys.executable,
|
||||||
"setup.py",
|
"-m",
|
||||||
"sdist",
|
"build",
|
||||||
"--formats=tar",
|
"--sdist",
|
||||||
"--dist-dir",
|
"--outdir",
|
||||||
str(tmpdir),
|
str(tmpdir),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
if hasattr(out, "decode"):
|
if hasattr(out, "decode"):
|
||||||
out = out.decode()
|
out = out.decode()
|
||||||
|
|
||||||
(sdist,) = tmpdir.visit("*.tar")
|
(sdist,) = tmpdir.visit("*.tar.gz")
|
||||||
|
|
||||||
with tarfile.open(str(sdist)) as tar:
|
with tarfile.open(str(sdist), "r:gz") as tar:
|
||||||
start = tar.getnames()[0] + "/"
|
start = tar.getnames()[0] + "/"
|
||||||
version = start[16:-1]
|
version = start[16:-1]
|
||||||
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
||||||
@ -203,9 +200,9 @@ def test_build_global_dist(monkeypatch, tmpdir):
|
|||||||
) as f:
|
) as f:
|
||||||
pyproject_toml = f.read()
|
pyproject_toml = f.read()
|
||||||
|
|
||||||
files = {"pybind11/{}".format(n) for n in all_files}
|
files = {f"pybind11/{n}" for n in all_files}
|
||||||
files |= sdist_files
|
files |= sdist_files
|
||||||
files |= {"pybind11_global{}".format(n) for n in local_sdist_files}
|
files |= {f"pybind11_global{n}" for n in local_sdist_files}
|
||||||
assert simpler == files
|
assert simpler == files
|
||||||
|
|
||||||
with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f:
|
with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f:
|
||||||
@ -230,7 +227,7 @@ def tests_build_wheel(monkeypatch, tmpdir):
|
|||||||
|
|
||||||
(wheel,) = tmpdir.visit("*.whl")
|
(wheel,) = tmpdir.visit("*.whl")
|
||||||
|
|
||||||
files = {"pybind11/{}".format(n) for n in all_files}
|
files = {f"pybind11/{n}" for n in all_files}
|
||||||
files |= {
|
files |= {
|
||||||
"dist-info/LICENSE",
|
"dist-info/LICENSE",
|
||||||
"dist-info/METADATA",
|
"dist-info/METADATA",
|
||||||
@ -244,9 +241,7 @@ def tests_build_wheel(monkeypatch, tmpdir):
|
|||||||
names = z.namelist()
|
names = z.namelist()
|
||||||
|
|
||||||
trimmed = {n for n in names if "dist-info" not in n}
|
trimmed = {n for n in names if "dist-info" not in n}
|
||||||
trimmed |= {
|
trimmed |= {f"dist-info/{n.split('/', 1)[-1]}" for n in names if "dist-info" in n}
|
||||||
"dist-info/{}".format(n.split("/", 1)[-1]) for n in names if "dist-info" in n
|
|
||||||
}
|
|
||||||
assert files == trimmed
|
assert files == trimmed
|
||||||
|
|
||||||
|
|
||||||
@ -260,8 +255,8 @@ def tests_build_global_wheel(monkeypatch, tmpdir):
|
|||||||
|
|
||||||
(wheel,) = tmpdir.visit("*.whl")
|
(wheel,) = tmpdir.visit("*.whl")
|
||||||
|
|
||||||
files = {"data/data/{}".format(n) for n in src_files}
|
files = {f"data/data/{n}" for n in src_files}
|
||||||
files |= {"data/headers/{}".format(n[8:]) for n in headers}
|
files |= {f"data/headers/{n[8:]}" for n in headers}
|
||||||
files |= {
|
files |= {
|
||||||
"dist-info/LICENSE",
|
"dist-info/LICENSE",
|
||||||
"dist-info/METADATA",
|
"dist-info/METADATA",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -19,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
|
|
||||||
(tmpdir / "setup.py").write_text(
|
(tmpdir / "setup.py").write_text(
|
||||||
dedent(
|
dedent(
|
||||||
u"""\
|
f"""\
|
||||||
import sys
|
import sys
|
||||||
sys.path.append({MAIN_DIR!r})
|
sys.path.append({MAIN_DIR!r})
|
||||||
|
|
||||||
@ -52,13 +51,13 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
ext_modules=ext_modules,
|
ext_modules=ext_modules,
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
).format(MAIN_DIR=MAIN_DIR, std=std, parallel=parallel),
|
),
|
||||||
encoding="ascii",
|
encoding="ascii",
|
||||||
)
|
)
|
||||||
|
|
||||||
(tmpdir / "main.cpp").write_text(
|
(tmpdir / "main.cpp").write_text(
|
||||||
dedent(
|
dedent(
|
||||||
u"""\
|
"""\
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
int f(int x) {
|
int f(int x) {
|
||||||
@ -96,7 +95,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
|
|
||||||
(tmpdir / "test.py").write_text(
|
(tmpdir / "test.py").write_text(
|
||||||
dedent(
|
dedent(
|
||||||
u"""\
|
"""\
|
||||||
import simple_setup
|
import simple_setup
|
||||||
assert simple_setup.f(3) == 9
|
assert simple_setup.f(3) == 9
|
||||||
"""
|
"""
|
||||||
@ -121,10 +120,11 @@ def test_intree_extensions(monkeypatch, tmpdir):
|
|||||||
subdir.ensure_dir()
|
subdir.ensure_dir()
|
||||||
src = subdir / "ext.cpp"
|
src = subdir / "ext.cpp"
|
||||||
src.ensure()
|
src.ensure()
|
||||||
(ext,) = intree_extensions([src.relto(tmpdir)])
|
relpath = src.relto(tmpdir)
|
||||||
|
(ext,) = intree_extensions([relpath])
|
||||||
assert ext.name == "ext"
|
assert ext.name == "ext"
|
||||||
subdir.ensure("__init__.py")
|
subdir.ensure("__init__.py")
|
||||||
(ext,) = intree_extensions([src.relto(tmpdir)])
|
(ext,) = intree_extensions([relpath])
|
||||||
assert ext.name == "dir.ext"
|
assert ext.name == "dir.ext"
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,15 +62,40 @@ void bind_ConstructorStats(py::module_ &m) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *cpp_std() {
|
||||||
|
return
|
||||||
|
#if defined(PYBIND11_CPP20)
|
||||||
|
"C++20";
|
||||||
|
#elif defined(PYBIND11_CPP17)
|
||||||
|
"C++17";
|
||||||
|
#elif defined(PYBIND11_CPP14)
|
||||||
|
"C++14";
|
||||||
|
#else
|
||||||
|
"C++11";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_MODULE(pybind11_tests, m) {
|
PYBIND11_MODULE(pybind11_tests, m) {
|
||||||
m.doc() = "pybind11 test module";
|
m.doc() = "pybind11 test module";
|
||||||
|
|
||||||
|
// Intentionally kept minimal to not create a maintenance chore
|
||||||
|
// ("just enough" to be conclusive).
|
||||||
|
#if defined(_MSC_FULL_VER)
|
||||||
|
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
|
||||||
|
#elif defined(__VERSION__)
|
||||||
|
m.attr("compiler_info") = __VERSION__;
|
||||||
|
#else
|
||||||
|
m.attr("compiler_info") = py::none();
|
||||||
|
#endif
|
||||||
|
m.attr("cpp_std") = cpp_std();
|
||||||
|
m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
|
||||||
|
|
||||||
bind_ConstructorStats(m);
|
bind_ConstructorStats(m);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
m.attr("debug_enabled") = true;
|
m.attr("detailed_error_messages_enabled") = true;
|
||||||
#else
|
#else
|
||||||
m.attr("debug_enabled") = false;
|
m.attr("detailed_error_messages_enabled") = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
|
py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
|
||||||
|
@ -3,12 +3,6 @@
|
|||||||
#include <pybind11/eval.h>
|
#include <pybind11/eval.h>
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
|
||||||
// We get some really long type names here which causes MSVC 2015 to emit warnings
|
|
||||||
# pragma warning( \
|
|
||||||
disable : 4503) // NOLINT: warning C4503: decorated name length exceeded, name was truncated
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
using namespace pybind11::literals;
|
using namespace pybind11::literals;
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
minversion = 3.1
|
minversion = 3.10
|
||||||
norecursedirs = test_* extra_*
|
norecursedirs = test_* extra_*
|
||||||
xfail_strict = True
|
xfail_strict = True
|
||||||
addopts =
|
addopts =
|
||||||
# show summary of skipped tests
|
# show summary of tests
|
||||||
-rs
|
-ra
|
||||||
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
|
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
|
||||||
--capture=sys
|
--capture=sys
|
||||||
|
# Show local info when a failure occurs
|
||||||
|
--showlocals
|
||||||
|
log_cli_level = info
|
||||||
filterwarnings =
|
filterwarnings =
|
||||||
# make warnings into errors but ignore certain third-party extension issues
|
# make warnings into errors but ignore certain third-party extension issues
|
||||||
error
|
error
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
numpy==1.16.6; python_version<"3.6" and sys_platform!="win32" and platform_python_implementation!="PyPy"
|
build==0.8.0
|
||||||
numpy==1.19.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.6"
|
numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
|
||||||
numpy==1.20.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
|
|
||||||
numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
|
numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
|
||||||
numpy==1.21.3; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.11"
|
numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"
|
||||||
py @ git+https://github.com/pytest-dev/py; python_version>="3.11"
|
numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11"
|
||||||
pytest==4.6.9; python_version<"3.5"
|
pytest==7.0.0
|
||||||
pytest==6.1.2; python_version=="3.5"
|
|
||||||
pytest==6.2.4; python_version>="3.6"
|
|
||||||
pytest-timeout
|
pytest-timeout
|
||||||
scipy==1.2.3; platform_python_implementation!="PyPy" and python_version<"3.6"
|
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.6" and python_version<"3.10"
|
scipy==1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10"
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
asyncio = pytest.importorskip("asyncio")
|
asyncio = pytest.importorskip("asyncio")
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import io
|
import io
|
||||||
import struct
|
import struct
|
||||||
@ -93,16 +92,16 @@ def test_pointer_to_member_fn():
|
|||||||
def test_readonly_buffer():
|
def test_readonly_buffer():
|
||||||
buf = m.BufferReadOnly(0x64)
|
buf = m.BufferReadOnly(0x64)
|
||||||
view = memoryview(buf)
|
view = memoryview(buf)
|
||||||
assert view[0] == b"d" if env.PY2 else 0x64
|
assert view[0] == 0x64
|
||||||
assert view.readonly
|
assert view.readonly
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
view[0] = b"\0" if env.PY2 else 0
|
view[0] = 0
|
||||||
|
|
||||||
|
|
||||||
def test_selective_readonly_buffer():
|
def test_selective_readonly_buffer():
|
||||||
buf = m.BufferReadOnlySelect()
|
buf = m.BufferReadOnlySelect()
|
||||||
|
|
||||||
memoryview(buf)[0] = b"d" if env.PY2 else 0x64
|
memoryview(buf)[0] = 0x64
|
||||||
assert buf.value == 0x64
|
assert buf.value == 0x64
|
||||||
|
|
||||||
io.BytesIO(b"A").readinto(buf)
|
io.BytesIO(b"A").readinto(buf)
|
||||||
@ -110,7 +109,7 @@ def test_selective_readonly_buffer():
|
|||||||
|
|
||||||
buf.readonly = True
|
buf.readonly = True
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
memoryview(buf)[0] = b"\0" if env.PY2 else 0
|
memoryview(buf)[0] = 0
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
io.BytesIO(b"1").readinto(buf)
|
io.BytesIO(b"1").readinto(buf)
|
||||||
|
|
||||||
@ -145,9 +144,6 @@ def test_ctypes_array_2d():
|
|||||||
assert not info.readonly
|
assert not info.readonly
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"env.PYPY and env.PY2", reason="PyPy2 bytes buffer not reported as readonly"
|
|
||||||
)
|
|
||||||
def test_ctypes_from_buffer():
|
def test_ctypes_from_buffer():
|
||||||
test_pystr = b"0123456789"
|
test_pystr = b"0123456789"
|
||||||
for pyarray in (test_pystr, bytearray(test_pystr)):
|
for pyarray in (test_pystr, bytearray(test_pystr)):
|
||||||
|
@ -110,8 +110,7 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
"def");
|
"def");
|
||||||
});
|
});
|
||||||
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
|
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
|
||||||
#if PY_MAJOR_VERSION >= 3
|
// Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
|
||||||
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger
|
|
||||||
// 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 (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
|
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
|
||||||
@ -119,7 +118,6 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
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'; });
|
||||||
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
m.def("u16_ibang", [=]() -> char16_t { return ib16; });
|
||||||
@ -198,12 +196,10 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
|
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
|
||||||
m.def("string_view_from_bytes",
|
m.def("string_view_from_bytes",
|
||||||
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
|
||||||
# if PY_MAJOR_VERSION >= 3
|
|
||||||
m.def("string_view_memoryview", []() {
|
m.def("string_view_memoryview", []() {
|
||||||
static constexpr auto val = "Have some \360\237\216\202"sv;
|
static constexpr auto val = "Have some \360\237\216\202"sv;
|
||||||
return py::memoryview::from_memory(val);
|
return py::memoryview::from_memory(val);
|
||||||
});
|
});
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef PYBIND11_HAS_U8STRING
|
# ifdef PYBIND11_HAS_U8STRING
|
||||||
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
|
||||||
@ -271,7 +267,8 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||||||
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
||||||
|
|
||||||
static std::pair<int, std::string> int_string_pair{2, "items"};
|
static std::pair<int, std::string> int_string_pair{2, "items"};
|
||||||
m.def("int_string_pair", []() { return &int_string_pair; });
|
m.def(
|
||||||
|
"int_string_pair", []() { return &int_string_pair; }, py::return_value_policy::reference);
|
||||||
|
|
||||||
// test_builtins_cast_return_none
|
// test_builtins_cast_return_none
|
||||||
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
import env
|
||||||
@ -12,12 +13,12 @@ def test_simple_string():
|
|||||||
|
|
||||||
def test_unicode_conversion():
|
def test_unicode_conversion():
|
||||||
"""Tests unicode conversion and error reporting."""
|
"""Tests unicode conversion and error reporting."""
|
||||||
assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀"
|
assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
|
||||||
assert m.good_utf16_string() == u"b‽🎂𝐀z"
|
assert m.good_utf16_string() == "b‽🎂𝐀z"
|
||||||
assert m.good_utf32_string() == u"a𝐀🎂‽z"
|
assert m.good_utf32_string() == "a𝐀🎂‽z"
|
||||||
assert m.good_wchar_string() == u"a⸘𝐀z"
|
assert m.good_wchar_string() == "a⸘𝐀z"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
|
assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
|
||||||
|
|
||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
m.bad_utf8_string()
|
m.bad_utf8_string()
|
||||||
@ -25,7 +26,7 @@ def test_unicode_conversion():
|
|||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
m.bad_utf16_string()
|
m.bad_utf16_string()
|
||||||
|
|
||||||
# These are provided only if they actually fail (they don't when 32-bit and under Python 2.7)
|
# These are provided only if they actually fail (they don't when 32-bit)
|
||||||
if hasattr(m, "bad_utf32_string"):
|
if hasattr(m, "bad_utf32_string"):
|
||||||
with pytest.raises(UnicodeDecodeError):
|
with pytest.raises(UnicodeDecodeError):
|
||||||
m.bad_utf32_string()
|
m.bad_utf32_string()
|
||||||
@ -37,10 +38,10 @@ def test_unicode_conversion():
|
|||||||
m.bad_utf8_u8string()
|
m.bad_utf8_u8string()
|
||||||
|
|
||||||
assert m.u8_Z() == "Z"
|
assert m.u8_Z() == "Z"
|
||||||
assert m.u8_eacute() == u"é"
|
assert m.u8_eacute() == "é"
|
||||||
assert m.u16_ibang() == u"‽"
|
assert m.u16_ibang() == "‽"
|
||||||
assert m.u32_mathbfA() == u"𝐀"
|
assert m.u32_mathbfA() == "𝐀"
|
||||||
assert m.wchar_heart() == u"♥"
|
assert m.wchar_heart() == "♥"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.u8_char8_Z() == "Z"
|
assert m.u8_char8_Z() == "Z"
|
||||||
|
|
||||||
@ -49,72 +50,72 @@ def test_single_char_arguments():
|
|||||||
"""Tests failures for passing invalid inputs to char-accepting functions"""
|
"""Tests failures for passing invalid inputs to char-accepting functions"""
|
||||||
|
|
||||||
def toobig_message(r):
|
def toobig_message(r):
|
||||||
return "Character code point not in range({:#x})".format(r)
|
return f"Character code point not in range({r:#x})"
|
||||||
|
|
||||||
toolong_message = "Expected a character, but multi-character string found"
|
toolong_message = "Expected a character, but multi-character string found"
|
||||||
|
|
||||||
assert m.ord_char(u"a") == 0x61 # simple ASCII
|
assert m.ord_char("a") == 0x61 # simple ASCII
|
||||||
assert m.ord_char_lv(u"b") == 0x62
|
assert m.ord_char_lv("b") == 0x62
|
||||||
assert (
|
assert (
|
||||||
m.ord_char(u"é") == 0xE9
|
m.ord_char("é") == 0xE9
|
||||||
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
assert m.ord_char("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||||
assert str(excinfo.value) == toobig_message(0x100)
|
assert str(excinfo.value) == toobig_message(0x100)
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char(u"ab")
|
assert m.ord_char("ab")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
assert m.ord_char16(u"a") == 0x61
|
assert m.ord_char16("a") == 0x61
|
||||||
assert m.ord_char16(u"é") == 0xE9
|
assert m.ord_char16("é") == 0xE9
|
||||||
assert m.ord_char16_lv(u"ê") == 0xEA
|
assert m.ord_char16_lv("ê") == 0xEA
|
||||||
assert m.ord_char16(u"Ā") == 0x100
|
assert m.ord_char16("Ā") == 0x100
|
||||||
assert m.ord_char16(u"‽") == 0x203D
|
assert m.ord_char16("‽") == 0x203D
|
||||||
assert m.ord_char16(u"♥") == 0x2665
|
assert m.ord_char16("♥") == 0x2665
|
||||||
assert m.ord_char16_lv(u"♡") == 0x2661
|
assert m.ord_char16_lv("♡") == 0x2661
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char16(u"🎂") == 0x1F382 # requires surrogate pair
|
assert m.ord_char16("🎂") == 0x1F382 # requires surrogate pair
|
||||||
assert str(excinfo.value) == toobig_message(0x10000)
|
assert str(excinfo.value) == toobig_message(0x10000)
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char16(u"aa")
|
assert m.ord_char16("aa")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
assert m.ord_char32(u"a") == 0x61
|
assert m.ord_char32("a") == 0x61
|
||||||
assert m.ord_char32(u"é") == 0xE9
|
assert m.ord_char32("é") == 0xE9
|
||||||
assert m.ord_char32(u"Ā") == 0x100
|
assert m.ord_char32("Ā") == 0x100
|
||||||
assert m.ord_char32(u"‽") == 0x203D
|
assert m.ord_char32("‽") == 0x203D
|
||||||
assert m.ord_char32(u"♥") == 0x2665
|
assert m.ord_char32("♥") == 0x2665
|
||||||
assert m.ord_char32(u"🎂") == 0x1F382
|
assert m.ord_char32("🎂") == 0x1F382
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char32(u"aa")
|
assert m.ord_char32("aa")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
assert m.ord_wchar(u"a") == 0x61
|
assert m.ord_wchar("a") == 0x61
|
||||||
assert m.ord_wchar(u"é") == 0xE9
|
assert m.ord_wchar("é") == 0xE9
|
||||||
assert m.ord_wchar(u"Ā") == 0x100
|
assert m.ord_wchar("Ā") == 0x100
|
||||||
assert m.ord_wchar(u"‽") == 0x203D
|
assert m.ord_wchar("‽") == 0x203D
|
||||||
assert m.ord_wchar(u"♥") == 0x2665
|
assert m.ord_wchar("♥") == 0x2665
|
||||||
if m.wchar_size == 2:
|
if m.wchar_size == 2:
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_wchar(u"🎂") == 0x1F382 # requires surrogate pair
|
assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair
|
||||||
assert str(excinfo.value) == toobig_message(0x10000)
|
assert str(excinfo.value) == toobig_message(0x10000)
|
||||||
else:
|
else:
|
||||||
assert m.ord_wchar(u"🎂") == 0x1F382
|
assert m.ord_wchar("🎂") == 0x1F382
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_wchar(u"aa")
|
assert m.ord_wchar("aa")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.ord_char8(u"a") == 0x61 # simple ASCII
|
assert m.ord_char8("a") == 0x61 # simple ASCII
|
||||||
assert m.ord_char8_lv(u"b") == 0x62
|
assert m.ord_char8_lv("b") == 0x62
|
||||||
assert (
|
assert (
|
||||||
m.ord_char8(u"é") == 0xE9
|
m.ord_char8("é") == 0xE9
|
||||||
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
) # requires 2 bytes in utf-8, but can be stuffed in a char
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char8(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
assert m.ord_char8("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
|
||||||
assert str(excinfo.value) == toobig_message(0x100)
|
assert str(excinfo.value) == toobig_message(0x100)
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
assert m.ord_char8(u"ab")
|
assert m.ord_char8("ab")
|
||||||
assert str(excinfo.value) == toolong_message
|
assert str(excinfo.value) == toolong_message
|
||||||
|
|
||||||
|
|
||||||
@ -123,18 +124,22 @@ def test_bytes_to_string():
|
|||||||
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
||||||
# Issue #816
|
# Issue #816
|
||||||
|
|
||||||
def to_bytes(s):
|
assert m.strlen(b"hi") == 2
|
||||||
b = s if env.PY2 else s.encode("utf8")
|
assert m.string_length(b"world") == 5
|
||||||
assert isinstance(b, bytes)
|
assert m.string_length("a\x00b".encode()) == 3
|
||||||
return b
|
assert m.strlen("a\x00b".encode()) == 1 # C-string limitation
|
||||||
|
|
||||||
assert m.strlen(to_bytes("hi")) == 2
|
|
||||||
assert m.string_length(to_bytes("world")) == 5
|
|
||||||
assert m.string_length(to_bytes("a\x00b")) == 3
|
|
||||||
assert m.strlen(to_bytes("a\x00b")) == 1 # C-string limitation
|
|
||||||
|
|
||||||
# passing in a utf8 encoded string should work
|
# passing in a utf8 encoded string should work
|
||||||
assert m.string_length(u"💩".encode("utf8")) == 4
|
assert m.string_length("💩".encode()) == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_bytearray_to_string():
|
||||||
|
"""Tests the ability to pass bytearray to C++ string-accepting functions"""
|
||||||
|
assert m.string_length(bytearray(b"Hi")) == 2
|
||||||
|
assert m.strlen(bytearray(b"bytearray")) == 9
|
||||||
|
assert m.string_length(bytearray()) == 0
|
||||||
|
assert m.string_length(bytearray("🦜", "utf-8", "strict")) == 4
|
||||||
|
assert m.string_length(bytearray(b"\x80")) == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
|
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
|
||||||
@ -142,26 +147,26 @@ def test_string_view(capture):
|
|||||||
"""Tests support for C++17 string_view arguments and return values"""
|
"""Tests support for C++17 string_view arguments and return values"""
|
||||||
assert m.string_view_chars("Hi") == [72, 105]
|
assert m.string_view_chars("Hi") == [72, 105]
|
||||||
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||||
assert m.string_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
|
||||||
assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874]
|
assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.string_view8_chars("Hi") == [72, 105]
|
assert m.string_view8_chars("Hi") == [72, 105]
|
||||||
assert m.string_view8_chars(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
|
||||||
|
|
||||||
assert m.string_view_return() == u"utf8 secret 🎂"
|
assert m.string_view_return() == "utf8 secret 🎂"
|
||||||
assert m.string_view16_return() == u"utf16 secret 🎂"
|
assert m.string_view16_return() == "utf16 secret 🎂"
|
||||||
assert m.string_view32_return() == u"utf32 secret 🎂"
|
assert m.string_view32_return() == "utf32 secret 🎂"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.string_view8_return() == u"utf8 secret 🎂"
|
assert m.string_view8_return() == "utf8 secret 🎂"
|
||||||
|
|
||||||
with capture:
|
with capture:
|
||||||
m.string_view_print("Hi")
|
m.string_view_print("Hi")
|
||||||
m.string_view_print("utf8 🎂")
|
m.string_view_print("utf8 🎂")
|
||||||
m.string_view16_print(u"utf16 🎂")
|
m.string_view16_print("utf16 🎂")
|
||||||
m.string_view32_print(u"utf32 🎂")
|
m.string_view32_print("utf32 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi 2
|
Hi 2
|
||||||
utf8 🎂 9
|
utf8 🎂 9
|
||||||
utf16 🎂 8
|
utf16 🎂 8
|
||||||
@ -171,10 +176,10 @@ def test_string_view(capture):
|
|||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
with capture:
|
with capture:
|
||||||
m.string_view8_print("Hi")
|
m.string_view8_print("Hi")
|
||||||
m.string_view8_print(u"utf8 🎂")
|
m.string_view8_print("utf8 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi 2
|
Hi 2
|
||||||
utf8 🎂 9
|
utf8 🎂 9
|
||||||
"""
|
"""
|
||||||
@ -183,11 +188,11 @@ def test_string_view(capture):
|
|||||||
with capture:
|
with capture:
|
||||||
m.string_view_print("Hi, ascii")
|
m.string_view_print("Hi, ascii")
|
||||||
m.string_view_print("Hi, utf8 🎂")
|
m.string_view_print("Hi, utf8 🎂")
|
||||||
m.string_view16_print(u"Hi, utf16 🎂")
|
m.string_view16_print("Hi, utf16 🎂")
|
||||||
m.string_view32_print(u"Hi, utf32 🎂")
|
m.string_view32_print("Hi, utf32 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi, ascii 9
|
Hi, ascii 9
|
||||||
Hi, utf8 🎂 13
|
Hi, utf8 🎂 13
|
||||||
Hi, utf16 🎂 12
|
Hi, utf16 🎂 12
|
||||||
@ -197,22 +202,21 @@ def test_string_view(capture):
|
|||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
with capture:
|
with capture:
|
||||||
m.string_view8_print("Hi, ascii")
|
m.string_view8_print("Hi, ascii")
|
||||||
m.string_view8_print(u"Hi, utf8 🎂")
|
m.string_view8_print("Hi, utf8 🎂")
|
||||||
assert (
|
assert (
|
||||||
capture
|
capture
|
||||||
== u"""
|
== """
|
||||||
Hi, ascii 9
|
Hi, ascii 9
|
||||||
Hi, utf8 🎂 13
|
Hi, utf8 🎂 13
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
assert m.string_view_bytes() == b"abc \x80\x80 def"
|
||||||
assert m.string_view_str() == u"abc ‽ def"
|
assert m.string_view_str() == "abc ‽ def"
|
||||||
assert m.string_view_from_bytes(u"abc ‽ def".encode("utf-8")) == u"abc ‽ def"
|
assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
|
||||||
if hasattr(m, "has_u8string"):
|
if hasattr(m, "has_u8string"):
|
||||||
assert m.string_view8_str() == u"abc ‽ def"
|
assert m.string_view8_str() == "abc ‽ def"
|
||||||
if not env.PY2:
|
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
||||||
assert m.string_view_memoryview() == "Have some 🎂".encode()
|
|
||||||
|
|
||||||
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
|
||||||
assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
|
assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
|
||||||
@ -224,20 +228,8 @@ def test_integer_casting():
|
|||||||
assert m.i64_str(-1) == "-1"
|
assert m.i64_str(-1) == "-1"
|
||||||
assert m.i32_str(2000000000) == "2000000000"
|
assert m.i32_str(2000000000) == "2000000000"
|
||||||
assert m.u32_str(2000000000) == "2000000000"
|
assert m.u32_str(2000000000) == "2000000000"
|
||||||
if env.PY2:
|
assert m.i64_str(-999999999999) == "-999999999999"
|
||||||
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
assert m.u64_str(999999999999) == "999999999999"
|
||||||
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
|
||||||
assert (
|
|
||||||
m.i64_str(long(-999999999999)) # noqa: F821 undefined name 'long'
|
|
||||||
== "-999999999999"
|
|
||||||
)
|
|
||||||
assert (
|
|
||||||
m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long'
|
|
||||||
== "999999999999"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
assert m.i64_str(-999999999999) == "-999999999999"
|
|
||||||
assert m.u64_str(999999999999) == "999999999999"
|
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
m.u32_str(-1)
|
m.u32_str(-1)
|
||||||
@ -252,46 +244,38 @@ def test_integer_casting():
|
|||||||
m.i32_str(3000000000)
|
m.i32_str(3000000000)
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
if env.PY2:
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
|
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
|
||||||
m.u64_str(long(-1)) # noqa: F821 undefined name 'long'
|
|
||||||
assert "incompatible function arguments" in str(excinfo.value)
|
|
||||||
|
|
||||||
|
|
||||||
def test_int_convert():
|
def test_int_convert():
|
||||||
class Int(object):
|
class Int:
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class NotInt(object):
|
class NotInt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Float(object):
|
class Float:
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
return 41.99999
|
return 41.99999
|
||||||
|
|
||||||
class Index(object):
|
class Index:
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class IntAndIndex(object):
|
class IntAndIndex:
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
class RaisingTypeErrorOnIndex(object):
|
class RaisingTypeErrorOnIndex:
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class RaisingValueErrorOnIndex(object):
|
class RaisingValueErrorOnIndex:
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@ -311,7 +295,7 @@ def test_int_convert():
|
|||||||
cant_convert(3.14159)
|
cant_convert(3.14159)
|
||||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||||
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
||||||
if (3, 8) <= env.PY < (3, 10) and env.CPYTHON:
|
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
||||||
with env.deprecated_call():
|
with env.deprecated_call():
|
||||||
assert convert(Int()) == 42
|
assert convert(Int()) == 42
|
||||||
else:
|
else:
|
||||||
@ -348,7 +332,7 @@ def test_numpy_int_convert():
|
|||||||
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
|
||||||
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
|
||||||
# https://github.com/pybind/pybind11/issues/3408
|
# https://github.com/pybind/pybind11/issues/3408
|
||||||
if (3, 8) <= env.PY < (3, 10) and env.CPYTHON:
|
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
|
||||||
with env.deprecated_call():
|
with env.deprecated_call():
|
||||||
assert convert(np.float32(3.14159)) == 3
|
assert convert(np.float32(3.14159)) == 3
|
||||||
else:
|
else:
|
||||||
@ -475,7 +459,7 @@ def test_bool_caster():
|
|||||||
require_implicit(None)
|
require_implicit(None)
|
||||||
assert convert(None) is False
|
assert convert(None) is False
|
||||||
|
|
||||||
class A(object):
|
class A:
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
self.x = x
|
self.x = x
|
||||||
|
|
||||||
@ -485,7 +469,7 @@ def test_bool_caster():
|
|||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
return self.x
|
return self.x
|
||||||
|
|
||||||
class B(object):
|
class B:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Arbitrary objects are not accepted
|
# Arbitrary objects are not accepted
|
||||||
@ -515,17 +499,9 @@ def test_numpy_bool():
|
|||||||
|
|
||||||
|
|
||||||
def test_int_long():
|
def test_int_long():
|
||||||
"""In Python 2, a C++ int should return a Python int rather than long
|
|
||||||
if possible: longs are not always accepted where ints are used (such
|
|
||||||
as the argument to sys.exit()). A C++ long long is always a Python
|
|
||||||
long."""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
must_be_long = type(getattr(sys, "maxint", 1) + 1)
|
|
||||||
assert isinstance(m.int_cast(), int)
|
assert isinstance(m.int_cast(), int)
|
||||||
assert isinstance(m.long_cast(), int)
|
assert isinstance(m.long_cast(), int)
|
||||||
assert isinstance(m.longlong_cast(), must_be_long)
|
assert isinstance(m.longlong_cast(), int)
|
||||||
|
|
||||||
|
|
||||||
def test_void_caster_2():
|
def test_void_caster_2():
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import time
|
import time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
@ -18,7 +17,7 @@ def test_callbacks():
|
|||||||
return "func2", a, b, c, d
|
return "func2", a, b, c, d
|
||||||
|
|
||||||
def func3(a):
|
def func3(a):
|
||||||
return "func3({})".format(a)
|
return f"func3({a})"
|
||||||
|
|
||||||
assert m.test_callback1(func1) == "func1"
|
assert m.test_callback1(func1) == "func1"
|
||||||
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
|
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
|
||||||
@ -189,14 +188,8 @@ def test_callback_num_times():
|
|||||||
if not rep:
|
if not rep:
|
||||||
print()
|
print()
|
||||||
print(
|
print(
|
||||||
"callback_num_times: {:d} million / {:.3f} seconds = {:.3f} million / second".format(
|
f"callback_num_times: {num_millions:d} million / {td:.3f} seconds = {rate:.3f} million / second"
|
||||||
num_millions, td, rate
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if len(rates) > 1:
|
if len(rates) > 1:
|
||||||
print("Min Mean Max")
|
print("Min Mean Max")
|
||||||
print(
|
print(f"{min(rates):6.3f} {sum(rates) / len(rates):6.3f} {max(rates):6.3f}")
|
||||||
"{:6.3f} {:6.3f} {:6.3f}".format(
|
|
||||||
min(rates), sum(rates) / len(rates), max(rates)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -101,7 +100,7 @@ SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
|
|||||||
)
|
)
|
||||||
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
|
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
|
||||||
if tz is not None:
|
if tz is not None:
|
||||||
monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz))
|
monkeypatch.setenv("TZ", f"/usr/share/zoneinfo/{tz}")
|
||||||
|
|
||||||
# Roundtrip the time
|
# Roundtrip the time
|
||||||
datetime2 = m.test_chrono2(time1)
|
datetime2 = m.test_chrono2(time1)
|
||||||
|
@ -354,13 +354,7 @@ TEST_SUBMODULE(class_, m) {
|
|||||||
using ProtectedA::foo;
|
using ProtectedA::foo;
|
||||||
};
|
};
|
||||||
|
|
||||||
py::class_<ProtectedA>(m, "ProtectedA")
|
py::class_<ProtectedA>(m, "ProtectedA").def(py::init<>()).def("foo", &PublicistA::foo);
|
||||||
.def(py::init<>())
|
|
||||||
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
|
||||||
.def("foo", &PublicistA::foo);
|
|
||||||
#else
|
|
||||||
.def("foo", static_cast<int (ProtectedA::*)() const>(&PublicistA::foo));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ProtectedB {
|
class ProtectedB {
|
||||||
public:
|
public:
|
||||||
@ -391,11 +385,7 @@ TEST_SUBMODULE(class_, m) {
|
|||||||
|
|
||||||
py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
|
py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
|
||||||
.def("foo", &PublicistB::foo);
|
.def("foo", &PublicistB::foo);
|
||||||
#else
|
|
||||||
.def("foo", static_cast<int (ProtectedB::*)() const>(&PublicistB::foo));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// test_brace_initialization
|
// test_brace_initialization
|
||||||
struct BraceInitialization {
|
struct BraceInitialization {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -7,7 +6,6 @@ from pybind11_tests import class_ as m
|
|||||||
|
|
||||||
|
|
||||||
def test_repr():
|
def test_repr():
|
||||||
# In Python 3.3+, repr() accesses __qualname__
|
|
||||||
assert "pybind11_type" in repr(type(UserType))
|
assert "pybind11_type" in repr(type(UserType))
|
||||||
assert "UserType" in repr(UserType)
|
assert "UserType" in repr(UserType)
|
||||||
|
|
||||||
@ -103,8 +101,8 @@ def test_docstrings(doc):
|
|||||||
|
|
||||||
|
|
||||||
def test_qualname(doc):
|
def test_qualname(doc):
|
||||||
"""Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
|
"""Tests that a properly qualified name is set in __qualname__ and that
|
||||||
backport the attribute) and that generated docstrings properly use it and the module name"""
|
generated docstrings properly use it and the module name"""
|
||||||
assert m.NestBase.__qualname__ == "NestBase"
|
assert m.NestBase.__qualname__ == "NestBase"
|
||||||
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
|
||||||
|
|
||||||
@ -130,13 +128,13 @@ def test_qualname(doc):
|
|||||||
doc(m.NestBase.Nested.fn)
|
doc(m.NestBase.Nested.fn)
|
||||||
== """
|
== """
|
||||||
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
doc(m.NestBase.Nested.fa)
|
doc(m.NestBase.Nested.fa)
|
||||||
== """
|
== """
|
||||||
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
||||||
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
|
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import test_cmake_build
|
import test_cmake_build
|
||||||
|
|
||||||
if str is not bytes: # If not Python2
|
assert isinstance(__file__, str) # Test this is properly set
|
||||||
assert isinstance(__file__, str) # Test this is properly set
|
|
||||||
|
|
||||||
assert test_cmake_build.add(1, 2) == 3
|
assert test_cmake_build.add(1, 2) == 3
|
||||||
print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
|
print(f"{sys.argv[1]} imports, runs, and adds: 1 + 2 = 3")
|
||||||
|
@ -4,65 +4,50 @@
|
|||||||
|
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
|
||||||
|
|
||||||
// MSVC 2015 fails in bizarre ways.
|
|
||||||
# define PYBIND11_SKIP_TEST_CONST_NAME
|
|
||||||
|
|
||||||
#else // Only test with MSVC 2017 or newer.
|
|
||||||
|
|
||||||
// IUT = Implementation Under Test
|
// IUT = Implementation Under Test
|
||||||
# define CONST_NAME_TESTS(TEST_FUNC, IUT) \
|
#define CONST_NAME_TESTS(TEST_FUNC, IUT) \
|
||||||
std::string TEST_FUNC(int selector) { \
|
std::string TEST_FUNC(int selector) { \
|
||||||
switch (selector) { \
|
switch (selector) { \
|
||||||
case 0: \
|
case 0: \
|
||||||
return IUT("").text; \
|
return IUT("").text; \
|
||||||
case 1: \
|
case 1: \
|
||||||
return IUT("A").text; \
|
return IUT("A").text; \
|
||||||
case 2: \
|
case 2: \
|
||||||
return IUT("Bd").text; \
|
return IUT("Bd").text; \
|
||||||
case 3: \
|
case 3: \
|
||||||
return IUT("Cef").text; \
|
return IUT("Cef").text; \
|
||||||
case 4: \
|
case 4: \
|
||||||
return IUT<int>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
return IUT<int>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||||
case 5: \
|
case 5: \
|
||||||
return IUT<std::string>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
return IUT<std::string>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||||
case 6: \
|
case 6: \
|
||||||
return IUT<true>("T1", "T2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
return IUT<true>("T1", "T2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||||
case 7: \
|
case 7: \
|
||||||
return IUT<false>("U1", "U2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
return IUT<false>("U1", "U2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||||
case 8: \
|
case 8: \
|
||||||
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
||||||
return IUT<true>(IUT("D1"), IUT("D2")).text; \
|
return IUT<true>(IUT("D1"), IUT("D2")).text; \
|
||||||
case 9: \
|
case 9: \
|
||||||
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
/*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
|
||||||
return IUT<false>(IUT("E1"), IUT("E2")).text; \
|
return IUT<false>(IUT("E1"), IUT("E2")).text; \
|
||||||
case 10: \
|
case 10: \
|
||||||
return IUT("KeepAtEnd").text; \
|
return IUT("KeepAtEnd").text; \
|
||||||
default: \
|
default: \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
throw std::runtime_error("Invalid selector value."); \
|
throw std::runtime_error("Invalid selector value."); \
|
||||||
}
|
}
|
||||||
|
|
||||||
CONST_NAME_TESTS(const_name_tests, py::detail::const_name)
|
CONST_NAME_TESTS(const_name_tests, py::detail::const_name)
|
||||||
|
|
||||||
# ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
||||||
CONST_NAME_TESTS(underscore_tests, py::detail::_)
|
CONST_NAME_TESTS(underscore_tests, py::detail::_)
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // MSVC >= 2017
|
|
||||||
|
|
||||||
TEST_SUBMODULE(const_name, m) {
|
|
||||||
#ifdef PYBIND11_SKIP_TEST_CONST_NAME
|
|
||||||
m.attr("const_name_tests") = "PYBIND11_SKIP_TEST_CONST_NAME";
|
|
||||||
#else
|
|
||||||
m.def("const_name_tests", const_name_tests);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PYBIND11_SKIP_TEST_CONST_NAME
|
TEST_SUBMODULE(const_name, m) {
|
||||||
m.attr("underscore_tests") = "PYBIND11_SKIP_TEST_CONST_NAME";
|
m.def("const_name_tests", const_name_tests);
|
||||||
#elif defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY)
|
|
||||||
|
#if defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY)
|
||||||
m.def("underscore_tests", underscore_tests);
|
m.def("underscore_tests", underscore_tests);
|
||||||
#else
|
#else
|
||||||
m.attr("underscore_tests") = "PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY not defined.";
|
m.attr("underscore_tests") = "PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY not defined.";
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env
|
|
||||||
from pybind11_tests import const_name as m
|
from pybind11_tests import const_name as m
|
||||||
|
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ from pybind11_tests import const_name as m
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_const_name(func, selector, expected):
|
def test_const_name(func, selector, expected):
|
||||||
if isinstance(func, type(u"") if env.PY2 else str):
|
if isinstance(func, str):
|
||||||
pytest.skip(func)
|
pytest.skip(func)
|
||||||
text = func(selector)
|
text = func(selector)
|
||||||
assert text == expected
|
assert text == expected
|
||||||
|
@ -31,8 +31,8 @@ py::bytes return_bytes() {
|
|||||||
std::string print_bytes(const py::bytes &bytes) {
|
std::string print_bytes(const py::bytes &bytes) {
|
||||||
std::string ret = "bytes[";
|
std::string ret = "bytes[";
|
||||||
const auto value = static_cast<std::string>(bytes);
|
const auto value = static_cast<std::string>(bytes);
|
||||||
for (size_t i = 0; i < value.length(); ++i) {
|
for (char c : value) {
|
||||||
ret += std::to_string(static_cast<int>(value[i])) + " ";
|
ret += std::to_string(static_cast<int>(c)) + ' ';
|
||||||
}
|
}
|
||||||
ret.back() = ']';
|
ret.back() = ']';
|
||||||
return ret;
|
return ret;
|
||||||
@ -137,18 +137,15 @@ TEST_SUBMODULE(constants_and_functions, m) {
|
|||||||
m.def("f4", f4);
|
m.def("f4", f4);
|
||||||
|
|
||||||
// test_function_record_leaks
|
// test_function_record_leaks
|
||||||
struct LargeCapture {
|
m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
|
||||||
// This should always be enough to trigger the alternative branch
|
// This should always be enough to trigger the alternative branch
|
||||||
// where `sizeof(capture) > sizeof(rec->data)`
|
// where `sizeof(capture) > sizeof(rec->data)`
|
||||||
uint64_t zeros[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
uint64_t capture[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||||
};
|
#if defined(__GNUC__) && __GNUC__ == 4 // CentOS7
|
||||||
m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
|
py::detail::silence_unused_warnings(capture);
|
||||||
LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here
|
#endif
|
||||||
m.def(
|
m.def(
|
||||||
"should_raise",
|
"should_raise", [capture](int) { return capture[9] + 33; }, py::kw_only(), py::arg());
|
||||||
[capture](int) { return capture.zeros[9] + 33; },
|
|
||||||
py::kw_only(),
|
|
||||||
py::arg());
|
|
||||||
});
|
});
|
||||||
m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
|
m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
|
||||||
m.def(
|
m.def(
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
||||||
|
@ -289,4 +289,7 @@ TEST_SUBMODULE(copy_move_policies, m) {
|
|||||||
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
|
||||||
|
m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import copy_move_policies as m
|
from pybind11_tests import copy_move_policies as m
|
||||||
@ -124,3 +123,10 @@ def test_move_fallback():
|
|||||||
assert m1.value == 1
|
assert m1.value == 1
|
||||||
m2 = m.get_moveissue2(2)
|
m2 = m.get_moveissue2(2)
|
||||||
assert m2.value == 2
|
assert m2.value == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytype_rvalue_cast():
|
||||||
|
"""Make sure that cast from pytype rvalue to other pytype works"""
|
||||||
|
|
||||||
|
value = m.get_pytype_rvalue_castissue(1.0)
|
||||||
|
assert value == 1
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import custom_type_casters as m
|
from pybind11_tests import custom_type_casters as m
|
||||||
@ -19,7 +18,7 @@ def test_noconvert_args(msg):
|
|||||||
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
||||||
13
|
13
|
||||||
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
msg(a.g("this is a", "this is b", 42))
|
msg(a.g("this is a", "this is b", 42))
|
||||||
@ -28,7 +27,7 @@ def test_noconvert_args(msg):
|
|||||||
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
|
||||||
42
|
42
|
||||||
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
msg(a.g("this is a", "this is b", 42, "this is d"))
|
msg(a.g("this is a", "this is b", 42, "this is d"))
|
||||||
@ -76,7 +75,7 @@ def test_noconvert_args(msg):
|
|||||||
1. (i: int) -> int
|
1. (i: int) -> int
|
||||||
|
|
||||||
Invoked with: 4.0
|
Invoked with: 4.0
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
assert m.ints_only(4) == 2
|
assert m.ints_only(4) == 2
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import gc
|
import gc
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from pybind11_tests import docstring_options as m
|
from pybind11_tests import docstring_options as m
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,9 +14,6 @@
|
|||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# if _MSC_VER < 1910 // VS 2015's MSVC
|
|
||||||
# pragma warning(disable : 4127) // C4127: conditional expression is constant
|
|
||||||
# endif
|
|
||||||
# pragma warning(disable : 4996) // C4996: std::unary_negation is deprecated
|
# pragma warning(disable : 4996) // C4996: std::unary_negation is deprecated
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -348,10 +345,13 @@ TEST_SUBMODULE(eigen, m) {
|
|||||||
},
|
},
|
||||||
py::arg{}.noconvert());
|
py::arg{}.noconvert());
|
||||||
|
|
||||||
// test_issue738
|
// test_issue738, test_zero_length
|
||||||
// Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an
|
// Issue #738: 1×N or N×1 2D matrices were neither accepted nor properly copied with an
|
||||||
// incompatible stride value on the length-1 dimension--but that should be allowed (without
|
// incompatible stride value on the length-1 dimension--but that should be allowed (without
|
||||||
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
|
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
|
||||||
|
// Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since
|
||||||
|
// they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to
|
||||||
|
// 0 if any dimension size is 0.
|
||||||
m.def("iss738_f1",
|
m.def("iss738_f1",
|
||||||
&adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
|
&adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
|
||||||
py::arg{}.noconvert());
|
py::arg{}.noconvert());
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import ConstructorStats
|
from pybind11_tests import ConstructorStats
|
||||||
@ -201,7 +200,7 @@ def test_negative_stride_from_python(msg):
|
|||||||
double_threer(): incompatible function arguments. The following argument types are supported:
|
double_threer(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
|
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
|
||||||
|
|
||||||
Invoked with: """ # noqa: E501 line too long
|
Invoked with: """
|
||||||
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -213,7 +212,7 @@ def test_negative_stride_from_python(msg):
|
|||||||
double_threec(): incompatible function arguments. The following argument types are supported:
|
double_threec(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
|
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
|
||||||
|
|
||||||
Invoked with: """ # noqa: E501 line too long
|
Invoked with: """
|
||||||
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -222,9 +221,7 @@ def test_nonunit_stride_to_python():
|
|||||||
assert np.all(m.diagonal(ref) == ref.diagonal())
|
assert np.all(m.diagonal(ref) == ref.diagonal())
|
||||||
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
||||||
for i in range(-5, 7):
|
for i in range(-5, 7):
|
||||||
assert np.all(
|
assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})"
|
||||||
m.diagonal_n(ref, i) == ref.diagonal(i)
|
|
||||||
), "m.diagonal_n({})".format(i)
|
|
||||||
|
|
||||||
assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
|
assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
|
||||||
assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
|
assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
|
||||||
@ -237,7 +234,7 @@ def test_eigen_ref_to_python():
|
|||||||
mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]]))
|
mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]]))
|
||||||
assert np.all(
|
assert np.all(
|
||||||
mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])
|
mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])
|
||||||
), "cholesky{}".format(i)
|
), f"cholesky{i}"
|
||||||
|
|
||||||
|
|
||||||
def assign_both(a1, a2, r, c, v):
|
def assign_both(a1, a2, r, c, v):
|
||||||
@ -724,13 +721,13 @@ def test_sparse_signature(doc):
|
|||||||
doc(m.sparse_copy_r)
|
doc(m.sparse_copy_r)
|
||||||
== """
|
== """
|
||||||
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
doc(m.sparse_copy_c)
|
doc(m.sparse_copy_c)
|
||||||
== """
|
== """
|
||||||
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
|
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
|
||||||
""" # noqa: E501 line too long
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -747,6 +744,13 @@ def test_issue738():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("func", [m.iss738_f1, m.iss738_f2])
|
||||||
|
@pytest.mark.parametrize("sizes", [(0, 2), (2, 0)])
|
||||||
|
def test_zero_length(func, sizes):
|
||||||
|
"""Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)"""
|
||||||
|
assert np.all(func(np.zeros(sizes)) == np.zeros(sizes))
|
||||||
|
|
||||||
|
|
||||||
def test_issue1105():
|
def test_issue1105():
|
||||||
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
|
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
|
||||||
compile-time row vectors or column vector"""
|
compile-time row vectors or column vector"""
|
||||||
|
@ -7,7 +7,7 @@ if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STR
|
|||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Catch 2.13.5)
|
find_package(Catch 2.13.9)
|
||||||
|
|
||||||
if(CATCH_FOUND)
|
if(CATCH_FOUND)
|
||||||
message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")
|
message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user