Merge pull request #1024 from YosysHQ/gatecat/pybind11-bump
3rdparty: Bump vendored pybind11 version for py3.11 support
This commit is contained in:
commit
3983d4fe53
8
3rdparty/pybind11/.appveyor.yml
vendored
8
3rdparty/pybind11/.appveyor.yml
vendored
@ -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,15 +11,13 @@ 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
|
||||||
python -W ignore -m pip install pytest numpy --no-warn-script-location
|
python -W ignore -m pip install pytest numpy --no-warn-script-location pytest-timeout
|
||||||
- ps: |
|
- ps: |
|
||||||
Start-FileDownload 'https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.zip'
|
Start-FileDownload 'https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.zip'
|
||||||
7z x eigen-3.3.7.zip -y > $null
|
7z x eigen-3.3.7.zip -y > $null
|
||||||
|
38
3rdparty/pybind11/.clang-format
vendored
Normal file
38
3rdparty/pybind11/.clang-format
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
# See all possible options and defaults with:
|
||||||
|
# clang-format --style=llvm --dump-config
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AllowShortLambdasOnASingleLine: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
ColumnLimit: 99
|
||||||
|
CommentPragmas: 'NOLINT:.*|^ IWYU pragma:'
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentWidth: 4
|
||||||
|
Language: Cpp
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
Standard: Cpp11
|
||||||
|
StatementMacros: ['PyObject_HEAD']
|
||||||
|
TabWidth: 4
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '<pybind11/.*'
|
||||||
|
Priority: -1
|
||||||
|
- Regex: 'pybind11.h"$'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^".*/?detail/'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 2
|
||||||
|
- Regex: '^"'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 3
|
||||||
|
- Regex: '<[[:alnum:]._]+>'
|
||||||
|
Priority: 4
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 5
|
||||||
|
...
|
82
3rdparty/pybind11/.clang-tidy
vendored
82
3rdparty/pybind11/.clang-tidy
vendored
@ -1,13 +1,77 @@
|
|||||||
FormatStyle: file
|
FormatStyle: file
|
||||||
|
|
||||||
Checks: '
|
Checks: |
|
||||||
llvm-namespace-comment,
|
*bugprone*,
|
||||||
modernize-use-override,
|
*performance*,
|
||||||
readability-container-size-empty,
|
clang-analyzer-optin.cplusplus.VirtualCall,
|
||||||
modernize-use-using,
|
clang-analyzer-optin.performance.Padding,
|
||||||
modernize-use-equals-default,
|
cppcoreguidelines-init-variables,
|
||||||
modernize-use-auto,
|
cppcoreguidelines-prefer-member-initializer,
|
||||||
modernize-use-emplace,
|
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
'
|
cppcoreguidelines-slicing,
|
||||||
|
google-explicit-constructor,
|
||||||
|
llvm-namespace-comment,
|
||||||
|
misc-definitions-in-headers,
|
||||||
|
misc-misplaced-const,
|
||||||
|
misc-non-copyable-objects,
|
||||||
|
misc-static-assert,
|
||||||
|
misc-throw-by-value-catch-by-reference,
|
||||||
|
misc-uniqueptr-reset-release,
|
||||||
|
misc-unused-parameters,
|
||||||
|
modernize-avoid-bind,
|
||||||
|
modernize-loop-convert,
|
||||||
|
modernize-make-shared,
|
||||||
|
modernize-redundant-void-arg,
|
||||||
|
modernize-replace-auto-ptr,
|
||||||
|
modernize-replace-disallow-copy-and-assign-macro,
|
||||||
|
modernize-replace-random-shuffle,
|
||||||
|
modernize-shrink-to-fit,
|
||||||
|
modernize-use-auto,
|
||||||
|
modernize-use-bool-literals,
|
||||||
|
modernize-use-default-member-init,
|
||||||
|
modernize-use-emplace,
|
||||||
|
modernize-use-equals-default,
|
||||||
|
modernize-use-equals-delete,
|
||||||
|
modernize-use-noexcept,
|
||||||
|
modernize-use-nullptr,
|
||||||
|
modernize-use-override,
|
||||||
|
modernize-use-using,
|
||||||
|
readability-avoid-const-params-in-decls,
|
||||||
|
readability-braces-around-statements,
|
||||||
|
readability-const-return-type,
|
||||||
|
readability-container-size-empty,
|
||||||
|
readability-delete-null-pointer,
|
||||||
|
readability-else-after-return,
|
||||||
|
readability-implicit-bool-conversion,
|
||||||
|
readability-inconsistent-declaration-parameter-name,
|
||||||
|
readability-make-member-function-const,
|
||||||
|
readability-misplaced-array-index,
|
||||||
|
readability-non-const-parameter,
|
||||||
|
readability-qualified-auto,
|
||||||
|
readability-redundant-function-ptr-dereference,
|
||||||
|
readability-redundant-smartptr-get,
|
||||||
|
readability-redundant-string-cstr,
|
||||||
|
readability-simplify-subscript-expr,
|
||||||
|
readability-static-accessed-through-instance,
|
||||||
|
readability-static-definition-in-anonymous-namespace,
|
||||||
|
readability-string-compare,
|
||||||
|
readability-suspicious-call-argument,
|
||||||
|
readability-uniqueptr-delete-release,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-exception-escape,
|
||||||
|
-bugprone-reserved-identifier,
|
||||||
|
-bugprone-unused-raii,
|
||||||
|
|
||||||
|
CheckOptions:
|
||||||
|
- key: modernize-use-equals-default.IgnoreMacros
|
||||||
|
value: false
|
||||||
|
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
||||||
|
value: true
|
||||||
|
- key: performance-inefficient-string-concatenation.StrictMode
|
||||||
|
value: true
|
||||||
|
- key: performance-unnecessary-value-param.AllowedTypes
|
||||||
|
value: 'exception_ptr$;'
|
||||||
|
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||||
|
value: true
|
||||||
|
|
||||||
HeaderFilterRegex: 'pybind11/.*h'
|
HeaderFilterRegex: 'pybind11/.*h'
|
||||||
|
24
3rdparty/pybind11/.codespell-ignore-lines
vendored
Normal file
24
3rdparty/pybind11/.codespell-ignore-lines
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>
|
||||||
|
template <typename ThisT>
|
||||||
|
auto &this_ = static_cast<ThisT &>(*this);
|
||||||
|
if (load_impl<ThisT>(temp, false)) {
|
||||||
|
ssize_t nd = 0;
|
||||||
|
auto trivial = broadcast(buffers, nd, shape);
|
||||||
|
auto ndim = (size_t) nd;
|
||||||
|
int nd;
|
||||||
|
ssize_t ndim() const { return detail::array_proxy(m_ptr)->nd; }
|
||||||
|
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||||
|
template <op_id id, op_type ot, typename L, typename R>
|
||||||
|
template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
|
||||||
|
class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
|
||||||
|
class_ &def_cast(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
|
||||||
|
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
|
||||||
|
struct IntStruct {
|
||||||
|
explicit IntStruct(int v) : value(v){};
|
||||||
|
~IntStruct() { value = -value; }
|
||||||
|
IntStruct(const IntStruct &) = default;
|
||||||
|
IntStruct &operator=(const IntStruct &) = default;
|
||||||
|
py::class_<IntStruct>(m, "IntStruct").def(py::init([](const int i) { return IntStruct(i); }));
|
||||||
|
py::implicitly_convertible<int, IntStruct>();
|
||||||
|
m.def("test", [](int expected, const IntStruct &in) {
|
||||||
|
[](int expected, const IntStruct &in) {
|
1
3rdparty/pybind11/.gitattributes
vendored
Normal file
1
3rdparty/pybind11/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
docs/*.svg binary
|
9
3rdparty/pybind11/.github/CODEOWNERS
vendored
Normal file
9
3rdparty/pybind11/.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
*.cmake @henryiii
|
||||||
|
CMakeLists.txt @henryiii
|
||||||
|
*.yml @henryiii
|
||||||
|
*.yaml @henryiii
|
||||||
|
/tools/ @henryiii
|
||||||
|
/pybind11/ @henryiii
|
||||||
|
noxfile.py @henryiii
|
||||||
|
.clang-format @henryiii
|
||||||
|
.clang-tidy @henryiii
|
105
3rdparty/pybind11/.github/CONTRIBUTING.md
vendored
105
3rdparty/pybind11/.github/CONTRIBUTING.md
vendored
@ -53,6 +53,33 @@ derivative works thereof, in binary and source code form.
|
|||||||
|
|
||||||
## Development of pybind11
|
## Development of pybind11
|
||||||
|
|
||||||
|
### Quick setup
|
||||||
|
|
||||||
|
To setup a quick development environment, use [`nox`](https://nox.thea.codes).
|
||||||
|
This will allow you to do some common tasks with minimal setup effort, but will
|
||||||
|
take more time to run and be less flexible than a full development environment.
|
||||||
|
If you use [`pipx run nox`](https://pipx.pypa.io), you don't even need to
|
||||||
|
install `nox`. Examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all available sessions
|
||||||
|
nox -l
|
||||||
|
|
||||||
|
# Run linters
|
||||||
|
nox -s lint
|
||||||
|
|
||||||
|
# Run tests on Python 3.9
|
||||||
|
nox -s tests-3.9
|
||||||
|
|
||||||
|
# Build and preview docs
|
||||||
|
nox -s docs -- serve
|
||||||
|
|
||||||
|
# Build SDists and wheels
|
||||||
|
nox -s build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full setup
|
||||||
|
|
||||||
To setup an ideal development environment, run the following commands on a
|
To setup an ideal development environment, run the following commands on a
|
||||||
system with CMake 3.14+:
|
system with CMake 3.14+:
|
||||||
|
|
||||||
@ -66,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
|
||||||
@ -78,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
|
||||||
@ -88,12 +114,12 @@ 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
|
||||||
* `-DDOWNLOAD_CATCH=ON`: Download catch to build the C++ tests
|
* `-DDOWNLOAD_CATCH=ON`: Download catch to build the C++ tests
|
||||||
* `-DOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests
|
* `-DDOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests
|
||||||
* `-DPYBIND11_INSTALL=ON/OFF`: Enable the install target (on by default for the
|
* `-DPYBIND11_INSTALL=ON/OFF`: Enable the install target (on by default for the
|
||||||
master project)
|
master project)
|
||||||
* `-DUSE_PYTHON_INSTALL_DIR=ON`: Try to install into the python dir
|
* `-DUSE_PYTHON_INSTALL_DIR=ON`: Try to install into the python dir
|
||||||
@ -126,13 +152,26 @@ cmake --build build --target check
|
|||||||
`--target` can be spelled `-t` in CMake 3.15+. You can also run individual
|
`--target` can be spelled `-t` in CMake 3.15+. You can also run individual
|
||||||
tests with these targets:
|
tests with these targets:
|
||||||
|
|
||||||
* `pytest`: Python tests only
|
* `pytest`: Python tests only, using the
|
||||||
|
[pytest](https://docs.pytest.org/en/stable/) framework
|
||||||
* `cpptest`: C++ tests only
|
* `cpptest`: C++ tests only
|
||||||
* `test_cmake_build`: Install / subdirectory tests
|
* `test_cmake_build`: Install / subdirectory tests
|
||||||
|
|
||||||
If you want to build just a subset of tests, use
|
If you want to build just a subset of tests, use
|
||||||
`-DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp"`. If this is
|
`-DPYBIND11_TEST_OVERRIDE="test_callbacks;test_pickling"`. If this is
|
||||||
empty, all tests will be built.
|
empty, all tests will be built. Tests are specified without an extension if they need both a .py and
|
||||||
|
.cpp file.
|
||||||
|
|
||||||
|
You may also pass flags to the `pytest` target by editing `tests/pytest.ini` or
|
||||||
|
by using the `PYTEST_ADDOPTS` environment variable
|
||||||
|
(see [`pytest` docs](https://docs.pytest.org/en/2.7.3/customize.html#adding-default-options)). As an example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
env PYTEST_ADDOPTS="--capture=no --exitfirst" \
|
||||||
|
cmake --build build --target pytest
|
||||||
|
# Or using abbreviated flags
|
||||||
|
env PYTEST_ADDOPTS="-s -x" cmake --build build --target pytest
|
||||||
|
```
|
||||||
|
|
||||||
### Formatting
|
### Formatting
|
||||||
|
|
||||||
@ -164,18 +203,46 @@ name, pre-commit):
|
|||||||
pre-commit install
|
pre-commit install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Clang-Tidy
|
### Clang-Format
|
||||||
|
|
||||||
To run Clang tidy, the following recipe should work. Files will be modified in
|
As of v2.6.2, pybind11 ships with a [`clang-format`][clang-format]
|
||||||
place, so you can use git to monitor the changes.
|
configuration file at the top level of the repo (the filename is
|
||||||
|
`.clang-format`). Currently, formatting is NOT applied automatically, but
|
||||||
|
manually using `clang-format` for newly developed files is highly encouraged.
|
||||||
|
To check if a file needs formatting:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --rm -v $PWD:/pybind11 -it silkeh/clang:10
|
clang-format -style=file --dry-run some.cpp
|
||||||
apt-get update && apt-get install python3-dev python3-pytest
|
|
||||||
cmake -S pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);-fix"
|
|
||||||
cmake --build build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The output will show things to be fixed, if any. To actually format the file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clang-format -style=file -i some.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the `-style-file` option searches the parent directories for the
|
||||||
|
`.clang-format` file, i.e. the commands above can be run in any subdirectory
|
||||||
|
of the pybind11 repo.
|
||||||
|
|
||||||
|
### Clang-Tidy
|
||||||
|
|
||||||
|
[`clang-tidy`][clang-tidy] performs deeper static code analyses and is
|
||||||
|
more complex to run, compared to `clang-format`, but support for `clang-tidy`
|
||||||
|
is built into the pybind11 CMake configuration. To run `clang-tidy`, the
|
||||||
|
following recipe should work. Run the `docker` command from the top-level
|
||||||
|
directory inside your pybind11 git clone. Files will be modified in place,
|
||||||
|
so you can use git to monitor the changes.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:13
|
||||||
|
apt-get update && apt-get install -y python3-dev python3-pytest
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
@ -186,12 +253,12 @@ cmake -S . -B build-iwyu -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=$(which include-what-y
|
|||||||
cmake --build build
|
cmake --build build
|
||||||
```
|
```
|
||||||
|
|
||||||
The report is sent to stderr; you can pip it into a file if you wish.
|
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
|
||||||
@ -313,6 +380,8 @@ if you really want to.
|
|||||||
|
|
||||||
|
|
||||||
[pre-commit]: https://pre-commit.com
|
[pre-commit]: https://pre-commit.com
|
||||||
|
[clang-format]: https://clang.llvm.org/docs/ClangFormat.html
|
||||||
|
[clang-tidy]: https://clang.llvm.org/extra/clang-tidy/
|
||||||
[pybind11.readthedocs.org]: http://pybind11.readthedocs.org/en/latest
|
[pybind11.readthedocs.org]: http://pybind11.readthedocs.org/en/latest
|
||||||
[issue tracker]: https://github.com/pybind/pybind11/issues
|
[issue tracker]: https://github.com/pybind/pybind11/issues
|
||||||
[gitter]: https://gitter.im/pybind/Lobby
|
[gitter]: https://gitter.im/pybind/Lobby
|
||||||
|
45
3rdparty/pybind11/.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
45
3rdparty/pybind11/.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: File an issue about a bug
|
||||||
|
title: "[BUG]: "
|
||||||
|
labels: [triage]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Maintainers will only make a best effort to triage PRs. Please do your best to make the issue as easy to act on as possible, and only open if clearly a problem with pybind11 (ask first if unsure).
|
||||||
|
- type: checkboxes
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: Required prerequisites
|
||||||
|
description: Make sure you've completed the following steps before submitting your issue -- thank you!
|
||||||
|
options:
|
||||||
|
- label: Make sure you've read the [documentation](https://pybind11.readthedocs.io). Your issue may be addressed there.
|
||||||
|
required: true
|
||||||
|
- label: Search the [issue tracker](https://github.com/pybind/pybind11/issues) and [Discussions](https:/pybind/pybind11/discussions) to verify that this hasn't already been reported. +1 or comment there if it has.
|
||||||
|
required: true
|
||||||
|
- label: Consider asking first in the [Gitter chat room](https://gitter.im/pybind/Lobby) or in a [Discussion](https:/pybind/pybind11/discussions/new).
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Problem description
|
||||||
|
placeholder: >-
|
||||||
|
Provide a short description, state the expected behavior and what
|
||||||
|
actually happens. Include relevant information like what version of
|
||||||
|
pybind11 you are using, what system you are on, and any useful commands
|
||||||
|
/ output.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: code
|
||||||
|
attributes:
|
||||||
|
label: Reproducible example code
|
||||||
|
placeholder: >-
|
||||||
|
The code should be minimal, have no external dependencies, isolate the
|
||||||
|
function(s) that cause breakage. Submit matched and complete C++ and
|
||||||
|
Python snippets that can be easily compiled and run to diagnose the
|
||||||
|
issue. If possible, make a PR with a new, failing test to give us a
|
||||||
|
starting point to work on!
|
||||||
|
render: text
|
@ -1,5 +1,8 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
|
- name: Ask a question
|
||||||
|
url: https://github.com/pybind/pybind11/discussions/new
|
||||||
|
about: Please ask and answer questions here, or propose new ideas.
|
||||||
- name: Gitter room
|
- name: Gitter room
|
||||||
url: https://gitter.im/pybind/Lobby
|
url: https://gitter.im/pybind/Lobby
|
||||||
about: A room for discussing pybind11 with an active community
|
about: A room for discussing pybind11 with an active community
|
||||||
|
4
3rdparty/pybind11/.github/dependabot.yml
vendored
4
3rdparty/pybind11/.github/dependabot.yml
vendored
@ -5,7 +5,3 @@ updates:
|
|||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
ignore:
|
|
||||||
# Offical actions have moving tags like v1
|
|
||||||
# that are used, so they don't need updates here
|
|
||||||
- dependency-name: "actions/*"
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
<!--
|
||||||
|
Title (above): please place [branch_name] at the beginning if you are targeting a branch other than master. *Do not target stable*.
|
||||||
|
It is recommended to use conventional commit format, see conventionalcommits.org, but not required.
|
||||||
|
-->
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!-- Include relevant issues or PRs here, describe what changed and why -->
|
<!-- Include relevant issues or PRs here, describe what changed and why -->
|
||||||
@ -5,7 +9,8 @@
|
|||||||
|
|
||||||
## Suggested changelog entry:
|
## Suggested changelog entry:
|
||||||
|
|
||||||
<!-- fill in the below block with the expected RestructuredText entry (delete if no entry needed) -->
|
<!-- Fill in the below block with the expected RestructuredText entry. Delete if no entry needed;
|
||||||
|
but do not delete header or rst block if an entry is needed! Will be collected via a script. -->
|
||||||
|
|
||||||
```rst
|
```rst
|
||||||
|
|
||||||
|
732
3rdparty/pybind11/.github/workflows/ci.yml
vendored
732
3rdparty/pybind11/.github/workflows/ci.yml
vendored
File diff suppressed because it is too large
Load Diff
@ -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.18]
|
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 }}
|
||||||
@ -55,7 +51,7 @@ jobs:
|
|||||||
# An action for adding a specific version of CMake:
|
# An action for adding a specific version of CMake:
|
||||||
# https://github.com/jwlawson/actions-setup-cmake
|
# https://github.com/jwlawson/actions-setup-cmake
|
||||||
- name: Setup CMake ${{ matrix.cmake }}
|
- name: Setup CMake ${{ matrix.cmake }}
|
||||||
uses: jwlawson/actions-setup-cmake@v1.3
|
uses: jwlawson/actions-setup-cmake@v1.12
|
||||||
with:
|
with:
|
||||||
cmake-version: ${{ matrix.cmake }}
|
cmake-version: ${{ matrix.cmake }}
|
||||||
|
|
||||||
|
23
3rdparty/pybind11/.github/workflows/format.yml
vendored
23
3rdparty/pybind11/.github/workflows/format.yml
vendored
@ -12,24 +12,33 @@ 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.0
|
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
|
||||||
|
|
||||||
clang-tidy:
|
clang-tidy:
|
||||||
|
# When making changes here, please also review the "Clang-Tidy" section
|
||||||
|
# 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:10
|
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
|
||||||
@ -37,10 +46,10 @@ jobs:
|
|||||||
- name: Configure
|
- name: Configure
|
||||||
run: >
|
run: >
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
-DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--warnings-as-errors=*"
|
-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
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build -j 2
|
run: cmake --build build -j 2 -- --keep-going
|
||||||
|
39
3rdparty/pybind11/.github/workflows/pip.yml
vendored
39
3rdparty/pybind11/.github/workflows/pip.yml
vendored
@ -12,24 +12,28 @@ on:
|
|||||||
types:
|
types:
|
||||||
- published
|
- published
|
||||||
|
|
||||||
|
env:
|
||||||
|
PIP_ONLY_BINARY: numpy
|
||||||
|
|
||||||
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: python -m pip install -r tests/requirements.txt --prefer-binary
|
run: |
|
||||||
|
python -m pip install -r tests/requirements.txt
|
||||||
|
|
||||||
- name: Python Packaging tests
|
- name: Python Packaging tests
|
||||||
run: pytest tests/extra_python_package/
|
run: pytest tests/extra_python_package/
|
||||||
@ -42,15 +46,16 @@ 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
|
||||||
|
|
||||||
- name: Prepare env
|
- name: Prepare env
|
||||||
run: python -m pip install -r tests/requirements.txt build twine --prefer-binary
|
run: |
|
||||||
|
python -m pip install -r tests/requirements.txt build twine
|
||||||
|
|
||||||
- name: Python Packaging tests
|
- name: Python Packaging tests
|
||||||
run: pytest tests/extra_python_package/
|
run: pytest tests/extra_python_package/
|
||||||
@ -64,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-*
|
||||||
@ -85,19 +90,21 @@ 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.4.1
|
uses: pypa/gh-action-pypi-publish@v1.5.1
|
||||||
with:
|
with:
|
||||||
password: ${{ secrets.pypi_password }}
|
password: ${{ secrets.pypi_password }}
|
||||||
packages_dir: standard/
|
packages_dir: standard/
|
||||||
|
|
||||||
- name: Publish global package
|
- name: Publish global package
|
||||||
uses: pypa/gh-action-pypi-publish@v1.4.1
|
uses: pypa/gh-action-pypi-publish@v1.5.1
|
||||||
with:
|
with:
|
||||||
password: ${{ secrets.pypi_password_global }}
|
password: ${{ secrets.pypi_password_global }}
|
||||||
packages_dir: global/
|
packages_dir: global/
|
||||||
|
112
3rdparty/pybind11/.github/workflows/upstream.yml
vendored
Normal file
112
3rdparty/pybind11/.github/workflows/upstream.yml
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
name: Upstream
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: upstream-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
PIP_ONLY_BINARY: numpy
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
standard:
|
||||||
|
name: "🐍 3.11 latest internals • ubuntu-latest • x64"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Python 3.11
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.11-dev"
|
||||||
|
|
||||||
|
- name: Setup Boost (Linux)
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: sudo apt-get install libboost-dev
|
||||||
|
|
||||||
|
- name: Update CMake
|
||||||
|
uses: jwlawson/actions-setup-cmake@v1.12
|
||||||
|
|
||||||
|
- name: Prepare env
|
||||||
|
run: |
|
||||||
|
python -m pip install -r tests/requirements.txt
|
||||||
|
|
||||||
|
- name: Setup annotations on Linux
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: python -m pip install pytest-github-actions-annotate-failures
|
||||||
|
|
||||||
|
# First build - C++11 mode and inplace
|
||||||
|
- name: Configure C++11
|
||||||
|
run: >
|
||||||
|
cmake -S . -B .
|
||||||
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DDOWNLOAD_CATCH=ON
|
||||||
|
-DDOWNLOAD_EIGEN=ON
|
||||||
|
-DCMAKE_CXX_STANDARD=11
|
||||||
|
|
||||||
|
- name: Build C++11
|
||||||
|
run: cmake --build . -j 2
|
||||||
|
|
||||||
|
- name: Python tests C++11
|
||||||
|
run: cmake --build . --target pytest -j 2
|
||||||
|
|
||||||
|
- name: C++11 tests
|
||||||
|
run: cmake --build . --target cpptest -j 2
|
||||||
|
|
||||||
|
- name: Interface test C++11
|
||||||
|
run: cmake --build . --target test_cmake_build
|
||||||
|
|
||||||
|
- name: Clean directory
|
||||||
|
run: git clean -fdx
|
||||||
|
|
||||||
|
# Second build - C++17 mode and in a build directory
|
||||||
|
- name: Configure C++17
|
||||||
|
run: >
|
||||||
|
cmake -S . -B build2
|
||||||
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DDOWNLOAD_CATCH=ON
|
||||||
|
-DDOWNLOAD_EIGEN=ON
|
||||||
|
-DCMAKE_CXX_STANDARD=17
|
||||||
|
${{ matrix.args }}
|
||||||
|
${{ matrix.args2 }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build2 -j 2
|
||||||
|
|
||||||
|
- name: Python tests
|
||||||
|
run: cmake --build build2 --target pytest
|
||||||
|
|
||||||
|
- name: C++ tests
|
||||||
|
run: cmake --build build2 --target cpptest
|
||||||
|
|
||||||
|
# Third build - C++17 mode with unstable ABI
|
||||||
|
- name: Configure (unstable ABI)
|
||||||
|
run: >
|
||||||
|
cmake -S . -B build3
|
||||||
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DDOWNLOAD_CATCH=ON
|
||||||
|
-DDOWNLOAD_EIGEN=ON
|
||||||
|
-DCMAKE_CXX_STANDARD=17
|
||||||
|
-DPYBIND11_INTERNALS_VERSION=10000000
|
||||||
|
"-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp"
|
||||||
|
${{ matrix.args }}
|
||||||
|
|
||||||
|
- name: Build (unstable ABI)
|
||||||
|
run: cmake --build build3 -j 2
|
||||||
|
|
||||||
|
- name: Python tests (unstable ABI)
|
||||||
|
run: cmake --build build3 --target pytest
|
||||||
|
|
||||||
|
- name: Interface test
|
||||||
|
run: cmake --build build3 --target test_cmake_build
|
||||||
|
|
||||||
|
# This makes sure the setup_helpers module can build packages using
|
||||||
|
# setuptools
|
||||||
|
- name: Setuptools helpers test
|
||||||
|
run: pytest tests/extra_setuptools
|
2
3rdparty/pybind11/.gitignore
vendored
2
3rdparty/pybind11/.gitignore
vendored
@ -41,3 +41,5 @@ pybind11Targets.cmake
|
|||||||
/.vscode
|
/.vscode
|
||||||
/pybind11/include/*
|
/pybind11/include/*
|
||||||
/pybind11/share/*
|
/pybind11/share/*
|
||||||
|
/docs/_build/*
|
||||||
|
.ipynb_checkpoints/
|
||||||
|
131
3rdparty/pybind11/.pre-commit-config.yaml
vendored
131
3rdparty/pybind11/.pre-commit-config.yaml
vendored
@ -12,49 +12,112 @@
|
|||||||
#
|
#
|
||||||
# See https://github.com/pre-commit/pre-commit
|
# See https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
|
# third-party content
|
||||||
|
exclude: ^tools/JoinPaths.cmake$
|
||||||
|
|
||||||
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: v3.2.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
|
||||||
|
- id: check-docstring-first
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
- id: check-symlinks
|
- id: check-symlinks
|
||||||
|
- id: check-toml
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: debug-statements
|
- id: debug-statements
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- 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
|
|
||||||
|
# Upgrade old Python syntax
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: "v2.37.3"
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: [--py36-plus]
|
||||||
|
|
||||||
|
# Nicely sort includes
|
||||||
|
- repo: https://github.com/PyCQA/isort
|
||||||
|
rev: "5.10.1"
|
||||||
|
hooks:
|
||||||
|
- 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: 20.8b1
|
rev: "22.8.0" # Keep in sync with blacken-docs
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
# By default, this ignores pyi files, though black supports them
|
|
||||||
types: [text]
|
# Also code format the docs
|
||||||
files: \.pyi?$
|
- repo: https://github.com/asottile/blacken-docs
|
||||||
|
rev: "v1.12.1"
|
||||||
|
hooks:
|
||||||
|
- id: blacken-docs
|
||||||
|
additional_dependencies:
|
||||||
|
- black==22.8.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.9
|
rev: "v1.3.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: remove-tabs
|
- id: remove-tabs
|
||||||
|
|
||||||
|
- repo: https://github.com/sirosen/texthooks
|
||||||
|
rev: "0.4.0"
|
||||||
|
hooks:
|
||||||
|
- id: fix-ligatures
|
||||||
|
- id: fix-smartquotes
|
||||||
|
|
||||||
|
# Autoremoves unused imports
|
||||||
|
- repo: https://github.com/hadialqattan/pycln
|
||||||
|
rev: "v2.1.1"
|
||||||
|
hooks:
|
||||||
|
- id: pycln
|
||||||
|
stages: [manual]
|
||||||
|
|
||||||
|
# Checking for common mistakes
|
||||||
|
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||||
|
rev: "v1.9.0"
|
||||||
|
hooks:
|
||||||
|
- id: python-check-blanket-noqa
|
||||||
|
- id: python-check-blanket-type-ignore
|
||||||
|
- id: python-no-log-warn
|
||||||
|
- id: python-use-type-annotations
|
||||||
|
- id: rst-backticks
|
||||||
|
- id: rst-directive-colons
|
||||||
|
- id: rst-inline-touching-normal
|
||||||
|
|
||||||
|
# Automatically remove noqa that are not used
|
||||||
|
- repo: https://github.com/asottile/yesqa
|
||||||
|
rev: "v1.4.0"
|
||||||
|
hooks:
|
||||||
|
- id: yesqa
|
||||||
|
additional_dependencies: &flake8_dependencies
|
||||||
|
- flake8-bugbear
|
||||||
|
- pep8-naming
|
||||||
|
|
||||||
# Flake8 also supports pre-commit natively (same author)
|
# Flake8 also supports pre-commit natively (same author)
|
||||||
- repo: https://gitlab.com/pycqa/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 3.8.3
|
rev: "5.0.4"
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
additional_dependencies: [flake8-bugbear, pep8-naming]
|
|
||||||
exclude: ^(docs/.*|tools/.*)$
|
exclude: ^(docs/.*|tools/.*)$
|
||||||
|
additional_dependencies: *flake8_dependencies
|
||||||
|
|
||||||
|
# PyLint has native support - not always usable, but works for us
|
||||||
|
- repo: https://github.com/PyCQA/pylint
|
||||||
|
rev: "v2.15.2"
|
||||||
|
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]
|
||||||
@ -63,38 +126,50 @@ 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.790
|
rev: "v0.971"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
# The default Python type ignores .pyi files, so let's rerun if detected
|
args: []
|
||||||
types: [text]
|
exclude: ^(tests|docs)/
|
||||||
files: ^pybind11.*\.pyi?$
|
additional_dependencies: [nox, rich]
|
||||||
# Running per-file misbehaves a bit, so just run on all files, it's fast
|
|
||||||
pass_filenames: false
|
|
||||||
|
|
||||||
# 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.43"
|
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]
|
||||||
|
|
||||||
# The original pybind11 checks for a few C++ style items
|
# Check for spelling
|
||||||
|
# Use tools/codespell_ignore_lines_from_errors.py
|
||||||
|
# to rebuild .codespell-ignore-lines
|
||||||
|
- repo: https://github.com/codespell-project/codespell
|
||||||
|
rev: "v2.2.1"
|
||||||
|
hooks:
|
||||||
|
- id: codespell
|
||||||
|
exclude: ".supp$"
|
||||||
|
args: ["-x", ".codespell-ignore-lines"]
|
||||||
|
|
||||||
|
# Check for common shell mistakes
|
||||||
|
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||||
|
rev: "v0.8.0.4"
|
||||||
|
hooks:
|
||||||
|
- id: shellcheck
|
||||||
|
|
||||||
|
# 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
|
entry: PyBind|Numpy|Cmake|CCache|PyTest
|
||||||
exclude: .pre-commit-config.yaml
|
exclude: ^\.pre-commit-config.yaml$
|
||||||
|
|
||||||
- repo: local
|
# Clang format the codebase automatically
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: "v14.0.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-style
|
- id: clang-format
|
||||||
name: Classic check-style
|
types_or: [c++, c, cuda]
|
||||||
language: system
|
|
||||||
types:
|
|
||||||
- c++
|
|
||||||
entry: ./tools/check-style.sh
|
|
||||||
|
76
3rdparty/pybind11/CMakeLists.txt
vendored
76
3rdparty/pybind11/CMakeLists.txt
vendored
@ -7,13 +7,18 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.4)
|
cmake_minimum_required(VERSION 3.4)
|
||||||
|
|
||||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.4...3.22)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
if(${CMAKE_VERSION} VERSION_LESS 3.22)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.18)
|
cmake_policy(VERSION 3.22)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Avoid infinite recursion if tests include this as a subdirectory
|
||||||
|
if(DEFINED PYBIND11_MASTER_PROJECT)
|
||||||
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Extract project version from source
|
# Extract project version from source
|
||||||
@ -73,6 +78,10 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
|||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(pybind11_system "")
|
||||||
|
|
||||||
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
else()
|
else()
|
||||||
set(PYBIND11_MASTER_PROJECT OFF)
|
set(PYBIND11_MASTER_PROJECT OFF)
|
||||||
set(pybind11_system SYSTEM)
|
set(pybind11_system SYSTEM)
|
||||||
@ -82,6 +91,9 @@ endif()
|
|||||||
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
|
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
|
||||||
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
|
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
|
||||||
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
|
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
|
||||||
|
set(PYBIND11_INTERNALS_VERSION
|
||||||
|
""
|
||||||
|
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
|
||||||
|
|
||||||
cmake_dependent_option(
|
cmake_dependent_option(
|
||||||
USE_PYTHON_INCLUDE_DIR
|
USE_PYTHON_INCLUDE_DIR
|
||||||
@ -98,6 +110,7 @@ set(PYBIND11_HEADERS
|
|||||||
include/pybind11/detail/descr.h
|
include/pybind11/detail/descr.h
|
||||||
include/pybind11/detail/init.h
|
include/pybind11/detail/init.h
|
||||||
include/pybind11/detail/internals.h
|
include/pybind11/detail/internals.h
|
||||||
|
include/pybind11/detail/type_caster_base.h
|
||||||
include/pybind11/detail/typeid.h
|
include/pybind11/detail/typeid.h
|
||||||
include/pybind11/attr.h
|
include/pybind11/attr.h
|
||||||
include/pybind11/buffer_info.h
|
include/pybind11/buffer_info.h
|
||||||
@ -109,6 +122,7 @@ set(PYBIND11_HEADERS
|
|||||||
include/pybind11/eigen.h
|
include/pybind11/eigen.h
|
||||||
include/pybind11/embed.h
|
include/pybind11/embed.h
|
||||||
include/pybind11/eval.h
|
include/pybind11/eval.h
|
||||||
|
include/pybind11/gil.h
|
||||||
include/pybind11/iostream.h
|
include/pybind11/iostream.h
|
||||||
include/pybind11/functional.h
|
include/pybind11/functional.h
|
||||||
include/pybind11/numpy.h
|
include/pybind11/numpy.h
|
||||||
@ -116,7 +130,8 @@ set(PYBIND11_HEADERS
|
|||||||
include/pybind11/pybind11.h
|
include/pybind11/pybind11.h
|
||||||
include/pybind11/pytypes.h
|
include/pybind11/pytypes.h
|
||||||
include/pybind11/stl.h
|
include/pybind11/stl.h
|
||||||
include/pybind11/stl_bind.h)
|
include/pybind11/stl_bind.h
|
||||||
|
include/pybind11/stl/filesystem.h)
|
||||||
|
|
||||||
# Compare with grep and warn if mismatched
|
# Compare with grep and warn if mismatched
|
||||||
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
|
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||||
@ -159,14 +174,33 @@ endif()
|
|||||||
# You can also place ifs *in* the Config.in, but not here.
|
# You can also place ifs *in* the Config.in, but not here.
|
||||||
|
|
||||||
# This section builds targets, but does *not* touch Python
|
# This section builds targets, but does *not* touch Python
|
||||||
|
# Non-IMPORT targets cannot be defined twice
|
||||||
|
if(NOT TARGET pybind11_headers)
|
||||||
|
# Build the headers-only target (no Python included):
|
||||||
|
# (long name used here to keep this from clashing in subdirectory mode)
|
||||||
|
add_library(pybind11_headers INTERFACE)
|
||||||
|
add_library(pybind11::pybind11_headers ALIAS pybind11_headers) # to match exported target
|
||||||
|
add_library(pybind11::headers ALIAS pybind11_headers) # easier to use/remember
|
||||||
|
|
||||||
# Build the headers-only target (no Python included):
|
target_include_directories(
|
||||||
# (long name used here to keep this from clashing in subdirectory mode)
|
pybind11_headers ${pybind11_system} INTERFACE $<BUILD_INTERFACE:${pybind11_INCLUDE_DIR}>
|
||||||
add_library(pybind11_headers INTERFACE)
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
add_library(pybind11::pybind11_headers ALIAS pybind11_headers) # to match exported target
|
|
||||||
add_library(pybind11::headers ALIAS pybind11_headers) # easier to use/remember
|
target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals
|
||||||
|
cxx_right_angle_brackets)
|
||||||
|
if(NOT "${PYBIND11_INTERNALS_VERSION}" STREQUAL "")
|
||||||
|
target_compile_definitions(
|
||||||
|
pybind11_headers INTERFACE "PYBIND11_INTERNALS_VERSION=${PYBIND11_INTERNALS_VERSION}")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# It is invalid to install a target twice, too.
|
||||||
|
set(PYBIND11_INSTALL OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake")
|
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake")
|
||||||
|
# https://github.com/jtojnar/cmake-snips/#concatenating-paths-when-building-pkg-config-files
|
||||||
|
# TODO: cmake 3.20 adds the cmake_path() function, which obsoletes this snippet
|
||||||
|
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/JoinPaths.cmake")
|
||||||
|
|
||||||
# Relative directory setting
|
# Relative directory setting
|
||||||
if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS)
|
if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS)
|
||||||
@ -175,20 +209,18 @@ elseif(USE_PYTHON_INCLUDE_DIR AND DEFINED PYTHON_INCLUDE_DIR)
|
|||||||
file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS})
|
file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Fill in headers target
|
|
||||||
target_include_directories(
|
|
||||||
pybind11_headers ${pybind11_system} INTERFACE $<BUILD_INTERFACE:${pybind11_INCLUDE_DIR}>
|
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
|
||||||
|
|
||||||
target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals
|
|
||||||
cxx_right_angle_brackets)
|
|
||||||
|
|
||||||
if(PYBIND11_INSTALL)
|
if(PYBIND11_INSTALL)
|
||||||
install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
set(PYBIND11_CMAKECONFIG_INSTALL_DIR
|
set(PYBIND11_CMAKECONFIG_INSTALL_DIR
|
||||||
"${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}"
|
"${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}"
|
||||||
CACHE STRING "install path for pybind11Config.cmake")
|
CACHE STRING "install path for pybind11Config.cmake")
|
||||||
|
|
||||||
|
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
set(pybind11_INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
|
||||||
|
else()
|
||||||
|
set(pybind11_INCLUDEDIR "\$\{PACKAGE_PREFIX_DIR\}/${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
configure_package_config_file(
|
configure_package_config_file(
|
||||||
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||||
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
@ -233,6 +265,16 @@ if(PYBIND11_INSTALL)
|
|||||||
NAMESPACE "pybind11::"
|
NAMESPACE "pybind11::"
|
||||||
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||||
|
|
||||||
|
# pkg-config support
|
||||||
|
if(NOT prefix_for_pc_file)
|
||||||
|
set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
|
||||||
|
endif()
|
||||||
|
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc" @ONLY)
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig/")
|
||||||
|
|
||||||
# Uninstall target
|
# Uninstall target
|
||||||
if(PYBIND11_MASTER_PROJECT)
|
if(PYBIND11_MASTER_PROJECT)
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in"
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in"
|
||||||
|
1
3rdparty/pybind11/MANIFEST.in
vendored
1
3rdparty/pybind11/MANIFEST.in
vendored
@ -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
|
||||||
|
61
3rdparty/pybind11/README.rst
vendored
61
3rdparty/pybind11/README.rst
vendored
@ -3,20 +3,16 @@
|
|||||||
|
|
||||||
**pybind11 — Seamless operability between C++11 and Python**
|
**pybind11 — Seamless operability between C++11 and Python**
|
||||||
|
|
||||||
|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |CI| |Build status|
|
|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions| |CI| |Build status|
|
||||||
|
|
||||||
.. warning::
|
|Repology| |PyPI package| |Conda-forge| |Python Versions|
|
||||||
|
|
||||||
Combining older versions of pybind11 (< 2.6.0) with the brand-new Python
|
`Setuptools example <https://github.com/pybind/python_example>`_
|
||||||
3.9.0 will trigger undefined behavior that typically manifests as crashes
|
• `Scikit-build example <https://github.com/pybind/scikit_build_example>`_
|
||||||
during interpreter shutdown (but could also destroy your data. **You have been
|
• `CMake example <https://github.com/pybind/cmake_example>`_
|
||||||
warned.**)
|
|
||||||
|
.. start
|
||||||
|
|
||||||
We recommend that you wait for Python 3.9.1 slated for release in December,
|
|
||||||
which will include a `fix <https://github.com/python/cpython/pull/22670>`_
|
|
||||||
that resolves this problem. In the meantime, please update to the latest
|
|
||||||
version of pybind11 (2.6.0 or newer), which includes a temporary workaround
|
|
||||||
specifically when Python 3.9.0 is detected at runtime.
|
|
||||||
|
|
||||||
**pybind11** is a lightweight header-only library that exposes C++ types
|
**pybind11** is a lightweight header-only library that exposes C++ types
|
||||||
in Python and vice versa, mainly to create Python bindings of existing
|
in Python and vice versa, mainly to create Python bindings of existing
|
||||||
@ -36,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
|
||||||
@ -82,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
|
||||||
@ -92,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.
|
||||||
|
|
||||||
@ -101,7 +97,7 @@ goodies:
|
|||||||
transparently applied to all entries of one or more NumPy array
|
transparently applied to all entries of one or more NumPy array
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
- Python’s slice-based access and assignment operations can be
|
- Python's slice-based access and assignment operations can be
|
||||||
supported with just a few lines of code.
|
supported with just a few lines of code.
|
||||||
|
|
||||||
- Everything is contained in just a few header files; there is no need
|
- Everything is contained in just a few header files; there is no need
|
||||||
@ -110,7 +106,7 @@ goodies:
|
|||||||
- Binaries are generally smaller by a factor of at least 2 compared to
|
- Binaries are generally smaller by a factor of at least 2 compared to
|
||||||
equivalent bindings generated by Boost.Python. A recent pybind11
|
equivalent bindings generated by Boost.Python. A recent pybind11
|
||||||
conversion of PyRosetta, an enormous Boost.Python binding project,
|
conversion of PyRosetta, an enormous Boost.Python binding project,
|
||||||
`reported <http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf>`_
|
`reported <https://graylab.jhu.edu/Sergey/2016.RosettaCon/PyRosetta-4.pdf>`_
|
||||||
a binary size reduction of **5.4x** and compile time reduction by
|
a binary size reduction of **5.4x** and compile time reduction by
|
||||||
**5.8x**.
|
**5.8x**.
|
||||||
|
|
||||||
@ -123,15 +119,14 @@ 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 C++ compiler 18 or newer
|
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
|
||||||
(`possible issue <https://github.com/pybind/pybind11/pull/2573>`_ on 20.2)
|
5. Cygwin/GCC (previously tested on 2.5.1)
|
||||||
5. Cygwin/GCC (tested on 2.5.1)
|
6. NVCC (CUDA 11.0 tested in CI)
|
||||||
6. NVCC (CUDA 11.0 tested)
|
7. NVIDIA PGI (20.9 tested in CI)
|
||||||
7. NVIDIA PGI (20.7 and 20.9 tested)
|
|
||||||
|
|
||||||
About
|
About
|
||||||
-----
|
-----
|
||||||
@ -139,7 +134,7 @@ About
|
|||||||
This project was created by `Wenzel
|
This project was created by `Wenzel
|
||||||
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
|
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
|
||||||
improvements to the code were contributed by Jonas Adler, Lori A. Burns,
|
improvements to the code were contributed by Jonas Adler, Lori A. Burns,
|
||||||
Sylvain Corlay, Eric Cousineau, Ralf Grosse-Kunstleve, Trent Houliston, Axel
|
Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel
|
||||||
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz Miąsko,
|
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz Miąsko,
|
||||||
Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim
|
Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim
|
||||||
Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart.
|
Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart.
|
||||||
@ -165,7 +160,7 @@ to the terms and conditions of this license.
|
|||||||
|
|
||||||
.. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest
|
.. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest
|
||||||
:target: http://pybind11.readthedocs.org/en/latest
|
:target: http://pybind11.readthedocs.org/en/latest
|
||||||
.. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue
|
.. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg
|
||||||
:target: http://pybind11.readthedocs.org/en/stable
|
:target: http://pybind11.readthedocs.org/en/stable
|
||||||
.. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg
|
.. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg
|
||||||
:target: https://gitter.im/pybind/Lobby
|
:target: https://gitter.im/pybind/Lobby
|
||||||
@ -173,3 +168,13 @@ to the terms and conditions of this license.
|
|||||||
:target: https://github.com/pybind/pybind11/actions
|
:target: https://github.com/pybind/pybind11/actions
|
||||||
.. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true
|
.. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true
|
||||||
:target: https://ci.appveyor.com/project/wjakob/pybind11
|
:target: https://ci.appveyor.com/project/wjakob/pybind11
|
||||||
|
.. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg
|
||||||
|
:target: https://pypi.org/project/pybind11/
|
||||||
|
.. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg
|
||||||
|
:target: https://github.com/conda-forge/pybind11-feedstock
|
||||||
|
.. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg
|
||||||
|
:target: https://repology.org/project/python:pybind11/versions
|
||||||
|
.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg
|
||||||
|
:target: https://pypi.org/project/pybind11/
|
||||||
|
.. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github
|
||||||
|
:target: https://github.com/pybind/pybind11/discussions
|
||||||
|
4
3rdparty/pybind11/docs/Doxyfile
vendored
4
3rdparty/pybind11/docs/Doxyfile
vendored
@ -18,6 +18,4 @@ ALIASES += "endrst=\endverbatim"
|
|||||||
QUIET = YES
|
QUIET = YES
|
||||||
WARNINGS = YES
|
WARNINGS = YES
|
||||||
WARN_IF_UNDOCUMENTED = NO
|
WARN_IF_UNDOCUMENTED = NO
|
||||||
PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \
|
PREDEFINED = PYBIND11_NOINLINE
|
||||||
PY_MAJOR_VERSION=3 \
|
|
||||||
PYBIND11_NOINLINE
|
|
||||||
|
3
3rdparty/pybind11/docs/_static/css/custom.css
vendored
Normal file
3
3rdparty/pybind11/docs/_static/css/custom.css
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.highlight .go {
|
||||||
|
color: #707070;
|
||||||
|
}
|
@ -26,7 +26,9 @@ The following Python snippet demonstrates the intended usage from the Python sid
|
|||||||
def __int__(self):
|
def __int__(self):
|
||||||
return 123
|
return 123
|
||||||
|
|
||||||
|
|
||||||
from example import print
|
from example import print
|
||||||
|
|
||||||
print(A())
|
print(A())
|
||||||
|
|
||||||
To register the necessary conversion routines, it is necessary to add an
|
To register the necessary conversion routines, it is necessary to add an
|
||||||
@ -36,7 +38,7 @@ type is explicitly allowed.
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
namespace pybind11 { namespace detail {
|
namespace PYBIND11_NAMESPACE { namespace detail {
|
||||||
template <> struct type_caster<inty> {
|
template <> struct type_caster<inty> {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -44,7 +46,7 @@ type is explicitly allowed.
|
|||||||
* function signatures and declares a local variable
|
* function signatures and declares a local variable
|
||||||
* 'value' of type inty
|
* 'value' of type inty
|
||||||
*/
|
*/
|
||||||
PYBIND11_TYPE_CASTER(inty, _("inty"));
|
PYBIND11_TYPE_CASTER(inty, const_name("inty"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversion part 1 (Python->C++): convert a PyObject into a inty
|
* Conversion part 1 (Python->C++): convert a PyObject into a inty
|
||||||
@ -76,7 +78,7 @@ type is explicitly allowed.
|
|||||||
return PyLong_FromLong(src.long_value);
|
return PyLong_FromLong(src.long_value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}} // namespace pybind11::detail
|
}} // namespace PYBIND11_NAMESPACE::detail
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ can be mapped *and* if the numpy array is writeable (that is
|
|||||||
the passed variable will be transparently carried out directly on the
|
the passed variable will be transparently carried out directly on the
|
||||||
``numpy.ndarray``.
|
``numpy.ndarray``.
|
||||||
|
|
||||||
This means you can can write code such as the following and have it work as
|
This means you can write code such as the following and have it work as
|
||||||
expected:
|
expected:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
@ -203,7 +203,7 @@ adding the ``order='F'`` option when creating an array:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
myarray = np.array(source, order='F')
|
myarray = np.array(source, order="F")
|
||||||
|
|
||||||
Such an object will be passable to a bound function accepting an
|
Such an object will be passable to a bound function accepting an
|
||||||
``Eigen::Ref<MatrixXd>`` (or similar column-major Eigen type).
|
``Eigen::Ref<MatrixXd>`` (or similar column-major Eigen type).
|
||||||
|
@ -75,91 +75,96 @@ The following basic data types are supported out of the box (some may require
|
|||||||
an additional extension header to be included). To pass other data structures
|
an additional extension header to be included). To pass other data structures
|
||||||
as arguments and return values, refer to the section on binding :ref:`classes`.
|
as arguments and return values, refer to the section on binding :ref:`classes`.
|
||||||
|
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| Data type | Description | Header file |
|
| Data type | Description | Header file |
|
||||||
+====================================+===========================+===============================+
|
+====================================+===========================+===================================+
|
||||||
| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` |
|
| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` |
|
| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` |
|
| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` |
|
| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` |
|
| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` |
|
| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` |
|
| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``char`` | Character literal | :file:`pybind11/pybind11.h` |
|
| ``char`` | Character literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` |
|
| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` |
|
| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` |
|
| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` |
|
| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` |
|
| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` |
|
| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` |
|
| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` |
|
| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` |
|
| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` |
|
| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` |
|
| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` |
|
| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` |
|
||||||
| ``std::u16string_view``, etc. | | |
|
| ``std::u16string_view``, etc. | | |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` |
|
| ``std::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` |
|
| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` |
|
| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::complex<T>`` | Complex numbers | :file:`pybind11/complex.h` |
|
| ``std::complex<T>`` | Complex numbers | :file:`pybind11/complex.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::array<T, Size>`` | STL static array | :file:`pybind11/stl.h` |
|
| ``std::array<T, Size>`` | STL static array | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::vector<T>`` | STL dynamic array | :file:`pybind11/stl.h` |
|
| ``std::vector<T>`` | STL dynamic array | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::deque<T>`` | STL double-ended queue | :file:`pybind11/stl.h` |
|
| ``std::deque<T>`` | STL double-ended queue | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::valarray<T>`` | STL value array | :file:`pybind11/stl.h` |
|
| ``std::valarray<T>`` | STL value array | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::list<T>`` | STL linked list | :file:`pybind11/stl.h` |
|
| ``std::list<T>`` | STL linked list | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::map<T1, T2>`` | STL ordered map | :file:`pybind11/stl.h` |
|
| ``std::map<T1, T2>`` | STL ordered map | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::unordered_map<T1, T2>`` | STL unordered map | :file:`pybind11/stl.h` |
|
| ``std::unordered_map<T1, T2>`` | STL unordered map | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::set<T>`` | STL ordered set | :file:`pybind11/stl.h` |
|
| ``std::set<T>`` | STL ordered set | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::unordered_set<T>`` | STL unordered set | :file:`pybind11/stl.h` |
|
| ``std::unordered_set<T>`` | STL unordered set | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::optional<T>`` | STL optional type (C++17) | :file:`pybind11/stl.h` |
|
| ``std::optional<T>`` | STL optional type (C++17) | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::experimental::optional<T>`` | STL optional type (exp.) | :file:`pybind11/stl.h` |
|
| ``std::experimental::optional<T>`` | STL optional type (exp.) | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` |
|
| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
|
| ``std::filesystem::path<T>`` | STL path (C++17) [#]_ | :file:`pybind11/stl/filesystem.h` |
|
||||||
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` |
|
| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` |
|
| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` |
|
| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` |
|
| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` |
|
| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` |
|
| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` |
|
||||||
+------------------------------------+---------------------------+-------------------------------+
|
+------------------------------------+---------------------------+-----------------------------------+
|
||||||
|
|
||||||
|
.. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and
|
||||||
|
``os.PathLike`` is converted to ``std::filesystem::path``.
|
||||||
|
19
3rdparty/pybind11/docs/advanced/cast/stl.rst
vendored
19
3rdparty/pybind11/docs/advanced/cast/stl.rst
vendored
@ -42,7 +42,7 @@ types:
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
// `boost::optional` as an example -- can be any `std::optional`-like container
|
// `boost::optional` as an example -- can be any `std::optional`-like container
|
||||||
namespace pybind11 { namespace detail {
|
namespace PYBIND11_NAMESPACE { namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
|
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
|
||||||
}}
|
}}
|
||||||
@ -54,7 +54,7 @@ for custom variant types:
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
// `boost::variant` as an example -- can be any `std::variant`-like container
|
// `boost::variant` as an example -- can be any `std::variant`-like container
|
||||||
namespace pybind11 { namespace detail {
|
namespace PYBIND11_NAMESPACE { namespace detail {
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
|
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
|
||||||
|
|
||||||
@ -66,18 +66,27 @@ for custom variant types:
|
|||||||
return boost::apply_visitor(args...);
|
return boost::apply_visitor(args...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}} // namespace pybind11::detail
|
}} // namespace PYBIND11_NAMESPACE::detail
|
||||||
|
|
||||||
The ``visit_helper`` specialization is not required if your ``name::variant`` provides
|
The ``visit_helper`` specialization is not required if your ``name::variant`` provides
|
||||||
a ``name::visit()`` function. For any other function name, the specialization must be
|
a ``name::visit()`` function. For any other function name, the specialization must be
|
||||||
included to tell pybind11 how to visit the variant.
|
included to tell pybind11 how to visit the variant.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
When converting a ``variant`` type, pybind11 follows the same rules as when
|
||||||
|
determining which function overload to call (:ref:`overload_resolution`), and
|
||||||
|
so the same caveats hold. In particular, the order in which the ``variant``'s
|
||||||
|
alternatives are listed is important, since pybind11 will try conversions in
|
||||||
|
this order. This means that, for example, when converting ``variant<int, bool>``,
|
||||||
|
the ``bool`` variant will never be selected, as any Python ``bool`` is already
|
||||||
|
an ``int`` and is convertible to a C++ ``int``. Changing the order of alternatives
|
||||||
|
(and using ``variant<bool, int>``, in this example) provides a solution.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
|
51
3rdparty/pybind11/docs/advanced/cast/strings.rst
vendored
51
3rdparty/pybind11/docs/advanced/cast/strings.rst
vendored
@ -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++
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@ -36,13 +28,13 @@ everywhere <http://utf8everywhere.org/>`_.
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> utf8_test('🎂')
|
>>> utf8_test("🎂")
|
||||||
utf-8 is icing on the cake.
|
utf-8 is icing on the cake.
|
||||||
🎂
|
🎂
|
||||||
|
|
||||||
>>> utf8_charptr('🍕')
|
>>> utf8_charptr("🍕")
|
||||||
My favorite food is
|
My favorite food is
|
||||||
🍕
|
🍕
|
||||||
|
|
||||||
@ -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
|
||||||
@ -80,7 +72,7 @@ raise a ``UnicodeDecodeError``.
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> isinstance(example.std_string_return(), str)
|
>>> isinstance(example.std_string_return(), str)
|
||||||
True
|
True
|
||||||
@ -114,7 +106,7 @@ conversion has the same overhead as implicit conversion.
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> str_output()
|
>>> str_output()
|
||||||
'Send your résumé to Alice in HR'
|
'Send your résumé to Alice in HR'
|
||||||
@ -143,7 +135,7 @@ returned to Python as ``bytes``, then one can return the data as a
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> example.return_bytes()
|
>>> example.return_bytes()
|
||||||
b'\xba\xd0\xba\xd0'
|
b'\xba\xd0\xba\xd0'
|
||||||
@ -160,7 +152,7 @@ encoding, but cannot convert ``std::string`` back to ``bytes`` implicitly.
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> isinstance(example.asymmetry(b"have some bytes"), str)
|
>>> isinstance(example.asymmetry(b"have some bytes"), str)
|
||||||
True
|
True
|
||||||
@ -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.
|
||||||
|
|
||||||
@ -229,16 +216,16 @@ character.
|
|||||||
m.def("pass_char", [](char c) { return c; });
|
m.def("pass_char", [](char c) { return c; });
|
||||||
m.def("pass_wchar", [](wchar_t w) { return w; });
|
m.def("pass_wchar", [](wchar_t w) { return w; });
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> example.pass_char('A')
|
>>> example.pass_char("A")
|
||||||
'A'
|
'A'
|
||||||
|
|
||||||
While C++ will cast integers to character types (``char c = 0x65;``), pybind11
|
While C++ will cast integers to character types (``char c = 0x65;``), pybind11
|
||||||
does not convert Python integers to characters implicitly. The Python function
|
does not convert Python integers to characters implicitly. The Python function
|
||||||
``chr()`` can be used to convert integers to characters.
|
``chr()`` can be used to convert integers to characters.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> example.pass_char(0x65)
|
>>> example.pass_char(0x65)
|
||||||
TypeError
|
TypeError
|
||||||
@ -259,17 +246,17 @@ a combining acute accent). The combining character will be lost if the
|
|||||||
two-character sequence is passed as an argument, even though it renders as a
|
two-character sequence is passed as an argument, even though it renders as a
|
||||||
single grapheme.
|
single grapheme.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> example.pass_wchar('é')
|
>>> example.pass_wchar("é")
|
||||||
'é'
|
'é'
|
||||||
|
|
||||||
>>> combining_e_acute = 'e' + '\u0301'
|
>>> combining_e_acute = "e" + "\u0301"
|
||||||
|
|
||||||
>>> combining_e_acute
|
>>> combining_e_acute
|
||||||
'é'
|
'é'
|
||||||
|
|
||||||
>>> combining_e_acute == 'é'
|
>>> combining_e_acute == "é"
|
||||||
False
|
False
|
||||||
|
|
||||||
>>> example.pass_wchar(combining_e_acute)
|
>>> example.pass_wchar(combining_e_acute)
|
||||||
@ -278,9 +265,9 @@ single grapheme.
|
|||||||
Normalizing combining characters before passing the character literal to C++
|
Normalizing combining characters before passing the character literal to C++
|
||||||
may resolve *some* of these issues:
|
may resolve *some* of these issues:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> example.pass_wchar(unicodedata.normalize('NFC', combining_e_acute))
|
>>> example.pass_wchar(unicodedata.normalize("NFC", combining_e_acute))
|
||||||
'é'
|
'é'
|
||||||
|
|
||||||
In some languages (Thai for example), there are `graphemes that cannot be
|
In some languages (Thai for example), there are `graphemes that cannot be
|
||||||
|
138
3rdparty/pybind11/docs/advanced/classes.rst
vendored
138
3rdparty/pybind11/docs/advanced/classes.rst
vendored
@ -9,7 +9,7 @@ that you are already familiar with the basics from :doc:`/classes`.
|
|||||||
Overriding virtual functions in Python
|
Overriding virtual functions in Python
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
Suppose that a C++ class or interface has a virtual function that we'd like to
|
Suppose that a C++ class or interface has a virtual function that we'd like
|
||||||
to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is
|
to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is
|
||||||
given as a specific example of how one would do this with traditional C++
|
given as a specific example of how one would do this with traditional C++
|
||||||
code).
|
code).
|
||||||
@ -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__``,
|
||||||
@ -161,6 +161,7 @@ Here is an example:
|
|||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
Dog.__init__(self) # Without this, a TypeError is raised.
|
Dog.__init__(self) # Without this, a TypeError is raised.
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def bark(self):
|
def bark(self):
|
||||||
return "yap!"
|
return "yap!"
|
||||||
|
|
||||||
@ -259,7 +260,7 @@ override the ``name()`` method):
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Note the trailing commas in the ``PYBIND11_OVERIDE`` calls to ``name()``
|
Note the trailing commas in the ``PYBIND11_OVERRIDE`` calls to ``name()``
|
||||||
and ``bark()``. These are needed to portably implement a trampoline for a
|
and ``bark()``. These are needed to portably implement a trampoline for a
|
||||||
function that does not take any arguments. For functions that take
|
function that does not take any arguments. For functions that take
|
||||||
a nonzero number of arguments, the trailing comma must be omitted.
|
a nonzero number of arguments, the trailing comma must be omitted.
|
||||||
@ -804,7 +805,7 @@ to bind these two functions:
|
|||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
The ``__setstate__`` part of the ``py::picke()`` definition follows the same
|
The ``__setstate__`` part of the ``py::pickle()`` definition follows the same
|
||||||
rules as the single-argument version of ``py::init()``. The return type can be
|
rules as the single-argument version of ``py::init()``. The return type can be
|
||||||
a value, pointer or holder type. See :ref:`custom_constructors` for details.
|
a value, pointer or holder type. See :ref:`custom_constructors` for details.
|
||||||
|
|
||||||
@ -812,26 +813,21 @@ An instance can now be pickled as follows:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
try:
|
|
||||||
import cPickle as pickle # Use cPickle on Python 2.7
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
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::
|
||||||
|
|
||||||
@ -848,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:
|
||||||
@ -1124,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
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@ -1153,12 +1140,65 @@ error:
|
|||||||
|
|
||||||
>>> class PyFinalChild(IsFinal):
|
>>> class PyFinalChild(IsFinal):
|
||||||
... pass
|
... pass
|
||||||
|
...
|
||||||
TypeError: type 'IsFinal' is not an acceptable base type
|
TypeError: type 'IsFinal' is not an acceptable base type
|
||||||
|
|
||||||
.. note:: This attribute is currently ignored on PyPy
|
.. note:: This attribute is currently ignored on PyPy
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
|
Binding classes with template parameters
|
||||||
|
========================================
|
||||||
|
|
||||||
|
pybind11 can also wrap classes that have template parameters. Consider these classes:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Cat {};
|
||||||
|
struct Dog {};
|
||||||
|
|
||||||
|
template <typename PetType>
|
||||||
|
struct Cage {
|
||||||
|
Cage(PetType& pet);
|
||||||
|
PetType& get();
|
||||||
|
};
|
||||||
|
|
||||||
|
C++ templates may only be instantiated at compile time, so pybind11 can only
|
||||||
|
wrap instantiated templated classes. You cannot wrap a non-instantiated template:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// BROKEN (this will not compile)
|
||||||
|
py::class_<Cage>(m, "Cage");
|
||||||
|
.def("get", &Cage::get);
|
||||||
|
|
||||||
|
You must explicitly specify each template/type combination that you want to
|
||||||
|
wrap separately.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// ok
|
||||||
|
py::class_<Cage<Cat>>(m, "CatCage")
|
||||||
|
.def("get", &Cage<Cat>::get);
|
||||||
|
|
||||||
|
// ok
|
||||||
|
py::class_<Cage<Dog>>(m, "DogCage")
|
||||||
|
.def("get", &Cage<Dog>::get);
|
||||||
|
|
||||||
|
If your class methods have template parameters you can wrap those as well,
|
||||||
|
but once again each instantiation must be explicitly specified:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
typename <typename T>
|
||||||
|
struct MyClass {
|
||||||
|
template <typename V>
|
||||||
|
T fn(V v);
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class<MyClass<int>>(m, "MyClassT")
|
||||||
|
.def("fn", &MyClass<int>::fn<std::string>);
|
||||||
|
|
||||||
Custom automatic downcasters
|
Custom automatic downcasters
|
||||||
============================
|
============================
|
||||||
|
|
||||||
@ -1188,7 +1228,7 @@ whether a downcast is safe, you can proceed by specializing the
|
|||||||
std::string bark() const { return sound; }
|
std::string bark() const { return sound; }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace PYBIND11_NAMESPACE {
|
||||||
template<> struct polymorphic_type_hook<Pet> {
|
template<> struct polymorphic_type_hook<Pet> {
|
||||||
static const void *get(const Pet *src, const std::type_info*& type) {
|
static const void *get(const Pet *src, const std::type_info*& type) {
|
||||||
// note that src may be nullptr
|
// note that src may be nullptr
|
||||||
@ -1199,7 +1239,7 @@ whether a downcast is safe, you can proceed by specializing the
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace pybind11
|
} // namespace PYBIND11_NAMESPACE
|
||||||
|
|
||||||
When pybind11 wants to convert a C++ pointer of type ``Base*`` to a
|
When pybind11 wants to convert a C++ pointer of type ``Base*`` to a
|
||||||
Python object, it calls ``polymorphic_type_hook<Base>::get()`` to
|
Python object, it calls ``polymorphic_type_hook<Base>::get()`` to
|
||||||
@ -1247,7 +1287,7 @@ Accessing the type object
|
|||||||
|
|
||||||
You can get the type object from a C++ class that has already been registered using:
|
You can get the type object from a C++ class that has already been registered using:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::type T_py = py::type::of<T>();
|
py::type T_py = py::type::of<T>();
|
||||||
|
|
||||||
@ -1259,3 +1299,37 @@ object, just like ``type(ob)`` in Python.
|
|||||||
Other types, like ``py::type::of<int>()``, do not work, see :ref:`type-conversions`.
|
Other types, like ``py::type::of<int>()``, do not work, see :ref:`type-conversions`.
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
|
Custom type setup
|
||||||
|
=================
|
||||||
|
|
||||||
|
For advanced use cases, such as enabling garbage collection support, you may
|
||||||
|
wish to directly manipulate the ``PyHeapTypeObject`` corresponding to a
|
||||||
|
``py::class_`` definition.
|
||||||
|
|
||||||
|
You can do that using ``py::custom_type_setup``:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct OwnsPythonObjects {
|
||||||
|
py::object value = py::none();
|
||||||
|
};
|
||||||
|
py::class_<OwnsPythonObjects> cls(
|
||||||
|
m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) {
|
||||||
|
auto *type = &heap_type->ht_type;
|
||||||
|
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||||
|
type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) {
|
||||||
|
auto &self = py::cast<OwnsPythonObjects&>(py::handle(self_base));
|
||||||
|
Py_VISIT(self.value.ptr());
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
type->tp_clear = [](PyObject *self_base) {
|
||||||
|
auto &self = py::cast<OwnsPythonObjects&>(py::handle(self_base));
|
||||||
|
self.value = py::none();
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
cls.def(py::init<>());
|
||||||
|
cls.def_readwrite("value", &OwnsPythonObjects::value);
|
||||||
|
|
||||||
|
.. versionadded:: 2.8
|
||||||
|
27
3rdparty/pybind11/docs/advanced/embedding.rst
vendored
27
3rdparty/pybind11/docs/advanced/embedding.rst
vendored
@ -40,15 +40,15 @@ The essential structure of the ``main.cpp`` file looks like this:
|
|||||||
}
|
}
|
||||||
|
|
||||||
The interpreter must be initialized before using any Python API, which includes
|
The interpreter must be initialized before using any Python API, which includes
|
||||||
all the functions and classes in pybind11. The RAII guard class `scoped_interpreter`
|
all the functions and classes in pybind11. The RAII guard class ``scoped_interpreter``
|
||||||
takes care of the interpreter lifetime. After the guard is destroyed, the interpreter
|
takes care of the interpreter lifetime. After the guard is destroyed, the interpreter
|
||||||
shuts down and clears its memory. No Python functions can be called after this.
|
shuts down and clears its memory. No Python functions can be called after this.
|
||||||
|
|
||||||
Executing Python code
|
Executing Python code
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
There are a few different ways to run Python code. One option is to use `eval`,
|
There are a few different ways to run Python code. One option is to use ``eval``,
|
||||||
`exec` or `eval_file`, as explained in :ref:`eval`. Here is a quick example in
|
``exec`` or ``eval_file``, as explained in :ref:`eval`. Here is a quick example in
|
||||||
the context of an executable with an embedded interpreter:
|
the context of an executable with an embedded interpreter:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
@ -108,7 +108,7 @@ The two approaches can also be combined:
|
|||||||
Importing modules
|
Importing modules
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Python modules can be imported using `module_::import()`:
|
Python modules can be imported using ``module_::import()``:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@ -122,6 +122,7 @@ embedding the interpreter. This makes it easy to import local Python files:
|
|||||||
|
|
||||||
"""calc.py located in the working directory"""
|
"""calc.py located in the working directory"""
|
||||||
|
|
||||||
|
|
||||||
def add(i, j):
|
def add(i, j):
|
||||||
return i + j
|
return i + j
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ embedding the interpreter. This makes it easy to import local Python files:
|
|||||||
int n = result.cast<int>();
|
int n = result.cast<int>();
|
||||||
assert(n == 3);
|
assert(n == 3);
|
||||||
|
|
||||||
Modules can be reloaded using `module_::reload()` if the source is modified e.g.
|
Modules can be reloaded using ``module_::reload()`` if the source is modified e.g.
|
||||||
by an external process. This can be useful in scenarios where the application
|
by an external process. This can be useful in scenarios where the application
|
||||||
imports a user defined data processing script which needs to be updated after
|
imports a user defined data processing script which needs to be updated after
|
||||||
changes by the user. Note that this function does not reload modules recursively.
|
changes by the user. Note that this function does not reload modules recursively.
|
||||||
@ -143,7 +144,7 @@ changes by the user. Note that this function does not reload modules recursively
|
|||||||
Adding embedded modules
|
Adding embedded modules
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
Embedded binary modules can be added using the `PYBIND11_EMBEDDED_MODULE` macro.
|
Embedded binary modules can be added using the ``PYBIND11_EMBEDDED_MODULE`` macro.
|
||||||
Note that the definition must be placed at global scope. They can be imported
|
Note that the definition must be placed at global scope. They can be imported
|
||||||
like any other module.
|
like any other module.
|
||||||
|
|
||||||
@ -169,7 +170,7 @@ like any other module.
|
|||||||
|
|
||||||
Unlike extension modules where only a single binary module can be created, on
|
Unlike extension modules where only a single binary module can be created, on
|
||||||
the embedded side an unlimited number of modules can be added using multiple
|
the embedded side an unlimited number of modules can be added using multiple
|
||||||
`PYBIND11_EMBEDDED_MODULE` definitions (as long as they have unique names).
|
``PYBIND11_EMBEDDED_MODULE`` definitions (as long as they have unique names).
|
||||||
|
|
||||||
These modules are added to Python's list of builtins, so they can also be
|
These modules are added to Python's list of builtins, so they can also be
|
||||||
imported in pure Python files loaded by the interpreter. Everything interacts
|
imported in pure Python files loaded by the interpreter. Everything interacts
|
||||||
@ -215,9 +216,9 @@ naturally:
|
|||||||
Interpreter lifetime
|
Interpreter lifetime
|
||||||
====================
|
====================
|
||||||
|
|
||||||
The Python interpreter shuts down when `scoped_interpreter` is destroyed. After
|
The Python interpreter shuts down when ``scoped_interpreter`` is destroyed. After
|
||||||
this, creating a new instance will restart the interpreter. Alternatively, the
|
this, creating a new instance will restart the interpreter. Alternatively, the
|
||||||
`initialize_interpreter` / `finalize_interpreter` pair of functions can be used
|
``initialize_interpreter`` / ``finalize_interpreter`` pair of functions can be used
|
||||||
to directly set the state at any time.
|
to directly set the state at any time.
|
||||||
|
|
||||||
Modules created with pybind11 can be safely re-initialized after the interpreter
|
Modules created with pybind11 can be safely re-initialized after the interpreter
|
||||||
@ -229,8 +230,8 @@ global data. All the details can be found in the CPython documentation.
|
|||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
Creating two concurrent `scoped_interpreter` guards is a fatal error. So is
|
Creating two concurrent ``scoped_interpreter`` guards is a fatal error. So is
|
||||||
calling `initialize_interpreter` for a second time after the interpreter
|
calling ``initialize_interpreter`` for a second time after the interpreter
|
||||||
has already been initialized.
|
has already been initialized.
|
||||||
|
|
||||||
Do not use the raw CPython API functions ``Py_Initialize`` and
|
Do not use the raw CPython API functions ``Py_Initialize`` and
|
||||||
@ -241,7 +242,7 @@ global data. All the details can be found in the CPython documentation.
|
|||||||
Sub-interpreter support
|
Sub-interpreter support
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
Creating multiple copies of `scoped_interpreter` is not possible because it
|
Creating multiple copies of ``scoped_interpreter`` is not possible because it
|
||||||
represents the main Python interpreter. Sub-interpreters are something different
|
represents the main Python interpreter. Sub-interpreters are something different
|
||||||
and they do permit the existence of multiple interpreters. This is an advanced
|
and they do permit the existence of multiple interpreters. This is an advanced
|
||||||
feature of the CPython API and should be handled with care. pybind11 does not
|
feature of the CPython API and should be handled with care. pybind11 does not
|
||||||
@ -257,5 +258,5 @@ We'll just mention a couple of caveats the sub-interpreters support in pybind11:
|
|||||||
2. Managing multiple threads, multiple interpreters and the GIL can be
|
2. Managing multiple threads, multiple interpreters and the GIL can be
|
||||||
challenging and there are several caveats here, even within the pure
|
challenging and there are several caveats here, even within the pure
|
||||||
CPython API (please refer to the Python docs for details). As for
|
CPython API (please refer to the Python docs for details). As for
|
||||||
pybind11, keep in mind that `gil_scoped_release` and `gil_scoped_acquire`
|
pybind11, keep in mind that ``gil_scoped_release`` and ``gil_scoped_acquire``
|
||||||
do not take sub-interpreters into account.
|
do not take sub-interpreters into account.
|
||||||
|
132
3rdparty/pybind11/docs/advanced/exceptions.rst
vendored
132
3rdparty/pybind11/docs/advanced/exceptions.rst
vendored
@ -43,18 +43,28 @@ at its exception handler.
|
|||||||
| | of bounds access in ``__getitem__``, |
|
| | of bounds access in ``__getitem__``, |
|
||||||
| | ``__setitem__``, etc.) |
|
| | ``__setitem__``, etc.) |
|
||||||
+--------------------------------------+--------------------------------------+
|
+--------------------------------------+--------------------------------------+
|
||||||
| :class:`pybind11::value_error` | ``ValueError`` (used to indicate |
|
|
||||||
| | wrong value passed in |
|
|
||||||
| | ``container.remove(...)``) |
|
|
||||||
+--------------------------------------+--------------------------------------+
|
|
||||||
| :class:`pybind11::key_error` | ``KeyError`` (used to indicate out |
|
| :class:`pybind11::key_error` | ``KeyError`` (used to indicate out |
|
||||||
| | of bounds access in ``__getitem__``, |
|
| | of bounds access in ``__getitem__``, |
|
||||||
| | ``__setitem__`` in dict-like |
|
| | ``__setitem__`` in dict-like |
|
||||||
| | objects, etc.) |
|
| | objects, etc.) |
|
||||||
+--------------------------------------+--------------------------------------+
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::value_error` | ``ValueError`` (used to indicate |
|
||||||
|
| | wrong value passed in |
|
||||||
|
| | ``container.remove(...)``) |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::type_error` | ``TypeError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::buffer_error` | ``BufferError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::import_error` | ``ImportError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| :class:`pybind11::attribute_error` | ``AttributeError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
| Any other exception | ``RuntimeError`` |
|
||||||
|
+--------------------------------------+--------------------------------------+
|
||||||
|
|
||||||
Exception translation is not bidirectional. That is, *catching* the C++
|
Exception translation is not bidirectional. That is, *catching* the C++
|
||||||
exceptions defined above above will not trap exceptions that originate from
|
exceptions defined above will not trap exceptions that originate from
|
||||||
Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below
|
Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below
|
||||||
<handling_python_exceptions_cpp>` for further details.
|
<handling_python_exceptions_cpp>` for further details.
|
||||||
|
|
||||||
@ -67,9 +77,10 @@ Registering custom translators
|
|||||||
|
|
||||||
If the default exception conversion policy described above is insufficient,
|
If the default exception conversion policy described above is insufficient,
|
||||||
pybind11 also provides support for registering custom exception translators.
|
pybind11 also provides support for registering custom exception translators.
|
||||||
To register a simple exception conversion that translates a C++ exception into
|
Similar to pybind11 classes, exception translators can be local to the module
|
||||||
a new Python exception using the C++ exception's ``what()`` method, a helper
|
they are defined in or global to the entire python session. To register a simple
|
||||||
function is available:
|
exception conversion that translates a C++ exception into a new Python exception
|
||||||
|
using the C++ exception's ``what()`` method, a helper function is available:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@ -79,29 +90,39 @@ This call creates a Python exception class with the name ``PyExp`` in the given
|
|||||||
module and automatically converts any encountered exceptions of type ``CppExp``
|
module and automatically converts any encountered exceptions of type ``CppExp``
|
||||||
into Python exceptions of type ``PyExp``.
|
into Python exceptions of type ``PyExp``.
|
||||||
|
|
||||||
|
A matching function is available for registering a local exception translator:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::register_local_exception<CppExp>(module, "PyExp");
|
||||||
|
|
||||||
|
|
||||||
It is possible to specify base class for the exception using the third
|
It is possible to specify base class for the exception using the third
|
||||||
parameter, a `handle`:
|
parameter, a ``handle``:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::register_exception<CppExp>(module, "PyExp", PyExc_RuntimeError);
|
py::register_exception<CppExp>(module, "PyExp", PyExc_RuntimeError);
|
||||||
|
py::register_local_exception<CppExp>(module, "PyExp", PyExc_RuntimeError);
|
||||||
|
|
||||||
Then `PyExp` can be caught both as `PyExp` and `RuntimeError`.
|
Then ``PyExp`` can be caught both as ``PyExp`` and ``RuntimeError``.
|
||||||
|
|
||||||
The class objects of the built-in Python exceptions are listed in the Python
|
The class objects of the built-in Python exceptions are listed in the Python
|
||||||
documentation on `Standard Exceptions <https://docs.python.org/3/c-api/exceptions.html#standard-exceptions>`_.
|
documentation on `Standard Exceptions <https://docs.python.org/3/c-api/exceptions.html#standard-exceptions>`_.
|
||||||
The default base class is `PyExc_Exception`.
|
The default base class is ``PyExc_Exception``.
|
||||||
|
|
||||||
When more advanced exception translation is needed, the function
|
When more advanced exception translation is needed, the functions
|
||||||
``py::register_exception_translator(translator)`` can be used to register
|
``py::register_exception_translator(translator)`` and
|
||||||
|
``py::register_local_exception_translator(translator)`` can be used to register
|
||||||
functions that can translate arbitrary exception types (and which may include
|
functions that can translate arbitrary exception types (and which may include
|
||||||
additional logic to do so). The function takes a stateless callable (e.g. a
|
additional logic to do so). The functions takes a stateless callable (e.g. a
|
||||||
function pointer or a lambda function without captured variables) with the call
|
function pointer or a lambda function without captured variables) with the call
|
||||||
signature ``void(std::exception_ptr)``.
|
signature ``void(std::exception_ptr)``.
|
||||||
|
|
||||||
When a C++ exception is thrown, the registered exception translators are tried
|
When a C++ exception is thrown, the registered exception translators are tried
|
||||||
in reverse order of registration (i.e. the last registered translator gets the
|
in reverse order of registration (i.e. the last registered translator gets the
|
||||||
first shot at handling the exception).
|
first shot at handling the exception). All local translators will be tried
|
||||||
|
before a global translator is tried.
|
||||||
|
|
||||||
Inside the translator, ``std::rethrow_exception`` should be used within
|
Inside the translator, ``std::rethrow_exception`` should be used within
|
||||||
a try block to re-throw the exception. One or more catch clauses to catch
|
a try block to re-throw the exception. One or more catch clauses to catch
|
||||||
@ -156,6 +177,57 @@ section.
|
|||||||
may be explicitly (re-)thrown to delegate it to the other,
|
may be explicitly (re-)thrown to delegate it to the other,
|
||||||
previously-declared existing exception translators.
|
previously-declared existing exception translators.
|
||||||
|
|
||||||
|
Note that ``libc++`` and ``libstdc++`` `behave differently <https://stackoverflow.com/questions/19496643/using-clang-fvisibility-hidden-and-typeinfo-and-type-erasure/28827430>`_
|
||||||
|
with ``-fvisibility=hidden``. Therefore exceptions that are used across ABI boundaries need to be explicitly exported, as exercised in ``tests/test_exceptions.h``.
|
||||||
|
See also: "Problems with C++ exceptions" under `GCC Wiki <https://gcc.gnu.org/wiki/Visibility>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Local vs Global Exception Translators
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
When a global exception translator is registered, it will be applied across all
|
||||||
|
modules in the reverse order of registration. This can create behavior where the
|
||||||
|
order of module import influences how exceptions are translated.
|
||||||
|
|
||||||
|
If module1 has the following translator:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::register_exception_translator([](std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) std::rethrow_exception(p);
|
||||||
|
} catch (const std::invalid_argument &e) {
|
||||||
|
PyErr_SetString("module1 handled this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
and module2 has the following similar translator:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::register_exception_translator([](std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) std::rethrow_exception(p);
|
||||||
|
} catch (const std::invalid_argument &e) {
|
||||||
|
PyErr_SetString("module2 handled this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
then which translator handles the invalid_argument will be determined by the
|
||||||
|
order that module1 and module2 are imported. Since exception translators are
|
||||||
|
applied in the reverse order of registration, which ever module was imported
|
||||||
|
last will "win" and that translator will be applied.
|
||||||
|
|
||||||
|
If there are multiple pybind11 modules that share exception types (either
|
||||||
|
standard built-in or custom) loaded into a single python instance and
|
||||||
|
consistent error handling behavior is needed, then local translators should be
|
||||||
|
used.
|
||||||
|
|
||||||
|
Changing the previous example to use ``register_local_exception_translator``
|
||||||
|
would mean that when invalid_argument is thrown in the module2 code, the
|
||||||
|
module2 translator will always handle it, while in module1, the module1
|
||||||
|
translator will do the same.
|
||||||
|
|
||||||
.. _handling_python_exceptions_cpp:
|
.. _handling_python_exceptions_cpp:
|
||||||
|
|
||||||
Handling exceptions from Python in C++
|
Handling exceptions from Python in C++
|
||||||
@ -188,7 +260,7 @@ For example:
|
|||||||
} catch (py::error_already_set &e) {
|
} catch (py::error_already_set &e) {
|
||||||
if (e.matches(PyExc_FileNotFoundError)) {
|
if (e.matches(PyExc_FileNotFoundError)) {
|
||||||
py::print("missing.txt not found");
|
py::print("missing.txt not found");
|
||||||
} else if (e.match(PyExc_PermissionError)) {
|
} else if (e.matches(PyExc_PermissionError)) {
|
||||||
py::print("missing.txt found but not accessible");
|
py::print("missing.txt found but not accessible");
|
||||||
} else {
|
} else {
|
||||||
throw;
|
throw;
|
||||||
@ -253,6 +325,34 @@ Alternately, to ignore the error, call `PyErr_Clear
|
|||||||
Any Python error must be thrown or cleared, or Python/pybind11 will be left in
|
Any Python error must be thrown or cleared, or Python/pybind11 will be left in
|
||||||
an invalid state.
|
an invalid state.
|
||||||
|
|
||||||
|
Chaining exceptions ('raise from')
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Python has a mechanism for indicating that exceptions were caused by other
|
||||||
|
exceptions:
|
||||||
|
|
||||||
|
.. code-block:: py
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(1 / 0)
|
||||||
|
except Exception as exc:
|
||||||
|
raise RuntimeError("could not divide by zero") from exc
|
||||||
|
|
||||||
|
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
|
||||||
|
you should ``throw py::error_already_set()``.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
try {
|
||||||
|
py::eval("print(1 / 0"));
|
||||||
|
} catch (py::error_already_set &e) {
|
||||||
|
py::raise_from(e, PyExc_RuntimeError, "could not divide by zero");
|
||||||
|
throw py::error_already_set();
|
||||||
|
}
|
||||||
|
|
||||||
|
.. versionadded:: 2.8
|
||||||
|
|
||||||
.. _unraisable_exceptions:
|
.. _unraisable_exceptions:
|
||||||
|
|
||||||
Handling unraisable exceptions
|
Handling unraisable exceptions
|
||||||
|
83
3rdparty/pybind11/docs/advanced/functions.rst
vendored
83
3rdparty/pybind11/docs/advanced/functions.rst
vendored
@ -50,7 +50,7 @@ implied transfer of ownership, i.e.:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
m.def("get_data", &get_data, return_value_policy::reference);
|
m.def("get_data", &get_data, py::return_value_policy::reference);
|
||||||
|
|
||||||
On the other hand, this is not the right policy for many other situations,
|
On the other hand, this is not the right policy for many other situations,
|
||||||
where ignoring ownership could lead to resource leaks.
|
where ignoring ownership could lead to resource leaks.
|
||||||
@ -90,17 +90,18 @@ The following table provides an overview of available policies:
|
|||||||
| | return value is referenced by Python. This is the default policy for |
|
| | return value is referenced by Python. This is the default policy for |
|
||||||
| | property getters created via ``def_property``, ``def_readwrite``, etc. |
|
| | property getters created via ``def_property``, ``def_readwrite``, etc. |
|
||||||
+--------------------------------------------------+----------------------------------------------------------------------------+
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
| :enum:`return_value_policy::automatic` | **Default policy.** This policy falls back to the policy |
|
| :enum:`return_value_policy::automatic` | This policy falls back to the policy |
|
||||||
| | :enum:`return_value_policy::take_ownership` when the return value is a |
|
| | :enum:`return_value_policy::take_ownership` when the return value is a |
|
||||||
| | pointer. Otherwise, it uses :enum:`return_value_policy::move` or |
|
| | pointer. Otherwise, it uses :enum:`return_value_policy::move` or |
|
||||||
| | :enum:`return_value_policy::copy` for rvalue and lvalue references, |
|
| | :enum:`return_value_policy::copy` for rvalue and lvalue references, |
|
||||||
| | respectively. See above for a description of what all of these different |
|
| | respectively. See above for a description of what all of these different |
|
||||||
| | policies do. |
|
| | policies do. This is the default policy for ``py::class_``-wrapped types. |
|
||||||
+--------------------------------------------------+----------------------------------------------------------------------------+
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
| :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the |
|
| :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the |
|
||||||
| | return value is a pointer. This is the default conversion policy for |
|
| | return value is a pointer. This is the default conversion policy for |
|
||||||
| | function arguments when calling Python functions manually from C++ code |
|
| | function arguments when calling Python functions manually from C++ code |
|
||||||
| | (i.e. via handle::operator()). You probably won't need to use this. |
|
| | (i.e. via ``handle::operator()``) and the casters in ``pybind11/stl.h``. |
|
||||||
|
| | You probably won't need to use this explicitly. |
|
||||||
+--------------------------------------------------+----------------------------------------------------------------------------+
|
+--------------------------------------------------+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
Return value policies can also be applied to properties:
|
Return value policies can also be applied to properties:
|
||||||
@ -119,7 +120,7 @@ targeted arguments can be passed through the :class:`cpp_function` constructor:
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
class_<MyClass>(m, "MyClass")
|
class_<MyClass>(m, "MyClass")
|
||||||
.def_property("data"
|
.def_property("data",
|
||||||
py::cpp_function(&MyClass::getData, py::return_value_policy::copy),
|
py::cpp_function(&MyClass::getData, py::return_value_policy::copy),
|
||||||
py::cpp_function(&MyClass::setData)
|
py::cpp_function(&MyClass::setData)
|
||||||
);
|
);
|
||||||
@ -182,6 +183,9 @@ relies on the ability to create a *weak reference* to the nurse object. When
|
|||||||
the nurse object is not a pybind11-registered type and does not support weak
|
the nurse object is not a pybind11-registered type and does not support weak
|
||||||
references, an exception will be thrown.
|
references, an exception will be thrown.
|
||||||
|
|
||||||
|
If you use an incorrect argument index, you will get a ``RuntimeError`` saying
|
||||||
|
``Could not activate keep_alive!``. You should review the indices you're using.
|
||||||
|
|
||||||
Consider the following example: here, the binding code for a list append
|
Consider the following example: here, the binding code for a list append
|
||||||
operation ties the lifetime of the newly added element to the underlying
|
operation ties the lifetime of the newly added element to the underlying
|
||||||
container:
|
container:
|
||||||
@ -228,7 +232,7 @@ is equivalent to the following pseudocode:
|
|||||||
});
|
});
|
||||||
|
|
||||||
The only requirement is that ``T`` is default-constructible, but otherwise any
|
The only requirement is that ``T`` is default-constructible, but otherwise any
|
||||||
scope guard will work. This is very useful in combination with `gil_scoped_release`.
|
scope guard will work. This is very useful in combination with ``gil_scoped_release``.
|
||||||
See :ref:`gil`.
|
See :ref:`gil`.
|
||||||
|
|
||||||
Multiple guards can also be specified as ``py::call_guard<T1, T2, T3...>``. The
|
Multiple guards can also be specified as ``py::call_guard<T1, T2, T3...>``. The
|
||||||
@ -251,7 +255,7 @@ For instance, the following statement iterates over a Python ``dict``:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
void print_dict(py::dict dict) {
|
void print_dict(const py::dict& dict) {
|
||||||
/* Easily interact with Python types */
|
/* Easily interact with Python types */
|
||||||
for (auto item : dict)
|
for (auto item : dict)
|
||||||
std::cout << "key=" << std::string(py::str(item.first)) << ", "
|
std::cout << "key=" << std::string(py::str(item.first)) << ", "
|
||||||
@ -268,7 +272,7 @@ And used in Python as usual:
|
|||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> print_dict({'foo': 123, 'bar': 'hello'})
|
>>> print_dict({"foo": 123, "bar": "hello"})
|
||||||
key=foo, value=123
|
key=foo, value=123
|
||||||
key=bar, value=hello
|
key=bar, value=hello
|
||||||
|
|
||||||
@ -289,7 +293,7 @@ Such functions can also be created using pybind11:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
void generic(py::args args, py::kwargs kwargs) {
|
void generic(py::args args, const py::kwargs& kwargs) {
|
||||||
/// .. do something with args
|
/// .. do something with args
|
||||||
if (kwargs)
|
if (kwargs)
|
||||||
/// .. do something with kwargs
|
/// .. do something with kwargs
|
||||||
@ -302,8 +306,9 @@ The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives
|
|||||||
from ``py::dict``.
|
from ``py::dict``.
|
||||||
|
|
||||||
You may also use just one or the other, and may combine these with other
|
You may also use just one or the other, and may combine these with other
|
||||||
arguments as long as the ``py::args`` and ``py::kwargs`` arguments are the last
|
arguments. Note, however, that ``py::kwargs`` must always be the last argument
|
||||||
arguments accepted by the function.
|
of the function, and ``py::args`` implies that any further arguments are
|
||||||
|
keyword-only (see :ref:`keyword_only_arguments`).
|
||||||
|
|
||||||
Please refer to the other examples for details on how to iterate over these,
|
Please refer to the other examples for details on how to iterate over these,
|
||||||
and on how to cast their entries into C++ objects. A demonstration is also
|
and on how to cast their entries into C++ objects. A demonstration is also
|
||||||
@ -362,10 +367,12 @@ like so:
|
|||||||
py::class_<MyClass>("MyClass")
|
py::class_<MyClass>("MyClass")
|
||||||
.def("myFunction", py::arg("arg") = static_cast<SomeType *>(nullptr));
|
.def("myFunction", py::arg("arg") = static_cast<SomeType *>(nullptr));
|
||||||
|
|
||||||
|
.. _keyword_only_arguments:
|
||||||
|
|
||||||
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
|
||||||
@ -373,6 +380,7 @@ argument in a function definition:
|
|||||||
def f(a, *, b): # a can be positional or via keyword; b must be via keyword
|
def f(a, *, b): # a can be positional or via keyword; b must be via keyword
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
f(a=1, b=2) # good
|
f(a=1, b=2) # good
|
||||||
f(b=2, a=1) # good
|
f(b=2, a=1) # good
|
||||||
f(1, b=2) # good
|
f(1, b=2) # good
|
||||||
@ -387,11 +395,19 @@ 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
|
||||||
|
|
||||||
|
A ``py::args`` argument implies that any following arguments are keyword-only,
|
||||||
|
as if ``py::kw_only()`` had been specified in the same relative location of the
|
||||||
|
argument list as the ``py::args`` argument. The ``py::kw_only()`` may be
|
||||||
|
included to be explicit about this, but is not required.
|
||||||
|
|
||||||
|
.. 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.
|
||||||
|
|
||||||
|
|
||||||
Positional-only arguments
|
Positional-only arguments
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
@ -524,6 +540,8 @@ The default behaviour when the tag is unspecified is to allow ``None``.
|
|||||||
not allow ``None`` as argument. To pass optional argument of these copied types consider
|
not allow ``None`` as argument. To pass optional argument of these copied types consider
|
||||||
using ``std::optional<T>``
|
using ``std::optional<T>``
|
||||||
|
|
||||||
|
.. _overload_resolution:
|
||||||
|
|
||||||
Overload resolution order
|
Overload resolution order
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
@ -559,3 +577,38 @@ prefers earlier-defined overloads to later-defined ones.
|
|||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
The ``py::prepend()`` tag.
|
The ``py::prepend()`` tag.
|
||||||
|
|
||||||
|
Binding functions with template parameters
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
You can bind functions that have template parameters. Here's a function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set(T t);
|
||||||
|
|
||||||
|
C++ templates cannot be instantiated at runtime, so you cannot bind the
|
||||||
|
non-instantiated function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// BROKEN (this will not compile)
|
||||||
|
m.def("set", &set);
|
||||||
|
|
||||||
|
You must bind each instantiated function template separately. You may bind
|
||||||
|
each instantiation with the same name, which will be treated the same as
|
||||||
|
an overloaded function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("set", &set<int>);
|
||||||
|
m.def("set", &set<std::string>);
|
||||||
|
|
||||||
|
Sometimes it's more clear to bind them with separate names, which is also
|
||||||
|
an option:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("setInt", &set<int>);
|
||||||
|
m.def("setString", &set<std::string>);
|
||||||
|
2
3rdparty/pybind11/docs/advanced/misc.rst
vendored
2
3rdparty/pybind11/docs/advanced/misc.rst
vendored
@ -84,7 +84,7 @@ could be realized as follows (important changes highlighted):
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
The ``call_go`` wrapper can also be simplified using the `call_guard` policy
|
The ``call_go`` wrapper can also be simplified using the ``call_guard`` policy
|
||||||
(see :ref:`call_policies`) which yields the same result:
|
(see :ref:`call_policies`) which yields the same result:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
67
3rdparty/pybind11/docs/advanced/pycpp/numpy.rst
vendored
67
3rdparty/pybind11/docs/advanced/pycpp/numpy.rst
vendored
@ -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!");
|
||||||
|
|
||||||
@ -150,8 +150,10 @@ NumPy array containing double precision values.
|
|||||||
|
|
||||||
When it is invoked with a different type (e.g. an integer or a list of
|
When it is invoked with a different type (e.g. an integer or a list of
|
||||||
integers), the binding code will attempt to cast the input into a NumPy array
|
integers), the binding code will attempt to cast the input into a NumPy array
|
||||||
of the requested type. Note that this feature requires the
|
of the requested type. This feature requires the :file:`pybind11/numpy.h`
|
||||||
:file:`pybind11/numpy.h` header to be included.
|
header to be included. Note that :file:`pybind11/numpy.h` does not depend on
|
||||||
|
the NumPy headers, and thus can be used without declaring a build-time
|
||||||
|
dependency on NumPy; NumPy>=1.7.0 is a runtime dependency.
|
||||||
|
|
||||||
Data in NumPy arrays is not guaranteed to packed in a dense manner;
|
Data in NumPy arrays is not guaranteed to packed in a dense manner;
|
||||||
furthermore, entries can be separated by arbitrary column and row strides.
|
furthermore, entries can be separated by arbitrary column and row strides.
|
||||||
@ -169,6 +171,31 @@ template parameter, and it ensures that non-conforming arguments are converted
|
|||||||
into an array satisfying the specified requirements instead of trying the next
|
into an array satisfying the specified requirements instead of trying the next
|
||||||
function overload.
|
function overload.
|
||||||
|
|
||||||
|
There are several methods on arrays; the methods listed below under references
|
||||||
|
work, as well as the following functions based on the NumPy API:
|
||||||
|
|
||||||
|
- ``.dtype()`` returns the type of the contained values.
|
||||||
|
|
||||||
|
- ``.strides()`` returns a pointer to the strides of the array (optionally pass
|
||||||
|
an integer axis to get a number).
|
||||||
|
|
||||||
|
- ``.flags()`` returns the flag settings. ``.writable()`` and ``.owndata()``
|
||||||
|
are directly available.
|
||||||
|
|
||||||
|
- ``.offset_at()`` returns the offset (optionally pass indices).
|
||||||
|
|
||||||
|
- ``.squeeze()`` returns a view with length-1 axes removed.
|
||||||
|
|
||||||
|
- ``.view(dtype)`` returns a view of the array with a different dtype.
|
||||||
|
|
||||||
|
- ``.reshape({i, j, ...})`` returns a view of the array with a different shape.
|
||||||
|
``.resize({...})`` is also available.
|
||||||
|
|
||||||
|
- ``.index_at(i, j, ...)`` gets the count from the beginning to a given index.
|
||||||
|
|
||||||
|
|
||||||
|
There are also several methods for getting references (described below).
|
||||||
|
|
||||||
Structured types
|
Structured types
|
||||||
================
|
================
|
||||||
|
|
||||||
@ -231,8 +258,8 @@ by the compiler. The result is returned as a NumPy array of type
|
|||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> x = np.array([[1, 3],[5, 7]])
|
>>> x = np.array([[1, 3], [5, 7]])
|
||||||
>>> y = np.array([[2, 4],[6, 8]])
|
>>> y = np.array([[2, 4], [6, 8]])
|
||||||
>>> z = 3
|
>>> z = 3
|
||||||
>>> result = vectorized_func(x, y, z)
|
>>> result = vectorized_func(x, y, z)
|
||||||
|
|
||||||
@ -343,21 +370,21 @@ The returned proxy object supports some of the same methods as ``py::array`` so
|
|||||||
that it can be used as a drop-in replacement for some existing, index-checked
|
that it can be used as a drop-in replacement for some existing, index-checked
|
||||||
uses of ``py::array``:
|
uses of ``py::array``:
|
||||||
|
|
||||||
- ``r.ndim()`` returns the number of dimensions
|
- ``.ndim()`` returns the number of dimensions
|
||||||
|
|
||||||
- ``r.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to
|
- ``.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to
|
||||||
the ``const T`` or ``T`` data, respectively, at the given indices. The
|
the ``const T`` or ``T`` data, respectively, at the given indices. The
|
||||||
latter is only available to proxies obtained via ``a.mutable_unchecked()``.
|
latter is only available to proxies obtained via ``a.mutable_unchecked()``.
|
||||||
|
|
||||||
- ``itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
|
- ``.itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
|
||||||
|
|
||||||
- ``ndim()`` returns the number of dimensions.
|
- ``.ndim()`` returns the number of dimensions.
|
||||||
|
|
||||||
- ``shape(n)`` returns the size of dimension ``n``
|
- ``.shape(n)`` returns the size of dimension ``n``
|
||||||
|
|
||||||
- ``size()`` returns the total number of elements (i.e. the product of the shapes).
|
- ``.size()`` returns the total number of elements (i.e. the product of the shapes).
|
||||||
|
|
||||||
- ``nbytes()`` returns the number of bytes used by the referenced elements
|
- ``.nbytes()`` returns the number of bytes used by the referenced elements
|
||||||
(i.e. ``itemsize()`` times ``size()``).
|
(i.e. ``itemsize()`` times ``size()``).
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
@ -368,15 +395,13 @@ 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
|
||||||
|
|
||||||
a = # a NumPy array
|
a = ... # a NumPy array
|
||||||
b = a[0, ..., 0]
|
b = a[0, ..., 0]
|
||||||
|
|
||||||
The function ``py::ellipsis()`` function can be used to perform the same
|
The function ``py::ellipsis()`` function can be used to perform the same
|
||||||
@ -387,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 avaliable in Python 2.
|
|
||||||
|
|
||||||
Memory view
|
Memory view
|
||||||
===========
|
===========
|
||||||
@ -410,7 +433,7 @@ following:
|
|||||||
{ 2, 4 }, // shape (rows, cols)
|
{ 2, 4 }, // shape (rows, cols)
|
||||||
{ sizeof(uint8_t) * 4, sizeof(uint8_t) } // strides in bytes
|
{ sizeof(uint8_t) * 4, sizeof(uint8_t) } // strides in bytes
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
This approach is meant for providing a ``memoryview`` for a C/C++ buffer not
|
This approach is meant for providing a ``memoryview`` for a C/C++ buffer not
|
||||||
managed by Python. The user is responsible for managing the lifetime of the
|
managed by Python. The user is responsible for managing the lifetime of the
|
||||||
@ -426,11 +449,7 @@ We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer:
|
|||||||
buffer, // buffer pointer
|
buffer, // buffer pointer
|
||||||
sizeof(uint8_t) * 8 // buffer size
|
sizeof(uint8_t) * 8 // buffer size
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
``memoryview::from_memory`` is not available in Python 2.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
.. versionchanged:: 2.6
|
||||||
``memoryview::from_memory`` added.
|
``memoryview::from_memory`` added.
|
||||||
|
37
3rdparty/pybind11/docs/advanced/pycpp/object.rst
vendored
37
3rdparty/pybind11/docs/advanced/pycpp/object.rst
vendored
@ -20,6 +20,40 @@ Available types include :class:`handle`, :class:`object`, :class:`bool_`,
|
|||||||
Be sure to review the :ref:`pytypes_gotchas` before using this heavily in
|
Be sure to review the :ref:`pytypes_gotchas` before using this heavily in
|
||||||
your C++ API.
|
your C++ API.
|
||||||
|
|
||||||
|
.. _instantiating_compound_types:
|
||||||
|
|
||||||
|
Instantiating compound Python types from C++
|
||||||
|
============================================
|
||||||
|
|
||||||
|
Dictionaries can be initialized in the :class:`dict` constructor:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
using namespace pybind11::literals; // to bring in the `_a` literal
|
||||||
|
py::dict d("spam"_a=py::none(), "eggs"_a=42);
|
||||||
|
|
||||||
|
A tuple of python objects can be instantiated using :func:`py::make_tuple`:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::tuple tup = py::make_tuple(42, py::none(), "spam");
|
||||||
|
|
||||||
|
Each element is converted to a supported Python type.
|
||||||
|
|
||||||
|
A `simple namespace`_ can be instantiated using
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
using namespace pybind11::literals; // to bring in the `_a` literal
|
||||||
|
py::object SimpleNamespace = py::module_::import("types").attr("SimpleNamespace");
|
||||||
|
py::object ns = SimpleNamespace("spam"_a=py::none(), "eggs"_a=42);
|
||||||
|
|
||||||
|
Attributes on a namespace can be modified with the :func:`py::delattr`,
|
||||||
|
:func:`py::getattr`, and :func:`py::setattr` functions. Simple namespaces can
|
||||||
|
be useful as lightweight stand-ins for class instances.
|
||||||
|
|
||||||
|
.. _simple namespace: https://docs.python.org/3/library/types.html#types.SimpleNamespace
|
||||||
|
|
||||||
.. _casting_back_and_forth:
|
.. _casting_back_and_forth:
|
||||||
|
|
||||||
Casting back and forth
|
Casting back and forth
|
||||||
@ -30,7 +64,7 @@ types to Python, which can be done using :func:`py::cast`:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
MyClass *cls = ..;
|
MyClass *cls = ...;
|
||||||
py::object obj = py::cast(cls);
|
py::object obj = py::cast(cls);
|
||||||
|
|
||||||
The reverse direction uses the following syntax:
|
The reverse direction uses the following syntax:
|
||||||
@ -132,6 +166,7 @@ Keyword arguments are also supported. In Python, there is the usual call syntax:
|
|||||||
def f(number, say, to):
|
def f(number, say, to):
|
||||||
... # function code
|
... # function code
|
||||||
|
|
||||||
|
|
||||||
f(1234, say="hello", to=some_instance) # keyword call in Python
|
f(1234, say="hello", to=some_instance) # keyword call in Python
|
||||||
|
|
||||||
In C++, the same call can be made using:
|
In C++, the same call can be made using:
|
||||||
|
@ -28,7 +28,7 @@ Capturing standard output from ostream
|
|||||||
|
|
||||||
Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print,
|
Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print,
|
||||||
but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr``
|
but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr``
|
||||||
redirection. Replacing a library's printing with `py::print <print>` may not
|
redirection. Replacing a library's printing with ``py::print <print>`` may not
|
||||||
be feasible. This can be fixed using a guard around the library function that
|
be feasible. This can be fixed using a guard around the library function that
|
||||||
redirects output to the corresponding Python streams:
|
redirects output to the corresponding Python streams:
|
||||||
|
|
||||||
@ -47,15 +47,26 @@ redirects output to the corresponding Python streams:
|
|||||||
call_noisy_func();
|
call_noisy_func();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The implementation in ``pybind11/iostream.h`` is NOT thread safe. Multiple
|
||||||
|
threads writing to a redirected ostream concurrently cause data races
|
||||||
|
and potentially buffer overflows. Therefore it is currently a requirement
|
||||||
|
that all (possibly) concurrent redirected ostream writes are protected by
|
||||||
|
a mutex. #HelpAppreciated: Work on iostream.h thread safety. For more
|
||||||
|
background see the discussions under
|
||||||
|
`PR #2982 <https://github.com/pybind/pybind11/pull/2982>`_ and
|
||||||
|
`PR #2995 <https://github.com/pybind/pybind11/pull/2995>`_.
|
||||||
|
|
||||||
This method respects flushes on the output streams and will flush if needed
|
This method respects flushes on the output streams and will flush if needed
|
||||||
when the scoped guard is destroyed. This allows the output to be redirected in
|
when the scoped guard is destroyed. This allows the output to be redirected in
|
||||||
real time, such as to a Jupyter notebook. The two arguments, the C++ stream and
|
real time, such as to a Jupyter notebook. The two arguments, the C++ stream and
|
||||||
the Python output, are optional, and default to standard output if not given. An
|
the Python output, are optional, and default to standard output if not given. An
|
||||||
extra type, `py::scoped_estream_redirect <scoped_estream_redirect>`, is identical
|
extra type, ``py::scoped_estream_redirect <scoped_estream_redirect>``, is identical
|
||||||
except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with
|
except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with
|
||||||
`py::call_guard`, which allows multiple items, but uses the default constructor:
|
``py::call_guard``, which allows multiple items, but uses the default constructor:
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: cpp
|
||||||
|
|
||||||
// Alternative: Call single function using call guard
|
// Alternative: Call single function using call guard
|
||||||
m.def("noisy_func", &call_noisy_function,
|
m.def("noisy_func", &call_noisy_function,
|
||||||
@ -63,7 +74,7 @@ except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful wi
|
|||||||
py::scoped_estream_redirect>());
|
py::scoped_estream_redirect>());
|
||||||
|
|
||||||
The redirection can also be done in Python with the addition of a context
|
The redirection can also be done in Python with the addition of a context
|
||||||
manager, using the `py::add_ostream_redirect() <add_ostream_redirect>` function:
|
manager, using the ``py::add_ostream_redirect() <add_ostream_redirect>`` function:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@ -92,7 +103,7 @@ arguments to disable one of the streams if needed.
|
|||||||
Evaluating Python expressions from strings and files
|
Evaluating Python expressions from strings and files
|
||||||
====================================================
|
====================================================
|
||||||
|
|
||||||
pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate
|
pybind11 provides the ``eval``, ``exec`` and ``eval_file`` functions to evaluate
|
||||||
Python expressions and statements. The following example illustrates how they
|
Python expressions and statements. The following example illustrates how they
|
||||||
can be used.
|
can be used.
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ segmentation fault).
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from example import Parent
|
from example import Parent
|
||||||
|
|
||||||
print(Parent().get_child())
|
print(Parent().get_child())
|
||||||
|
|
||||||
The problem is that ``Parent::get_child()`` returns a pointer to an instance of
|
The problem is that ``Parent::get_child()`` returns a pointer to an instance of
|
||||||
@ -156,7 +157,7 @@ specialized:
|
|||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
|
||||||
|
|
||||||
// Only needed if the type's `.get()` goes by another name
|
// Only needed if the type's `.get()` goes by another name
|
||||||
namespace pybind11 { namespace detail {
|
namespace PYBIND11_NAMESPACE { namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct holder_helper<SmartPtr<T>> { // <-- specialization
|
struct holder_helper<SmartPtr<T>> { // <-- specialization
|
||||||
static const T *get(const SmartPtr<T> &p) { return p.getPointer(); }
|
static const T *get(const SmartPtr<T> &p) { return p.getPointer(); }
|
||||||
|
20
3rdparty/pybind11/docs/basics.rst
vendored
20
3rdparty/pybind11/docs/basics.rst
vendored
@ -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::
|
||||||
|
|
||||||
@ -109,7 +108,7 @@ a file named :file:`example.cpp` with the following contents:
|
|||||||
PYBIND11_MODULE(example, m) {
|
PYBIND11_MODULE(example, m) {
|
||||||
m.doc() = "pybind11 example plugin"; // optional module docstring
|
m.doc() = "pybind11 example plugin"; // optional module docstring
|
||||||
|
|
||||||
m.def("add", &add, "A function which adds two numbers");
|
m.def("add", &add, "A function that adds two numbers");
|
||||||
}
|
}
|
||||||
|
|
||||||
.. [#f1] In practice, implementation and binding code will generally be located
|
.. [#f1] In practice, implementation and binding code will generally be located
|
||||||
@ -136,7 +135,14 @@ On Linux, the above example can be compiled using the following command:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ 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)
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If you used :ref:`include_as_a_submodule` to get the pybind11 source, then
|
||||||
|
use ``$(python3-config --includes) -Iextern/pybind11/include`` instead of
|
||||||
|
``$(python3 -m pybind11 --includes)`` in the above compilation, as
|
||||||
|
explained in :ref:`building_manually`.
|
||||||
|
|
||||||
For more details on the required compiler flags on Linux and macOS, see
|
For more details on the required compiler flags on Linux and macOS, see
|
||||||
:ref:`building_manually`. For complete cross-platform compilation instructions,
|
:ref:`building_manually`. For complete cross-platform compilation instructions,
|
||||||
@ -159,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:
|
||||||
|
33
3rdparty/pybind11/docs/benchmark.py
vendored
33
3rdparty/pybind11/docs/benchmark.py
vendored
@ -1,8 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import random
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
|
||||||
nfns = 4 # Functions per class
|
nfns = 4 # Functions per class
|
||||||
nargs = 4 # Arguments per function
|
nargs = 4 # Arguments per function
|
||||||
@ -13,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"
|
||||||
|
|
||||||
@ -44,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"
|
||||||
|
|
||||||
@ -76,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()
|
||||||
|
934
3rdparty/pybind11/docs/changelog.rst
vendored
934
3rdparty/pybind11/docs/changelog.rst
vendored
@ -6,6 +6,931 @@ Changelog
|
|||||||
Starting with version 1.8.0, pybind11 releases use a `semantic versioning
|
Starting with version 1.8.0, pybind11 releases use a `semantic versioning
|
||||||
<http://semver.org>`_ policy.
|
<http://semver.org>`_ policy.
|
||||||
|
|
||||||
|
Changes will be added here periodically from the "Suggested changelog entry"
|
||||||
|
block in pull request descriptions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IN DEVELOPMENT
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Changes will be summarized here periodically.
|
||||||
|
|
||||||
|
Version 2.10.0 (Jul 15, 2022)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
2019 or 2022 be used. Initial support added for Python 3.11.
|
||||||
|
|
||||||
|
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
|
||||||
|
that allows ``std::variant`` to act as an optional, or allows default
|
||||||
|
construction of a ``std::variant`` holding a non-default constructible type.
|
||||||
|
`#3818 <https://github.com/pybind/pybind11/pull/3818>`_
|
||||||
|
|
||||||
|
* ``pybind11::capsule::set_name`` added to mutate the name of the capsule instance.
|
||||||
|
`#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:
|
||||||
|
|
||||||
|
* Python 3.6 is now the minimum supported version.
|
||||||
|
`#3688 <https://github.com/pybind/pybind11/pull/3688>`_
|
||||||
|
`#3719 <https://github.com/pybind/pybind11/pull/3719>`_
|
||||||
|
|
||||||
|
* The minimum version for MSVC is now 2017.
|
||||||
|
`#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.
|
||||||
|
`#3826 <https://github.com/pybind/pybind11/pull/3826>`_
|
||||||
|
|
||||||
|
* The bindings for capsules now have more consistent exception handling.
|
||||||
|
`#3825 <https://github.com/pybind/pybind11/pull/3825>`_
|
||||||
|
|
||||||
|
* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can now be
|
||||||
|
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:
|
||||||
|
|
||||||
|
* Fix exception handling when ``pybind11::weakref()`` fails.
|
||||||
|
`#3739 <https://github.com/pybind/pybind11/pull/3739>`_
|
||||||
|
|
||||||
|
* ``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:
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
`#3784 <https://github.com/pybind/pybind11/pull/3784>`_
|
||||||
|
|
||||||
|
* MSVC 2022 C++20 coverage was added to GitHub Actions, including Eigen.
|
||||||
|
`#3732 <https://github.com/pybind/pybind11/pull/3732>`_,
|
||||||
|
`#3741 <https://github.com/pybind/pybind11/pull/3741>`_
|
||||||
|
|
||||||
|
|
||||||
|
Backend and tidying up:
|
||||||
|
|
||||||
|
* 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>`_
|
||||||
|
|
||||||
|
* ``#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)
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* Enum now has an ``__index__`` method on Python <3.8 too.
|
||||||
|
`#3700 <https://github.com/pybind/pybind11/pull/3700>`_
|
||||||
|
|
||||||
|
* Local internals are now cleared after finalizing the interpreter.
|
||||||
|
`#3744 <https://github.com/pybind/pybind11/pull/3744>`_
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Better support for Python 3.11 alphas.
|
||||||
|
`#3694 <https://github.com/pybind/pybind11/pull/3694>`_
|
||||||
|
|
||||||
|
* ``PYBIND11_TYPE_CASTER`` now uses fully qualified symbols, so it can be used
|
||||||
|
outside of ``pybind11::detail``.
|
||||||
|
`#3758 <https://github.com/pybind/pybind11/pull/3758>`_
|
||||||
|
|
||||||
|
* Some fixes for PyPy 3.9.
|
||||||
|
`#3768 <https://github.com/pybind/pybind11/pull/3768>`_
|
||||||
|
|
||||||
|
* Fixed a potential memleak in PyPy in ``get_type_override``.
|
||||||
|
`#3774 <https://github.com/pybind/pybind11/pull/3774>`_
|
||||||
|
|
||||||
|
* Fix usage of ``VISIBILITY_INLINES_HIDDEN``.
|
||||||
|
`#3721 <https://github.com/pybind/pybind11/pull/3721>`_
|
||||||
|
|
||||||
|
|
||||||
|
Build system improvements:
|
||||||
|
|
||||||
|
* Uses ``sysconfig`` module to determine installation locations on Python >=
|
||||||
|
3.10, instead of ``distutils`` which has been deprecated.
|
||||||
|
`#3764 <https://github.com/pybind/pybind11/pull/3764>`_
|
||||||
|
|
||||||
|
* Support Catch 2.13.5+ (supporting GLIBC 2.34+).
|
||||||
|
`#3679 <https://github.com/pybind/pybind11/pull/3679>`_
|
||||||
|
|
||||||
|
* Fix test failures with numpy 1.22 by ignoring whitespace when comparing
|
||||||
|
``str()`` of dtypes.
|
||||||
|
`#3682 <https://github.com/pybind/pybind11/pull/3682>`_
|
||||||
|
|
||||||
|
|
||||||
|
Backend and tidying up:
|
||||||
|
|
||||||
|
* clang-tidy: added ``readability-qualified-auto``,
|
||||||
|
``readability-braces-around-statements``,
|
||||||
|
``cppcoreguidelines-prefer-member-initializer``,
|
||||||
|
``clang-analyzer-optin.performance.Padding``,
|
||||||
|
``cppcoreguidelines-pro-type-static-cast-downcast``, and
|
||||||
|
``readability-inconsistent-declaration-parameter-name``.
|
||||||
|
`#3702 <https://github.com/pybind/pybind11/pull/3702>`_,
|
||||||
|
`#3699 <https://github.com/pybind/pybind11/pull/3699>`_,
|
||||||
|
`#3716 <https://github.com/pybind/pybind11/pull/3716>`_,
|
||||||
|
`#3709 <https://github.com/pybind/pybind11/pull/3709>`_
|
||||||
|
|
||||||
|
* clang-format was added to the pre-commit actions, and the entire code base
|
||||||
|
automatically reformatted (after several iterations preparing for this leap).
|
||||||
|
`#3713 <https://github.com/pybind/pybind11/pull/3713>`_
|
||||||
|
|
||||||
|
|
||||||
|
Version 2.9.1 (Feb 2, 2022)
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* If possible, attach Python exception with ``py::raise_from`` to ``TypeError``
|
||||||
|
when casting from C++ to Python. This will give additional info if Python
|
||||||
|
exceptions occur in the caster. Adds a test case of trying to convert a set
|
||||||
|
from C++ to Python when the hash function is not defined in Python.
|
||||||
|
`#3605 <https://github.com/pybind/pybind11/pull/3605>`_
|
||||||
|
|
||||||
|
* Add a mapping of C++11 nested exceptions to their Python exception
|
||||||
|
equivalent using ``py::raise_from``. This attaches the nested exceptions in
|
||||||
|
Python using the ``__cause__`` field.
|
||||||
|
`#3608 <https://github.com/pybind/pybind11/pull/3608>`_
|
||||||
|
|
||||||
|
* Propagate Python exception traceback using ``raise_from`` if a pybind11
|
||||||
|
function runs out of overloads.
|
||||||
|
`#3671 <https://github.com/pybind/pybind11/pull/3671>`_
|
||||||
|
|
||||||
|
* ``py::multiple_inheritance`` is now only needed when C++ bases are hidden
|
||||||
|
from pybind11.
|
||||||
|
`#3650 <https://github.com/pybind/pybind11/pull/3650>`_ and
|
||||||
|
`#3659 <https://github.com/pybind/pybind11/pull/3659>`_
|
||||||
|
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Remove a boolean cast in ``numpy.h`` that causes MSVC C4800 warnings when
|
||||||
|
compiling against Python 3.10 or newer.
|
||||||
|
`#3669 <https://github.com/pybind/pybind11/pull/3669>`_
|
||||||
|
|
||||||
|
* Render ``py::bool_`` and ``py::float_`` as ``bool`` and ``float``
|
||||||
|
respectively.
|
||||||
|
`#3622 <https://github.com/pybind/pybind11/pull/3622>`_
|
||||||
|
|
||||||
|
Build system improvements:
|
||||||
|
|
||||||
|
* Fix CMake extension suffix computation on Python 3.10+.
|
||||||
|
`#3663 <https://github.com/pybind/pybind11/pull/3663>`_
|
||||||
|
|
||||||
|
* Allow ``CMAKE_ARGS`` to override CMake args in pybind11's own ``setup.py``.
|
||||||
|
`#3577 <https://github.com/pybind/pybind11/pull/3577>`_
|
||||||
|
|
||||||
|
* Remove a few deprecated c-headers.
|
||||||
|
`#3610 <https://github.com/pybind/pybind11/pull/3610>`_
|
||||||
|
|
||||||
|
* More uniform handling of test targets.
|
||||||
|
`#3590 <https://github.com/pybind/pybind11/pull/3590>`_
|
||||||
|
|
||||||
|
* Add clang-tidy readability check to catch potentially swapped function args.
|
||||||
|
`#3611 <https://github.com/pybind/pybind11/pull/3611>`_
|
||||||
|
|
||||||
|
|
||||||
|
Version 2.9.0 (Dec 28, 2021)
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
This is the last version to support Python 2.7 and 3.5.
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
* Allow ``py::args`` to be followed by other arguments; the remaining arguments
|
||||||
|
are implicitly keyword-only, as if a ``py::kw_only{}`` annotation had been
|
||||||
|
used.
|
||||||
|
`#3402 <https://github.com/pybind/pybind11/pull/3402>`_
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* Make str/bytes/memoryview more interoperable with ``std::string_view``.
|
||||||
|
`#3521 <https://github.com/pybind/pybind11/pull/3521>`_
|
||||||
|
|
||||||
|
* Replace ``_`` with ``const_name`` in internals, avoid defining ``pybind::_``
|
||||||
|
if ``_`` defined as macro (common gettext usage)
|
||||||
|
`#3423 <https://github.com/pybind/pybind11/pull/3423>`_
|
||||||
|
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Fix a rare warning about extra copy in an Eigen constructor.
|
||||||
|
`#3486 <https://github.com/pybind/pybind11/pull/3486>`_
|
||||||
|
|
||||||
|
* Fix caching of the C++ overrides.
|
||||||
|
`#3465 <https://github.com/pybind/pybind11/pull/3465>`_
|
||||||
|
|
||||||
|
* Add missing ``std::forward`` calls to some ``cpp_function`` overloads.
|
||||||
|
`#3443 <https://github.com/pybind/pybind11/pull/3443>`_
|
||||||
|
|
||||||
|
* Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the
|
||||||
|
``python dev`` label.
|
||||||
|
`#3419 <https://github.com/pybind/pybind11/pull/3419>`_
|
||||||
|
|
||||||
|
* Replace usage of deprecated ``Eigen::MappedSparseMatrix`` with
|
||||||
|
``Eigen::Map<Eigen::SparseMatrix<...>>`` for Eigen 3.3+.
|
||||||
|
`#3499 <https://github.com/pybind/pybind11/pull/3499>`_
|
||||||
|
|
||||||
|
* Tweaks to support Microsoft Visual Studio 2022.
|
||||||
|
`#3497 <https://github.com/pybind/pybind11/pull/3497>`_
|
||||||
|
|
||||||
|
Build system improvements:
|
||||||
|
|
||||||
|
* Nicer CMake printout and IDE organisation for pybind11's own tests.
|
||||||
|
`#3479 <https://github.com/pybind/pybind11/pull/3479>`_
|
||||||
|
|
||||||
|
* CMake: report version type as part of the version string to avoid a spurious
|
||||||
|
space in the package status message.
|
||||||
|
`#3472 <https://github.com/pybind/pybind11/pull/3472>`_
|
||||||
|
|
||||||
|
* Flags starting with ``-g`` in ``$CFLAGS`` and ``$CPPFLAGS`` are no longer
|
||||||
|
overridden by ``.Pybind11Extension``.
|
||||||
|
`#3436 <https://github.com/pybind/pybind11/pull/3436>`_
|
||||||
|
|
||||||
|
* Ensure ThreadPool is closed in ``setup_helpers``.
|
||||||
|
`#3548 <https://github.com/pybind/pybind11/pull/3548>`_
|
||||||
|
|
||||||
|
* Avoid LTS on ``mips64`` and ``ppc64le`` (reported broken).
|
||||||
|
`#3557 <https://github.com/pybind/pybind11/pull/3557>`_
|
||||||
|
|
||||||
|
|
||||||
|
v2.8.1 (Oct 27, 2021)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Changes and additions:
|
||||||
|
|
||||||
|
* The simple namespace creation shortcut added in 2.8.0 was deprecated due to
|
||||||
|
usage of CPython internal API, and will be removed soon. Use
|
||||||
|
``py::module_::import("types").attr("SimpleNamespace")``.
|
||||||
|
`#3374 <https://github.com/pybinyyd/pybind11/pull/3374>`_
|
||||||
|
|
||||||
|
* Add C++ Exception type to throw and catch ``AttributeError``. Useful for
|
||||||
|
defining custom ``__setattr__`` and ``__getattr__`` methods.
|
||||||
|
`#3387 <https://github.com/pybind/pybind11/pull/3387>`_
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
|
||||||
|
* Fixed the potential for dangling references when using properties with
|
||||||
|
``std::optional`` types.
|
||||||
|
`#3376 <https://github.com/pybind/pybind11/pull/3376>`_
|
||||||
|
|
||||||
|
* Modernize usage of ``PyCodeObject`` on Python 3.9+ (moving toward support for
|
||||||
|
Python 3.11a1)
|
||||||
|
`#3368 <https://github.com/pybind/pybind11/pull/3368>`_
|
||||||
|
|
||||||
|
* A long-standing bug in ``eigen.h`` was fixed (originally PR #3343). The bug
|
||||||
|
was unmasked by newly added ``static_assert``'s in the Eigen 3.4.0 release.
|
||||||
|
`#3352 <https://github.com/pybind/pybind11/pull/3352>`_
|
||||||
|
|
||||||
|
* Support multiple raw inclusion of CMake helper files (Conan.io does this for
|
||||||
|
multi-config generators).
|
||||||
|
`#3420 <https://github.com/pybind/pybind11/pull/3420>`_
|
||||||
|
|
||||||
|
* Fix harmless warning on upcoming CMake 3.22.
|
||||||
|
`#3368 <https://github.com/pybind/pybind11/pull/3368>`_
|
||||||
|
|
||||||
|
* Fix 2.8.0 regression with MSVC 2017 + C++17 mode + Python 3.
|
||||||
|
`#3407 <https://github.com/pybind/pybind11/pull/3407>`_
|
||||||
|
|
||||||
|
* Fix 2.8.0 regression that caused undefined behavior (typically
|
||||||
|
segfaults) in ``make_key_iterator``/``make_value_iterator`` if dereferencing
|
||||||
|
the iterator returned a temporary value instead of a reference.
|
||||||
|
`#3348 <https://github.com/pybind/pybind11/pull/3348>`_
|
||||||
|
|
||||||
|
|
||||||
|
v2.8.0 (Oct 4, 2021)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
New features:
|
||||||
|
|
||||||
|
* Added ``py::raise_from`` to enable chaining exceptions.
|
||||||
|
`#3215 <https://github.com/pybind/pybind11/pull/3215>`_
|
||||||
|
|
||||||
|
* Allow exception translators to be optionally registered local to a module
|
||||||
|
instead of applying globally across all pybind11 modules. Use
|
||||||
|
``register_local_exception_translator(ExceptionTranslator&& translator)``
|
||||||
|
instead of ``register_exception_translator(ExceptionTranslator&&
|
||||||
|
translator)`` to keep your exception remapping code local to the module.
|
||||||
|
`#2650 <https://github.com/pybinyyd/pybind11/pull/2650>`_
|
||||||
|
|
||||||
|
* Add ``make_simple_namespace`` function for instantiating Python
|
||||||
|
``SimpleNamespace`` objects. **Deprecated in 2.8.1.**
|
||||||
|
`#2840 <https://github.com/pybind/pybind11/pull/2840>`_
|
||||||
|
|
||||||
|
* ``pybind11::scoped_interpreter`` and ``initialize_interpreter`` have new
|
||||||
|
arguments to allow ``sys.argv`` initialization.
|
||||||
|
`#2341 <https://github.com/pybind/pybind11/pull/2341>`_
|
||||||
|
|
||||||
|
* Allow Python builtins to be used as callbacks in CPython.
|
||||||
|
`#1413 <https://github.com/pybind/pybind11/pull/1413>`_
|
||||||
|
|
||||||
|
* Added ``view`` to view arrays with a different datatype.
|
||||||
|
`#987 <https://github.com/pybind/pybind11/pull/987>`_
|
||||||
|
|
||||||
|
* Implemented ``reshape`` on arrays.
|
||||||
|
`#984 <https://github.com/pybind/pybind11/pull/984>`_
|
||||||
|
|
||||||
|
* Enable defining custom ``__new__`` methods on classes by fixing bug
|
||||||
|
preventing overriding methods if they have non-pybind11 siblings.
|
||||||
|
`#3265 <https://github.com/pybind/pybind11/pull/3265>`_
|
||||||
|
|
||||||
|
* Add ``make_value_iterator()``, and fix ``make_key_iterator()`` to return
|
||||||
|
references instead of copies.
|
||||||
|
`#3293 <https://github.com/pybind/pybind11/pull/3293>`_
|
||||||
|
|
||||||
|
* Improve the classes generated by ``bind_map``: `#3310 <https://github.com/pybind/pybind11/pull/3310>`_
|
||||||
|
|
||||||
|
* Change ``.items`` from an iterator to a dictionary view.
|
||||||
|
* Add ``.keys`` and ``.values`` (both dictionary views).
|
||||||
|
* Allow ``__contains__`` to take any object.
|
||||||
|
|
||||||
|
* ``pybind11::custom_type_setup`` was added, for customizing the
|
||||||
|
``PyHeapTypeObject`` corresponding to a class, which may be useful for
|
||||||
|
enabling garbage collection support, among other things.
|
||||||
|
`#3287 <https://github.com/pybind/pybind11/pull/3287>`_
|
||||||
|
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* Set ``__file__`` constant when running ``eval_file`` in an embedded interpreter.
|
||||||
|
`#3233 <https://github.com/pybind/pybind11/pull/3233>`_
|
||||||
|
|
||||||
|
* Python objects and (C++17) ``std::optional`` now accepted in ``py::slice``
|
||||||
|
constructor.
|
||||||
|
`#1101 <https://github.com/pybind/pybind11/pull/1101>`_
|
||||||
|
|
||||||
|
* The pybind11 proxy types ``str``, ``bytes``, ``bytearray``, ``tuple``,
|
||||||
|
``list`` now consistently support passing ``ssize_t`` values for sizes and
|
||||||
|
indexes. Previously, only ``size_t`` was accepted in several interfaces.
|
||||||
|
`#3219 <https://github.com/pybind/pybind11/pull/3219>`_
|
||||||
|
|
||||||
|
* Avoid evaluating ``PYBIND11_TLS_REPLACE_VALUE`` arguments more than once.
|
||||||
|
`#3290 <https://github.com/pybind/pybind11/pull/3290>`_
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
|
||||||
|
* Bug fix: enum value's ``__int__`` returning non-int when underlying type is
|
||||||
|
bool or of char type.
|
||||||
|
`#1334 <https://github.com/pybind/pybind11/pull/1334>`_
|
||||||
|
|
||||||
|
* Fixes bug in setting error state in Capsule's pointer methods.
|
||||||
|
`#3261 <https://github.com/pybind/pybind11/pull/3261>`_
|
||||||
|
|
||||||
|
* A long-standing memory leak in ``py::cpp_function::initialize`` was fixed.
|
||||||
|
`#3229 <https://github.com/pybind/pybind11/pull/3229>`_
|
||||||
|
|
||||||
|
* Fixes thread safety for some ``pybind11::type_caster`` which require lifetime
|
||||||
|
extension, such as for ``std::string_view``.
|
||||||
|
`#3237 <https://github.com/pybind/pybind11/pull/3237>`_
|
||||||
|
|
||||||
|
* Restore compatibility with gcc 4.8.4 as distributed by ubuntu-trusty, linuxmint-17.
|
||||||
|
`#3270 <https://github.com/pybind/pybind11/pull/3270>`_
|
||||||
|
|
||||||
|
|
||||||
|
Build system improvements:
|
||||||
|
|
||||||
|
* Fix regression in CMake Python package config: improper use of absolute path.
|
||||||
|
`#3144 <https://github.com/pybind/pybind11/pull/3144>`_
|
||||||
|
|
||||||
|
* Cached Python version information could become stale when CMake was re-run
|
||||||
|
with a different Python version. The build system now detects this and
|
||||||
|
updates this information.
|
||||||
|
`#3299 <https://github.com/pybind/pybind11/pull/3299>`_
|
||||||
|
|
||||||
|
* Specified UTF8-encoding in setup.py calls of open().
|
||||||
|
`#3137 <https://github.com/pybind/pybind11/pull/3137>`_
|
||||||
|
|
||||||
|
* Fix a harmless warning from CMake 3.21 with the classic Python discovery.
|
||||||
|
`#3220 <https://github.com/pybind/pybind11/pull/3220>`_
|
||||||
|
|
||||||
|
* Eigen repo and version can now be specified as cmake options.
|
||||||
|
`#3324 <https://github.com/pybind/pybind11/pull/3324>`_
|
||||||
|
|
||||||
|
|
||||||
|
Backend and tidying up:
|
||||||
|
|
||||||
|
* Reduced thread-local storage required for keeping alive temporary data for
|
||||||
|
type conversion to one key per ABI version, rather than one key per extension
|
||||||
|
module. This makes the total thread-local storage required by pybind11 2
|
||||||
|
keys per ABI version.
|
||||||
|
`#3275 <https://github.com/pybind/pybind11/pull/3275>`_
|
||||||
|
|
||||||
|
* Optimize NumPy array construction with additional moves.
|
||||||
|
`#3183 <https://github.com/pybind/pybind11/pull/3183>`_
|
||||||
|
|
||||||
|
* Conversion to ``std::string`` and ``std::string_view`` now avoids making an
|
||||||
|
extra copy of the data on Python >= 3.3.
|
||||||
|
`#3257 <https://github.com/pybind/pybind11/pull/3257>`_
|
||||||
|
|
||||||
|
* Remove const modifier from certain C++ methods on Python collections
|
||||||
|
(``list``, ``set``, ``dict``) such as (``clear()``, ``append()``,
|
||||||
|
``insert()``, etc...) and annotated them with ``py-non-const``.
|
||||||
|
|
||||||
|
* Enable readability ``clang-tidy-const-return`` and remove useless consts.
|
||||||
|
`#3254 <https://github.com/pybind/pybind11/pull/3254>`_
|
||||||
|
`#3194 <https://github.com/pybind/pybind11/pull/3194>`_
|
||||||
|
|
||||||
|
* The clang-tidy ``google-explicit-constructor`` option was enabled.
|
||||||
|
`#3250 <https://github.com/pybind/pybind11/pull/3250>`_
|
||||||
|
|
||||||
|
* Mark a pytype move constructor as noexcept (perf).
|
||||||
|
`#3236 <https://github.com/pybind/pybind11/pull/3236>`_
|
||||||
|
|
||||||
|
* Enable clang-tidy check to guard against inheritance slicing.
|
||||||
|
`#3210 <https://github.com/pybind/pybind11/pull/3210>`_
|
||||||
|
|
||||||
|
* Legacy warning suppression pragma were removed from eigen.h. On Unix
|
||||||
|
platforms, please use -isystem for Eigen include directories, to suppress
|
||||||
|
compiler warnings originating from Eigen headers. Note that CMake does this
|
||||||
|
by default. No adjustments are needed for Windows.
|
||||||
|
`#3198 <https://github.com/pybind/pybind11/pull/3198>`_
|
||||||
|
|
||||||
|
* Format pybind11 with isort consistent ordering of imports
|
||||||
|
`#3195 <https://github.com/pybind/pybind11/pull/3195>`_
|
||||||
|
|
||||||
|
* The warnings-suppression "pragma clamp" at the top/bottom of pybind11 was
|
||||||
|
removed, clearing the path to refactoring and IWYU cleanup.
|
||||||
|
`#3186 <https://github.com/pybind/pybind11/pull/3186>`_
|
||||||
|
|
||||||
|
* Enable most bugprone checks in clang-tidy and fix the found potential bugs
|
||||||
|
and poor coding styles.
|
||||||
|
`#3166 <https://github.com/pybind/pybind11/pull/3166>`_
|
||||||
|
|
||||||
|
* Add ``clang-tidy-readability`` rules to make boolean casts explicit improving
|
||||||
|
code readability. Also enabled other misc and readability clang-tidy checks.
|
||||||
|
`#3148 <https://github.com/pybind/pybind11/pull/3148>`_
|
||||||
|
|
||||||
|
* Move object in ``.pop()`` for list.
|
||||||
|
`#3116 <https://github.com/pybind/pybind11/pull/3116>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v2.7.1 (Aug 3, 2021)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Minor missing functionality added:
|
||||||
|
|
||||||
|
* Allow Python builtins to be used as callbacks in CPython.
|
||||||
|
`#1413 <https://github.com/pybind/pybind11/pull/1413>`_
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Fix regression in CMake Python package config: improper use of absolute path.
|
||||||
|
`#3144 <https://github.com/pybind/pybind11/pull/3144>`_
|
||||||
|
|
||||||
|
* Fix Mingw64 and add to the CI testing matrix.
|
||||||
|
`#3132 <https://github.com/pybind/pybind11/pull/3132>`_
|
||||||
|
|
||||||
|
* Specified UTF8-encoding in setup.py calls of open().
|
||||||
|
`#3137 <https://github.com/pybind/pybind11/pull/3137>`_
|
||||||
|
|
||||||
|
* Add clang-tidy-readability rules to make boolean casts explicit improving
|
||||||
|
code readability. Also enabled other misc and readability clang-tidy checks.
|
||||||
|
`#3148 <https://github.com/pybind/pybind11/pull/3148>`_
|
||||||
|
|
||||||
|
* Move object in ``.pop()`` for list.
|
||||||
|
`#3116 <https://github.com/pybind/pybind11/pull/3116>`_
|
||||||
|
|
||||||
|
Backend and tidying up:
|
||||||
|
|
||||||
|
* Removed and fixed warning suppressions.
|
||||||
|
`#3127 <https://github.com/pybind/pybind11/pull/3127>`_
|
||||||
|
`#3129 <https://github.com/pybind/pybind11/pull/3129>`_
|
||||||
|
`#3135 <https://github.com/pybind/pybind11/pull/3135>`_
|
||||||
|
`#3141 <https://github.com/pybind/pybind11/pull/3141>`_
|
||||||
|
`#3142 <https://github.com/pybind/pybind11/pull/3142>`_
|
||||||
|
`#3150 <https://github.com/pybind/pybind11/pull/3150>`_
|
||||||
|
`#3152 <https://github.com/pybind/pybind11/pull/3152>`_
|
||||||
|
`#3160 <https://github.com/pybind/pybind11/pull/3160>`_
|
||||||
|
`#3161 <https://github.com/pybind/pybind11/pull/3161>`_
|
||||||
|
|
||||||
|
|
||||||
|
v2.7.0 (Jul 16, 2021)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
New features:
|
||||||
|
|
||||||
|
* Enable ``py::implicitly_convertible<py::none, ...>`` for
|
||||||
|
``py::class_``-wrapped types.
|
||||||
|
`#3059 <https://github.com/pybind/pybind11/pull/3059>`_
|
||||||
|
|
||||||
|
* Allow function pointer extraction from overloaded functions.
|
||||||
|
`#2944 <https://github.com/pybind/pybind11/pull/2944>`_
|
||||||
|
|
||||||
|
* NumPy: added ``.char_()`` to type which gives the NumPy public ``char``
|
||||||
|
result, which also distinguishes types by bit length (unlike ``.kind()``).
|
||||||
|
`#2864 <https://github.com/pybind/pybind11/pull/2864>`_
|
||||||
|
|
||||||
|
* Add ``pybind11::bytearray`` to manipulate ``bytearray`` similar to ``bytes``.
|
||||||
|
`#2799 <https://github.com/pybind/pybind11/pull/2799>`_
|
||||||
|
|
||||||
|
* ``pybind11/stl/filesystem.h`` registers a type caster that, on C++17/Python
|
||||||
|
3.6+, converts ``std::filesystem::path`` to ``pathlib.Path`` and any
|
||||||
|
``os.PathLike`` to ``std::filesystem::path``.
|
||||||
|
`#2730 <https://github.com/pybind/pybind11/pull/2730>`_
|
||||||
|
|
||||||
|
* A ``PYBIND11_VERSION_HEX`` define was added, similar to ``PY_VERSION_HEX``.
|
||||||
|
`#3120 <https://github.com/pybind/pybind11/pull/3120>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
* ``py::str`` changed to exclusively hold ``PyUnicodeObject``. Previously
|
||||||
|
``py::str`` could also hold ``bytes``, which is probably surprising, was
|
||||||
|
never documented, and can mask bugs (e.g. accidental use of ``py::str``
|
||||||
|
instead of ``py::bytes``).
|
||||||
|
`#2409 <https://github.com/pybind/pybind11/pull/2409>`_
|
||||||
|
|
||||||
|
* Add a safety guard to ensure that the Python GIL is held when C++ calls back
|
||||||
|
into Python via ``object_api<>::operator()`` (e.g. ``py::function``
|
||||||
|
``__call__``). (This feature is available for Python 3.6+ only.)
|
||||||
|
`#2919 <https://github.com/pybind/pybind11/pull/2919>`_
|
||||||
|
|
||||||
|
* Catch a missing ``self`` argument in calls to ``__init__()``.
|
||||||
|
`#2914 <https://github.com/pybind/pybind11/pull/2914>`_
|
||||||
|
|
||||||
|
* Use ``std::string_view`` if available to avoid a copy when passing an object
|
||||||
|
to a ``std::ostream``.
|
||||||
|
`#3042 <https://github.com/pybind/pybind11/pull/3042>`_
|
||||||
|
|
||||||
|
* An important warning about thread safety was added to the ``iostream.h``
|
||||||
|
documentation; attempts to make ``py::scoped_ostream_redirect`` thread safe
|
||||||
|
have been removed, as it was only partially effective.
|
||||||
|
`#2995 <https://github.com/pybind/pybind11/pull/2995>`_
|
||||||
|
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
|
||||||
|
* Performance: avoid unnecessary strlen calls.
|
||||||
|
`#3058 <https://github.com/pybind/pybind11/pull/3058>`_
|
||||||
|
|
||||||
|
* Fix auto-generated documentation string when using ``const T`` in
|
||||||
|
``pyarray_t``.
|
||||||
|
`#3020 <https://github.com/pybind/pybind11/pull/3020>`_
|
||||||
|
|
||||||
|
* Unify error messages thrown by ``simple_collector``/``unpacking_collector``.
|
||||||
|
`#3013 <https://github.com/pybind/pybind11/pull/3013>`_
|
||||||
|
|
||||||
|
* ``pybind11::builtin_exception`` is now explicitly exported, which means the
|
||||||
|
types included/defined in different modules are identical, and exceptions
|
||||||
|
raised in different modules can be caught correctly. The documentation was
|
||||||
|
updated to explain that custom exceptions that are used across module
|
||||||
|
boundaries need to be explicitly exported as well.
|
||||||
|
`#2999 <https://github.com/pybind/pybind11/pull/2999>`_
|
||||||
|
|
||||||
|
* Fixed exception when printing UTF-8 to a ``scoped_ostream_redirect``.
|
||||||
|
`#2982 <https://github.com/pybind/pybind11/pull/2982>`_
|
||||||
|
|
||||||
|
* Pickle support enhancement: ``setstate`` implementation will attempt to
|
||||||
|
``setattr`` ``__dict__`` only if the unpickled ``dict`` object is not empty,
|
||||||
|
to not force use of ``py::dynamic_attr()`` unnecessarily.
|
||||||
|
`#2972 <https://github.com/pybind/pybind11/pull/2972>`_
|
||||||
|
|
||||||
|
* Allow negative timedelta values to roundtrip.
|
||||||
|
`#2870 <https://github.com/pybind/pybind11/pull/2870>`_
|
||||||
|
|
||||||
|
* Fix unchecked errors could potentially swallow signals/other exceptions.
|
||||||
|
`#2863 <https://github.com/pybind/pybind11/pull/2863>`_
|
||||||
|
|
||||||
|
* Add null pointer check with ``std::localtime``.
|
||||||
|
`#2846 <https://github.com/pybind/pybind11/pull/2846>`_
|
||||||
|
|
||||||
|
* Fix the ``weakref`` constructor from ``py::object`` to create a new
|
||||||
|
``weakref`` on conversion.
|
||||||
|
`#2832 <https://github.com/pybind/pybind11/pull/2832>`_
|
||||||
|
|
||||||
|
* Avoid relying on exceptions in C++17 when getting a ``shared_ptr`` holder
|
||||||
|
from a ``shared_from_this`` class.
|
||||||
|
`#2819 <https://github.com/pybind/pybind11/pull/2819>`_
|
||||||
|
|
||||||
|
* Allow the codec's exception to be raised instead of :code:`RuntimeError` when
|
||||||
|
casting from :code:`py::str` to :code:`std::string`.
|
||||||
|
`#2903 <https://github.com/pybind/pybind11/pull/2903>`_
|
||||||
|
|
||||||
|
|
||||||
|
Build system improvements:
|
||||||
|
|
||||||
|
* In ``setup_helpers.py``, test for platforms that have some multiprocessing
|
||||||
|
features but lack semaphores, which ``ParallelCompile`` requires.
|
||||||
|
`#3043 <https://github.com/pybind/pybind11/pull/3043>`_
|
||||||
|
|
||||||
|
* Fix ``pybind11_INCLUDE_DIR`` in case ``CMAKE_INSTALL_INCLUDEDIR`` is
|
||||||
|
absolute.
|
||||||
|
`#3005 <https://github.com/pybind/pybind11/pull/3005>`_
|
||||||
|
|
||||||
|
* Fix bug not respecting ``WITH_SOABI`` or ``WITHOUT_SOABI`` to CMake.
|
||||||
|
`#2938 <https://github.com/pybind/pybind11/pull/2938>`_
|
||||||
|
|
||||||
|
* Fix the default ``Pybind11Extension`` compilation flags with a Mingw64 python.
|
||||||
|
`#2921 <https://github.com/pybind/pybind11/pull/2921>`_
|
||||||
|
|
||||||
|
* Clang on Windows: do not pass ``/MP`` (ignored flag).
|
||||||
|
`#2824 <https://github.com/pybind/pybind11/pull/2824>`_
|
||||||
|
|
||||||
|
* ``pybind11.setup_helpers.intree_extensions`` can be used to generate
|
||||||
|
``Pybind11Extension`` instances from cpp files placed in the Python package
|
||||||
|
source tree.
|
||||||
|
`#2831 <https://github.com/pybind/pybind11/pull/2831>`_
|
||||||
|
|
||||||
|
Backend and tidying up:
|
||||||
|
|
||||||
|
* Enable clang-tidy performance, readability, and modernization checks
|
||||||
|
throughout the codebase to enforce best coding practices.
|
||||||
|
`#3046 <https://github.com/pybind/pybind11/pull/3046>`_,
|
||||||
|
`#3049 <https://github.com/pybind/pybind11/pull/3049>`_,
|
||||||
|
`#3051 <https://github.com/pybind/pybind11/pull/3051>`_,
|
||||||
|
`#3052 <https://github.com/pybind/pybind11/pull/3052>`_,
|
||||||
|
`#3080 <https://github.com/pybind/pybind11/pull/3080>`_, and
|
||||||
|
`#3094 <https://github.com/pybind/pybind11/pull/3094>`_
|
||||||
|
|
||||||
|
|
||||||
|
* Checks for common misspellings were added to the pre-commit hooks.
|
||||||
|
`#3076 <https://github.com/pybind/pybind11/pull/3076>`_
|
||||||
|
|
||||||
|
* Changed ``Werror`` to stricter ``Werror-all`` for Intel compiler and fixed
|
||||||
|
minor issues.
|
||||||
|
`#2948 <https://github.com/pybind/pybind11/pull/2948>`_
|
||||||
|
|
||||||
|
* Fixed compilation with GCC < 5 when the user defines ``_GLIBCXX_USE_CXX11_ABI``.
|
||||||
|
`#2956 <https://github.com/pybind/pybind11/pull/2956>`_
|
||||||
|
|
||||||
|
* Added nox support for easier local testing and linting of contributions.
|
||||||
|
`#3101 <https://github.com/pybind/pybind11/pull/3101>`_ and
|
||||||
|
`#3121 <https://github.com/pybind/pybind11/pull/3121>`_
|
||||||
|
|
||||||
|
* Avoid RTD style issue with docutils 0.17+.
|
||||||
|
`#3119 <https://github.com/pybind/pybind11/pull/3119>`_
|
||||||
|
|
||||||
|
* Support pipx run, such as ``pipx run pybind11 --include`` for a quick compile.
|
||||||
|
`#3117 <https://github.com/pybind/pybind11/pull/3117>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v2.6.2 (Jan 26, 2021)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Minor missing functionality added:
|
||||||
|
|
||||||
|
* enum: add missing Enum.value property.
|
||||||
|
`#2739 <https://github.com/pybind/pybind11/pull/2739>`_
|
||||||
|
|
||||||
|
* Allow thread termination to be avoided during shutdown for CPython 3.7+ via
|
||||||
|
``.disarm`` for ``gil_scoped_acquire``/``gil_scoped_release``.
|
||||||
|
`#2657 <https://github.com/pybind/pybind11/pull/2657>`_
|
||||||
|
|
||||||
|
Fixed or improved behavior in a few special cases:
|
||||||
|
|
||||||
|
* Fix bug where the constructor of ``object`` subclasses would not throw on
|
||||||
|
being passed a Python object of the wrong type.
|
||||||
|
`#2701 <https://github.com/pybind/pybind11/pull/2701>`_
|
||||||
|
|
||||||
|
* The ``type_caster`` for integers does not convert Python objects with
|
||||||
|
``__int__`` anymore with ``noconvert`` or during the first round of trying
|
||||||
|
overloads.
|
||||||
|
`#2698 <https://github.com/pybind/pybind11/pull/2698>`_
|
||||||
|
|
||||||
|
* When casting to a C++ integer, ``__index__`` is always called and not
|
||||||
|
considered as conversion, consistent with Python 3.8+.
|
||||||
|
`#2801 <https://github.com/pybind/pybind11/pull/2801>`_
|
||||||
|
|
||||||
|
Build improvements:
|
||||||
|
|
||||||
|
* Setup helpers: ``extra_compile_args`` and ``extra_link_args`` automatically set by
|
||||||
|
Pybind11Extension are now prepended, which allows them to be overridden
|
||||||
|
by user-set ``extra_compile_args`` and ``extra_link_args``.
|
||||||
|
`#2808 <https://github.com/pybind/pybind11/pull/2808>`_
|
||||||
|
|
||||||
|
* Setup helpers: Don't trigger unused parameter warning.
|
||||||
|
`#2735 <https://github.com/pybind/pybind11/pull/2735>`_
|
||||||
|
|
||||||
|
* CMake: Support running with ``--warn-uninitialized`` active.
|
||||||
|
`#2806 <https://github.com/pybind/pybind11/pull/2806>`_
|
||||||
|
|
||||||
|
* CMake: Avoid error if included from two submodule directories.
|
||||||
|
`#2804 <https://github.com/pybind/pybind11/pull/2804>`_
|
||||||
|
|
||||||
|
* CMake: Fix ``STATIC`` / ``SHARED`` being ignored in FindPython mode.
|
||||||
|
`#2796 <https://github.com/pybind/pybind11/pull/2796>`_
|
||||||
|
|
||||||
|
* CMake: Respect the setting for ``CMAKE_CXX_VISIBILITY_PRESET`` if defined.
|
||||||
|
`#2793 <https://github.com/pybind/pybind11/pull/2793>`_
|
||||||
|
|
||||||
|
* CMake: Fix issue with FindPython2/FindPython3 not working with ``pybind11::embed``.
|
||||||
|
`#2662 <https://github.com/pybind/pybind11/pull/2662>`_
|
||||||
|
|
||||||
|
* CMake: mixing local and installed pybind11's would prioritize the installed
|
||||||
|
one over the local one (regression in 2.6.0).
|
||||||
|
`#2716 <https://github.com/pybind/pybind11/pull/2716>`_
|
||||||
|
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Fixed segfault in multithreaded environments when using
|
||||||
|
``scoped_ostream_redirect``.
|
||||||
|
`#2675 <https://github.com/pybind/pybind11/pull/2675>`_
|
||||||
|
|
||||||
|
* Leave docstring unset when all docstring-related options are disabled, rather
|
||||||
|
than set an empty string.
|
||||||
|
`#2745 <https://github.com/pybind/pybind11/pull/2745>`_
|
||||||
|
|
||||||
|
* The module key in builtins that pybind11 uses to store its internals changed
|
||||||
|
from std::string to a python str type (more natural on Python 2, no change on
|
||||||
|
Python 3).
|
||||||
|
`#2814 <https://github.com/pybind/pybind11/pull/2814>`_
|
||||||
|
|
||||||
|
* Fixed assertion error related to unhandled (later overwritten) exception in
|
||||||
|
CPython 3.8 and 3.9 debug builds.
|
||||||
|
`#2685 <https://github.com/pybind/pybind11/pull/2685>`_
|
||||||
|
|
||||||
|
* Fix ``py::gil_scoped_acquire`` assert with CPython 3.9 debug build.
|
||||||
|
`#2683 <https://github.com/pybind/pybind11/pull/2683>`_
|
||||||
|
|
||||||
|
* Fix issue with a test failing on pytest 6.2.
|
||||||
|
`#2741 <https://github.com/pybind/pybind11/pull/2741>`_
|
||||||
|
|
||||||
|
Warning fixes:
|
||||||
|
|
||||||
|
* Fix warning modifying constructor parameter 'flag' that shadows a field of
|
||||||
|
'set_flag' ``[-Wshadow-field-in-constructor-modified]``.
|
||||||
|
`#2780 <https://github.com/pybind/pybind11/pull/2780>`_
|
||||||
|
|
||||||
|
* Suppressed some deprecation warnings about old-style
|
||||||
|
``__init__``/``__setstate__`` in the tests.
|
||||||
|
`#2759 <https://github.com/pybind/pybind11/pull/2759>`_
|
||||||
|
|
||||||
|
Valgrind work:
|
||||||
|
|
||||||
|
* Fix invalid access when calling a pybind11 ``__init__`` on a non-pybind11
|
||||||
|
class instance.
|
||||||
|
`#2755 <https://github.com/pybind/pybind11/pull/2755>`_
|
||||||
|
|
||||||
|
* Fixed various minor memory leaks in pybind11's test suite.
|
||||||
|
`#2758 <https://github.com/pybind/pybind11/pull/2758>`_
|
||||||
|
|
||||||
|
* Resolved memory leak in cpp_function initialization when exceptions occurred.
|
||||||
|
`#2756 <https://github.com/pybind/pybind11/pull/2756>`_
|
||||||
|
|
||||||
|
* Added a Valgrind build, checking for leaks and memory-related UB, to CI.
|
||||||
|
`#2746 <https://github.com/pybind/pybind11/pull/2746>`_
|
||||||
|
|
||||||
|
Compiler support:
|
||||||
|
|
||||||
|
* Intel compiler was not activating C++14 support due to a broken define.
|
||||||
|
`#2679 <https://github.com/pybind/pybind11/pull/2679>`_
|
||||||
|
|
||||||
|
* Support ICC and NVIDIA HPC SDK in C++17 mode.
|
||||||
|
`#2729 <https://github.com/pybind/pybind11/pull/2729>`_
|
||||||
|
|
||||||
|
* Support Intel OneAPI compiler (ICC 20.2) and add to CI.
|
||||||
|
`#2573 <https://github.com/pybind/pybind11/pull/2573>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
v2.6.1 (Nov 11, 2020)
|
v2.6.1 (Nov 11, 2020)
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
@ -14,7 +939,7 @@ v2.6.1 (Nov 11, 2020)
|
|||||||
and ``eval`` in pure Python.
|
and ``eval`` in pure Python.
|
||||||
`#2616 <https://github.com/pybind/pybind11/pull/2616>`_
|
`#2616 <https://github.com/pybind/pybind11/pull/2616>`_
|
||||||
|
|
||||||
* ``setup_helpers`` will no longer set a minimum macOS version lower than the
|
* ``setup_helpers`` will no longer set a minimum macOS version higher than the
|
||||||
current version.
|
current version.
|
||||||
`#2622 <https://github.com/pybind/pybind11/pull/2622>`_
|
`#2622 <https://github.com/pybind/pybind11/pull/2622>`_
|
||||||
|
|
||||||
@ -142,7 +1067,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
|
||||||
@ -374,7 +1299,7 @@ v2.4.0 (Sep 19, 2019)
|
|||||||
`#1888 <https://github.com/pybind/pybind11/pull/1888>`_.
|
`#1888 <https://github.com/pybind/pybind11/pull/1888>`_.
|
||||||
|
|
||||||
* ``py::details::overload_cast_impl`` is available in C++11 mode, can be used
|
* ``py::details::overload_cast_impl`` is available in C++11 mode, can be used
|
||||||
like ``overload_cast`` with an additional set of parantheses.
|
like ``overload_cast`` with an additional set of parentheses.
|
||||||
`#1581 <https://github.com/pybind/pybind11/pull/1581>`_.
|
`#1581 <https://github.com/pybind/pybind11/pull/1581>`_.
|
||||||
|
|
||||||
* Fixed ``get_include()`` on Conda.
|
* Fixed ``get_include()`` on Conda.
|
||||||
@ -696,6 +1621,7 @@ v2.2.0 (August 31, 2017)
|
|||||||
|
|
||||||
from cpp_module import CppBase1, CppBase2
|
from cpp_module import CppBase1, CppBase2
|
||||||
|
|
||||||
|
|
||||||
class PyDerived(CppBase1, CppBase2):
|
class PyDerived(CppBase1, CppBase2):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
CppBase1.__init__(self) # C++ bases must be initialized explicitly
|
CppBase1.__init__(self) # C++ bases must be initialized explicitly
|
||||||
@ -908,7 +1834,7 @@ v2.2.0 (August 31, 2017)
|
|||||||
* Intel C++ compiler compatibility fixes.
|
* Intel C++ compiler compatibility fixes.
|
||||||
`#937 <https://github.com/pybind/pybind11/pull/937>`_.
|
`#937 <https://github.com/pybind/pybind11/pull/937>`_.
|
||||||
|
|
||||||
* Fixed implicit conversion of `py::enum_` to integer types on Python 2.7.
|
* Fixed implicit conversion of ``py::enum_`` to integer types on Python 2.7.
|
||||||
`#821 <https://github.com/pybind/pybind11/pull/821>`_.
|
`#821 <https://github.com/pybind/pybind11/pull/821>`_.
|
||||||
|
|
||||||
* Added ``py::hash`` to fetch the hash value of Python objects, and
|
* Added ``py::hash`` to fetch the hash value of Python objects, and
|
||||||
|
59
3rdparty/pybind11/docs/classes.rst
vendored
59
3rdparty/pybind11/docs/classes.rst
vendored
@ -44,14 +44,14 @@ interactive Python session demonstrating this example is shown below:
|
|||||||
|
|
||||||
% python
|
% python
|
||||||
>>> import example
|
>>> import example
|
||||||
>>> p = example.Pet('Molly')
|
>>> p = example.Pet("Molly")
|
||||||
>>> 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::
|
||||||
|
|
||||||
@ -122,12 +122,12 @@ This makes it possible to write
|
|||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> 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.
|
||||||
@ -174,10 +174,10 @@ Native Python classes can pick up new attributes dynamically:
|
|||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> class Pet:
|
>>> class Pet:
|
||||||
... name = 'Molly'
|
... name = "Molly"
|
||||||
...
|
...
|
||||||
>>> p = Pet()
|
>>> p = Pet()
|
||||||
>>> p.name = 'Charly' # overwrite existing
|
>>> p.name = "Charly" # overwrite existing
|
||||||
>>> p.age = 2 # dynamically add a new attribute
|
>>> p.age = 2 # dynamically add a new attribute
|
||||||
|
|
||||||
By default, classes exported from C++ do not support this and the only writable
|
By default, classes exported from C++ do not support this and the only writable
|
||||||
@ -195,7 +195,7 @@ Trying to set any other attribute results in an error:
|
|||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> p = example.Pet()
|
>>> p = example.Pet()
|
||||||
>>> p.name = 'Charly' # OK, attribute defined in C++
|
>>> p.name = "Charly" # OK, attribute defined in C++
|
||||||
>>> p.age = 2 # fail
|
>>> p.age = 2 # fail
|
||||||
AttributeError: 'Pet' object has no attribute 'age'
|
AttributeError: 'Pet' object has no attribute 'age'
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ Now everything works as expected:
|
|||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> p = example.Pet()
|
>>> p = example.Pet()
|
||||||
>>> p.name = 'Charly' # OK, overwrite value in C++
|
>>> p.name = "Charly" # OK, overwrite value in C++
|
||||||
>>> p.age = 2 # OK, dynamically add a new attribute
|
>>> p.age = 2 # OK, dynamically add a new attribute
|
||||||
>>> p.__dict__ # just like a native Python class
|
>>> p.__dict__ # just like a native Python class
|
||||||
{'age': 2}
|
{'age': 2}
|
||||||
@ -280,11 +280,11 @@ expose fields and methods of both types:
|
|||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> 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::
|
||||||
|
|
||||||
@ -446,8 +445,7 @@ you can use ``py::detail::overload_cast_impl`` with an additional set of parenth
|
|||||||
Enumerations and internal types
|
Enumerations and internal types
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
Let's now suppose that the example class contains an internal enumeration type,
|
Let's now suppose that the example class contains internal types like enumerations, e.g.:
|
||||||
e.g.:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@ -457,10 +455,15 @@ e.g.:
|
|||||||
Cat
|
Cat
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Attributes {
|
||||||
|
float age = 0;
|
||||||
|
};
|
||||||
|
|
||||||
Pet(const std::string &name, Kind type) : name(name), type(type) { }
|
Pet(const std::string &name, Kind type) : name(name), type(type) { }
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
Kind type;
|
Kind type;
|
||||||
|
Attributes attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
The binding code for this example looks as follows:
|
The binding code for this example looks as follows:
|
||||||
@ -471,22 +474,28 @@ The binding code for this example looks as follows:
|
|||||||
|
|
||||||
pet.def(py::init<const std::string &, Pet::Kind>())
|
pet.def(py::init<const std::string &, Pet::Kind>())
|
||||||
.def_readwrite("name", &Pet::name)
|
.def_readwrite("name", &Pet::name)
|
||||||
.def_readwrite("type", &Pet::type);
|
.def_readwrite("type", &Pet::type)
|
||||||
|
.def_readwrite("attr", &Pet::attr);
|
||||||
|
|
||||||
py::enum_<Pet::Kind>(pet, "Kind")
|
py::enum_<Pet::Kind>(pet, "Kind")
|
||||||
.value("Dog", Pet::Kind::Dog)
|
.value("Dog", Pet::Kind::Dog)
|
||||||
.value("Cat", Pet::Kind::Cat)
|
.value("Cat", Pet::Kind::Cat)
|
||||||
.export_values();
|
.export_values();
|
||||||
|
|
||||||
To ensure that the ``Kind`` type is created within the scope of ``Pet``, the
|
py::class_<Pet::Attributes>(pet, "Attributes")
|
||||||
``pet`` :class:`class_` instance must be supplied to the :class:`enum_`.
|
.def(py::init<>())
|
||||||
|
.def_readwrite("age", &Pet::Attributes::age);
|
||||||
|
|
||||||
|
|
||||||
|
To ensure that the nested types ``Kind`` and ``Attributes`` are created within the scope of ``Pet``, the
|
||||||
|
``pet`` :class:`class_` instance must be supplied to the :class:`enum_` and :class:`class_`
|
||||||
constructor. The :func:`enum_::export_values` function exports the enum entries
|
constructor. The :func:`enum_::export_values` function exports the enum entries
|
||||||
into the parent scope, which should be skipped for newer C++11-style strongly
|
into the parent scope, which should be skipped for newer C++11-style strongly
|
||||||
typed enums.
|
typed enums.
|
||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> p = Pet('Lucy', Pet.Cat)
|
>>> p = Pet("Lucy", Pet.Cat)
|
||||||
>>> p.type
|
>>> p.type
|
||||||
Kind.Cat
|
Kind.Cat
|
||||||
>>> int(p.type)
|
>>> int(p.type)
|
||||||
@ -508,7 +517,7 @@ The ``name`` property returns the name of the enum value as a unicode string.
|
|||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
>>> p = Pet( "Lucy", Pet.Cat )
|
>>> p = Pet("Lucy", Pet.Cat)
|
||||||
>>> pet_type = p.type
|
>>> pet_type = p.type
|
||||||
>>> pet_type
|
>>> pet_type
|
||||||
Pet.Cat
|
Pet.Cat
|
||||||
|
94
3rdparty/pybind11/docs/compiling.rst
vendored
94
3rdparty/pybind11/docs/compiling.rst
vendored
@ -42,10 +42,7 @@ An example of a ``setup.py`` using pybind11's helpers:
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
setup(
|
setup(..., ext_modules=ext_modules)
|
||||||
...,
|
|
||||||
ext_modules=ext_modules
|
|
||||||
)
|
|
||||||
|
|
||||||
If you want to do an automatic search for the highest supported C++ standard,
|
If you want to do an automatic search for the highest supported C++ standard,
|
||||||
that is supported via a ``build_ext`` command override; it will only affect
|
that is supported via a ``build_ext`` command override; it will only affect
|
||||||
@ -64,11 +61,20 @@ that is supported via a ``build_ext`` command override; it will only affect
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
setup(
|
setup(..., cmdclass={"build_ext": build_ext}, ext_modules=ext_modules)
|
||||||
...,
|
|
||||||
cmdclass={"build_ext": build_ext},
|
If you have single-file extension modules that are directly stored in the
|
||||||
ext_modules=ext_modules
|
Python source tree (``foo.cpp`` in the same directory as where a ``foo.py``
|
||||||
)
|
would be located), you can also generate ``Pybind11Extensions`` using
|
||||||
|
``setup_helpers.intree_extensions``: ``intree_extensions(["path/to/foo.cpp",
|
||||||
|
...])`` returns a list of ``Pybind11Extensions`` which can be passed to
|
||||||
|
``ext_modules``, possibly after further customizing their attributes
|
||||||
|
(``libraries``, ``include_dirs``, etc.). By doing so, a ``foo.*.so`` extension
|
||||||
|
module will be generated and made available upon installation.
|
||||||
|
|
||||||
|
``intree_extension`` will automatically detect if you are using a ``src``-style
|
||||||
|
layout (as long as no namespace packages are involved), but you can also
|
||||||
|
explicitly pass ``package_dir`` to it (as in ``setuptools.setup``).
|
||||||
|
|
||||||
Since pybind11 does not require NumPy when building, a light-weight replacement
|
Since pybind11 does not require NumPy when building, a light-weight replacement
|
||||||
for NumPy's parallel compilation distutils tool is included. Use it like this:
|
for NumPy's parallel compilation distutils tool is included. Use it like this:
|
||||||
@ -84,22 +90,23 @@ for NumPy's parallel compilation distutils tool is included. Use it like this:
|
|||||||
|
|
||||||
The argument is the name of an environment variable to control the number of
|
The argument is the name of an environment variable to control the number of
|
||||||
threads, such as ``NPY_NUM_BUILD_JOBS`` (as used by NumPy), though you can set
|
threads, such as ``NPY_NUM_BUILD_JOBS`` (as used by NumPy), though you can set
|
||||||
something different if you want. You can also pass ``default=N`` to set the
|
something different if you want; ``CMAKE_BUILD_PARALLEL_LEVEL`` is another choice
|
||||||
default number of threads (0 will take the number of threads available) and
|
a user might expect. You can also pass ``default=N`` to set the default number
|
||||||
``max=N``, the maximum number of threads; if you have a large extension you may
|
of threads (0 will take the number of threads available) and ``max=N``, the
|
||||||
want set this to a memory dependent number.
|
maximum number of threads; if you have a large extension you may want set this
|
||||||
|
to a memory dependent number.
|
||||||
|
|
||||||
If you are developing rapidly and have a lot of C++ files, you may want to
|
If you are developing rapidly and have a lot of C++ files, you may want to
|
||||||
avoid rebuilding files that have not changed. For simple cases were you are
|
avoid rebuilding files that have not changed. For simple cases were you are
|
||||||
using ``pip install -e .`` and do not have local headers, you can skip the
|
using ``pip install -e .`` and do not have local headers, you can skip the
|
||||||
rebuild if a object file is newer than it's source (headers are not checked!)
|
rebuild if an object file is newer than its source (headers are not checked!)
|
||||||
with the following:
|
with the following:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from pybind11.setup_helpers import ParallelCompile, naive_recompile
|
from pybind11.setup_helpers import ParallelCompile, naive_recompile
|
||||||
|
|
||||||
SmartCompile("NPY_NUM_BUILD_JOBS", needs_recompile=naive_recompile).install()
|
ParallelCompile("NPY_NUM_BUILD_JOBS", needs_recompile=naive_recompile).install()
|
||||||
|
|
||||||
|
|
||||||
If you have a more complex build, you can implement a smarter function and pass
|
If you have a more complex build, you can implement a smarter function and pass
|
||||||
@ -136,7 +143,7 @@ Your ``pyproject.toml`` file will likely look something like this:
|
|||||||
.. code-block:: toml
|
.. code-block:: toml
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools", "wheel", "pybind11==2.6.0"]
|
requires = ["setuptools>=42", "wheel", "pybind11~=2.6.1"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
@ -147,10 +154,12 @@ Your ``pyproject.toml`` file will likely look something like this:
|
|||||||
in Python) using something like `cibuildwheel`_, remember that ``setup.py``
|
in Python) using something like `cibuildwheel`_, remember that ``setup.py``
|
||||||
and ``pyproject.toml`` are not even contained in the wheel, so this high
|
and ``pyproject.toml`` are not even contained in the wheel, so this high
|
||||||
Pip requirement is only for source builds, and will not affect users of
|
Pip requirement is only for source builds, and will not affect users of
|
||||||
your binary wheels.
|
your binary wheels. If you are building SDists and wheels, then
|
||||||
|
`pypa-build`_ is the recommended official tool.
|
||||||
|
|
||||||
.. _PEP 517: https://www.python.org/dev/peps/pep-0517/
|
.. _PEP 517: https://www.python.org/dev/peps/pep-0517/
|
||||||
.. _cibuildwheel: https://cibuildwheel.readthedocs.io
|
.. _cibuildwheel: https://cibuildwheel.readthedocs.io
|
||||||
|
.. _pypa-build: https://pypa-build.readthedocs.io/en/latest/
|
||||||
|
|
||||||
.. _setup_helpers-setup_requires:
|
.. _setup_helpers-setup_requires:
|
||||||
|
|
||||||
@ -331,7 +340,7 @@ standard explicitly with
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ version selection") # or 11, 14, 17, 20
|
set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ version selection") # or 11, 14, 17, 20
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # optional, ensure standard is supported
|
set(CMAKE_CXX_STANDARD_REQUIRED ON) # optional, ensure standard is supported
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF) # optional, keep compiler extensionsn off
|
set(CMAKE_CXX_EXTENSIONS OFF) # optional, keep compiler extensions off
|
||||||
|
|
||||||
The variables can also be set when calling CMake from the command line using
|
The variables can also be set when calling CMake from the command line using
|
||||||
the ``-D<variable>=<value>`` flag. You can also manually set ``CXX_STANDARD``
|
the ``-D<variable>=<value>`` flag. You can also manually set ``CXX_STANDARD``
|
||||||
@ -401,16 +410,17 @@ can refer to the same [cmake_example]_ repository for a full sample project
|
|||||||
FindPython mode
|
FindPython mode
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
CMake 3.12+ (3.15+ recommended) added a new module called FindPython that had a
|
CMake 3.12+ (3.15+ recommended, 3.18.2+ ideal) added a new module called
|
||||||
highly improved search algorithm and modern targets and tools. If you use
|
FindPython that had a highly improved search algorithm and modern targets
|
||||||
FindPython, pybind11 will detect this and use the existing targets instead:
|
and tools. If you use FindPython, pybind11 will detect this and use the
|
||||||
|
existing targets instead:
|
||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
|
|
||||||
cmake_minumum_required(VERSION 3.15...3.18)
|
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)
|
||||||
|
|
||||||
@ -423,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>`_),
|
||||||
@ -433,6 +442,14 @@ setting ``Python_ROOT_DIR`` may be the most common one (though with
|
|||||||
virtualenv/venv support, and Conda support, this tends to find the correct
|
virtualenv/venv support, and Conda support, this tends to find the correct
|
||||||
Python version more often than the old system did).
|
Python version more often than the old system did).
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
When the Python libraries (i.e. ``libpythonXX.a`` and ``libpythonXX.so``
|
||||||
|
on Unix) are not available, as is the case on a manylinux image, the
|
||||||
|
``Development`` component will not be resolved by ``FindPython``. When not
|
||||||
|
using the embedding functionality, CMake 3.18+ allows you to specify
|
||||||
|
``Development.Module`` instead of ``Development`` to resolve this issue.
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
Advanced: interface library targets
|
Advanced: interface library targets
|
||||||
@ -444,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
|
||||||
@ -457,7 +471,7 @@ available in all modes. The targets provided are:
|
|||||||
Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper``
|
Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper``
|
||||||
|
|
||||||
``pybind11::embed``
|
``pybind11::embed``
|
||||||
Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Embed`` (FindPython) or Python libs
|
Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs
|
||||||
|
|
||||||
``pybind11::lto`` / ``pybind11::thin_lto``
|
``pybind11::lto`` / ``pybind11::thin_lto``
|
||||||
An alternative to `INTERPROCEDURAL_OPTIMIZATION` for adding link-time optimization.
|
An alternative to `INTERPROCEDURAL_OPTIMIZATION` for adding link-time optimization.
|
||||||
@ -491,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)
|
||||||
|
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
|
||||||
|
# Strip unnecessary sections of the binary on Linux/macOS
|
||||||
pybind11_strip(example)
|
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")
|
||||||
@ -504,7 +521,7 @@ Instead of setting properties, you can set ``CMAKE_*`` variables to initialize t
|
|||||||
compiler flags are provided to ensure high quality code generation. In
|
compiler flags are provided to ensure high quality code generation. In
|
||||||
contrast to the ``pybind11_add_module()`` command, the CMake interface
|
contrast to the ``pybind11_add_module()`` command, the CMake interface
|
||||||
provides a *composable* set of targets to ensure that you retain flexibility.
|
provides a *composable* set of targets to ensure that you retain flexibility.
|
||||||
It can be expecially important to provide or set these properties; the
|
It can be especially important to provide or set these properties; the
|
||||||
:ref:`FAQ <faq:symhidden>` contains an explanation on why these are needed.
|
:ref:`FAQ <faq:symhidden>` contains an explanation on why these are needed.
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
@ -557,10 +574,7 @@ On Linux, you can compile an example such as the one given in
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ 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
|
||||||
@ -568,19 +582,13 @@ 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:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ c++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
|
$ c++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
|
||||||
|
|
||||||
In general, it is advisable to include several additional build parameters
|
In general, it is advisable to include several additional build parameters
|
||||||
that can considerably reduce the size of the created binary. Refer to section
|
that can considerably reduce the size of the created binary. Refer to section
|
||||||
|
42
3rdparty/pybind11/docs/conf.py
vendored
42
3rdparty/pybind11/docs/conf.py
vendored
@ -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.
|
||||||
@ -13,12 +12,11 @@
|
|||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import shlex
|
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
DIR = Path(__file__).parent.resolve()
|
DIR = Path(__file__).parent.resolve()
|
||||||
|
|
||||||
@ -37,6 +35,7 @@ DIR = Path(__file__).parent.resolve()
|
|||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
"breathe",
|
"breathe",
|
||||||
|
"sphinx_copybutton",
|
||||||
"sphinxcontrib.rsvgconverter",
|
"sphinxcontrib.rsvgconverter",
|
||||||
"sphinxcontrib.moderncmakedomain",
|
"sphinxcontrib.moderncmakedomain",
|
||||||
]
|
]
|
||||||
@ -127,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
|
||||||
@ -174,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.
|
||||||
@ -239,6 +226,8 @@ htmlhelp_basename = "pybind11doc"
|
|||||||
|
|
||||||
# -- Options for LaTeX output ---------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
latex_engine = "pdflatex"
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
# 'papersize': 'letterpaper',
|
# 'papersize': 'letterpaper',
|
||||||
@ -344,17 +333,20 @@ 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):
|
||||||
with open(DIR.parent / "README.rst") as f:
|
with open(DIR.parent / "README.rst") as f:
|
||||||
contents = f.read()
|
contents = f.read()
|
||||||
|
|
||||||
# Filter out section titles for index.rst for LaTeX
|
|
||||||
if app.builder.name == "latex":
|
if app.builder.name == "latex":
|
||||||
|
# Remove badges and stuff from start
|
||||||
|
contents = contents[contents.find(r".. start") :]
|
||||||
|
|
||||||
|
# Filter out section titles for index.rst for LaTeX
|
||||||
contents = re.sub(r"^(.*)\n[-~]{3,}$", r"**\1**", contents, flags=re.MULTILINE)
|
contents = re.sub(r"^(.*)\n[-~]{3,}$", r"**\1**", contents, flags=re.MULTILINE)
|
||||||
|
|
||||||
with open(DIR / "readme.rst", "w") as f:
|
with open(DIR / "readme.rst", "w") as f:
|
||||||
|
50
3rdparty/pybind11/docs/faq.rst
vendored
50
3rdparty/pybind11/docs/faq.rst
vendored
@ -5,12 +5,10 @@ Frequently asked questions
|
|||||||
===========================================================
|
===========================================================
|
||||||
|
|
||||||
1. Make sure that the name specified in PYBIND11_MODULE is identical to the
|
1. Make sure that the name specified in PYBIND11_MODULE is identical to the
|
||||||
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
|
||||||
@ -169,8 +167,8 @@ can be changed, but even if it isn't it is not always enough to guarantee
|
|||||||
complete independence of the symbols involved when not using
|
complete independence of the symbols involved when not using
|
||||||
``-fvisibility=hidden``.
|
``-fvisibility=hidden``.
|
||||||
|
|
||||||
Additionally, ``-fvisiblity=hidden`` can deliver considerably binary size
|
Additionally, ``-fvisibility=hidden`` can deliver considerably binary size
|
||||||
savings. (See the following section for more details).
|
savings. (See the following section for more details.)
|
||||||
|
|
||||||
|
|
||||||
.. _`faq:symhidden`:
|
.. _`faq:symhidden`:
|
||||||
@ -180,7 +178,7 @@ How can I create smaller binaries?
|
|||||||
|
|
||||||
To do its job, pybind11 extensively relies on a programming technique known as
|
To do its job, pybind11 extensively relies on a programming technique known as
|
||||||
*template metaprogramming*, which is a way of performing computation at compile
|
*template metaprogramming*, which is a way of performing computation at compile
|
||||||
time using type information. Template metaprogamming usually instantiates code
|
time using type information. Template metaprogramming usually instantiates code
|
||||||
involving significant numbers of deeply nested types that are either completely
|
involving significant numbers of deeply nested types that are either completely
|
||||||
removed or reduced to just a few instructions during the compiler's optimization
|
removed or reduced to just a few instructions during the compiler's optimization
|
||||||
phase. However, due to the nested nature of these types, the resulting symbol
|
phase. However, due to the nested nature of these types, the resulting symbol
|
||||||
@ -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:
|
||||||
|
|
||||||
|
4
3rdparty/pybind11/docs/installing.rst
vendored
4
3rdparty/pybind11/docs/installing.rst
vendored
@ -8,6 +8,8 @@ There are several ways to get the pybind11 source, which lives at
|
|||||||
developers recommend one of the first three ways listed here, submodule, PyPI,
|
developers recommend one of the first three ways listed here, submodule, PyPI,
|
||||||
or conda-forge, for obtaining pybind11.
|
or conda-forge, for obtaining pybind11.
|
||||||
|
|
||||||
|
.. _include_as_a_submodule:
|
||||||
|
|
||||||
Include as a submodule
|
Include as a submodule
|
||||||
======================
|
======================
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ as a submodule. From your git repository, use:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
git submodule add ../../pybind/pybind11 extern/pybind11 -b stable
|
git submodule add -b stable ../../pybind/pybind11 extern/pybind11
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
||||||
This assumes you are placing your dependencies in ``extern/``, and that you are
|
This assumes you are placing your dependencies in ``extern/``, and that you are
|
||||||
|
20
3rdparty/pybind11/docs/limitations.rst
vendored
20
3rdparty/pybind11/docs/limitations.rst
vendored
@ -57,16 +57,16 @@ clean, well written patch would likely be accepted to solve them.
|
|||||||
Python 3.9.0 warning
|
Python 3.9.0 warning
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Combining older versions of pybind11 (< 2.6.0) with Python on 3.9.0 will
|
Combining older versions of pybind11 (< 2.6.0) with Python on exactly 3.9.0
|
||||||
trigger undefined behavior that typically manifests as crashes during
|
will trigger undefined behavior that typically manifests as crashes during
|
||||||
interpreter shutdown (but could also destroy your data. **You have been
|
interpreter shutdown (but could also destroy your data. **You have been
|
||||||
warned**).
|
warned**).
|
||||||
|
|
||||||
This issue has been
|
This issue was `fixed in Python <https://github.com/python/cpython/pull/22670>`_.
|
||||||
`fixed in Python <https://github.com/python/cpython/pull/22670>`_. As a
|
As a mitigation for this bug, pybind11 2.6.0 or newer includes a workaround
|
||||||
mitigation until 3.9.1 is released and commonly used, pybind11 (2.6.0 or newer)
|
specifically when Python 3.9.0 is detected at runtime, leaking about 50 bytes
|
||||||
includes a temporary workaround specifically when Python 3.9.0 is detected at
|
of memory when a callback function is garbage collected. For reference, the
|
||||||
runtime, leaking about 50 bytes of memory when a callback function is garbage
|
pybind11 test suite has about 2,000 such callbacks, but only 49 are garbage
|
||||||
collected. For reference; the pybind11 test suite has about 2,000 such
|
collected before the end-of-process. Wheels (even if built with Python 3.9.0)
|
||||||
callbacks, but only 49 are garbage collected before the end-of-process. Wheels
|
will correctly avoid the leak when run in Python 3.9.1, and this does not
|
||||||
built with Python 3.9.0 will correctly avoid the leak when run in Python 3.9.1.
|
affect other 3.X versions.
|
||||||
|
BIN
3rdparty/pybind11/docs/pybind11-logo.png
vendored
BIN
3rdparty/pybind11/docs/pybind11-logo.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 60 KiB |
15
3rdparty/pybind11/docs/reference.rst
vendored
15
3rdparty/pybind11/docs/reference.rst
vendored
@ -52,6 +52,20 @@ Convenience classes for specific Python types
|
|||||||
.. doxygengroup:: pytypes
|
.. doxygengroup:: pytypes
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Convenience functions converting to Python types
|
||||||
|
================================================
|
||||||
|
|
||||||
|
.. doxygenfunction:: make_tuple(Args&&...)
|
||||||
|
|
||||||
|
.. doxygenfunction:: make_iterator(Iterator, Sentinel, Extra &&...)
|
||||||
|
.. doxygenfunction:: make_iterator(Type &, Extra&&...)
|
||||||
|
|
||||||
|
.. doxygenfunction:: make_key_iterator(Iterator, Sentinel, Extra &&...)
|
||||||
|
.. doxygenfunction:: make_key_iterator(Type &, Extra&&...)
|
||||||
|
|
||||||
|
.. doxygenfunction:: make_value_iterator(Iterator, Sentinel, Extra &&...)
|
||||||
|
.. doxygenfunction:: make_value_iterator(Type &, Extra&&...)
|
||||||
|
|
||||||
.. _extras:
|
.. _extras:
|
||||||
|
|
||||||
Passing extra arguments to ``def`` or ``class_``
|
Passing extra arguments to ``def`` or ``class_``
|
||||||
@ -110,7 +124,6 @@ Exceptions
|
|||||||
.. doxygenclass:: builtin_exception
|
.. doxygenclass:: builtin_exception
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Literals
|
Literals
|
||||||
========
|
========
|
||||||
|
|
||||||
|
48
3rdparty/pybind11/docs/release.rst
vendored
48
3rdparty/pybind11/docs/release.rst
vendored
@ -15,22 +15,33 @@ For example:
|
|||||||
|
|
||||||
For beta, ``PYBIND11_VERSION_PATCH`` should be ``Z.b1``. RC's can be ``Z.rc1``.
|
For beta, ``PYBIND11_VERSION_PATCH`` should be ``Z.b1``. RC's can be ``Z.rc1``.
|
||||||
Always include the dot (even though PEP 440 allows it to be dropped). For a
|
Always include the dot (even though PEP 440 allows it to be dropped). For a
|
||||||
final release, this must be a simple integer.
|
final release, this must be a simple integer. There is also a HEX version of
|
||||||
|
the version just below.
|
||||||
|
|
||||||
|
|
||||||
To release a new version of pybind11:
|
To release a new version of pybind11:
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If you don't have nox, you should either use ``pipx run nox`` instead, or use
|
||||||
|
``pipx install nox`` or ``brew install nox`` (Unix).
|
||||||
|
|
||||||
- Update the version number
|
- Update the version number
|
||||||
- Update ``PYBIND11_VERSION_MAJOR`` etc. in
|
- Update ``PYBIND11_VERSION_MAJOR`` etc. in
|
||||||
``include/pybind11/detail/common.h``. PATCH should be a simple integer.
|
``include/pybind11/detail/common.h``. PATCH should be a simple integer.
|
||||||
|
- Update the version HEX just below, as well.
|
||||||
- Update ``pybind11/_version.py`` (match above)
|
- Update ``pybind11/_version.py`` (match above)
|
||||||
- Ensure that all the information in ``setup.py`` is up-to-date.
|
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
|
||||||
|
- Ensure that all the information in ``setup.cfg`` is up-to-date, like
|
||||||
|
supported Python versions.
|
||||||
- Add release date in ``docs/changelog.rst``.
|
- Add release date in ``docs/changelog.rst``.
|
||||||
|
- Check to make sure
|
||||||
|
`needs-changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_
|
||||||
|
issues are entered in the changelog (clear the label when done).
|
||||||
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
|
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
|
||||||
fails due to a known flake issue, either ignore or restart CI.)
|
fails due to a known flake issue, either ignore or restart CI.)
|
||||||
- Add a release branch if this is a new minor version
|
- Add a release branch if this is a new minor version, or update the existing release branch if it is a patch version
|
||||||
- ``git checkout -b vX.Y``, ``git push -u origin vX.Y``
|
- New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y``
|
||||||
|
- Update branch: ``git checkout vX.Y``, ``git merge <release branch>``, ``git push``
|
||||||
- Update tags (optional; if you skip this, the GitHub release makes a
|
- Update tags (optional; if you skip this, the GitHub release makes a
|
||||||
non-annotated tag for you)
|
non-annotated tag for you)
|
||||||
- ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``.
|
- ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``.
|
||||||
@ -42,12 +53,13 @@ To release a new version of pybind11:
|
|||||||
- Make a GitHub release (this shows up in the UI, sends new release
|
- Make a GitHub release (this shows up in the UI, sends new release
|
||||||
notifications to users watching releases, and also uploads PyPI packages).
|
notifications to users watching releases, and also uploads PyPI packages).
|
||||||
(Note: if you do not use an existing tag, this creates a new lightweight tag
|
(Note: if you do not use an existing tag, this creates a new lightweight tag
|
||||||
for you, so you could skip the above step).
|
for you, so you could skip the above step.)
|
||||||
- GUI method: click "Create a new release" on the far right, fill in the tag
|
- GUI method: Under `releases <https://github.com/pybind/pybind11/releases>`_
|
||||||
name (if you didn't tag above, it will be made here), fill in a release
|
click "Draft a new release" on the far right, fill in the tag name
|
||||||
name like "Version X.Y.Z", and optionally copy-and-paste the changelog into
|
(if you didn't tag above, it will be made here), fill in a release name
|
||||||
the description (processed as markdown by Pandoc). Check "pre-release" if
|
like "Version X.Y.Z", and copy-and-paste the markdown-formatted (!) changelog
|
||||||
this is a beta/RC.
|
into the description (usually ``cat docs/changelog.rst | pandoc -f rst -t gfm``).
|
||||||
|
Check "pre-release" if this is a beta/RC.
|
||||||
- CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"``
|
- CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"``
|
||||||
If this is a pre-release, add ``-p``.
|
If this is a pre-release, add ``-p``.
|
||||||
|
|
||||||
@ -56,11 +68,21 @@ To release a new version of pybind11:
|
|||||||
- Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to
|
- Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to
|
||||||
``0.dev1`` and increment MINOR).
|
``0.dev1`` and increment MINOR).
|
||||||
- Update ``_version.py`` to match
|
- Update ``_version.py`` to match
|
||||||
- Add a plot for in-development updates in ``docs/changelog.rst``.
|
- Run ``nox -s tests_packaging`` to ensure this was done correctly.
|
||||||
|
- Add a spot for in-development updates in ``docs/changelog.rst``.
|
||||||
- ``git add``, ``git commit``, ``git push``
|
- ``git add``, ``git commit``, ``git push``
|
||||||
|
|
||||||
If a version branch is updated, remember to set PATCH to ``1.dev1``.
|
If a version branch is updated, remember to set PATCH to ``1.dev1``.
|
||||||
|
|
||||||
|
If you'd like to bump homebrew, run:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
brew bump-formula-pr --url https://github.com/pybind/pybind11/archive/vX.Y.Z.tar.gz
|
||||||
|
|
||||||
|
Conda-forge should automatically make a PR in a few hours, and automatically
|
||||||
|
merge it if there are no issues.
|
||||||
|
|
||||||
|
|
||||||
Manual packaging
|
Manual packaging
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
@ -69,9 +91,7 @@ If you need to manually upload releases, you can download the releases from the
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
python3 -m pip install build
|
nox -s build
|
||||||
python3 -m build
|
|
||||||
PYBIND11_SDIST_GLOBAL=1 python3 -m build
|
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
|
||||||
This makes SDists and wheels, and the final line uploads them.
|
This makes SDists and wheels, and the final line uploads them.
|
||||||
|
13
3rdparty/pybind11/docs/requirements.txt
vendored
13
3rdparty/pybind11/docs/requirements.txt
vendored
@ -1,7 +1,6 @@
|
|||||||
breathe==4.20.0
|
breathe==4.34.0
|
||||||
commonmark==0.9.1
|
furo==2022.6.21
|
||||||
recommonmark==0.6.0
|
sphinx==5.0.2
|
||||||
sphinx==3.2.1
|
sphinx-copybutton==0.5.0
|
||||||
sphinx_rtd_theme==0.5.0
|
sphinxcontrib-moderncmakedomain==3.21.4
|
||||||
sphinxcontrib-moderncmakedomain==3.13
|
sphinxcontrib-svg2pdfconverter==1.2.0
|
||||||
sphinxcontrib-svg2pdfconverter==1.1.0
|
|
||||||
|
46
3rdparty/pybind11/docs/upgrade.rst
vendored
46
3rdparty/pybind11/docs/upgrade.rst
vendored
@ -8,6 +8,46 @@ to a new version. But it goes into more detail. This includes things like
|
|||||||
deprecated APIs and their replacements, build system changes, general code
|
deprecated APIs and their replacements, build system changes, general code
|
||||||
modernization and other useful information.
|
modernization and other useful information.
|
||||||
|
|
||||||
|
.. _upgrade-guide-2.9:
|
||||||
|
|
||||||
|
v2.9
|
||||||
|
====
|
||||||
|
|
||||||
|
* Any usage of the recently added ``py::make_simple_namespace`` should be
|
||||||
|
converted to using ``py::module_::import("types").attr("SimpleNamespace")``
|
||||||
|
instead.
|
||||||
|
|
||||||
|
* The use of ``_`` in custom type casters can now be replaced with the more
|
||||||
|
readable ``const_name`` instead. The old ``_`` shortcut has been retained
|
||||||
|
unless it is being used as a macro (like for gettext).
|
||||||
|
|
||||||
|
|
||||||
|
.. _upgrade-guide-2.7:
|
||||||
|
|
||||||
|
v2.7
|
||||||
|
====
|
||||||
|
|
||||||
|
*Before* v2.7, ``py::str`` can hold ``PyUnicodeObject`` or ``PyBytesObject``,
|
||||||
|
and ``py::isinstance<str>()`` is ``true`` for both ``py::str`` and
|
||||||
|
``py::bytes``. Starting with v2.7, ``py::str`` exclusively holds
|
||||||
|
``PyUnicodeObject`` (`#2409 <https://github.com/pybind/pybind11/pull/2409>`_),
|
||||||
|
and ``py::isinstance<str>()`` is ``true`` only for ``py::str``. To help in
|
||||||
|
the transition of user code, the ``PYBIND11_STR_LEGACY_PERMISSIVE`` macro
|
||||||
|
is provided as an escape hatch to go back to the legacy behavior. This macro
|
||||||
|
will be removed in future releases. Two types of required fixes are expected
|
||||||
|
to be common:
|
||||||
|
|
||||||
|
* Accidental use of ``py::str`` instead of ``py::bytes``, masked by the legacy
|
||||||
|
behavior. These are probably very easy to fix, by changing from
|
||||||
|
``py::str`` to ``py::bytes``.
|
||||||
|
|
||||||
|
* Reliance on py::isinstance<str>(obj) being ``true`` for
|
||||||
|
``py::bytes``. This is likely to be easy to fix in most cases by adding
|
||||||
|
``|| py::isinstance<bytes>(obj)``, but a fix may be more involved, e.g. if
|
||||||
|
``py::isinstance<T>`` appears in a template. Such situations will require
|
||||||
|
careful review and custom fixes.
|
||||||
|
|
||||||
|
|
||||||
.. _upgrade-guide-2.6:
|
.. _upgrade-guide-2.6:
|
||||||
|
|
||||||
v2.6
|
v2.6
|
||||||
@ -192,7 +232,7 @@ way to get and set object state. See :ref:`pickling` for details.
|
|||||||
...
|
...
|
||||||
.def(py::pickle(
|
.def(py::pickle(
|
||||||
[](const Foo &self) { // __getstate__
|
[](const Foo &self) { // __getstate__
|
||||||
return py::make_tuple(f.value1(), f.value2(), ...); // unchanged
|
return py::make_tuple(self.value1(), self.value2(), ...); // unchanged
|
||||||
},
|
},
|
||||||
[](py::tuple t) { // __setstate__, note: no `self` argument
|
[](py::tuple t) { // __setstate__, note: no `self` argument
|
||||||
return new Foo(t[0].cast<std::string>(), ...);
|
return new Foo(t[0].cast<std::string>(), ...);
|
||||||
@ -256,7 +296,7 @@ Within pybind11's CMake build system, ``pybind11_add_module`` has always been
|
|||||||
setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's
|
setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's
|
||||||
being applied unconditionally, even in debug mode and it can no longer be opted
|
being applied unconditionally, even in debug mode and it can no longer be opted
|
||||||
out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also
|
out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also
|
||||||
adds this flag to it's interface. The ``pybind11::embed`` target is unchanged.
|
adds this flag to its interface. The ``pybind11::embed`` target is unchanged.
|
||||||
|
|
||||||
The most significant change here is for the ``pybind11::module`` target. If you
|
The most significant change here is for the ``pybind11::module`` target. If you
|
||||||
were previously relying on default visibility, i.e. if your Python module was
|
were previously relying on default visibility, i.e. if your Python module was
|
||||||
@ -484,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.
|
||||||
|
|
||||||
|
|
||||||
|
353
3rdparty/pybind11/include/pybind11/attr.h
vendored
353
3rdparty/pybind11/include/pybind11/attr.h
vendored
@ -10,72 +10,113 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
#include "cast.h"
|
#include "cast.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
/// \addtogroup annotations
|
/// \addtogroup annotations
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Annotation for methods
|
/// Annotation for methods
|
||||||
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
|
struct is_method {
|
||||||
|
handle class_;
|
||||||
|
explicit is_method(const handle &c) : class_(c) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Annotation for operators
|
/// Annotation for operators
|
||||||
struct is_operator { };
|
struct is_operator {};
|
||||||
|
|
||||||
/// Annotation for classes that cannot be subclassed
|
/// Annotation for classes that cannot be subclassed
|
||||||
struct is_final { };
|
struct is_final {};
|
||||||
|
|
||||||
/// Annotation for parent scope
|
/// Annotation for parent scope
|
||||||
struct scope { handle value; scope(const handle &s) : value(s) { } };
|
struct scope {
|
||||||
|
handle value;
|
||||||
|
explicit scope(const handle &s) : value(s) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Annotation for documentation
|
/// Annotation for documentation
|
||||||
struct doc { const char *value; doc(const char *value) : value(value) { } };
|
struct doc {
|
||||||
|
const char *value;
|
||||||
|
explicit doc(const char *value) : value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Annotation for function names
|
/// Annotation for function names
|
||||||
struct name { const char *value; name(const char *value) : value(value) { } };
|
struct name {
|
||||||
|
const char *value;
|
||||||
|
explicit name(const char *value) : value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Annotation indicating that a function is an overload associated with a given "sibling"
|
/// Annotation indicating that a function is an overload associated with a given "sibling"
|
||||||
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
|
struct sibling {
|
||||||
|
handle value;
|
||||||
|
explicit sibling(const handle &value) : value(value.ptr()) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Annotation indicating that a class derives from another given type
|
/// Annotation indicating that a class derives from another given type
|
||||||
template <typename T> struct base {
|
template <typename T>
|
||||||
|
struct base {
|
||||||
|
|
||||||
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
PYBIND11_DEPRECATED(
|
||||||
base() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
|
"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
||||||
|
base() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Keep patient alive while nurse lives
|
/// Keep patient alive while nurse lives
|
||||||
template <size_t Nurse, size_t Patient> struct keep_alive { };
|
template <size_t Nurse, size_t Patient>
|
||||||
|
struct keep_alive {};
|
||||||
|
|
||||||
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
||||||
struct multiple_inheritance { };
|
struct multiple_inheritance {};
|
||||||
|
|
||||||
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
|
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
|
||||||
struct dynamic_attr { };
|
struct dynamic_attr {};
|
||||||
|
|
||||||
/// Annotation which enables the buffer protocol for a type
|
/// Annotation which enables the buffer protocol for a type
|
||||||
struct buffer_protocol { };
|
struct buffer_protocol {};
|
||||||
|
|
||||||
/// Annotation which requests that a special metaclass is created for a type
|
/// Annotation which requests that a special metaclass is created for a type
|
||||||
struct metaclass {
|
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.")
|
||||||
metaclass() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
|
metaclass() = default;
|
||||||
|
|
||||||
/// Override pybind11's default metaclass
|
/// Override pybind11's default metaclass
|
||||||
explicit metaclass(handle value) : value(value) { }
|
explicit metaclass(handle value) : value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that
|
||||||
|
/// may be used to customize the Python type.
|
||||||
|
///
|
||||||
|
/// The callback is invoked immediately before `PyType_Ready`.
|
||||||
|
///
|
||||||
|
/// Note: This is an advanced interface, and uses of it may require changes to
|
||||||
|
/// work with later versions of pybind11. You may wish to consult the
|
||||||
|
/// implementation of `make_new_python_type` in `detail/classes.h` to understand
|
||||||
|
/// the context in which the callback will be run.
|
||||||
|
struct custom_type_setup {
|
||||||
|
using callback = std::function<void(PyHeapTypeObject *heap_type)>;
|
||||||
|
|
||||||
|
explicit custom_type_setup(callback value) : value(std::move(value)) {}
|
||||||
|
|
||||||
|
callback value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Annotation that marks a class as local to the module:
|
/// Annotation that marks a class as local to the module:
|
||||||
struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } };
|
struct module_local {
|
||||||
|
const bool value;
|
||||||
|
constexpr explicit module_local(bool v = true) : value(v) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Annotation to mark enums as an arithmetic type
|
/// Annotation to mark enums as an arithmetic type
|
||||||
struct arithmetic { };
|
struct arithmetic {};
|
||||||
|
|
||||||
/// Mark a function for addition at the beginning of the existing overload chain instead of the end
|
/// Mark a function for addition at the beginning of the existing overload chain instead of the end
|
||||||
struct prepend { };
|
struct prepend {};
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
A call policy which places one or more guard variables (``Ts...``) around the function call.
|
A call policy which places one or more guard variables (``Ts...``) around the function call.
|
||||||
@ -95,9 +136,13 @@ struct prepend { };
|
|||||||
return foo(args...); // forwarded arguments
|
return foo(args...); // forwarded arguments
|
||||||
});
|
});
|
||||||
\endrst */
|
\endrst */
|
||||||
template <typename... Ts> struct call_guard;
|
template <typename... Ts>
|
||||||
|
struct call_guard;
|
||||||
|
|
||||||
template <> struct call_guard<> { using type = detail::void_type; };
|
template <>
|
||||||
|
struct call_guard<> {
|
||||||
|
using type = detail::void_type;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct call_guard<T> {
|
struct call_guard<T> {
|
||||||
@ -122,8 +167,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
enum op_id : int;
|
enum op_id : int;
|
||||||
enum op_type : int;
|
enum op_type : int;
|
||||||
struct undefined_t;
|
struct undefined_t;
|
||||||
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
|
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>
|
||||||
inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
|
struct op_;
|
||||||
|
void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
|
||||||
|
|
||||||
/// Internal data structure which holds metadata about a keyword argument
|
/// Internal data structure which holds metadata about a keyword argument
|
||||||
struct argument_record {
|
struct argument_record {
|
||||||
@ -134,15 +180,16 @@ struct argument_record {
|
|||||||
bool none : 1; ///< True if None is allowed when loading
|
bool none : 1; ///< True if None is allowed when loading
|
||||||
|
|
||||||
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
|
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
|
||||||
: name(name), descr(descr), value(value), convert(convert), none(none) { }
|
: name(name), descr(descr), value(value), convert(convert), none(none) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
|
/// Internal data structure which holds metadata about a bound function (signature, overloads,
|
||||||
|
/// etc.)
|
||||||
struct function_record {
|
struct function_record {
|
||||||
function_record()
|
function_record()
|
||||||
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
|
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
|
||||||
is_operator(false), is_method(false), has_args(false),
|
is_operator(false), is_method(false), has_args(false), has_kwargs(false),
|
||||||
has_kwargs(false), has_kw_only_args(false), prepend(false) { }
|
prepend(false) {}
|
||||||
|
|
||||||
/// Function name
|
/// Function name
|
||||||
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
||||||
@ -157,13 +204,13 @@ struct function_record {
|
|||||||
std::vector<argument_record> args;
|
std::vector<argument_record> args;
|
||||||
|
|
||||||
/// Pointer to lambda function which converts arguments and performs the actual call
|
/// Pointer to lambda function which converts arguments and performs the actual call
|
||||||
handle (*impl) (function_call &) = nullptr;
|
handle (*impl)(function_call &) = nullptr;
|
||||||
|
|
||||||
/// Storage for the wrapped function pointer and captured data, if any
|
/// Storage for the wrapped function pointer and captured data, if any
|
||||||
void *data[3] = { };
|
void *data[3] = {};
|
||||||
|
|
||||||
/// Pointer to custom destructor for 'data' (if needed)
|
/// Pointer to custom destructor for 'data' (if needed)
|
||||||
void (*free_data) (function_record *ptr) = nullptr;
|
void (*free_data)(function_record *ptr) = nullptr;
|
||||||
|
|
||||||
/// Return value policy associated with this function
|
/// Return value policy associated with this function
|
||||||
return_value_policy policy = return_value_policy::automatic;
|
return_value_policy policy = return_value_policy::automatic;
|
||||||
@ -189,17 +236,15 @@ struct function_record {
|
|||||||
/// True if the function has a '**kwargs' argument
|
/// True if the function has a '**kwargs' argument
|
||||||
bool has_kwargs : 1;
|
bool has_kwargs : 1;
|
||||||
|
|
||||||
/// True once a 'py::kw_only' is encountered (any following args are keyword-only)
|
|
||||||
bool has_kw_only_args : 1;
|
|
||||||
|
|
||||||
/// True if this function is to be inserted at the beginning of the overload resolution chain
|
/// True if this function is to be inserted at the beginning of the overload resolution chain
|
||||||
bool prepend : 1;
|
bool prepend : 1;
|
||||||
|
|
||||||
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
||||||
std::uint16_t nargs;
|
std::uint16_t nargs;
|
||||||
|
|
||||||
/// Number of trailing arguments (counted in `nargs`) that are keyword-only
|
/// Number of leading positional arguments, which are terminated by a py::args or py::kwargs
|
||||||
std::uint16_t nargs_kw_only = 0;
|
/// argument or by a py::kw_only annotation.
|
||||||
|
std::uint16_t nargs_pos = 0;
|
||||||
|
|
||||||
/// Number of leading arguments (counted in `nargs`) that are positional-only
|
/// Number of leading arguments (counted in `nargs`) that are positional-only
|
||||||
std::uint16_t nargs_pos_only = 0;
|
std::uint16_t nargs_pos_only = 0;
|
||||||
@ -221,7 +266,7 @@ struct function_record {
|
|||||||
struct type_record {
|
struct type_record {
|
||||||
PYBIND11_NOINLINE type_record()
|
PYBIND11_NOINLINE type_record()
|
||||||
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
|
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
|
||||||
default_holder(true), module_local(false), is_final(false) { }
|
default_holder(true), module_local(false), is_final(false) {}
|
||||||
|
|
||||||
/// Handle to the parent scope
|
/// Handle to the parent scope
|
||||||
handle scope;
|
handle scope;
|
||||||
@ -259,6 +304,9 @@ struct type_record {
|
|||||||
/// Custom metaclass (optional)
|
/// Custom metaclass (optional)
|
||||||
handle metaclass;
|
handle metaclass;
|
||||||
|
|
||||||
|
/// Custom type setup.
|
||||||
|
custom_type_setup::callback custom_type_setup_callback;
|
||||||
|
|
||||||
/// Multiple inheritance marker
|
/// Multiple inheritance marker
|
||||||
bool multiple_inheritance : 1;
|
bool multiple_inheritance : 1;
|
||||||
|
|
||||||
@ -277,42 +325,45 @@ struct type_record {
|
|||||||
/// Is the class inheritable from python classes?
|
/// Is the class inheritable from python classes?
|
||||||
bool is_final : 1;
|
bool is_final : 1;
|
||||||
|
|
||||||
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) {
|
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) {
|
||||||
auto base_info = detail::get_type_info(base, false);
|
auto *base_info = detail::get_type_info(base, false);
|
||||||
if (!base_info) {
|
if (!base_info) {
|
||||||
std::string tname(base.name());
|
std::string tname(base.name());
|
||||||
detail::clean_type_id(tname);
|
detail::clean_type_id(tname);
|
||||||
pybind11_fail("generic_type: type \"" + std::string(name) +
|
pybind11_fail("generic_type: type \"" + std::string(name)
|
||||||
"\" referenced unknown base type \"" + tname + "\"");
|
+ "\" referenced unknown base type \"" + tname + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (default_holder != base_info->default_holder) {
|
if (default_holder != base_info->default_holder) {
|
||||||
std::string tname(base.name());
|
std::string tname(base.name());
|
||||||
detail::clean_type_id(tname);
|
detail::clean_type_id(tname);
|
||||||
pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
|
pybind11_fail("generic_type: type \"" + std::string(name) + "\" "
|
||||||
(default_holder ? "does not have" : "has") +
|
+ (default_holder ? "does not have" : "has")
|
||||||
" a non-default holder type while its base \"" + tname + "\" " +
|
+ " a non-default holder type while its base \"" + tname + "\" "
|
||||||
(base_info->default_holder ? "does not" : "does"));
|
+ (base_info->default_holder ? "does not" : "does"));
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline function_call::function_call(const function_record &f, handle p) :
|
inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) {
|
||||||
func(f), parent(p) {
|
|
||||||
args.reserve(f.nargs);
|
args.reserve(f.nargs);
|
||||||
args_convert.reserve(f.nargs);
|
args_convert.reserve(f.nargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tag for a new-style `__init__` defined in `detail/init.h`
|
/// Tag for a new-style `__init__` defined in `detail/init.h`
|
||||||
struct is_new_style_constructor { };
|
struct is_new_style_constructor {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Partial template specializations to process custom attributes provided to
|
* Partial template specializations to process custom attributes provided to
|
||||||
@ -320,129 +371,177 @@ struct is_new_style_constructor { };
|
|||||||
* fields in the type_record and function_record data structures or executed at
|
* fields in the type_record and function_record data structures or executed at
|
||||||
* runtime to deal with custom call policies (e.g. keep_alive).
|
* runtime to deal with custom call policies (e.g. keep_alive).
|
||||||
*/
|
*/
|
||||||
template <typename T, typename SFINAE = void> struct process_attribute;
|
template <typename T, typename SFINAE = void>
|
||||||
|
struct process_attribute;
|
||||||
|
|
||||||
template <typename T> struct process_attribute_default {
|
template <typename T>
|
||||||
|
struct process_attribute_default {
|
||||||
/// Default implementation: do nothing
|
/// Default implementation: do nothing
|
||||||
static void init(const T &, function_record *) { }
|
static void init(const T &, function_record *) {}
|
||||||
static void init(const T &, type_record *) { }
|
static void init(const T &, type_record *) {}
|
||||||
static void precall(function_call &) { }
|
static void precall(function_call &) {}
|
||||||
static void postcall(function_call &, handle) { }
|
static void postcall(function_call &, handle) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute specifying the function's name
|
/// Process an attribute specifying the function's name
|
||||||
template <> struct process_attribute<name> : process_attribute_default<name> {
|
template <>
|
||||||
|
struct process_attribute<name> : process_attribute_default<name> {
|
||||||
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
|
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute specifying the function's docstring
|
/// Process an attribute specifying the function's docstring
|
||||||
template <> struct process_attribute<doc> : process_attribute_default<doc> {
|
template <>
|
||||||
|
struct process_attribute<doc> : process_attribute_default<doc> {
|
||||||
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
|
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute specifying the function's docstring (provided as a C-style string)
|
/// Process an attribute specifying the function's docstring (provided as a C-style string)
|
||||||
template <> struct process_attribute<const char *> : process_attribute_default<const char *> {
|
template <>
|
||||||
|
struct process_attribute<const char *> : process_attribute_default<const char *> {
|
||||||
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
|
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
|
||||||
static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
|
static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
|
||||||
};
|
};
|
||||||
template <> struct process_attribute<char *> : process_attribute<const char *> { };
|
template <>
|
||||||
|
struct process_attribute<char *> : process_attribute<const char *> {};
|
||||||
|
|
||||||
/// Process an attribute indicating the function's return value policy
|
/// Process an attribute indicating the function's return value policy
|
||||||
template <> struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
|
template <>
|
||||||
|
struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
|
||||||
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
|
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute which indicates that this is an overloaded function associated with a given sibling
|
/// Process an attribute which indicates that this is an overloaded function associated with a
|
||||||
template <> struct process_attribute<sibling> : process_attribute_default<sibling> {
|
/// given sibling
|
||||||
|
template <>
|
||||||
|
struct process_attribute<sibling> : process_attribute_default<sibling> {
|
||||||
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
|
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute which indicates that this function is a method
|
/// Process an attribute which indicates that this function is a method
|
||||||
template <> struct process_attribute<is_method> : process_attribute_default<is_method> {
|
template <>
|
||||||
static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; }
|
struct process_attribute<is_method> : process_attribute_default<is_method> {
|
||||||
|
static void init(const is_method &s, function_record *r) {
|
||||||
|
r->is_method = true;
|
||||||
|
r->scope = s.class_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute which indicates the parent scope of a method
|
/// Process an attribute which indicates the parent scope of a method
|
||||||
template <> struct process_attribute<scope> : process_attribute_default<scope> {
|
template <>
|
||||||
|
struct process_attribute<scope> : process_attribute_default<scope> {
|
||||||
static void init(const scope &s, function_record *r) { r->scope = s.value; }
|
static void init(const scope &s, function_record *r) { r->scope = s.value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process an attribute which indicates that this function is an operator
|
/// Process an attribute which indicates that this function is an operator
|
||||||
template <> struct process_attribute<is_operator> : process_attribute_default<is_operator> {
|
template <>
|
||||||
|
struct process_attribute<is_operator> : process_attribute_default<is_operator> {
|
||||||
static void init(const is_operator &, function_record *r) { r->is_operator = true; }
|
static void init(const is_operator &, function_record *r) { r->is_operator = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct process_attribute<is_new_style_constructor> : process_attribute_default<is_new_style_constructor> {
|
template <>
|
||||||
static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; }
|
struct process_attribute<is_new_style_constructor>
|
||||||
|
: process_attribute_default<is_new_style_constructor> {
|
||||||
|
static void init(const is_new_style_constructor &, function_record *r) {
|
||||||
|
r->is_new_style_constructor = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void process_kw_only_arg(const arg &a, function_record *r) {
|
inline void check_kw_only_arg(const arg &a, function_record *r) {
|
||||||
if (!a.name || strlen(a.name) == 0)
|
if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) {
|
||||||
pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation");
|
pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or "
|
||||||
++r->nargs_kw_only;
|
"args() argument");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void append_self_arg_if_needed(function_record *r) {
|
||||||
|
if (r->is_method && r->args.empty()) {
|
||||||
|
r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a keyword argument attribute (*without* a default value)
|
/// Process a keyword argument attribute (*without* a default value)
|
||||||
template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
template <>
|
||||||
|
struct process_attribute<arg> : process_attribute_default<arg> {
|
||||||
static void init(const arg &a, function_record *r) {
|
static void init(const arg &a, function_record *r) {
|
||||||
if (r->is_method && r->args.empty())
|
append_self_arg_if_needed(r);
|
||||||
r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/);
|
|
||||||
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
|
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
|
||||||
|
|
||||||
if (r->has_kw_only_args) process_kw_only_arg(a, r);
|
check_kw_only_arg(a, r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process a keyword argument attribute (*with* a default value)
|
/// Process a keyword argument attribute (*with* a default value)
|
||||||
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
template <>
|
||||||
|
struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||||
static void init(const arg_v &a, function_record *r) {
|
static void init(const arg_v &a, function_record *r) {
|
||||||
if (r->is_method && r->args.empty())
|
if (r->is_method && r->args.empty()) {
|
||||||
r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/);
|
r->args.emplace_back(
|
||||||
|
"self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!a.value) {
|
if (!a.value) {
|
||||||
#if !defined(NDEBUG)
|
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
std::string descr("'");
|
std::string descr("'");
|
||||||
if (a.name) descr += std::string(a.name) + ": ";
|
if (a.name) {
|
||||||
|
descr += std::string(a.name) + ": ";
|
||||||
|
}
|
||||||
descr += a.type + "'";
|
descr += a.type + "'";
|
||||||
if (r->is_method) {
|
if (r->is_method) {
|
||||||
if (r->name)
|
if (r->name) {
|
||||||
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
|
descr += " in method '" + (std::string) str(r->scope) + "."
|
||||||
else
|
+ (std::string) r->name + "'";
|
||||||
|
} else {
|
||||||
descr += " in method of '" + (std::string) str(r->scope) + "'";
|
descr += " in method of '" + (std::string) str(r->scope) + "'";
|
||||||
|
}
|
||||||
} else if (r->name) {
|
} else if (r->name) {
|
||||||
descr += " in function '" + (std::string) r->name + "'";
|
descr += " in function '" + (std::string) r->name + "'";
|
||||||
}
|
}
|
||||||
pybind11_fail("arg(): could not convert default argument "
|
pybind11_fail("arg(): could not convert default argument " + descr
|
||||||
+ descr + " into a Python object (type not registered yet?)");
|
+ " into a Python object (type not registered yet?)");
|
||||||
#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);
|
||||||
|
|
||||||
if (r->has_kw_only_args) process_kw_only_arg(a, r);
|
check_kw_only_arg(a, r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process a keyword-only-arguments-follow pseudo argument
|
/// Process a keyword-only-arguments-follow pseudo argument
|
||||||
template <> struct process_attribute<kw_only> : process_attribute_default<kw_only> {
|
template <>
|
||||||
|
struct process_attribute<kw_only> : process_attribute_default<kw_only> {
|
||||||
static void init(const kw_only &, function_record *r) {
|
static void init(const kw_only &, function_record *r) {
|
||||||
r->has_kw_only_args = true;
|
append_self_arg_if_needed(r);
|
||||||
|
if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) {
|
||||||
|
pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative "
|
||||||
|
"argument location (or omit kw_only() entirely)");
|
||||||
|
}
|
||||||
|
r->nargs_pos = static_cast<std::uint16_t>(r->args.size());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process a positional-only-argument maker
|
/// Process a positional-only-argument maker
|
||||||
template <> struct process_attribute<pos_only> : process_attribute_default<pos_only> {
|
template <>
|
||||||
|
struct process_attribute<pos_only> : process_attribute_default<pos_only> {
|
||||||
static void init(const pos_only &, function_record *r) {
|
static void init(const pos_only &, function_record *r) {
|
||||||
|
append_self_arg_if_needed(r);
|
||||||
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
|
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
|
||||||
|
if (r->nargs_pos_only > r->nargs_pos) {
|
||||||
|
pybind11_fail("pos_only(): cannot follow a py::args() argument");
|
||||||
|
}
|
||||||
|
// It also can't follow a kw_only, but a static_assert in pybind11.h checks that
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
|
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees
|
||||||
|
/// that)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
|
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>>
|
||||||
|
: process_attribute_default<handle> {
|
||||||
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -455,7 +554,9 @@ struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
|||||||
/// Process a multiple inheritance attribute
|
/// Process a multiple inheritance attribute
|
||||||
template <>
|
template <>
|
||||||
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
||||||
static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; }
|
static void init(const multiple_inheritance &, type_record *r) {
|
||||||
|
r->multiple_inheritance = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -463,6 +564,13 @@ struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr>
|
|||||||
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
|
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct process_attribute<custom_type_setup> {
|
||||||
|
static void init(const custom_type_setup &value, type_record *r) {
|
||||||
|
r->custom_type_setup_callback = value.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct process_attribute<is_final> : process_attribute_default<is_final> {
|
struct process_attribute<is_final> : process_attribute_default<is_final> {
|
||||||
static void init(const is_final &, type_record *r) { r->is_final = true; }
|
static void init(const is_final &, type_record *r) { r->is_final = true; }
|
||||||
@ -494,41 +602,59 @@ template <>
|
|||||||
struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
|
struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> { };
|
struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
||||||
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
|
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
|
||||||
* otherwise
|
* otherwise
|
||||||
*/
|
*/
|
||||||
template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
|
template <size_t Nurse, size_t Patient>
|
||||||
|
struct process_attribute<keep_alive<Nurse, Patient>>
|
||||||
|
: public process_attribute_default<keep_alive<Nurse, Patient>> {
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||||
static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); }
|
static void precall(function_call &call) {
|
||||||
|
keep_alive_impl(Nurse, Patient, call, handle());
|
||||||
|
}
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||||
static void postcall(function_call &, handle) { }
|
static void postcall(function_call &, handle) {}
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||||
static void precall(function_call &) { }
|
static void precall(function_call &) {}
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||||
static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); }
|
static void postcall(function_call &call, handle ret) {
|
||||||
|
keep_alive_impl(Nurse, Patient, call, ret);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Recursively iterate over variadic template arguments
|
/// Recursively iterate over variadic template arguments
|
||||||
template <typename... Args> struct process_attributes {
|
template <typename... Args>
|
||||||
static void init(const Args&... args, function_record *r) {
|
struct process_attributes {
|
||||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
static void init(const Args &...args, function_record *r) {
|
||||||
ignore_unused(unused);
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
|
||||||
|
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
|
||||||
|
using expander = int[];
|
||||||
|
(void) expander{
|
||||||
|
0, ((void) process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
|
||||||
}
|
}
|
||||||
static void init(const Args&... args, type_record *r) {
|
static void init(const Args &...args, type_record *r) {
|
||||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
|
||||||
ignore_unused(unused);
|
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
|
||||||
|
using expander = int[];
|
||||||
|
(void) expander{0,
|
||||||
|
(process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
|
||||||
}
|
}
|
||||||
static void precall(function_call &call) {
|
static void precall(function_call &call) {
|
||||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call);
|
||||||
ignore_unused(unused);
|
using expander = int[];
|
||||||
|
(void) expander{0,
|
||||||
|
(process_attribute<typename std::decay<Args>::type>::precall(call), 0)...};
|
||||||
}
|
}
|
||||||
static void postcall(function_call &call, handle fn_ret) {
|
static void postcall(function_call &call, handle fn_ret) {
|
||||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret);
|
||||||
ignore_unused(unused);
|
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret);
|
||||||
|
using expander = int[];
|
||||||
|
(void) expander{
|
||||||
|
0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0)...};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -544,7 +670,8 @@ template <typename... Extra,
|
|||||||
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
|
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
|
||||||
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
|
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
|
||||||
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
|
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
|
||||||
return named == 0 || (self + named + has_args + has_kwargs) == nargs;
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs);
|
||||||
|
return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
121
3rdparty/pybind11/include/pybind11/buffer_info.h
vendored
121
3rdparty/pybind11/include/pybind11/buffer_info.h
vendored
@ -19,9 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
|
inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
|
||||||
auto ndim = shape.size();
|
auto ndim = shape.size();
|
||||||
std::vector<ssize_t> strides(ndim, itemsize);
|
std::vector<ssize_t> strides(ndim, itemsize);
|
||||||
if (ndim > 0)
|
if (ndim > 0) {
|
||||||
for (size_t i = ndim - 1; i > 0; --i)
|
for (size_t i = ndim - 1; i > 0; --i) {
|
||||||
strides[i - 1] = strides[i] * shape[i];
|
strides[i - 1] = strides[i] * shape[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
return strides;
|
return strides;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,8 +31,9 @@ inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t
|
|||||||
inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
|
inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
|
||||||
auto ndim = shape.size();
|
auto ndim = shape.size();
|
||||||
std::vector<ssize_t> strides(ndim, itemsize);
|
std::vector<ssize_t> strides(ndim, itemsize);
|
||||||
for (size_t i = 1; i < ndim; ++i)
|
for (size_t i = 1; i < ndim; ++i) {
|
||||||
strides[i] = strides[i - 1] * shape[i - 1];
|
strides[i] = strides[i - 1] * shape[i - 1];
|
||||||
|
}
|
||||||
return strides;
|
return strides;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,41 +44,69 @@ struct buffer_info {
|
|||||||
void *ptr = nullptr; // Pointer to the underlying storage
|
void *ptr = nullptr; // Pointer to the underlying storage
|
||||||
ssize_t itemsize = 0; // Size of individual items in bytes
|
ssize_t itemsize = 0; // Size of individual items in bytes
|
||||||
ssize_t size = 0; // Total number of entries
|
ssize_t size = 0; // Total number of entries
|
||||||
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format()
|
std::string format; // For homogeneous buffers, this should be set to
|
||||||
|
// format_descriptor<T>::format()
|
||||||
ssize_t ndim = 0; // Number of dimensions
|
ssize_t ndim = 0; // Number of dimensions
|
||||||
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
||||||
std::vector<ssize_t> strides; // Number of bytes between adjacent entries (for each per dimension)
|
std::vector<ssize_t> strides; // Number of bytes between adjacent entries
|
||||||
|
// (for each per dimension)
|
||||||
bool readonly = false; // flag to indicate if the underlying storage may be written to
|
bool readonly = false; // flag to indicate if the underlying storage may be written to
|
||||||
|
|
||||||
buffer_info() = default;
|
buffer_info() = default;
|
||||||
|
|
||||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
buffer_info(void *ptr,
|
||||||
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false)
|
ssize_t itemsize,
|
||||||
|
const std::string &format,
|
||||||
|
ssize_t ndim,
|
||||||
|
detail::any_container<ssize_t> shape_in,
|
||||||
|
detail::any_container<ssize_t> strides_in,
|
||||||
|
bool readonly = false)
|
||||||
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
||||||
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
|
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
|
||||||
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size())
|
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
|
||||||
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
||||||
for (size_t i = 0; i < (size_t) ndim; ++i)
|
}
|
||||||
|
for (size_t i = 0; i < (size_t) ndim; ++i) {
|
||||||
size *= shape[i];
|
size *= shape[i];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false)
|
buffer_info(T *ptr,
|
||||||
: buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), std::move(strides_in), readonly) { }
|
detail::any_container<ssize_t> shape_in,
|
||||||
|
detail::any_container<ssize_t> strides_in,
|
||||||
|
bool readonly = false)
|
||||||
|
: buffer_info(private_ctr_tag(),
|
||||||
|
ptr,
|
||||||
|
sizeof(T),
|
||||||
|
format_descriptor<T>::format(),
|
||||||
|
static_cast<ssize_t>(shape_in->size()),
|
||||||
|
std::move(shape_in),
|
||||||
|
std::move(strides_in),
|
||||||
|
readonly) {}
|
||||||
|
|
||||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false)
|
buffer_info(void *ptr,
|
||||||
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { }
|
ssize_t itemsize,
|
||||||
|
const std::string &format,
|
||||||
|
ssize_t size,
|
||||||
|
bool readonly = false)
|
||||||
|
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
buffer_info(T *ptr, ssize_t size, bool readonly=false)
|
buffer_info(T *ptr, ssize_t size, bool readonly = false)
|
||||||
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) { }
|
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
buffer_info(const T *ptr, ssize_t size, bool readonly=true)
|
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
|
||||||
: buffer_info(const_cast<T*>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) { }
|
: buffer_info(
|
||||||
|
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
|
||||||
|
|
||||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||||
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
|
: buffer_info(
|
||||||
|
view->buf,
|
||||||
|
view->itemsize,
|
||||||
|
view->format,
|
||||||
|
view->ndim,
|
||||||
{view->shape, view->shape + view->ndim},
|
{view->shape, view->shape + view->ndim},
|
||||||
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
|
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
|
||||||
* ignore this flag and return a view with NULL strides.
|
* ignore this flag and return a view with NULL strides.
|
||||||
@ -83,19 +114,19 @@ struct buffer_info {
|
|||||||
view->strides
|
view->strides
|
||||||
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
|
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
|
||||||
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
|
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
|
||||||
view->readonly) {
|
(view->readonly != 0)) {
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||||
this->m_view = view;
|
this->m_view = view;
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||||
this->ownview = ownview;
|
this->ownview = ownview;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_info(const buffer_info &) = delete;
|
buffer_info(const buffer_info &) = delete;
|
||||||
buffer_info& operator=(const buffer_info &) = delete;
|
buffer_info &operator=(const buffer_info &) = delete;
|
||||||
|
|
||||||
buffer_info(buffer_info &&other) {
|
buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
|
||||||
(*this) = std::move(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_info& operator=(buffer_info &&rhs) {
|
buffer_info &operator=(buffer_info &&rhs) noexcept {
|
||||||
ptr = rhs.ptr;
|
ptr = rhs.ptr;
|
||||||
itemsize = rhs.itemsize;
|
itemsize = rhs.itemsize;
|
||||||
size = rhs.size;
|
size = rhs.size;
|
||||||
@ -110,17 +141,28 @@ struct buffer_info {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~buffer_info() {
|
~buffer_info() {
|
||||||
if (m_view && ownview) { PyBuffer_Release(m_view); delete m_view; }
|
if (m_view && ownview) {
|
||||||
|
PyBuffer_Release(m_view);
|
||||||
|
delete m_view;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_buffer *view() const { return m_view; }
|
Py_buffer *view() const { return m_view; }
|
||||||
Py_buffer *&view() { return m_view; }
|
Py_buffer *&view() { return m_view; }
|
||||||
private:
|
|
||||||
struct private_ctr_tag { };
|
|
||||||
|
|
||||||
buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
private:
|
||||||
detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in, bool readonly)
|
struct private_ctr_tag {};
|
||||||
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { }
|
|
||||||
|
buffer_info(private_ctr_tag,
|
||||||
|
void *ptr,
|
||||||
|
ssize_t itemsize,
|
||||||
|
const std::string &format,
|
||||||
|
ssize_t ndim,
|
||||||
|
detail::any_container<ssize_t> &&shape_in,
|
||||||
|
detail::any_container<ssize_t> &&strides_in,
|
||||||
|
bool readonly)
|
||||||
|
: buffer_info(
|
||||||
|
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
|
||||||
|
|
||||||
Py_buffer *m_view = nullptr;
|
Py_buffer *m_view = nullptr;
|
||||||
bool ownview = false;
|
bool ownview = false;
|
||||||
@ -128,17 +170,22 @@ private:
|
|||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
template <typename T, typename SFINAE = void> struct compare_buffer_info {
|
template <typename T, typename SFINAE = void>
|
||||||
static bool compare(const buffer_info& b) {
|
struct compare_buffer_info {
|
||||||
|
static bool compare(const buffer_info &b) {
|
||||||
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
template <typename T>
|
||||||
static bool compare(const buffer_info& b) {
|
struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||||
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
|
static bool compare(const buffer_info &b) {
|
||||||
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
return (size_t) b.itemsize == sizeof(T)
|
||||||
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
&& (b.format == format_descriptor<T>::value
|
||||||
|
|| ((sizeof(T) == sizeof(long))
|
||||||
|
&& b.format == (std::is_unsigned<T>::value ? "L" : "l"))
|
||||||
|
|| ((sizeof(T) == sizeof(size_t))
|
||||||
|
&& b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2120
3rdparty/pybind11/include/pybind11/cast.h
vendored
2120
3rdparty/pybind11/include/pybind11/cast.h
vendored
File diff suppressed because it is too large
Load Diff
126
3rdparty/pybind11/include/pybind11/chrono.h
vendored
126
3rdparty/pybind11/include/pybind11/chrono.h
vendored
@ -11,39 +11,36 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <chrono>
|
|
||||||
#include <datetime.h>
|
#include <datetime.h>
|
||||||
|
#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)
|
||||||
|
|
||||||
template <typename type> class duration_caster {
|
template <typename type>
|
||||||
|
class duration_caster {
|
||||||
public:
|
public:
|
||||||
using rep = typename type::rep;
|
using rep = typename type::rep;
|
||||||
using period = typename type::period;
|
using period = typename type::period;
|
||||||
|
|
||||||
using days = std::chrono::duration<uint_fast32_t, std::ratio<86400>>;
|
// signed 25 bits required by the standard.
|
||||||
|
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool) {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
// Lazy initialise the PyDateTime import
|
||||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
if (!PyDateTimeAPI) {
|
||||||
|
PyDateTime_IMPORT;
|
||||||
|
}
|
||||||
|
|
||||||
if (!src) return false;
|
if (!src) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// If invoked with datetime.delta object
|
// If invoked with datetime.delta object
|
||||||
if (PyDelta_Check(src.ptr())) {
|
if (PyDelta_Check(src.ptr())) {
|
||||||
value = type(duration_cast<duration<rep, period>>(
|
value = type(duration_cast<duration<rep, period>>(
|
||||||
@ -53,20 +50,24 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// If invoked with a float we assume it is seconds and convert
|
// If invoked with a float we assume it is seconds and convert
|
||||||
else if (PyFloat_Check(src.ptr())) {
|
if (PyFloat_Check(src.ptr())) {
|
||||||
value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
|
value = type(duration_cast<duration<rep, period>>(
|
||||||
|
duration<double>(PyFloat_AsDouble(src.ptr()))));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a duration just return it back
|
// If this is a duration just return it back
|
||||||
static const std::chrono::duration<rep, period>& get_duration(const std::chrono::duration<rep, period> &src) {
|
static const std::chrono::duration<rep, period> &
|
||||||
|
get_duration(const std::chrono::duration<rep, period> &src) {
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a time_point get the time_since_epoch
|
// If this is a time_point get the time_since_epoch
|
||||||
template <typename Clock> static std::chrono::duration<rep, period> get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
|
template <typename Clock>
|
||||||
|
static std::chrono::duration<rep, period>
|
||||||
|
get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
|
||||||
return src.time_since_epoch();
|
return src.time_since_epoch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,9 +79,12 @@ public:
|
|||||||
auto d = get_duration(src);
|
auto d = get_duration(src);
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
// Lazy initialise the PyDateTime import
|
||||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
if (!PyDateTimeAPI) {
|
||||||
|
PyDateTime_IMPORT;
|
||||||
|
}
|
||||||
|
|
||||||
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
// Declare these special duration types so the conversions happen with the correct
|
||||||
|
// primitive types (int)
|
||||||
using dd_t = duration<int, std::ratio<86400>>;
|
using dd_t = duration<int, std::ratio<86400>>;
|
||||||
using ss_t = duration<int, std::ratio<1>>;
|
using ss_t = duration<int, std::ratio<1>>;
|
||||||
using us_t = duration<int, std::micro>;
|
using us_t = duration<int, std::micro>;
|
||||||
@ -92,20 +96,41 @@ public:
|
|||||||
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
|
PYBIND11_TYPE_CASTER(type, const_name("datetime.timedelta"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {
|
||||||
|
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER)
|
||||||
|
if (localtime_s(buf, time))
|
||||||
|
return nullptr;
|
||||||
|
return buf;
|
||||||
|
#else
|
||||||
|
static std::mutex mtx;
|
||||||
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
|
std::tm *tm_ptr = std::localtime(time);
|
||||||
|
if (tm_ptr != nullptr) {
|
||||||
|
*buf = *tm_ptr;
|
||||||
|
}
|
||||||
|
return tm_ptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// This is for casting times on the system clock into datetime.datetime instances
|
// This is for casting times on the system clock into datetime.datetime instances
|
||||||
template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
template <typename Duration>
|
||||||
|
class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||||
public:
|
public:
|
||||||
using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool) {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
// Lazy initialise the PyDateTime import
|
||||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
if (!PyDateTimeAPI) {
|
||||||
|
PyDateTime_IMPORT;
|
||||||
|
}
|
||||||
|
|
||||||
if (!src) return false;
|
if (!src) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::tm cal;
|
std::tm cal;
|
||||||
microseconds msecs;
|
microseconds msecs;
|
||||||
@ -137,34 +162,43 @@ public:
|
|||||||
cal.tm_year = 70; // earliest available date for Python's datetime
|
cal.tm_year = 70; // earliest available date for Python's datetime
|
||||||
cal.tm_isdst = -1;
|
cal.tm_isdst = -1;
|
||||||
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
|
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else return false;
|
|
||||||
|
|
||||||
value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);
|
value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) {
|
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src,
|
||||||
|
return_value_policy /* policy */,
|
||||||
|
handle /* parent */) {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
// Lazy initialise the PyDateTime import
|
||||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
if (!PyDateTimeAPI) {
|
||||||
|
PyDateTime_IMPORT;
|
||||||
|
}
|
||||||
|
|
||||||
// Get out microseconds, and make sure they are positive, to avoid bug in eastern hemisphere time zones
|
// Get out microseconds, and make sure they are positive, to avoid bug in eastern
|
||||||
// (cfr. https://github.com/pybind/pybind11/issues/2417)
|
// hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417)
|
||||||
using us_t = duration<int, std::micro>;
|
using us_t = duration<int, std::micro>;
|
||||||
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
|
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
|
||||||
if (us.count() < 0)
|
if (us.count() < 0) {
|
||||||
us += seconds(1);
|
us += seconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Subtract microseconds BEFORE `system_clock::to_time_t`, because:
|
// Subtract microseconds BEFORE `system_clock::to_time_t`, because:
|
||||||
// > If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated.
|
// > If std::time_t has lower precision, it is implementation-defined whether the value is
|
||||||
// (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
|
// rounded or truncated. (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
|
||||||
std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
|
std::time_t tt
|
||||||
// this function uses static memory so it's best to copy it out asap just in case
|
= system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
|
||||||
// otherwise other code that is using localtime may break this (not just python code)
|
|
||||||
std::tm localtime = *std::localtime(&tt);
|
|
||||||
|
|
||||||
|
std::tm localtime;
|
||||||
|
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
|
||||||
|
if (!localtime_ptr) {
|
||||||
|
throw cast_error("Unable to represent system_clock in local time");
|
||||||
|
}
|
||||||
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
||||||
localtime.tm_mon + 1,
|
localtime.tm_mon + 1,
|
||||||
localtime.tm_mday,
|
localtime.tm_mday,
|
||||||
@ -173,19 +207,19 @@ public:
|
|||||||
localtime.tm_sec,
|
localtime.tm_sec,
|
||||||
us.count());
|
us.count());
|
||||||
}
|
}
|
||||||
PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
|
PYBIND11_TYPE_CASTER(type, const_name("datetime.datetime"));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Other clocks that are not the system clock are not measured as datetime.datetime objects
|
// Other clocks that are not the system clock are not measured as datetime.datetime objects
|
||||||
// since they are not measured on calendar time. So instead we just make them timedeltas
|
// since they are not measured on calendar time. So instead we just make them timedeltas
|
||||||
// Or if they have passed us a time as a float we convert that
|
// Or if they have passed us a time as a float we convert that
|
||||||
template <typename Clock, typename Duration> class type_caster<std::chrono::time_point<Clock, Duration>>
|
template <typename Clock, typename Duration>
|
||||||
: public duration_caster<std::chrono::time_point<Clock, Duration>> {
|
class type_caster<std::chrono::time_point<Clock, Duration>>
|
||||||
};
|
: public duration_caster<std::chrono::time_point<Clock, Duration>> {};
|
||||||
|
|
||||||
template <typename Rep, typename Period> class type_caster<std::chrono::duration<Rep, Period>>
|
template <typename Rep, typename Period>
|
||||||
: public duration_caster<std::chrono::duration<Rep, Period>> {
|
class type_caster<std::chrono::duration<Rep, Period>>
|
||||||
};
|
: public duration_caster<std::chrono::duration<Rep, Period>> {};
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
29
3rdparty/pybind11/include/pybind11/complex.h
vendored
29
3rdparty/pybind11/include/pybind11/complex.h
vendored
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#include <complex>
|
#include <complex>
|
||||||
|
|
||||||
/// glibc defines I as a macro which breaks things, e.g., boost template names
|
/// glibc defines I as a macro which breaks things, e.g., boost template names
|
||||||
@ -19,33 +20,40 @@
|
|||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
template <typename T>
|
||||||
|
struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||||
static constexpr const char c = format_descriptor<T>::c;
|
static constexpr const char c = format_descriptor<T>::c;
|
||||||
static constexpr const char value[3] = { 'Z', c, '\0' };
|
static constexpr const char value[3] = {'Z', c, '\0'};
|
||||||
static std::string format() { return std::string(value); }
|
static std::string format() { return std::string(value); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef PYBIND11_CPP17
|
#ifndef PYBIND11_CPP17
|
||||||
|
|
||||||
template <typename T> constexpr const char format_descriptor<
|
template <typename T>
|
||||||
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
constexpr const char
|
||||||
|
format_descriptor<std::complex<T>,
|
||||||
|
detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
template <typename T>
|
||||||
|
struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||||
static constexpr bool value = true;
|
static constexpr bool value = true;
|
||||||
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> class type_caster<std::complex<T>> {
|
template <typename T>
|
||||||
|
class type_caster<std::complex<T>> {
|
||||||
public:
|
public:
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!src)
|
if (!src) {
|
||||||
return false;
|
return false;
|
||||||
if (!convert && !PyComplex_Check(src.ptr()))
|
}
|
||||||
|
if (!convert && !PyComplex_Check(src.ptr())) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
@ -55,11 +63,12 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
static handle
|
||||||
|
cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(std::complex<T>, _("complex"));
|
PYBIND11_TYPE_CASTER(std::complex<T>, const_name("complex"));
|
||||||
};
|
};
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
309
3rdparty/pybind11/include/pybind11/detail/class.h
vendored
309
3rdparty/pybind11/include/pybind11/detail/class.h
vendored
@ -15,13 +15,14 @@
|
|||||||
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) setattr((PyObject *) obj, "__qualname__", nameobj)
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
||||||
|
setattr((PyObject *) obj, "__qualname__", nameobj)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
|
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
|
||||||
@ -65,24 +66,26 @@ inline PyTypeObject *make_static_property_type() {
|
|||||||
issue no Python C API calls which could potentially invoke the
|
issue no Python C API calls which could potentially invoke the
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
turn find the newly constructed type in an invalid state) */
|
turn find the newly constructed type in an invalid state) */
|
||||||
auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
||||||
if (!heap_type)
|
if (!heap_type) {
|
||||||
pybind11_fail("make_static_property_type(): error allocating type!");
|
pybind11_fail("make_static_property_type(): error allocating type!");
|
||||||
|
}
|
||||||
|
|
||||||
heap_type->ht_name = name_obj.inc_ref().ptr();
|
heap_type->ht_name = name_obj.inc_ref().ptr();
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
# ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
auto type = &heap_type->ht_type;
|
auto *type = &heap_type->ht_type;
|
||||||
type->tp_name = name;
|
type->tp_name = name;
|
||||||
type->tp_base = type_incref(&PyProperty_Type);
|
type->tp_base = type_incref(&PyProperty_Type);
|
||||||
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
||||||
type->tp_descr_get = pybind11_static_get;
|
type->tp_descr_get = pybind11_static_get;
|
||||||
type->tp_descr_set = pybind11_static_set;
|
type->tp_descr_set = pybind11_static_set;
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0)
|
if (PyType_Ready(type) < 0) {
|
||||||
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
|
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
|
||||||
|
}
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
@ -98,15 +101,17 @@ inline PyTypeObject *make_static_property_type() {
|
|||||||
inline PyTypeObject *make_static_property_type() {
|
inline PyTypeObject *make_static_property_type() {
|
||||||
auto d = dict();
|
auto d = dict();
|
||||||
PyObject *result = PyRun_String(R"(\
|
PyObject *result = PyRun_String(R"(\
|
||||||
class pybind11_static_property(property):
|
class pybind11_static_property(property):
|
||||||
def __get__(self, obj, cls):
|
def __get__(self, obj, cls):
|
||||||
return property.__get__(self, cls, cls)
|
return property.__get__(self, cls, cls)
|
||||||
|
|
||||||
def __set__(self, obj, value):
|
def __set__(self, obj, value):
|
||||||
cls = obj if isinstance(obj, type) else type(obj)
|
cls = obj if isinstance(obj, type) else type(obj)
|
||||||
property.__set__(self, cls, value)
|
property.__set__(self, cls, value)
|
||||||
)", Py_file_input, d.ptr(), d.ptr()
|
)",
|
||||||
);
|
Py_file_input,
|
||||||
|
d.ptr(),
|
||||||
|
d.ptr());
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
@ -119,7 +124,7 @@ inline PyTypeObject *make_static_property_type() {
|
|||||||
By default, Python replaces the `static_property` itself, but for wrapped C++ types
|
By default, Python replaces the `static_property` itself, but for wrapped C++ types
|
||||||
we need to call `static_property.__set__()` in order to propagate the new value to
|
we need to call `static_property.__set__()` in order to propagate the new value to
|
||||||
the underlying C++ data structure. */
|
the underlying C++ data structure. */
|
||||||
extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) {
|
extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyObject *value) {
|
||||||
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
|
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
|
||||||
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
|
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
|
||||||
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
|
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
|
||||||
@ -128,9 +133,10 @@ extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyOb
|
|||||||
// 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)`
|
// 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)`
|
||||||
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
|
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
|
||||||
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
|
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
|
||||||
const auto static_prop = (PyObject *) get_internals().static_property_type;
|
auto *const static_prop = (PyObject *) get_internals().static_property_type;
|
||||||
const auto call_descr_set = descr && value && PyObject_IsInstance(descr, static_prop)
|
const auto call_descr_set = (descr != nullptr) && (value != nullptr)
|
||||||
&& !PyObject_IsInstance(value, static_prop);
|
&& (PyObject_IsInstance(descr, static_prop) != 0)
|
||||||
|
&& (PyObject_IsInstance(value, static_prop) == 0);
|
||||||
if (call_descr_set) {
|
if (call_descr_set) {
|
||||||
// Call `static_property.__set__()` instead of replacing the `static_property`.
|
// Call `static_property.__set__()` instead of replacing the `static_property`.
|
||||||
#if !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
@ -149,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,
|
||||||
@ -162,11 +167,8 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
|
|||||||
Py_INCREF(descr);
|
Py_INCREF(descr);
|
||||||
return descr;
|
return descr;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
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) {
|
||||||
@ -178,12 +180,13 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This must be a pybind11 instance
|
// This must be a pybind11 instance
|
||||||
auto instance = reinterpret_cast<detail::instance *>(self);
|
auto *instance = reinterpret_cast<detail::instance *>(self);
|
||||||
|
|
||||||
// Ensure that the base __init__ function(s) were called
|
// Ensure that the base __init__ function(s) were called
|
||||||
for (const auto &vh : values_and_holders(instance)) {
|
for (const auto &vh : values_and_holders(instance)) {
|
||||||
if (!vh.holder_constructed()) {
|
if (!vh.holder_constructed()) {
|
||||||
PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__",
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%.200s.__init__() must be called when overriding __init__",
|
||||||
get_fully_qualified_tp_name(vh.type->type).c_str());
|
get_fully_qualified_tp_name(vh.type->type).c_str());
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -202,28 +205,29 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
|
|||||||
// 1) be found in internals.registered_types_py
|
// 1) be found in internals.registered_types_py
|
||||||
// 2) have exactly one associated `detail::type_info`
|
// 2) have exactly one associated `detail::type_info`
|
||||||
auto found_type = internals.registered_types_py.find(type);
|
auto found_type = internals.registered_types_py.find(type);
|
||||||
if (found_type != internals.registered_types_py.end() &&
|
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
|
||||||
found_type->second.size() == 1 &&
|
&& found_type->second[0]->type == type) {
|
||||||
found_type->second[0]->type == type) {
|
|
||||||
|
|
||||||
auto *tinfo = found_type->second[0];
|
auto *tinfo = found_type->second[0];
|
||||||
auto tindex = std::type_index(*tinfo->cpptype);
|
auto tindex = std::type_index(*tinfo->cpptype);
|
||||||
internals.direct_conversions.erase(tindex);
|
internals.direct_conversions.erase(tindex);
|
||||||
|
|
||||||
if (tinfo->module_local)
|
if (tinfo->module_local) {
|
||||||
registered_local_types_cpp().erase(tindex);
|
get_local_internals().registered_types_cpp.erase(tindex);
|
||||||
else
|
} else {
|
||||||
internals.registered_types_cpp.erase(tindex);
|
internals.registered_types_cpp.erase(tindex);
|
||||||
|
}
|
||||||
internals.registered_types_py.erase(tinfo->type);
|
internals.registered_types_py.erase(tinfo->type);
|
||||||
|
|
||||||
// Actually just `std::erase_if`, but that's only available in C++20
|
// Actually just `std::erase_if`, but that's only available in C++20
|
||||||
auto &cache = internals.inactive_override_cache;
|
auto &cache = internals.inactive_override_cache;
|
||||||
for (auto it = cache.begin(), last = cache.end(); it != last; ) {
|
for (auto it = cache.begin(), last = cache.end(); it != last;) {
|
||||||
if (it->first == (PyObject *) tinfo->type)
|
if (it->first == (PyObject *) tinfo->type) {
|
||||||
it = cache.erase(it);
|
it = cache.erase(it);
|
||||||
else
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete tinfo;
|
delete tinfo;
|
||||||
}
|
}
|
||||||
@ -234,7 +238,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
|
|||||||
/** This metaclass is assigned by default to all pybind11 types and is required in order
|
/** This metaclass is assigned by default to all pybind11 types and is required in order
|
||||||
for static properties to function correctly. Users may override this using `py::metaclass`.
|
for static properties to function correctly. Users may override this using `py::metaclass`.
|
||||||
Return value: New reference. */
|
Return value: New reference. */
|
||||||
inline PyTypeObject* make_default_metaclass() {
|
inline PyTypeObject *make_default_metaclass() {
|
||||||
constexpr auto *name = "pybind11_type";
|
constexpr auto *name = "pybind11_type";
|
||||||
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
||||||
|
|
||||||
@ -242,16 +246,17 @@ inline PyTypeObject* make_default_metaclass() {
|
|||||||
issue no Python C API calls which could potentially invoke the
|
issue no Python C API calls which could potentially invoke the
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
turn find the newly constructed type in an invalid state) */
|
turn find the newly constructed type in an invalid state) */
|
||||||
auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
||||||
if (!heap_type)
|
if (!heap_type) {
|
||||||
pybind11_fail("make_default_metaclass(): error allocating metaclass!");
|
pybind11_fail("make_default_metaclass(): error allocating metaclass!");
|
||||||
|
}
|
||||||
|
|
||||||
heap_type->ht_name = name_obj.inc_ref().ptr();
|
heap_type->ht_name = name_obj.inc_ref().ptr();
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto type = &heap_type->ht_type;
|
auto *type = &heap_type->ht_type;
|
||||||
type->tp_name = name;
|
type->tp_name = name;
|
||||||
type->tp_base = type_incref(&PyType_Type);
|
type->tp_base = type_incref(&PyType_Type);
|
||||||
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
||||||
@ -259,14 +264,13 @@ 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;
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0)
|
if (PyType_Ready(type) < 0) {
|
||||||
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
|
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
|
||||||
|
}
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
@ -276,16 +280,20 @@ inline PyTypeObject* make_default_metaclass() {
|
|||||||
|
|
||||||
/// For multiple inheritance types we need to recursively register/deregister base pointers for any
|
/// For multiple inheritance types we need to recursively register/deregister base pointers for any
|
||||||
/// base classes with pointers that are difference from the instance value pointer so that we can
|
/// base classes with pointers that are difference from the instance value pointer so that we can
|
||||||
/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs.
|
/// correctly recognize an offset base class pointer. This calls a function with any offset base
|
||||||
inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self,
|
/// ptrs.
|
||||||
|
inline void traverse_offset_bases(void *valueptr,
|
||||||
|
const detail::type_info *tinfo,
|
||||||
|
instance *self,
|
||||||
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
|
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
|
||||||
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
|
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
|
||||||
if (auto parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
|
if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
|
||||||
for (auto &c : parent_tinfo->implicit_casts) {
|
for (auto &c : parent_tinfo->implicit_casts) {
|
||||||
if (c.first == tinfo->cpptype) {
|
if (c.first == tinfo->cpptype) {
|
||||||
auto *parentptr = c.second(valueptr);
|
auto *parentptr = c.second(valueptr);
|
||||||
if (parentptr != valueptr)
|
if (parentptr != valueptr) {
|
||||||
f(parentptr, self);
|
f(parentptr, self);
|
||||||
|
}
|
||||||
traverse_offset_bases(parentptr, parent_tinfo, self, f);
|
traverse_offset_bases(parentptr, parent_tinfo, self, f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -312,36 +320,36 @@ inline bool deregister_instance_impl(void *ptr, instance *self) {
|
|||||||
|
|
||||||
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
|
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
|
||||||
register_instance_impl(valptr, self);
|
register_instance_impl(valptr, self);
|
||||||
if (!tinfo->simple_ancestors)
|
if (!tinfo->simple_ancestors) {
|
||||||
traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
|
traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
|
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
|
||||||
bool ret = deregister_instance_impl(valptr, self);
|
bool ret = deregister_instance_impl(valptr, self);
|
||||||
if (!tinfo->simple_ancestors)
|
if (!tinfo->simple_ancestors) {
|
||||||
traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
|
traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instance creation function for all pybind11 types. It allocates the internal instance layout for
|
/// Instance creation function for all pybind11 types. It allocates the internal instance layout
|
||||||
/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast
|
/// for holding C++ objects and holders. Allocation is done lazily (the first time the instance is
|
||||||
/// to a reference or pointer), and initialization is done by an `__init__` function.
|
/// cast to a reference or pointer), and initialization is done by an `__init__` function.
|
||||||
inline PyObject *make_new_instance(PyTypeObject *type) {
|
inline PyObject *make_new_instance(PyTypeObject *type) {
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited
|
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first
|
||||||
// object is a a plain Python type (i.e. not derived from an extension type). Fix it.
|
// inherited object is a plain Python type (i.e. not derived from an extension type). Fix it.
|
||||||
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
|
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
|
||||||
if (type->tp_basicsize < instance_size) {
|
if (type->tp_basicsize < instance_size) {
|
||||||
type->tp_basicsize = instance_size;
|
type->tp_basicsize = instance_size;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
PyObject *self = type->tp_alloc(type, 0);
|
PyObject *self = type->tp_alloc(type, 0);
|
||||||
auto inst = reinterpret_cast<instance *>(self);
|
auto *inst = reinterpret_cast<instance *>(self);
|
||||||
// Allocate the value/holder internals:
|
// Allocate the value/holder internals:
|
||||||
inst->allocate_layout();
|
inst->allocate_layout();
|
||||||
|
|
||||||
inst->owned = true;
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,14 +371,14 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject
|
|||||||
|
|
||||||
inline void add_patient(PyObject *nurse, PyObject *patient) {
|
inline void add_patient(PyObject *nurse, PyObject *patient) {
|
||||||
auto &internals = get_internals();
|
auto &internals = get_internals();
|
||||||
auto instance = reinterpret_cast<detail::instance *>(nurse);
|
auto *instance = reinterpret_cast<detail::instance *>(nurse);
|
||||||
instance->has_patients = true;
|
instance->has_patients = true;
|
||||||
Py_INCREF(patient);
|
Py_INCREF(patient);
|
||||||
internals.patients[nurse].push_back(patient);
|
internals.patients[nurse].push_back(patient);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void clear_patients(PyObject *self) {
|
inline void clear_patients(PyObject *self) {
|
||||||
auto instance = reinterpret_cast<detail::instance *>(self);
|
auto *instance = reinterpret_cast<detail::instance *>(self);
|
||||||
auto &internals = get_internals();
|
auto &internals = get_internals();
|
||||||
auto pos = internals.patients.find(self);
|
auto pos = internals.patients.find(self);
|
||||||
assert(pos != internals.patients.end());
|
assert(pos != internals.patients.end());
|
||||||
@ -380,14 +388,15 @@ inline void clear_patients(PyObject *self) {
|
|||||||
auto patients = std::move(pos->second);
|
auto patients = std::move(pos->second);
|
||||||
internals.patients.erase(pos);
|
internals.patients.erase(pos);
|
||||||
instance->has_patients = false;
|
instance->has_patients = false;
|
||||||
for (PyObject *&patient : patients)
|
for (PyObject *&patient : patients) {
|
||||||
Py_CLEAR(patient);
|
Py_CLEAR(patient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears all internal data from the instance and removes it from registered instances in
|
/// Clears all internal data from the instance and removes it from registered instances in
|
||||||
/// preparation for deallocation.
|
/// preparation for deallocation.
|
||||||
inline void clear_instance(PyObject *self) {
|
inline void clear_instance(PyObject *self) {
|
||||||
auto instance = reinterpret_cast<detail::instance *>(self);
|
auto *instance = reinterpret_cast<detail::instance *>(self);
|
||||||
|
|
||||||
// Deallocate any values/holders, if present:
|
// Deallocate any values/holders, if present:
|
||||||
for (auto &v_h : values_and_holders(instance)) {
|
for (auto &v_h : values_and_holders(instance)) {
|
||||||
@ -395,25 +404,32 @@ inline void clear_instance(PyObject *self) {
|
|||||||
|
|
||||||
// We have to deregister before we call dealloc because, for virtual MI types, we still
|
// We have to deregister before we call dealloc because, for virtual MI types, we still
|
||||||
// need to be able to get the parent pointers.
|
// need to be able to get the parent pointers.
|
||||||
if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type))
|
if (v_h.instance_registered()
|
||||||
pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
&& !deregister_instance(instance, v_h.value_ptr(), v_h.type)) {
|
||||||
|
pybind11_fail(
|
||||||
|
"pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
||||||
|
}
|
||||||
|
|
||||||
if (instance->owned || v_h.holder_constructed())
|
if (instance->owned || v_h.holder_constructed()) {
|
||||||
v_h.type->dealloc(v_h);
|
v_h.type->dealloc(v_h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Deallocate the value/holder layout internals:
|
// Deallocate the value/holder layout internals:
|
||||||
instance->deallocate_layout();
|
instance->deallocate_layout();
|
||||||
|
|
||||||
if (instance->weakrefs)
|
if (instance->weakrefs) {
|
||||||
PyObject_ClearWeakRefs(self);
|
PyObject_ClearWeakRefs(self);
|
||||||
|
}
|
||||||
|
|
||||||
PyObject **dict_ptr = _PyObject_GetDictPtr(self);
|
PyObject **dict_ptr = _PyObject_GetDictPtr(self);
|
||||||
if (dict_ptr)
|
if (dict_ptr) {
|
||||||
Py_CLEAR(*dict_ptr);
|
Py_CLEAR(*dict_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (instance->has_patients)
|
if (instance->has_patients) {
|
||||||
clear_patients(self);
|
clear_patients(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
|
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
|
||||||
@ -421,7 +437,7 @@ inline void clear_instance(PyObject *self) {
|
|||||||
extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
||||||
clear_instance(self);
|
clear_instance(self);
|
||||||
|
|
||||||
auto type = Py_TYPE(self);
|
auto *type = Py_TYPE(self);
|
||||||
type->tp_free(self);
|
type->tp_free(self);
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x03080000
|
#if PY_VERSION_HEX < 0x03080000
|
||||||
@ -439,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. */
|
||||||
@ -450,16 +468,17 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
|||||||
issue no Python C API calls which could potentially invoke the
|
issue no Python C API calls which could potentially invoke the
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
turn find the newly constructed type in an invalid state) */
|
turn find the newly constructed type in an invalid state) */
|
||||||
auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
||||||
if (!heap_type)
|
if (!heap_type) {
|
||||||
pybind11_fail("make_object_base_type(): error allocating type!");
|
pybind11_fail("make_object_base_type(): error allocating type!");
|
||||||
|
}
|
||||||
|
|
||||||
heap_type->ht_name = name_obj.inc_ref().ptr();
|
heap_type->ht_name = name_obj.inc_ref().ptr();
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto type = &heap_type->ht_type;
|
auto *type = &heap_type->ht_type;
|
||||||
type->tp_name = name;
|
type->tp_name = name;
|
||||||
type->tp_base = type_incref(&PyBaseObject_Type);
|
type->tp_base = type_incref(&PyBaseObject_Type);
|
||||||
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
||||||
@ -472,8 +491,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
|||||||
/* Support weak references (needed for the keep_alive feature) */
|
/* Support weak references (needed for the keep_alive feature) */
|
||||||
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"));
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
||||||
@ -482,33 +502,14 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
|||||||
return (PyObject *) heap_type;
|
return (PyObject *) heap_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// dynamic_attr: Support for `d = instance.__dict__`.
|
|
||||||
extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
|
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
|
||||||
if (!dict)
|
|
||||||
dict = PyDict_New();
|
|
||||||
Py_XINCREF(dict);
|
|
||||||
return dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dynamic_attr: Support for `instance.__dict__ = dict()`.
|
|
||||||
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
|
|
||||||
if (!PyDict_Check(new_dict)) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
|
|
||||||
get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
|
||||||
Py_INCREF(new_dict);
|
|
||||||
Py_CLEAR(dict);
|
|
||||||
dict = new_dict;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
|
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
|
||||||
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,17 +522,28 @@ extern "C" inline int pybind11_clear(PyObject *self) {
|
|||||||
|
|
||||||
/// Give instances of this type a `__dict__` and opt into garbage collection.
|
/// Give instances of this type a `__dict__` and opt into garbage collection.
|
||||||
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;
|
||||||
|
|
||||||
static PyGetSetDef getset[] = {
|
static PyGetSetDef getset[] = {{
|
||||||
{const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
|
#if PY_VERSION_HEX < 0x03070000
|
||||||
{nullptr, nullptr, nullptr, nullptr, nullptr}
|
const_cast<char *>("__dict__"),
|
||||||
};
|
#else
|
||||||
|
"__dict__",
|
||||||
|
#endif
|
||||||
|
PyObject_GenericGetDict,
|
||||||
|
PyObject_GenericSetDict,
|
||||||
|
nullptr,
|
||||||
|
nullptr},
|
||||||
|
{nullptr, nullptr, nullptr, nullptr, nullptr}};
|
||||||
type->tp_getset = getset;
|
type->tp_getset = getset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,38 +553,42 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
|||||||
type_info *tinfo = nullptr;
|
type_info *tinfo = nullptr;
|
||||||
for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
|
for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
|
||||||
tinfo = get_type_info((PyTypeObject *) type.ptr());
|
tinfo = get_type_info((PyTypeObject *) type.ptr());
|
||||||
if (tinfo && tinfo->get_buffer)
|
if (tinfo && tinfo->get_buffer) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (view == nullptr || !tinfo || !tinfo->get_buffer) {
|
if (view == nullptr || !tinfo || !tinfo->get_buffer) {
|
||||||
if (view)
|
if (view) {
|
||||||
view->obj = nullptr;
|
view->obj = nullptr;
|
||||||
|
}
|
||||||
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
std::memset(view, 0, sizeof(Py_buffer));
|
std::memset(view, 0, sizeof(Py_buffer));
|
||||||
buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
|
buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
|
||||||
|
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
||||||
|
delete info;
|
||||||
|
// view->obj = nullptr; // Was just memset to 0, so not necessary
|
||||||
|
PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
view->obj = obj;
|
view->obj = obj;
|
||||||
view->ndim = 1;
|
view->ndim = 1;
|
||||||
view->internal = info;
|
view->internal = info;
|
||||||
view->buf = info->ptr;
|
view->buf = info->ptr;
|
||||||
view->itemsize = info->itemsize;
|
view->itemsize = info->itemsize;
|
||||||
view->len = view->itemsize;
|
view->len = view->itemsize;
|
||||||
for (auto s : info->shape)
|
for (auto s : info->shape) {
|
||||||
view->len *= s;
|
view->len *= s;
|
||||||
view->readonly = info->readonly;
|
|
||||||
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
|
||||||
if (view)
|
|
||||||
view->obj = nullptr;
|
|
||||||
PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
view->readonly = static_cast<int>(info->readonly);
|
||||||
|
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
|
||||||
view->format = const_cast<char *>(info->format.c_str());
|
view->format = const_cast<char *>(info->format.c_str());
|
||||||
|
}
|
||||||
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
||||||
view->ndim = (int) info->ndim;
|
view->ndim = (int) info->ndim;
|
||||||
view->strides = &info->strides[0];
|
view->strides = info->strides.data();
|
||||||
view->shape = &info->shape[0];
|
view->shape = info->shape.data();
|
||||||
}
|
}
|
||||||
Py_INCREF(view->obj);
|
Py_INCREF(view->obj);
|
||||||
return 0;
|
return 0;
|
||||||
@ -586,9 +602,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;
|
||||||
@ -596,28 +609,25 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
|||||||
|
|
||||||
/** Create a brand new Python type according to the `type_record` specification.
|
/** Create a brand new Python type according to the `type_record` specification.
|
||||||
Return value: New reference. */
|
Return value: New reference. */
|
||||||
inline PyObject* make_new_python_type(const type_record &rec) {
|
inline PyObject *make_new_python_type(const type_record &rec) {
|
||||||
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
|
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
|
||||||
|
|
||||||
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_;
|
||||||
if (rec.scope) {
|
if (rec.scope) {
|
||||||
if (hasattr(rec.scope, "__module__"))
|
if (hasattr(rec.scope, "__module__")) {
|
||||||
module_ = rec.scope.attr("__module__");
|
module_ = rec.scope.attr("__module__");
|
||||||
else if (hasattr(rec.scope, "__name__"))
|
} else if (hasattr(rec.scope, "__name__")) {
|
||||||
module_ = rec.scope.attr("__name__");
|
module_ = rec.scope.attr("__name__");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto full_name = c_str(
|
const auto *full_name = c_str(
|
||||||
#if !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
module_ ? str(module_).cast<std::string>() + "." + rec.name :
|
module_ ? str(module_).cast<std::string>() + "." + rec.name :
|
||||||
#endif
|
#endif
|
||||||
@ -627,39 +637,40 @@ inline PyObject* make_new_python_type(const type_record &rec) {
|
|||||||
if (rec.doc && options::show_user_defined_docstrings()) {
|
if (rec.doc && options::show_user_defined_docstrings()) {
|
||||||
/* Allocate memory for docstring (using PyObject_MALLOC, since
|
/* Allocate memory for docstring (using PyObject_MALLOC, since
|
||||||
Python will free this later on) */
|
Python will free this later on) */
|
||||||
size_t size = strlen(rec.doc) + 1;
|
size_t size = std::strlen(rec.doc) + 1;
|
||||||
tp_doc = (char *) PyObject_MALLOC(size);
|
tp_doc = (char *) PyObject_MALLOC(size);
|
||||||
memcpy((void *) tp_doc, rec.doc, size);
|
std::memcpy((void *) tp_doc, rec.doc, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &internals = get_internals();
|
auto &internals = get_internals();
|
||||||
auto bases = tuple(rec.bases);
|
auto bases = tuple(rec.bases);
|
||||||
auto base = (bases.empty()) ? internals.instance_base
|
auto *base = (bases.empty()) ? internals.instance_base : bases[0].ptr();
|
||||||
: bases[0].ptr();
|
|
||||||
|
|
||||||
/* Danger zone: from now (and until PyType_Ready), make sure to
|
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||||
issue no Python C API calls which could potentially invoke the
|
issue no Python C API calls which could potentially invoke the
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
turn find the newly constructed type in an invalid state) */
|
turn find the newly constructed type in an invalid state) */
|
||||||
auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr()
|
auto *metaclass
|
||||||
: internals.default_metaclass;
|
= rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() : internals.default_metaclass;
|
||||||
|
|
||||||
auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
||||||
if (!heap_type)
|
if (!heap_type) {
|
||||||
pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
|
pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
|
||||||
|
}
|
||||||
|
|
||||||
heap_type->ht_name = name.release().ptr();
|
heap_type->ht_name = name.release().ptr();
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
#ifdef PYBIND11_BUILTIN_QUALNAME
|
||||||
heap_type->ht_qualname = qualname.inc_ref().ptr();
|
heap_type->ht_qualname = qualname.inc_ref().ptr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto type = &heap_type->ht_type;
|
auto *type = &heap_type->ht_type;
|
||||||
type->tp_name = full_name;
|
type->tp_name = full_name;
|
||||||
type->tp_doc = tp_doc;
|
type->tp_doc = tp_doc;
|
||||||
type->tp_base = type_incref((PyTypeObject *)base);
|
type->tp_base = type_incref((PyTypeObject *) base);
|
||||||
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
||||||
if (!bases.empty())
|
if (!bases.empty()) {
|
||||||
type->tp_bases = bases.release().ptr();
|
type->tp_bases = bases.release().ptr();
|
||||||
|
}
|
||||||
|
|
||||||
/* Don't inherit base __init__ */
|
/* Don't inherit base __init__ */
|
||||||
type->tp_init = pybind11_object_init;
|
type->tp_init = pybind11_object_init;
|
||||||
@ -668,38 +679,42 @@ 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
|
if (!rec.is_final) {
|
||||||
type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
|
|
||||||
#endif
|
|
||||||
if (!rec.is_final)
|
|
||||||
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
||||||
|
}
|
||||||
|
|
||||||
if (rec.dynamic_attr)
|
if (rec.dynamic_attr) {
|
||||||
enable_dynamic_attributes(heap_type);
|
enable_dynamic_attributes(heap_type);
|
||||||
|
}
|
||||||
|
|
||||||
if (rec.buffer_protocol)
|
if (rec.buffer_protocol) {
|
||||||
enable_buffer_protocol(heap_type);
|
enable_buffer_protocol(heap_type);
|
||||||
|
}
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0)
|
if (rec.custom_type_setup_callback) {
|
||||||
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!");
|
rec.custom_type_setup_callback(heap_type);
|
||||||
|
}
|
||||||
|
|
||||||
assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)
|
if (PyType_Ready(type) < 0) {
|
||||||
: !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed: " + error_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
||||||
|
|
||||||
/* Register type with the parent scope */
|
/* Register type with the parent scope */
|
||||||
if (rec.scope)
|
if (rec.scope) {
|
||||||
setattr(rec.scope, rec.name, (PyObject *) type);
|
setattr(rec.scope, rec.name, (PyObject *) type);
|
||||||
else
|
} else {
|
||||||
Py_INCREF(type); // Keep it alive forever (reference leak)
|
Py_INCREF(type); // Keep it alive forever (reference leak)
|
||||||
|
}
|
||||||
|
|
||||||
if (module_) // Needed by pydoc
|
if (module_) { // Needed by pydoc
|
||||||
setattr((PyObject *) type, "__module__", module_);
|
setattr((PyObject *) type, "__module__", module_);
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
|
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
|
||||||
|
|
||||||
|
832
3rdparty/pybind11/include/pybind11/detail/common.h
vendored
832
3rdparty/pybind11/include/pybind11/detail/common.h
vendored
File diff suppressed because it is too large
Load Diff
104
3rdparty/pybind11/include/pybind11/detail/descr.h
vendored
104
3rdparty/pybind11/include/pybind11/detail/descr.h
vendored
@ -23,16 +23,18 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
/* Concatenate type signatures at compile time */
|
/* Concatenate type signatures at compile time */
|
||||||
template <size_t N, typename... Ts>
|
template <size_t N, typename... Ts>
|
||||||
struct descr {
|
struct descr {
|
||||||
char text[N + 1];
|
char text[N + 1]{'\0'};
|
||||||
|
|
||||||
constexpr descr() : text{'\0'} { }
|
constexpr descr() = default;
|
||||||
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { }
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence<N>()) {}
|
||||||
|
|
||||||
template <size_t... Is>
|
template <size_t... Is>
|
||||||
constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { }
|
constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\0'} {}
|
||||||
|
|
||||||
template <typename... Chars>
|
template <typename... Chars>
|
||||||
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { }
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} {}
|
||||||
|
|
||||||
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
|
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
|
||||||
return {{&typeid(Ts)..., nullptr}};
|
return {{&typeid(Ts)..., nullptr}};
|
||||||
@ -40,60 +42,116 @@ struct descr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
|
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
|
||||||
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b,
|
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,
|
||||||
index_sequence<Is1...>, index_sequence<Is2...>) {
|
const descr<N2, Ts2...> &b,
|
||||||
|
index_sequence<Is1...>,
|
||||||
|
index_sequence<Is2...>) {
|
||||||
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
|
||||||
return {a.text[Is1]..., b.text[Is2]...};
|
return {a.text[Is1]..., b.text[Is2]...};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
|
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
|
||||||
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) {
|
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a,
|
||||||
|
const descr<N2, Ts2...> &b) {
|
||||||
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
|
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
constexpr descr<N - 1> _(char const(&text)[N]) { return descr<N - 1>(text); }
|
constexpr descr<N - 1> const_name(char const (&text)[N]) {
|
||||||
constexpr descr<0> _(char const(&)[1]) { return {}; }
|
return descr<N - 1>(text);
|
||||||
|
}
|
||||||
|
constexpr descr<0> const_name(char const (&)[1]) { return {}; }
|
||||||
|
|
||||||
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
|
template <size_t Rem, size_t... Digits>
|
||||||
template <size_t...Digits> struct int_to_str<0, Digits...> {
|
struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};
|
||||||
|
template <size_t... Digits>
|
||||||
|
struct int_to_str<0, Digits...> {
|
||||||
|
// WARNING: This only works with C++17 or higher.
|
||||||
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
|
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ternary description (like std::conditional)
|
// Ternary description (like std::conditional)
|
||||||
template <bool B, size_t N1, size_t N2>
|
template <bool B, size_t N1, size_t N2>
|
||||||
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&)[N2]) {
|
constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {
|
||||||
return _(text1);
|
return const_name(text1);
|
||||||
}
|
}
|
||||||
template <bool B, size_t N1, size_t N2>
|
template <bool B, size_t N1, size_t N2>
|
||||||
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&)[N1], char const(&text2)[N2]) {
|
constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {
|
||||||
return _(text2);
|
return const_name(text2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool B, typename T1, typename T2>
|
template <bool B, typename T1, typename T2>
|
||||||
constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; }
|
constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
template <bool B, typename T1, typename T2>
|
template <bool B, typename T1, typename T2>
|
||||||
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; }
|
constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
template <size_t Size>
|
||||||
|
auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
|
||||||
return int_to_str<Size / 10, Size % 10>::digits;
|
return int_to_str<Size / 10, Size % 10>::digits;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type> constexpr descr<1, Type> _() { return {'%'}; }
|
template <typename Type>
|
||||||
|
constexpr descr<1, Type> const_name() {
|
||||||
|
return {'%'};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If "_" is defined as a macro, py::detail::_ cannot be provided.
|
||||||
|
// It is therefore best to use py::detail::const_name universally.
|
||||||
|
// This block is for backward compatibility only.
|
||||||
|
// (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
|
||||||
|
#ifndef _
|
||||||
|
# define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
||||||
|
template <size_t N>
|
||||||
|
constexpr descr<N - 1> _(char const (&text)[N]) {
|
||||||
|
return const_name<N>(text);
|
||||||
|
}
|
||||||
|
template <bool B, size_t N1, size_t N2>
|
||||||
|
constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
|
||||||
|
return const_name<B, N1, N2>(text1, text2);
|
||||||
|
}
|
||||||
|
template <bool B, size_t N1, size_t N2>
|
||||||
|
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
|
||||||
|
return const_name<B, N1, N2>(text1, text2);
|
||||||
|
}
|
||||||
|
template <bool B, typename T1, typename T2>
|
||||||
|
constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {
|
||||||
|
return const_name<B, T1, T2>(d1, d2);
|
||||||
|
}
|
||||||
|
template <bool B, typename T1, typename T2>
|
||||||
|
constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {
|
||||||
|
return const_name<B, T1, T2>(d1, d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t Size>
|
||||||
|
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
|
||||||
|
return const_name<Size>();
|
||||||
|
}
|
||||||
|
template <typename Type>
|
||||||
|
constexpr descr<1, Type> _() {
|
||||||
|
return const_name<Type>();
|
||||||
|
}
|
||||||
|
#endif // #ifndef _
|
||||||
|
|
||||||
constexpr descr<0> concat() { return {}; }
|
constexpr descr<0> concat() { return {}; }
|
||||||
|
|
||||||
template <size_t N, typename... Ts>
|
template <size_t N, typename... Ts>
|
||||||
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; }
|
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
|
||||||
|
return descr;
|
||||||
|
}
|
||||||
|
|
||||||
template <size_t N, typename... Ts, typename... Args>
|
template <size_t N, typename... Ts, typename... Args>
|
||||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
||||||
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
||||||
return d + _(", ") + concat(args...);
|
return d + const_name(", ") + concat(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N, typename... Ts>
|
template <size_t N, typename... Ts>
|
||||||
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
|
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
|
||||||
return _("{") + descr + _("}");
|
return const_name("{") + descr + const_name("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
268
3rdparty/pybind11/include/pybind11/detail/init.h
vendored
268
3rdparty/pybind11/include/pybind11/detail/init.h
vendored
@ -22,9 +22,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename> using cast_op_type = value_and_holder &;
|
template <typename>
|
||||||
operator value_and_holder &() { return *value; }
|
using cast_op_type = value_and_holder &;
|
||||||
static constexpr auto name = _<value_and_holder>();
|
explicit operator value_and_holder &() { return *value; }
|
||||||
|
static constexpr auto name = const_name<value_and_holder>();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_and_holder *value = nullptr;
|
value_and_holder *value = nullptr;
|
||||||
@ -33,15 +34,21 @@ private:
|
|||||||
PYBIND11_NAMESPACE_BEGIN(initimpl)
|
PYBIND11_NAMESPACE_BEGIN(initimpl)
|
||||||
|
|
||||||
inline void no_nullptr(void *ptr) {
|
inline void no_nullptr(void *ptr) {
|
||||||
if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr");
|
if (!ptr) {
|
||||||
|
throw type_error("pybind11::init(): factory function returned nullptr");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing functions for all forms of py::init<...> and py::init(...)
|
// Implementing functions for all forms of py::init<...> and py::init(...)
|
||||||
template <typename Class> using Cpp = typename Class::type;
|
template <typename Class>
|
||||||
template <typename Class> using Alias = typename Class::type_alias;
|
using Cpp = typename Class::type;
|
||||||
template <typename Class> using Holder = typename Class::holder_type;
|
template <typename Class>
|
||||||
|
using Alias = typename Class::type_alias;
|
||||||
|
template <typename Class>
|
||||||
|
using Holder = typename Class::holder_type;
|
||||||
|
|
||||||
template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
|
template <typename Class>
|
||||||
|
using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
|
||||||
|
|
||||||
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
|
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
|
||||||
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
||||||
@ -50,17 +57,27 @@ bool is_alias(Cpp<Class> *ptr) {
|
|||||||
}
|
}
|
||||||
// Failing fallback version of the above for a no-alias class (always returns false)
|
// Failing fallback version of the above for a no-alias class (always returns false)
|
||||||
template <typename /*Class*/>
|
template <typename /*Class*/>
|
||||||
constexpr bool is_alias(void *) { return false; }
|
constexpr bool is_alias(void *) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
||||||
// back to brace aggregate initiailization so that for aggregate initialization can be used with
|
// back to brace aggregate initiailization so that for aggregate initialization can be used with
|
||||||
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
||||||
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
||||||
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
||||||
template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
|
template <typename Class,
|
||||||
inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); }
|
typename... Args,
|
||||||
template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
|
detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
|
||||||
inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
|
inline Class *construct_or_initialize(Args &&...args) {
|
||||||
|
return new Class(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
template <typename Class,
|
||||||
|
typename... Args,
|
||||||
|
detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
|
||||||
|
inline Class *construct_or_initialize(Args &&...args) {
|
||||||
|
return new Class{std::forward<Args>(args)...};
|
||||||
|
}
|
||||||
|
|
||||||
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
|
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
|
||||||
// an alias to provide only a single Cpp factory function as long as the Alias can be
|
// an alias to provide only a single Cpp factory function as long as the Alias can be
|
||||||
@ -69,12 +86,14 @@ inline Class *construct_or_initialize(Args &&...args) { return new Class{std::fo
|
|||||||
// inherit all the base class constructors.
|
// inherit all the base class constructors.
|
||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
|
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
|
||||||
value_and_holder &v_h, Cpp<Class> &&base) {
|
value_and_holder &v_h,
|
||||||
|
Cpp<Class> &&base) {
|
||||||
v_h.value_ptr() = new Alias<Class>(std::move(base));
|
v_h.value_ptr() = new Alias<Class>(std::move(base));
|
||||||
}
|
}
|
||||||
template <typename Class>
|
template <typename Class>
|
||||||
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
|
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
|
||||||
value_and_holder &, Cpp<Class> &&) {
|
value_and_holder &,
|
||||||
|
Cpp<Class> &&) {
|
||||||
throw type_error("pybind11::init(): unable to convert returned instance to required "
|
throw type_error("pybind11::init(): unable to convert returned instance to required "
|
||||||
"alias class: no `Alias<Class>(Class &&)` constructor available");
|
"alias class: no `Alias<Class>(Class &&)` constructor available");
|
||||||
}
|
}
|
||||||
@ -94,8 +113,9 @@ void construct(...) {
|
|||||||
// construct an Alias from the returned base instance.
|
// construct an Alias from the returned base instance.
|
||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
||||||
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
||||||
no_nullptr(ptr);
|
no_nullptr(ptr);
|
||||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
|
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
|
||||||
// We're going to try to construct an alias by moving the cpp type. Whether or not
|
// We're going to try to construct an alias by moving the cpp type. Whether or not
|
||||||
// that succeeds, we still need to destroy the original cpp pointer (either the
|
// that succeeds, we still need to destroy the original cpp pointer (either the
|
||||||
// moved away leftover, if the alias construction works, or the value itself if we
|
// moved away leftover, if the alias construction works, or the value itself if we
|
||||||
@ -128,15 +148,18 @@ void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
|
|||||||
|
|
||||||
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
|
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
|
||||||
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
|
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
|
||||||
// derived type (through those holder's implicit conversion from derived class holder constructors).
|
// derived type (through those holder's implicit conversion from derived class holder
|
||||||
|
// constructors).
|
||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
||||||
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
||||||
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
||||||
no_nullptr(ptr);
|
no_nullptr(ptr);
|
||||||
// If we need an alias, check that the held pointer is actually an alias instance
|
// If we need an alias, check that the held pointer is actually an alias instance
|
||||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr))
|
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
|
||||||
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
|
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
|
||||||
"is not an alias instance");
|
"is not an alias instance");
|
||||||
|
}
|
||||||
|
|
||||||
v_h.value_ptr() = ptr;
|
v_h.value_ptr() = ptr;
|
||||||
v_h.type->init_instance(v_h.inst, &holder);
|
v_h.type->init_instance(v_h.inst, &holder);
|
||||||
@ -148,12 +171,14 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
|||||||
// need it, we simply move-construct the cpp value into a new instance.
|
// need it, we simply move-construct the cpp value into a new instance.
|
||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
||||||
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
||||||
static_assert(std::is_move_constructible<Cpp<Class>>::value,
|
static_assert(std::is_move_constructible<Cpp<Class>>::value,
|
||||||
"pybind11::init() return-by-value factory function requires a movable class");
|
"pybind11::init() return-by-value factory function requires a movable class");
|
||||||
if (Class::has_alias && need_alias)
|
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) {
|
||||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
||||||
else
|
} else {
|
||||||
v_h.value_ptr() = new Cpp<Class>(std::move(result));
|
v_h.value_ptr() = new Cpp<Class>(std::move(result));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
|
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
|
||||||
@ -161,7 +186,8 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
|||||||
// cases where Alias initialization is always desired.
|
// cases where Alias initialization is always desired.
|
||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
||||||
static_assert(std::is_move_constructible<Alias<Class>>::value,
|
static_assert(
|
||||||
|
std::is_move_constructible<Alias<Class>>::value,
|
||||||
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
||||||
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
||||||
}
|
}
|
||||||
@ -170,48 +196,76 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
|||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
struct constructor {
|
struct constructor {
|
||||||
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
|
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
|
||||||
static void execute(Class &cl, const Extra&... extra) {
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
cl.def(
|
||||||
|
"__init__",
|
||||||
|
[](value_and_holder &v_h, Args... args) {
|
||||||
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||||
}, is_new_style_constructor(), extra...);
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Class, typename... Extra,
|
template <typename Class,
|
||||||
enable_if_t<Class::has_alias &&
|
typename... Extra,
|
||||||
std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
|
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value,
|
||||||
static void execute(Class &cl, const Extra&... extra) {
|
int> = 0>
|
||||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
cl.def(
|
||||||
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
"__init__",
|
||||||
else
|
[](value_and_holder &v_h, Args... args) {
|
||||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
if (Py_TYPE(v_h.inst) == v_h.type->type) {
|
||||||
}, is_new_style_constructor(), extra...);
|
v_h.value_ptr()
|
||||||
|
= construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
|
v_h.value_ptr()
|
||||||
|
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Class, typename... Extra,
|
template <typename Class,
|
||||||
enable_if_t<Class::has_alias &&
|
typename... Extra,
|
||||||
!std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
|
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value,
|
||||||
static void execute(Class &cl, const Extra&... extra) {
|
int> = 0>
|
||||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
cl.def(
|
||||||
}, is_new_style_constructor(), extra...);
|
"__init__",
|
||||||
|
[](value_and_holder &v_h, Args... args) {
|
||||||
|
v_h.value_ptr()
|
||||||
|
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||||
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementing class for py::init_alias<...>()
|
// Implementing class for py::init_alias<...>()
|
||||||
template <typename... Args> struct alias_constructor {
|
template <typename... Args>
|
||||||
template <typename Class, typename... Extra,
|
struct alias_constructor {
|
||||||
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
|
template <typename Class,
|
||||||
static void execute(Class &cl, const Extra&... extra) {
|
typename... Extra,
|
||||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value,
|
||||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
int> = 0>
|
||||||
}, is_new_style_constructor(), extra...);
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
|
cl.def(
|
||||||
|
"__init__",
|
||||||
|
[](value_and_holder &v_h, Args... args) {
|
||||||
|
v_h.value_ptr()
|
||||||
|
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||||
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
|
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
|
||||||
template <typename CFunc, typename AFunc = void_type (*)(),
|
template <typename CFunc,
|
||||||
typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>>
|
typename AFunc = void_type (*)(),
|
||||||
|
typename = function_signature_t<CFunc>,
|
||||||
|
typename = function_signature_t<AFunc>>
|
||||||
struct factory;
|
struct factory;
|
||||||
|
|
||||||
// Specialization for py::init(Func)
|
// Specialization for py::init(Func)
|
||||||
@ -219,7 +273,8 @@ template <typename Func, typename Return, typename... Args>
|
|||||||
struct factory<Func, void_type (*)(), Return(Args...)> {
|
struct factory<Func, void_type (*)(), Return(Args...)> {
|
||||||
remove_reference_t<Func> class_factory;
|
remove_reference_t<Func> class_factory;
|
||||||
|
|
||||||
factory(Func &&f) : class_factory(std::forward<Func>(f)) { }
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
|
||||||
|
|
||||||
// The given class either has no alias or has no separate alias factory;
|
// The given class either has no alias or has no separate alias factory;
|
||||||
// this always constructs the class itself. If the class is registered with an alias
|
// this always constructs the class itself. If the class is registered with an alias
|
||||||
@ -228,22 +283,32 @@ struct factory<Func, void_type (*)(), Return(Args...)> {
|
|||||||
// instance, or the alias needs to be constructible from a `Class &&` argument.
|
// instance, or the alias needs to be constructible from a `Class &&` argument.
|
||||||
template <typename Class, typename... Extra>
|
template <typename Class, typename... Extra>
|
||||||
void execute(Class &cl, const Extra &...extra) && {
|
void execute(Class &cl, const Extra &...extra) && {
|
||||||
#if defined(PYBIND11_CPP14)
|
#if defined(PYBIND11_CPP14)
|
||||||
cl.def("__init__", [func = std::move(class_factory)]
|
cl.def(
|
||||||
#else
|
"__init__",
|
||||||
|
[func = std::move(class_factory)]
|
||||||
|
#else
|
||||||
auto &func = class_factory;
|
auto &func = class_factory;
|
||||||
cl.def("__init__", [func]
|
cl.def(
|
||||||
#endif
|
"__init__",
|
||||||
|
[func]
|
||||||
|
#endif
|
||||||
(value_and_holder &v_h, Args... args) {
|
(value_and_holder &v_h, Args... args) {
|
||||||
construct<Class>(v_h, func(std::forward<Args>(args)...),
|
construct<Class>(
|
||||||
Py_TYPE(v_h.inst) != v_h.type->type);
|
v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
|
||||||
}, is_new_style_constructor(), extra...);
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specialization for py::init(Func, AliasFunc)
|
// Specialization for py::init(Func, AliasFunc)
|
||||||
template <typename CFunc, typename AFunc,
|
template <typename CFunc,
|
||||||
typename CReturn, typename... CArgs, typename AReturn, typename... AArgs>
|
typename AFunc,
|
||||||
|
typename CReturn,
|
||||||
|
typename... CArgs,
|
||||||
|
typename AReturn,
|
||||||
|
typename... AArgs>
|
||||||
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
|
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
|
||||||
static_assert(sizeof...(CArgs) == sizeof...(AArgs),
|
static_assert(sizeof...(CArgs) == sizeof...(AArgs),
|
||||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||||
@ -256,29 +321,37 @@ struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
|
|||||||
remove_reference_t<AFunc> alias_factory;
|
remove_reference_t<AFunc> alias_factory;
|
||||||
|
|
||||||
factory(CFunc &&c, AFunc &&a)
|
factory(CFunc &&c, AFunc &&a)
|
||||||
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
|
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
|
||||||
|
|
||||||
// The class factory is called when the `self` type passed to `__init__` is the direct
|
// The class factory is called when the `self` type passed to `__init__` is the direct
|
||||||
// class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
|
// class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
|
||||||
template <typename Class, typename... Extra>
|
template <typename Class, typename... Extra>
|
||||||
void execute(Class &cl, const Extra&... extra) && {
|
void execute(Class &cl, const Extra &...extra) && {
|
||||||
static_assert(Class::has_alias, "The two-argument version of `py::init()` can "
|
static_assert(Class::has_alias,
|
||||||
|
"The two-argument version of `py::init()` can "
|
||||||
"only be used if the class has an alias");
|
"only be used if the class has an alias");
|
||||||
#if defined(PYBIND11_CPP14)
|
#if defined(PYBIND11_CPP14)
|
||||||
cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
|
cl.def(
|
||||||
#else
|
"__init__",
|
||||||
|
[class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
|
||||||
|
#else
|
||||||
auto &class_func = class_factory;
|
auto &class_func = class_factory;
|
||||||
auto &alias_func = alias_factory;
|
auto &alias_func = alias_factory;
|
||||||
cl.def("__init__", [class_func, alias_func]
|
cl.def(
|
||||||
#endif
|
"__init__",
|
||||||
|
[class_func, alias_func]
|
||||||
|
#endif
|
||||||
(value_and_holder &v_h, CArgs... args) {
|
(value_and_holder &v_h, CArgs... args) {
|
||||||
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
if (Py_TYPE(v_h.inst) == v_h.type->type) {
|
||||||
// If the instance type equals the registered type we don't have inheritance, so
|
// If the instance type equals the registered type we don't have inheritance,
|
||||||
// don't need the alias and can construct using the class function:
|
// so don't need the alias and can construct using the class function:
|
||||||
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
|
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
|
||||||
else
|
} else {
|
||||||
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
|
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
|
||||||
}, is_new_style_constructor(), extra...);
|
}
|
||||||
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -289,20 +362,34 @@ void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set both the C++ and Python states
|
/// Set both the C++ and Python states
|
||||||
template <typename Class, typename T, typename O,
|
template <typename Class,
|
||||||
|
typename T,
|
||||||
|
typename O,
|
||||||
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
|
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
|
||||||
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
|
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
|
||||||
construct<Class>(v_h, std::move(result.first), need_alias);
|
construct<Class>(v_h, std::move(result.first), need_alias);
|
||||||
setattr((PyObject *) v_h.inst, "__dict__", result.second);
|
auto d = handle(result.second);
|
||||||
|
if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
|
||||||
|
// Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
|
||||||
|
// See PR #2972 for details.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setattr((PyObject *) v_h.inst, "__dict__", d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation for py::pickle(GetState, SetState)
|
/// Implementation for py::pickle(GetState, SetState)
|
||||||
template <typename Get, typename Set,
|
template <typename Get,
|
||||||
typename = function_signature_t<Get>, typename = function_signature_t<Set>>
|
typename Set,
|
||||||
|
typename = function_signature_t<Get>,
|
||||||
|
typename = function_signature_t<Set>>
|
||||||
struct pickle_factory;
|
struct pickle_factory;
|
||||||
|
|
||||||
template <typename Get, typename Set,
|
template <typename Get,
|
||||||
typename RetState, typename Self, typename NewInstance, typename ArgState>
|
typename Set,
|
||||||
|
typename RetState,
|
||||||
|
typename Self,
|
||||||
|
typename NewInstance,
|
||||||
|
typename ArgState>
|
||||||
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
||||||
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
|
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
|
||||||
"The type returned by `__getstate__` must be the same "
|
"The type returned by `__getstate__` must be the same "
|
||||||
@ -311,26 +398,31 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
|||||||
remove_reference_t<Get> get;
|
remove_reference_t<Get> get;
|
||||||
remove_reference_t<Set> set;
|
remove_reference_t<Set> set;
|
||||||
|
|
||||||
pickle_factory(Get get, Set set)
|
pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
|
||||||
: get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
|
|
||||||
|
|
||||||
template <typename Class, typename... Extra>
|
template <typename Class, typename... Extra>
|
||||||
void execute(Class &cl, const Extra &...extra) && {
|
void execute(Class &cl, const Extra &...extra) && {
|
||||||
cl.def("__getstate__", std::move(get));
|
cl.def("__getstate__", std::move(get));
|
||||||
|
|
||||||
#if defined(PYBIND11_CPP14)
|
#if defined(PYBIND11_CPP14)
|
||||||
cl.def("__setstate__", [func = std::move(set)]
|
cl.def(
|
||||||
|
"__setstate__",
|
||||||
|
[func = std::move(set)]
|
||||||
#else
|
#else
|
||||||
auto &func = set;
|
auto &func = set;
|
||||||
cl.def("__setstate__", [func]
|
cl.def(
|
||||||
|
"__setstate__",
|
||||||
|
[func]
|
||||||
#endif
|
#endif
|
||||||
(value_and_holder &v_h, ArgState state) {
|
(value_and_holder &v_h, ArgState state) {
|
||||||
setstate<Class>(v_h, func(std::forward<ArgState>(state)),
|
setstate<Class>(
|
||||||
Py_TYPE(v_h.inst) != v_h.type->type);
|
v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
|
||||||
}, is_new_style_constructor(), extra...);
|
},
|
||||||
|
is_new_style_constructor(),
|
||||||
|
extra...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
|
@ -11,8 +11,32 @@
|
|||||||
|
|
||||||
#include "../pytypes.h"
|
#include "../pytypes.h"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
|
||||||
|
///
|
||||||
|
/// Some portions of the code use an ABI that is conditional depending on this
|
||||||
|
/// version number. That allows ABI-breaking changes to be "pre-implemented".
|
||||||
|
/// Once the default version number is incremented, the conditional logic that
|
||||||
|
/// no longer applies can be removed. Additionally, users that need not
|
||||||
|
/// maintain ABI compatibility can increase the version number in order to take
|
||||||
|
/// advantage of any functionality/efficiency improvements that depend on the
|
||||||
|
/// newer ABI.
|
||||||
|
///
|
||||||
|
/// WARNING: If you choose to manually increase the ABI version, note that
|
||||||
|
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
|
||||||
|
/// further ABI-incompatible changes may be made before the ABI is officially
|
||||||
|
/// changed to the new version.
|
||||||
|
#ifndef PYBIND11_INTERNALS_VERSION
|
||||||
|
# define PYBIND11_INTERNALS_VERSION 4
|
||||||
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
using ExceptionTranslator = void (*)(std::exception_ptr);
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
inline PyTypeObject *make_static_property_type();
|
inline PyTypeObject *make_static_property_type();
|
||||||
inline PyTypeObject *make_default_metaclass();
|
inline PyTypeObject *make_default_metaclass();
|
||||||
@ -21,30 +45,59 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
|||||||
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
||||||
// Thread Specific Storage (TSS) API.
|
// Thread Specific Storage (TSS) API.
|
||||||
#if PY_VERSION_HEX >= 0x03070000
|
#if PY_VERSION_HEX >= 0x03070000
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
|
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
|
||||||
|
// `Py_LIMITED_API` anyway.
|
||||||
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
|
# define PYBIND11_TLS_KEY_REF Py_tss_t &
|
||||||
|
# ifdef __GNUC__
|
||||||
|
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
|
||||||
|
// for every field.
|
||||||
|
# define PYBIND11_TLS_KEY_INIT(var) \
|
||||||
|
_Pragma("GCC diagnostic push") /**/ \
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
||||||
|
Py_tss_t var \
|
||||||
|
= Py_tss_NEEDS_INIT; \
|
||||||
|
_Pragma("GCC diagnostic pop")
|
||||||
|
# else
|
||||||
|
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
|
||||||
|
# endif
|
||||||
|
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
|
||||||
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
|
||||||
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
|
||||||
|
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
|
||||||
|
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
|
||||||
|
# else
|
||||||
|
# define PYBIND11_TLS_KEY_REF Py_tss_t *
|
||||||
|
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
|
||||||
|
# define PYBIND11_TLS_KEY_CREATE(var) \
|
||||||
|
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
||||||
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
||||||
#else
|
|
||||||
// Usually an int but a long on Cygwin64 with Python 3.x
|
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
|
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
|
||||||
# if PY_MAJOR_VERSION < 3
|
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
|
||||||
PyThread_delete_key_value(key)
|
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
|
||||||
do { \
|
|
||||||
PyThread_delete_key_value((key)); \
|
|
||||||
PyThread_set_key_value((key), (value)); \
|
|
||||||
} while (false)
|
|
||||||
# else
|
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
|
||||||
PyThread_set_key_value((key), nullptr)
|
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
|
||||||
PyThread_set_key_value((key), (value))
|
|
||||||
# endif
|
# endif
|
||||||
# define PYBIND11_TLS_FREE(key) (void)key
|
#else
|
||||||
|
// Usually an int but a long on Cygwin64 with Python 3.x
|
||||||
|
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
|
||||||
|
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
||||||
|
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
||||||
|
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||||
|
# if defined(PYPY_VERSION)
|
||||||
|
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
||||||
|
// the value if it has already been set. Instead, it must first be deleted and
|
||||||
|
// then set again.
|
||||||
|
inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {
|
||||||
|
PyThread_delete_key_value(key);
|
||||||
|
PyThread_set_key_value(key, value);
|
||||||
|
}
|
||||||
|
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)
|
||||||
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||||
|
::pybind11::detail::tls_replace_value((key), (value))
|
||||||
|
# else
|
||||||
|
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
|
||||||
|
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
|
||||||
|
# endif
|
||||||
|
# define PYBIND11_TLS_FREE(key) (void) key
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
||||||
@ -66,8 +119,9 @@ struct type_hash {
|
|||||||
size_t operator()(const std::type_index &t) const {
|
size_t operator()(const std::type_index &t) const {
|
||||||
size_t hash = 5381;
|
size_t hash = 5381;
|
||||||
const char *ptr = t.name();
|
const char *ptr = t.name();
|
||||||
while (auto c = static_cast<unsigned char>(*ptr++))
|
while (auto c = static_cast<unsigned char>(*ptr++)) {
|
||||||
hash = (hash * 33) ^ c;
|
hash = (hash * 33) ^ c;
|
||||||
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -83,9 +137,9 @@ template <typename value_type>
|
|||||||
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
||||||
|
|
||||||
struct override_hash {
|
struct override_hash {
|
||||||
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
inline size_t operator()(const std::pair<const PyObject *, const char *> &v) const {
|
||||||
size_t value = std::hash<const void *>()(v.first);
|
size_t value = std::hash<const void *>()(v.first);
|
||||||
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
|
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) + (value >> 2);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -94,30 +148,44 @@ struct override_hash {
|
|||||||
/// Whenever binary incompatible changes are made to this structure,
|
/// Whenever binary incompatible changes are made to this structure,
|
||||||
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
||||||
struct internals {
|
struct internals {
|
||||||
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
|
// std::type_index -> pybind11's type information
|
||||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
|
type_map<type_info *> registered_types_cpp;
|
||||||
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
|
// PyTypeObject* -> base type_info(s)
|
||||||
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
|
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
|
||||||
|
std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
|
||||||
|
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
|
||||||
|
inactive_override_cache;
|
||||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||||
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
||||||
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
|
std::forward_list<ExceptionTranslator> registered_exception_translators;
|
||||||
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
|
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across
|
||||||
std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
|
// extensions
|
||||||
std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
|
#if PYBIND11_INTERNALS_VERSION == 4
|
||||||
|
std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5;
|
||||||
|
#endif
|
||||||
|
std::forward_list<std::string> static_strings; // Stores the std::strings backing
|
||||||
|
// detail::c_str()
|
||||||
PyTypeObject *static_property_type;
|
PyTypeObject *static_property_type;
|
||||||
PyTypeObject *default_metaclass;
|
PyTypeObject *default_metaclass;
|
||||||
PyObject *instance_base;
|
PyObject *instance_base;
|
||||||
#if defined(WITH_THREAD)
|
#if defined(WITH_THREAD)
|
||||||
PYBIND11_TLS_KEY_INIT(tstate);
|
PYBIND11_TLS_KEY_INIT(tstate)
|
||||||
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
|
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
||||||
|
# endif // PYBIND11_INTERNALS_VERSION > 4
|
||||||
PyInterpreterState *istate = nullptr;
|
PyInterpreterState *istate = nullptr;
|
||||||
~internals() {
|
~internals() {
|
||||||
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
|
PYBIND11_TLS_FREE(loader_life_support_tls_key);
|
||||||
|
# endif // PYBIND11_INTERNALS_VERSION > 4
|
||||||
|
|
||||||
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
|
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
|
||||||
// That *SHOULD BE* fine. The following details what happens whe PyThread_tss_free is called.
|
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
|
||||||
// PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing.
|
// called. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does
|
||||||
// PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
|
// nothing. PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
|
||||||
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither
|
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX).
|
||||||
// of those have anything to do with CPython internals.
|
// Neither of those have anything to do with CPython internals. PyMem_RawFree *requires*
|
||||||
// PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator.
|
// that the `tstate` be allocated with the CPython allocator.
|
||||||
PYBIND11_TLS_FREE(tstate);
|
PYBIND11_TLS_FREE(tstate);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -132,14 +200,16 @@ struct type_info {
|
|||||||
void *(*operator_new)(size_t);
|
void *(*operator_new)(size_t);
|
||||||
void (*init_instance)(instance *, const void *);
|
void (*init_instance)(instance *, const void *);
|
||||||
void (*dealloc)(value_and_holder &v_h);
|
void (*dealloc)(value_and_holder &v_h);
|
||||||
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
std::vector<PyObject *(*) (PyObject *, PyTypeObject *)> implicit_conversions;
|
||||||
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
|
std::vector<std::pair<const std::type_info *, void *(*) (void *)>> implicit_casts;
|
||||||
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
||||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||||
void *get_buffer_data = nullptr;
|
void *get_buffer_data = nullptr;
|
||||||
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
||||||
/* A simple type never occurs as a (direct or indirect) parent
|
/* A simple type never occurs as a (direct or indirect) parent
|
||||||
* of a class that makes use of multiple inheritance */
|
* of a class that makes use of multiple inheritance.
|
||||||
|
* A type can be simple even if it has non-simple ancestors as long as it has no descendants.
|
||||||
|
*/
|
||||||
bool simple_type : 1;
|
bool simple_type : 1;
|
||||||
/* True if there is no multiple inheritance in this type's inheritance tree */
|
/* True if there is no multiple inheritance in this type's inheritance tree */
|
||||||
bool simple_ancestors : 1;
|
bool simple_ancestors : 1;
|
||||||
@ -149,9 +219,6 @@ struct type_info {
|
|||||||
bool module_local : 1;
|
bool module_local : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
|
|
||||||
#define PYBIND11_INTERNALS_VERSION 4
|
|
||||||
|
|
||||||
/// On MSVC, debug and release builds are not ABI-compatible!
|
/// On MSVC, debug and release builds are not ABI-compatible!
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||||
# define PYBIND11_BUILD_TYPE "_debug"
|
# define PYBIND11_BUILD_TYPE "_debug"
|
||||||
@ -210,11 +277,15 @@ struct type_info {
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
|
#define PYBIND11_INTERNALS_ID \
|
||||||
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||||
|
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
||||||
|
PYBIND11_BUILD_TYPE "__"
|
||||||
|
|
||||||
#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
|
#define PYBIND11_MODULE_LOCAL_ID \
|
||||||
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
|
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||||
|
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
||||||
|
PYBIND11_BUILD_TYPE "__"
|
||||||
|
|
||||||
/// Each module locally stores a pointer to the `internals` data. The data
|
/// Each module locally stores a pointer to the `internals` data. The data
|
||||||
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
||||||
@ -223,21 +294,93 @@ inline internals **&get_internals_pp() {
|
|||||||
return internals_pp;
|
return internals_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// forward decl
|
||||||
|
inline void translate_exception(std::exception_ptr);
|
||||||
|
|
||||||
|
template <class T,
|
||||||
|
enable_if_t<std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>
|
||||||
|
bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
|
||||||
|
std::exception_ptr nested = exc.nested_ptr();
|
||||||
|
if (nested != nullptr && nested != p) {
|
||||||
|
translate_exception(nested);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T,
|
||||||
|
enable_if_t<!std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>
|
||||||
|
bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
|
||||||
|
if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(exc))) {
|
||||||
|
return handle_nested_exception(*nep, p);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool raise_err(PyObject *exc_type, const char *msg) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
raise_from(exc_type, msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PyErr_SetString(exc_type, msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
inline void translate_exception(std::exception_ptr p) {
|
inline void translate_exception(std::exception_ptr p) {
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (p) std::rethrow_exception(p);
|
std::rethrow_exception(p);
|
||||||
} catch (error_already_set &e) { e.restore(); return;
|
} catch (error_already_set &e) {
|
||||||
} catch (const builtin_exception &e) { e.set_error(); return;
|
handle_nested_exception(e, p);
|
||||||
} catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return;
|
e.restore();
|
||||||
} catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
return;
|
||||||
} catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
} catch (const builtin_exception &e) {
|
||||||
} catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
// Could not use template since it's an abstract class.
|
||||||
} catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return;
|
if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(e))) {
|
||||||
} catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
handle_nested_exception(*nep, p);
|
||||||
} catch (const std::overflow_error &e) { PyErr_SetString(PyExc_OverflowError, e.what()); return;
|
}
|
||||||
} catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return;
|
e.set_error();
|
||||||
|
return;
|
||||||
|
} catch (const std::bad_alloc &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_MemoryError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::domain_error &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_ValueError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::invalid_argument &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_ValueError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::length_error &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_ValueError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::out_of_range &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_IndexError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::range_error &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_ValueError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::overflow_error &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_OverflowError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_RuntimeError, e.what());
|
||||||
|
return;
|
||||||
|
} catch (const std::nested_exception &e) {
|
||||||
|
handle_nested_exception(e, p);
|
||||||
|
raise_err(PyExc_RuntimeError, "Caught an unknown nested exception!");
|
||||||
|
return;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
|
raise_err(PyExc_RuntimeError, "Caught an unknown exception!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,28 +388,36 @@ inline void translate_exception(std::exception_ptr p) {
|
|||||||
#if !defined(__GLIBCXX__)
|
#if !defined(__GLIBCXX__)
|
||||||
inline void translate_local_exception(std::exception_ptr p) {
|
inline void translate_local_exception(std::exception_ptr p) {
|
||||||
try {
|
try {
|
||||||
if (p) std::rethrow_exception(p);
|
if (p) {
|
||||||
} catch (error_already_set &e) { e.restore(); return;
|
std::rethrow_exception(p);
|
||||||
} catch (const builtin_exception &e) { e.set_error(); return;
|
}
|
||||||
|
} catch (error_already_set &e) {
|
||||||
|
e.restore();
|
||||||
|
return;
|
||||||
|
} catch (const builtin_exception &e) {
|
||||||
|
e.set_error();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Return a reference to the current `internals` data
|
/// Return a reference to the current `internals` data
|
||||||
PYBIND11_NOINLINE inline internals &get_internals() {
|
PYBIND11_NOINLINE internals &get_internals() {
|
||||||
auto **&internals_pp = get_internals_pp();
|
auto **&internals_pp = get_internals_pp();
|
||||||
if (internals_pp && *internals_pp)
|
if (internals_pp && *internals_pp) {
|
||||||
return **internals_pp;
|
return **internals_pp;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that the GIL is held since we will need to make Python calls.
|
// Ensure that the GIL is held since we will need to make Python calls.
|
||||||
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
|
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
|
||||||
struct gil_scoped_acquire_local {
|
struct gil_scoped_acquire_local {
|
||||||
gil_scoped_acquire_local() : state (PyGILState_Ensure()) {}
|
gil_scoped_acquire_local() : state(PyGILState_Ensure()) {}
|
||||||
~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;
|
||||||
|
|
||||||
constexpr auto *id = PYBIND11_INTERNALS_ID;
|
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
|
||||||
auto builtins = handle(PyEval_GetBuiltins());
|
auto builtins = handle(PyEval_GetBuiltins());
|
||||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
||||||
internals_pp = static_cast<internals **>(capsule(builtins[id]));
|
internals_pp = static_cast<internals **>(capsule(builtins[id]));
|
||||||
@ -276,30 +427,34 @@ PYBIND11_NOINLINE inline internals &get_internals() {
|
|||||||
// initial exception translator, below, so add another for our local exception classes.
|
// initial exception translator, below, so add another for our local exception classes.
|
||||||
//
|
//
|
||||||
// libstdc++ doesn't require this (types there are identified only by name)
|
// libstdc++ doesn't require this (types there are identified only by name)
|
||||||
|
// libc++ with CPython doesn't require this (types are explicitly exported)
|
||||||
|
// libc++ with PyPy still need it, awaiting further investigation
|
||||||
#if !defined(__GLIBCXX__)
|
#if !defined(__GLIBCXX__)
|
||||||
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
|
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (!internals_pp) internals_pp = new internals*();
|
if (!internals_pp) {
|
||||||
|
internals_pp = new internals *();
|
||||||
|
}
|
||||||
auto *&internals_ptr = *internals_pp;
|
auto *&internals_ptr = *internals_pp;
|
||||||
internals_ptr = new internals();
|
internals_ptr = new internals();
|
||||||
#if defined(WITH_THREAD)
|
#if defined(WITH_THREAD)
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x03090000
|
# if PY_VERSION_HEX < 0x03090000
|
||||||
PyEval_InitThreads();
|
PyEval_InitThreads();
|
||||||
#endif
|
# endif
|
||||||
PyThreadState *tstate = PyThreadState_Get();
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
#if PY_VERSION_HEX >= 0x03070000
|
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {
|
||||||
internals_ptr->tstate = PyThread_tss_alloc();
|
pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!");
|
||||||
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
|
}
|
||||||
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
|
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
|
||||||
PyThread_tss_set(internals_ptr->tstate, tstate);
|
|
||||||
#else
|
# if PYBIND11_INTERNALS_VERSION > 4
|
||||||
internals_ptr->tstate = PyThread_create_key();
|
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
|
||||||
if (internals_ptr->tstate == -1)
|
pybind11_fail("get_internals: could not successfully initialize the "
|
||||||
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
|
"loader_life_support TSS key!");
|
||||||
PyThread_set_key_value(internals_ptr->tstate, tstate);
|
}
|
||||||
#endif
|
# endif
|
||||||
internals_ptr->istate = tstate->interp;
|
internals_ptr->istate = tstate->interp;
|
||||||
#endif
|
#endif
|
||||||
builtins[id] = capsule(internals_pp);
|
builtins[id] = capsule(internals_pp);
|
||||||
@ -311,9 +466,53 @@ PYBIND11_NOINLINE inline internals &get_internals() {
|
|||||||
return **internals_pp;
|
return **internals_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Works like `internals.registered_types_cpp`, but for module-local registered types:
|
// the internals struct (above) is shared between all the modules. local_internals are only
|
||||||
inline type_map<type_info *> ®istered_local_types_cpp() {
|
// for a single module. Any changes made to internals may require an update to
|
||||||
static type_map<type_info *> locals{};
|
// PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
|
||||||
|
// restricted to a single module. Whether a module has local internals or not should not
|
||||||
|
// impact any other modules, because the only things accessing the local internals is the
|
||||||
|
// module that contains them.
|
||||||
|
struct local_internals {
|
||||||
|
type_map<type_info *> registered_types_cpp;
|
||||||
|
std::forward_list<ExceptionTranslator> registered_exception_translators;
|
||||||
|
#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
||||||
|
|
||||||
|
// For ABI compatibility, we can't store the loader_life_support TLS key in
|
||||||
|
// the `internals` struct directly. Instead, we store it in `shared_data` and
|
||||||
|
// cache a copy in `local_internals`. If we allocated a separate TLS key for
|
||||||
|
// each instance of `local_internals`, we could end up allocating hundreds of
|
||||||
|
// TLS keys if hundreds of different pybind11 modules are loaded (which is a
|
||||||
|
// plausible number).
|
||||||
|
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
||||||
|
|
||||||
|
// Holds the shared TLS key for the loader_life_support stack.
|
||||||
|
struct shared_loader_life_support_data {
|
||||||
|
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
||||||
|
shared_loader_life_support_data() {
|
||||||
|
if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
|
||||||
|
pybind11_fail("local_internals: could not successfully initialize the "
|
||||||
|
"loader_life_support TLS key!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We can't help but leak the TLS key, because Python never unloads extension modules.
|
||||||
|
};
|
||||||
|
|
||||||
|
local_internals() {
|
||||||
|
auto &internals = get_internals();
|
||||||
|
// Get or create the `loader_life_support_stack_key`.
|
||||||
|
auto &ptr = internals.shared_data["_life_support"];
|
||||||
|
if (!ptr) {
|
||||||
|
ptr = new shared_loader_life_support_data;
|
||||||
|
}
|
||||||
|
loader_life_support_tls_key
|
||||||
|
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
|
||||||
|
}
|
||||||
|
#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Works like `get_internals`, but for things which are locally registered.
|
||||||
|
inline local_internals &get_local_internals() {
|
||||||
|
static local_internals locals;
|
||||||
return locals;
|
return locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,14 +532,14 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
/// Returns a named pointer that is shared among all extension modules (using the same
|
/// Returns a named pointer that is shared among all extension modules (using the same
|
||||||
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
||||||
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
||||||
inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
||||||
auto &internals = detail::get_internals();
|
auto &internals = detail::get_internals();
|
||||||
auto it = internals.shared_data.find(name);
|
auto it = internals.shared_data.find(name);
|
||||||
return it != internals.shared_data.end() ? it->second : nullptr;
|
return it != internals.shared_data.end() ? it->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
||||||
inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
||||||
detail::get_internals().shared_data[name] = data;
|
detail::get_internals().shared_data[name] = data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -348,7 +547,7 @@ inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *da
|
|||||||
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
||||||
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
|
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
|
||||||
/// added to the shared data under the given name and a reference to it is returned.
|
/// added to the shared data under the given name and a reference to it is returned.
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T &get_or_create_shared_data(const std::string &name) {
|
T &get_or_create_shared_data(const std::string &name) {
|
||||||
auto &internals = detail::get_internals();
|
auto &internals = detail::get_internals();
|
||||||
auto it = internals.shared_data.find(name);
|
auto it = internals.shared_data.find(name);
|
||||||
|
1010
3rdparty/pybind11/include/pybind11/detail/type_caster_base.h
vendored
Normal file
1010
3rdparty/pybind11/include/pybind11/detail/type_caster_base.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,29 +13,33 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#if defined(__GNUG__)
|
#if defined(__GNUG__)
|
||||||
#include <cxxabi.h>
|
# include <cxxabi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
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;;) {
|
||||||
pos = string.find(search, pos);
|
pos = string.find(search, pos);
|
||||||
if (pos == std::string::npos) break;
|
if (pos == std::string::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
string.erase(pos, search.length());
|
string.erase(pos, search.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
|
PYBIND11_NOINLINE void clean_type_id(std::string &name) {
|
||||||
#if defined(__GNUG__)
|
#if defined(__GNUG__)
|
||||||
int status = 0;
|
int status = 0;
|
||||||
std::unique_ptr<char, void (*)(void *)> res {
|
std::unique_ptr<char, void (*)(void *)> res{
|
||||||
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
|
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
|
||||||
if (status == 0)
|
if (status == 0) {
|
||||||
name = res.get();
|
name = res.get();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
detail::erase_all(name, "class ");
|
detail::erase_all(name, "class ");
|
||||||
detail::erase_all(name, "struct ");
|
detail::erase_all(name, "struct ");
|
||||||
@ -43,13 +47,19 @@ PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
|
|||||||
#endif
|
#endif
|
||||||
detail::erase_all(name, "pybind11::");
|
detail::erase_all(name, "pybind11::");
|
||||||
}
|
}
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
/// Return a string representation of a C++ type
|
inline std::string clean_type_id(const char *typeid_name) {
|
||||||
template <typename T> static std::string type_id() {
|
std::string name(typeid_name);
|
||||||
std::string name(typeid(T).name());
|
|
||||||
detail::clean_type_id(name);
|
detail::clean_type_id(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
/// Return a string representation of a C++ type
|
||||||
|
template <typename T>
|
||||||
|
static std::string type_id() {
|
||||||
|
return detail::clean_type_id(typeid(T).name());
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
524
3rdparty/pybind11/include/pybind11/eigen.h
vendored
524
3rdparty/pybind11/include/pybind11/eigen.h
vendored
@ -9,218 +9,266 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
|
||||||
|
See also:
|
||||||
|
https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
|
||||||
|
https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
|
||||||
|
*/
|
||||||
|
|
||||||
#include "numpy.h"
|
#include "numpy.h"
|
||||||
|
|
||||||
#if defined(__INTEL_COMPILER)
|
// The C4127 suppression was introduced for Eigen 3.4.0. In theory we could
|
||||||
# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
|
// make it version specific, or even remove it later, but considering that
|
||||||
#elif defined(__GNUG__) || defined(__clang__)
|
// 1. C4127 is generally far more distracting than useful for modern template code, and
|
||||||
# pragma GCC diagnostic push
|
// 2. we definitely want to ignore any MSVC warnings originating from Eigen code,
|
||||||
# pragma GCC diagnostic ignored "-Wconversion"
|
// it is probably best to keep this around indefinitely.
|
||||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
# ifdef __clang__
|
|
||||||
// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated
|
|
||||||
// under Clang, so disable that warning here:
|
|
||||||
# pragma GCC diagnostic ignored "-Wdeprecated"
|
|
||||||
# endif
|
|
||||||
# if __GNUC__ >= 7
|
|
||||||
# pragma GCC diagnostic ignored "-Wint-in-bool-context"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
# pragma warning(disable : 4127) // C4127: conditional expression is constant
|
||||||
# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
|
# pragma warning(disable : 5054) // https://github.com/pybind/pybind11/pull/3741
|
||||||
|
// C5054: operator '&': deprecated between enumerations of different types
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/SparseCore>
|
#include <Eigen/SparseCore>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
|
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
|
||||||
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
|
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
|
||||||
// of matrices seems highly undesirable.
|
// of matrices seems highly undesirable.
|
||||||
static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7");
|
static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
|
||||||
|
"Eigen support in pybind11 requires Eigen >= 3.2.7");
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
|
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
|
||||||
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
|
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
|
||||||
template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
|
template <typename MatrixType>
|
||||||
template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
|
using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
|
||||||
|
template <typename MatrixType>
|
||||||
|
using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
#if EIGEN_VERSION_AT_LEAST(3,3,0)
|
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
|
||||||
using EigenIndex = Eigen::Index;
|
using EigenIndex = Eigen::Index;
|
||||||
|
template <typename Scalar, int Flags, typename StorageIndex>
|
||||||
|
using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
|
||||||
#else
|
#else
|
||||||
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
|
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
|
||||||
|
template <typename Scalar, int Flags, typename StorageIndex>
|
||||||
|
using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
|
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
|
||||||
template <typename T> using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
|
template <typename T>
|
||||||
template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
|
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
|
||||||
template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
|
std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
|
||||||
template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
|
template <typename T>
|
||||||
|
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
|
||||||
|
template <typename T>
|
||||||
|
using is_eigen_dense_plain
|
||||||
|
= all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
|
||||||
|
template <typename T>
|
||||||
|
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
|
||||||
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
|
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
|
||||||
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
|
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
|
||||||
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
|
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
|
||||||
// SelfAdjointView fall into this category.
|
// SelfAdjointView fall into this category.
|
||||||
template <typename T> using is_eigen_other = all_of<
|
template <typename T>
|
||||||
is_template_base_of<Eigen::EigenBase, T>,
|
using is_eigen_other
|
||||||
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>
|
= all_of<is_template_base_of<Eigen::EigenBase, T>,
|
||||||
>;
|
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
|
||||||
|
|
||||||
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
|
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
|
||||||
template <bool EigenRowMajor> struct EigenConformable {
|
template <bool EigenRowMajor>
|
||||||
|
struct EigenConformable {
|
||||||
bool conformable = false;
|
bool conformable = false;
|
||||||
EigenIndex rows = 0, cols = 0;
|
EigenIndex rows = 0, cols = 0;
|
||||||
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
|
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
|
||||||
bool negativestrides = false; // If true, do not use stride!
|
bool negativestrides = false; // If true, do not use stride!
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
EigenConformable(bool fits = false) : conformable{fits} {}
|
EigenConformable(bool fits = false) : conformable{fits} {}
|
||||||
// Matrix type:
|
// Matrix type:
|
||||||
EigenConformable(EigenIndex r, EigenIndex c,
|
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
|
||||||
EigenIndex rstride, EigenIndex cstride) :
|
: conformable{true}, rows{r}, cols{c},
|
||||||
conformable{true}, rows{r}, cols{c} {
|
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
|
||||||
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
|
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
|
||||||
if (rstride < 0 || cstride < 0) {
|
stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
|
||||||
negativestrides = true;
|
: (cstride > 0 ? cstride : 0) /* outer stride */,
|
||||||
} else {
|
EigenRowMajor ? (cstride > 0 ? cstride : 0)
|
||||||
stride = {EigenRowMajor ? rstride : cstride /* outer stride */,
|
: (rstride > 0 ? rstride : 0) /* inner stride */},
|
||||||
EigenRowMajor ? cstride : rstride /* inner stride */ };
|
negativestrides{rstride < 0 || cstride < 0} {}
|
||||||
}
|
|
||||||
}
|
|
||||||
// Vector type:
|
// Vector type:
|
||||||
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
|
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
|
||||||
: EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
|
: EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
|
||||||
|
|
||||||
template <typename props> bool stride_compatible() const {
|
template <typename props>
|
||||||
|
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 irrelevant)
|
// matching strides, or a dimension size of 1 (in which case the stride value is
|
||||||
return
|
// irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
|
||||||
!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;
|
||||||
(props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
|
|
||||||
(EigenRowMajor ? rows : cols) == 1);
|
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
|
|| (EigenRowMajor ? rows : cols) == 1);
|
||||||
|
}
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
operator bool() const { return conformable; }
|
operator bool() const { return conformable; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type> struct eigen_extract_stride { using type = Type; };
|
template <typename Type>
|
||||||
|
struct eigen_extract_stride {
|
||||||
|
using type = Type;
|
||||||
|
};
|
||||||
template <typename PlainObjectType, int MapOptions, typename StrideType>
|
template <typename PlainObjectType, int MapOptions, typename StrideType>
|
||||||
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; };
|
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
|
||||||
|
using type = StrideType;
|
||||||
|
};
|
||||||
template <typename PlainObjectType, int Options, typename StrideType>
|
template <typename PlainObjectType, int Options, typename StrideType>
|
||||||
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
|
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
|
||||||
|
using type = StrideType;
|
||||||
|
};
|
||||||
|
|
||||||
// Helper struct for extracting information from an Eigen type
|
// Helper struct for extracting information from an Eigen type
|
||||||
template <typename Type_> struct EigenProps {
|
template <typename Type_>
|
||||||
|
struct EigenProps {
|
||||||
using Type = Type_;
|
using Type = Type_;
|
||||||
using Scalar = typename Type::Scalar;
|
using Scalar = typename Type::Scalar;
|
||||||
using StrideType = typename eigen_extract_stride<Type>::type;
|
using StrideType = typename eigen_extract_stride<Type>::type;
|
||||||
static constexpr EigenIndex
|
static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
|
||||||
rows = Type::RowsAtCompileTime,
|
|
||||||
cols = Type::ColsAtCompileTime,
|
|
||||||
size = Type::SizeAtCompileTime;
|
size = Type::SizeAtCompileTime;
|
||||||
static constexpr bool
|
static constexpr bool row_major = Type::IsRowMajor,
|
||||||
row_major = Type::IsRowMajor,
|
vector
|
||||||
vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
|
= Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
|
||||||
fixed_rows = rows != Eigen::Dynamic,
|
fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
|
||||||
fixed_cols = cols != Eigen::Dynamic,
|
|
||||||
fixed = size != Eigen::Dynamic, // Fully-fixed size
|
fixed = size != Eigen::Dynamic, // Fully-fixed size
|
||||||
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
|
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
|
||||||
|
|
||||||
template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
|
template <EigenIndex i, EigenIndex ifzero>
|
||||||
static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
|
using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
|
||||||
outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
|
static constexpr EigenIndex inner_stride
|
||||||
vector ? size : row_major ? cols : rows>::value;
|
= if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
|
||||||
static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
|
outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
|
||||||
static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
|
vector ? size
|
||||||
static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
|
: row_major ? cols
|
||||||
|
: rows > ::value;
|
||||||
|
static constexpr bool dynamic_stride
|
||||||
|
= inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
|
||||||
|
static constexpr bool requires_row_major
|
||||||
|
= !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
|
||||||
|
static constexpr bool requires_col_major
|
||||||
|
= !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
|
||||||
|
|
||||||
// Takes an input array and determines whether we can make it fit into the Eigen type. If
|
// Takes an input array and determines whether we can make it fit into the Eigen type. If
|
||||||
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
|
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
|
||||||
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
|
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
|
||||||
static EigenConformable<row_major> conformable(const array &a) {
|
static EigenConformable<row_major> conformable(const array &a) {
|
||||||
const auto dims = a.ndim();
|
const auto dims = a.ndim();
|
||||||
if (dims < 1 || dims > 2)
|
if (dims < 1 || dims > 2) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (dims == 2) { // Matrix type: require exact match (or dynamic)
|
if (dims == 2) { // Matrix type: require exact match (or dynamic)
|
||||||
|
|
||||||
EigenIndex
|
EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
|
||||||
np_rows = a.shape(0),
|
|
||||||
np_cols = a.shape(1),
|
|
||||||
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
|
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
|
||||||
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
|
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
|
||||||
if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols))
|
if ((PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && np_rows != rows)
|
||||||
|
|| (PYBIND11_SILENCE_MSVC_C4127(fixed_cols) && np_cols != cols)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return {np_rows, np_cols, np_rstride, np_cstride};
|
return {np_rows, np_cols, np_rstride, np_cstride};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever
|
// Otherwise we're storing an n-vector. Only one of the strides will be used, but
|
||||||
// is used, we want the (single) numpy stride value.
|
// whichever is used, we want the (single) numpy stride value.
|
||||||
const EigenIndex n = a.shape(0),
|
const EigenIndex n = a.shape(0),
|
||||||
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
|
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
|
||||||
|
|
||||||
if (vector) { // Eigen type is a compile-time vector
|
if (vector) { // Eigen type is a compile-time vector
|
||||||
if (fixed && size != n)
|
if (PYBIND11_SILENCE_MSVC_C4127(fixed) && size != n) {
|
||||||
return false; // Vector size mismatch
|
return false; // Vector size mismatch
|
||||||
|
}
|
||||||
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
|
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
|
||||||
}
|
}
|
||||||
else if (fixed) {
|
if (fixed) {
|
||||||
// The type has a fixed size, but is not a vector: abort
|
// The type has a fixed size, but is not a vector: abort
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (fixed_cols) {
|
if (fixed_cols) {
|
||||||
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
|
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
|
||||||
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
|
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
|
||||||
if (cols != n) return false;
|
if (cols != n) {
|
||||||
return {1, n, stride};
|
return false;
|
||||||
|
}
|
||||||
|
return {1, n, stride};
|
||||||
|
} // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
|
||||||
|
if (PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && rows != n) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Otherwise it's either fully dynamic, or column dynamic; both become a column vector
|
|
||||||
if (fixed_rows && rows != n) return false;
|
|
||||||
return {n, 1, stride};
|
return {n, 1, stride};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
|
static constexpr bool show_writeable
|
||||||
|
= is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
|
||||||
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
|
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
|
||||||
static constexpr bool show_c_contiguous = show_order && requires_row_major;
|
static constexpr bool show_c_contiguous = show_order && requires_row_major;
|
||||||
static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
|
static constexpr bool show_f_contiguous
|
||||||
|
= !show_c_contiguous && show_order && requires_col_major;
|
||||||
|
|
||||||
static constexpr auto descriptor =
|
static constexpr auto descriptor
|
||||||
_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name +
|
= const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
|
||||||
_("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
|
+ const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
|
||||||
_(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
|
+ const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
|
||||||
_("]") +
|
+
|
||||||
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
|
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
|
||||||
// satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
|
// be satisfied: writeable=True (for a mutable reference), and, depending on the map's
|
||||||
// options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
|
// stride options, possibly f_contiguous or c_contiguous. We include them in the
|
||||||
// to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
|
// descriptor output to provide some hint as to why a TypeError is occurring (otherwise
|
||||||
// see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
|
// it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
|
||||||
// *gave* a numpy.ndarray of the right type and dimensions.
|
// an error message that you *gave* a numpy.ndarray of the right type and dimensions.
|
||||||
_<show_writeable>(", flags.writeable", "") +
|
const_name<show_writeable>(", flags.writeable", "")
|
||||||
_<show_c_contiguous>(", flags.c_contiguous", "") +
|
+ const_name<show_c_contiguous>(", flags.c_contiguous", "")
|
||||||
_<show_f_contiguous>(", flags.f_contiguous", "") +
|
+ const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
|
||||||
_("]");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
||||||
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
||||||
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
template <typename props>
|
||||||
|
handle
|
||||||
|
eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
||||||
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
|
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
|
||||||
array a;
|
array a;
|
||||||
if (props::vector)
|
if (props::vector) {
|
||||||
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
|
a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
|
||||||
else
|
} else {
|
||||||
a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() },
|
a = array({src.rows(), src.cols()},
|
||||||
src.data(), base);
|
{elem_size * src.rowStride(), elem_size * src.colStride()},
|
||||||
|
src.data(),
|
||||||
|
base);
|
||||||
|
}
|
||||||
|
|
||||||
if (!writeable)
|
if (!writeable) {
|
||||||
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
||||||
|
}
|
||||||
|
|
||||||
return a.release();
|
return a.release();
|
||||||
}
|
}
|
||||||
@ -236,10 +284,10 @@ handle eigen_ref_array(Type &src, handle parent = none()) {
|
|||||||
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
|
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy
|
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
|
||||||
// array that references the encapsulated data with a python-side reference to the capsule to tie
|
// numpy array that references the encapsulated data with a python-side reference to the capsule to
|
||||||
// its destruction to that of any dependent python objects. Const-ness is determined by whether or
|
// tie its destruction to that of any dependent python objects. Const-ness is determined by
|
||||||
// not the Type of the pointer given is const.
|
// whether or not the Type of the pointer given is const.
|
||||||
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
|
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
|
||||||
handle eigen_encapsulate(Type *src) {
|
handle eigen_encapsulate(Type *src) {
|
||||||
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
|
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
|
||||||
@ -248,35 +296,42 @@ handle eigen_encapsulate(Type *src) {
|
|||||||
|
|
||||||
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
|
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
|
||||||
// types.
|
// types.
|
||||||
template<typename Type>
|
template <typename Type>
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
||||||
using Scalar = typename Type::Scalar;
|
using Scalar = typename Type::Scalar;
|
||||||
using props = EigenProps<Type>;
|
using props = EigenProps<Type>;
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
// If we're in no-convert mode, only load if given an array of the correct type
|
// If we're in no-convert mode, only load if given an array of the correct type
|
||||||
if (!convert && !isinstance<array_t<Scalar>>(src))
|
if (!convert && !isinstance<array_t<Scalar>>(src)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
|
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
|
||||||
auto buf = array::ensure(src);
|
auto buf = array::ensure(src);
|
||||||
|
|
||||||
if (!buf)
|
if (!buf) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto dims = buf.ndim();
|
auto dims = buf.ndim();
|
||||||
if (dims < 1 || dims > 2)
|
if (dims < 1 || dims > 2) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto fits = props::conformable(buf);
|
auto fits = props::conformable(buf);
|
||||||
if (!fits)
|
if (!fits) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate the new type, then build a numpy reference into it
|
// Allocate the new type, then build a numpy reference into it
|
||||||
value = Type(fits.rows, fits.cols);
|
value = Type(fits.rows, fits.cols);
|
||||||
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
|
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
|
||||||
if (dims == 1) ref = ref.squeeze();
|
if (dims == 1) {
|
||||||
else if (ref.ndim() == 1) buf = buf.squeeze();
|
ref = ref.squeeze();
|
||||||
|
} else if (ref.ndim() == 1) {
|
||||||
|
buf = buf.squeeze();
|
||||||
|
}
|
||||||
|
|
||||||
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
|
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
|
||||||
|
|
||||||
@ -289,7 +344,6 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Cast implementation
|
// Cast implementation
|
||||||
template <typename CType>
|
template <typename CType>
|
||||||
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
|
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
|
||||||
@ -312,7 +366,6 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Normal returned non-reference, non-const value:
|
// Normal returned non-reference, non-const value:
|
||||||
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
|
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
|
||||||
return cast_impl(&src, return_value_policy::move, parent);
|
return cast_impl(&src, return_value_policy::move, parent);
|
||||||
@ -323,14 +376,18 @@ public:
|
|||||||
}
|
}
|
||||||
// lvalue reference return; default (automatic) becomes copy
|
// lvalue reference return; default (automatic) becomes copy
|
||||||
static handle cast(Type &src, return_value_policy policy, handle parent) {
|
static handle cast(Type &src, return_value_policy policy, handle parent) {
|
||||||
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
if (policy == return_value_policy::automatic
|
||||||
|
|| policy == return_value_policy::automatic_reference) {
|
||||||
policy = return_value_policy::copy;
|
policy = return_value_policy::copy;
|
||||||
|
}
|
||||||
return cast_impl(&src, policy, parent);
|
return cast_impl(&src, policy, parent);
|
||||||
}
|
}
|
||||||
// const lvalue reference return; default (automatic) becomes copy
|
// const lvalue reference return; default (automatic) becomes copy
|
||||||
static handle cast(const Type &src, return_value_policy policy, handle parent) {
|
static handle cast(const Type &src, return_value_policy policy, handle parent) {
|
||||||
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
if (policy == return_value_policy::automatic
|
||||||
|
|| policy == return_value_policy::automatic_reference) {
|
||||||
policy = return_value_policy::copy;
|
policy = return_value_policy::copy;
|
||||||
|
}
|
||||||
return cast(&src, policy, parent);
|
return cast(&src, policy, parent);
|
||||||
}
|
}
|
||||||
// non-const pointer return
|
// non-const pointer return
|
||||||
@ -344,28 +401,32 @@ public:
|
|||||||
|
|
||||||
static constexpr auto name = props::descriptor;
|
static constexpr auto name = props::descriptor;
|
||||||
|
|
||||||
operator Type*() { return &value; }
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
operator Type&() { return value; }
|
operator Type *() { return &value; }
|
||||||
operator Type&&() && { return std::move(value); }
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
template <typename T> using cast_op_type = movable_cast_op_type<T>;
|
operator Type &() { return value; }
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
operator Type &&() && { return std::move(value); }
|
||||||
|
template <typename T>
|
||||||
|
using cast_op_type = movable_cast_op_type<T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type value;
|
Type value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Base class for casting reference/map/block/etc. objects back to python.
|
// Base class for casting reference/map/block/etc. objects back to python.
|
||||||
template <typename MapType> struct eigen_map_caster {
|
template <typename MapType>
|
||||||
|
struct eigen_map_caster {
|
||||||
private:
|
private:
|
||||||
using props = EigenProps<MapType>;
|
using props = EigenProps<MapType>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
|
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
|
||||||
// to stay around), but we'll allow it under the assumption that you know what you're doing (and
|
// to stay around), but we'll allow it under the assumption that you know what you're doing
|
||||||
// have an appropriate keep_alive in place). We return a numpy array pointing directly at the
|
// (and have an appropriate keep_alive in place). We return a numpy array pointing directly at
|
||||||
// ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note
|
// the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
|
||||||
// that this means you need to ensure you don't destroy the object in some other way (e.g. with
|
// Note that this means you need to ensure you don't destroy the object in some other way (e.g.
|
||||||
// an appropriate keep_alive, or with a reference to a statically allocated matrix).
|
// with an appropriate keep_alive, or with a reference to a statically allocated matrix).
|
||||||
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
|
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
|
||||||
switch (policy) {
|
switch (policy) {
|
||||||
case return_value_policy::copy:
|
case return_value_policy::copy:
|
||||||
@ -389,43 +450,50 @@ public:
|
|||||||
// you end up here if you try anyway.
|
// you end up here if you try anyway.
|
||||||
bool load(handle, bool) = delete;
|
bool load(handle, bool) = delete;
|
||||||
operator MapType() = delete;
|
operator MapType() = delete;
|
||||||
template <typename> using cast_op_type = MapType;
|
template <typename>
|
||||||
|
using cast_op_type = MapType;
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can return any map-like object (but can only load Refs, specialized next):
|
// We can return any map-like object (but can only load Refs, specialized next):
|
||||||
template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
|
template <typename Type>
|
||||||
: eigen_map_caster<Type> {};
|
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
|
||||||
|
|
||||||
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
|
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
|
||||||
// copying (it requires some extra effort in many cases).
|
// copying (it requires some extra effort in many cases).
|
||||||
template <typename PlainObjectType, typename StrideType>
|
template <typename PlainObjectType, typename StrideType>
|
||||||
struct type_caster<
|
struct type_caster<
|
||||||
Eigen::Ref<PlainObjectType, 0, StrideType>,
|
Eigen::Ref<PlainObjectType, 0, StrideType>,
|
||||||
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
|
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
|
||||||
> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
|
: public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
|
||||||
private:
|
private:
|
||||||
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
|
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
|
||||||
using props = EigenProps<Type>;
|
using props = EigenProps<Type>;
|
||||||
using Scalar = typename props::Scalar;
|
using Scalar = typename props::Scalar;
|
||||||
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
|
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
|
||||||
using Array = array_t<Scalar, array::forcecast |
|
using Array
|
||||||
((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
|
= array_t<Scalar,
|
||||||
(props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
|
array::forcecast
|
||||||
|
| ((props::row_major ? props::inner_stride : props::outer_stride) == 1
|
||||||
|
? array::c_style
|
||||||
|
: (props::row_major ? props::outer_stride : props::inner_stride) == 1
|
||||||
|
? array::f_style
|
||||||
|
: 0)>;
|
||||||
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
|
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
|
||||||
// Delay construction (these have no default constructor)
|
// Delay construction (these have no default constructor)
|
||||||
std::unique_ptr<MapType> map;
|
std::unique_ptr<MapType> map;
|
||||||
std::unique_ptr<Type> ref;
|
std::unique_ptr<Type> ref;
|
||||||
// Our array. When possible, this is just a numpy array pointing to the source data, but
|
// Our array. When possible, this is just a numpy array pointing to the source data, but
|
||||||
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible
|
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
|
||||||
// layout, or is an array of a type that needs to be converted). Using a numpy temporary
|
// incompatible layout, or is an array of a type that needs to be converted). Using a numpy
|
||||||
// (rather than an Eigen temporary) saves an extra copy when we need both type conversion and
|
// temporary (rather than an Eigen temporary) saves an extra copy when we need both type
|
||||||
// storage order conversion. (Note that we refuse to use this temporary copy when loading an
|
// conversion and storage order conversion. (Note that we refuse to use this temporary copy
|
||||||
// argument for a Ref<M> with M non-const, i.e. a read-write reference).
|
// when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
|
||||||
Array copy_or_ref;
|
Array copy_or_ref;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
// First check whether what we have is already an array of the right type. If not, we can't
|
// First check whether what we have is already an array of the right type. If not, we
|
||||||
// avoid a copy (because the copy is also going to do type conversion).
|
// can't avoid a copy (because the copy is also going to do type conversion).
|
||||||
bool need_copy = !isinstance<Array>(src);
|
bool need_copy = !isinstance<Array>(src);
|
||||||
|
|
||||||
EigenConformable<props::row_major> fits;
|
EigenConformable<props::row_major> fits;
|
||||||
@ -436,13 +504,15 @@ public:
|
|||||||
|
|
||||||
if (aref && (!need_writeable || aref.writeable())) {
|
if (aref && (!need_writeable || aref.writeable())) {
|
||||||
fits = props::conformable(aref);
|
fits = props::conformable(aref);
|
||||||
if (!fits) return false; // Incompatible dimensions
|
if (!fits) {
|
||||||
if (!fits.template stride_compatible<props>())
|
return false; // Incompatible dimensions
|
||||||
|
}
|
||||||
|
if (!fits.template stride_compatible<props>()) {
|
||||||
need_copy = true;
|
need_copy = true;
|
||||||
else
|
} else {
|
||||||
copy_or_ref = std::move(aref);
|
copy_or_ref = std::move(aref);
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
need_copy = true;
|
need_copy = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,64 +521,93 @@ public:
|
|||||||
// We need to copy: If we need a mutable reference, or we're not supposed to convert
|
// We need to copy: If we need a mutable reference, or we're not supposed to convert
|
||||||
// (either because we're in the no-convert overload pass, or because we're explicitly
|
// (either because we're in the no-convert overload pass, or because we're explicitly
|
||||||
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
|
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
|
||||||
if (!convert || need_writeable) return false;
|
if (!convert || need_writeable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Array copy = Array::ensure(src);
|
Array copy = Array::ensure(src);
|
||||||
if (!copy) return false;
|
if (!copy) {
|
||||||
fits = props::conformable(copy);
|
|
||||||
if (!fits || !fits.template stride_compatible<props>())
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
fits = props::conformable(copy);
|
||||||
|
if (!fits || !fits.template stride_compatible<props>()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
copy_or_ref = std::move(copy);
|
copy_or_ref = std::move(copy);
|
||||||
loader_life_support::add_patient(copy_or_ref);
|
loader_life_support::add_patient(copy_or_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref.reset();
|
ref.reset();
|
||||||
map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
|
map.reset(new MapType(data(copy_or_ref),
|
||||||
|
fits.rows,
|
||||||
|
fits.cols,
|
||||||
|
make_stride(fits.stride.outer(), fits.stride.inner())));
|
||||||
ref.reset(new Type(*map));
|
ref.reset(new Type(*map));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator Type*() { return ref.get(); }
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
operator Type&() { return *ref; }
|
operator Type *() { return ref.get(); }
|
||||||
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
|
operator Type &() { return *ref; }
|
||||||
|
template <typename _T>
|
||||||
|
using cast_op_type = pybind11::detail::cast_op_type<_T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
|
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
|
||||||
Scalar *data(Array &a) { return a.mutable_data(); }
|
Scalar *data(Array &a) {
|
||||||
|
return a.mutable_data();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
|
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
|
||||||
const Scalar *data(Array &a) { return a.data(); }
|
const Scalar *data(Array &a) {
|
||||||
|
return a.data();
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to figure out a constructor of `Stride` that will work.
|
// Attempt to figure out a constructor of `Stride` that will work.
|
||||||
// If both strides are fixed, use a default constructor:
|
// If both strides are fixed, use a default constructor:
|
||||||
template <typename S> using stride_ctor_default = bool_constant<
|
template <typename S>
|
||||||
S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
|
using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
|
||||||
std::is_default_constructible<S>::value>;
|
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
|
||||||
|
&& std::is_default_constructible<S>::value>;
|
||||||
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
|
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
|
||||||
// Eigen::Stride, and use it:
|
// Eigen::Stride, and use it:
|
||||||
template <typename S> using stride_ctor_dual = bool_constant<
|
template <typename S>
|
||||||
!stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
|
using stride_ctor_dual
|
||||||
|
= bool_constant<!stride_ctor_default<S>::value
|
||||||
|
&& std::is_constructible<S, EigenIndex, EigenIndex>::value>;
|
||||||
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
|
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
|
||||||
// it (passing whichever stride is dynamic).
|
// it (passing whichever stride is dynamic).
|
||||||
template <typename S> using stride_ctor_outer = bool_constant<
|
template <typename S>
|
||||||
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
|
using stride_ctor_outer
|
||||||
S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
|
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
|
||||||
std::is_constructible<S, EigenIndex>::value>;
|
&& S::OuterStrideAtCompileTime == Eigen::Dynamic
|
||||||
template <typename S> using stride_ctor_inner = bool_constant<
|
&& S::InnerStrideAtCompileTime != Eigen::Dynamic
|
||||||
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
|
&& std::is_constructible<S, EigenIndex>::value>;
|
||||||
S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
|
template <typename S>
|
||||||
std::is_constructible<S, EigenIndex>::value>;
|
using stride_ctor_inner
|
||||||
|
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
|
||||||
|
&& S::InnerStrideAtCompileTime == Eigen::Dynamic
|
||||||
|
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
|
||||||
|
&& std::is_constructible<S, EigenIndex>::value>;
|
||||||
|
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
|
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
|
||||||
static S make_stride(EigenIndex, EigenIndex) { return S(); }
|
static S make_stride(EigenIndex, EigenIndex) {
|
||||||
|
return S();
|
||||||
|
}
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
|
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
|
||||||
static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); }
|
static S make_stride(EigenIndex outer, EigenIndex inner) {
|
||||||
|
return S(outer, inner);
|
||||||
|
}
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
|
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
|
||||||
static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); }
|
static S make_stride(EigenIndex outer, EigenIndex) {
|
||||||
|
return S(outer);
|
||||||
|
}
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
|
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
|
||||||
static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); }
|
static S make_stride(EigenIndex, EigenIndex inner) {
|
||||||
|
return S(inner);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
|
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
|
||||||
@ -518,14 +617,18 @@ private:
|
|||||||
template <typename Type>
|
template <typename Type>
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
|
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
|
||||||
protected:
|
protected:
|
||||||
using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
|
using Matrix
|
||||||
|
= Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
|
||||||
using props = EigenProps<Matrix>;
|
using props = EigenProps<Matrix>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
handle h = eigen_encapsulate<props>(new Matrix(src));
|
handle h = eigen_encapsulate<props>(new Matrix(src));
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
|
static handle cast(const Type *src, return_value_policy policy, handle parent) {
|
||||||
|
return cast(*src, policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr auto name = props::descriptor;
|
static constexpr auto name = props::descriptor;
|
||||||
|
|
||||||
@ -534,10 +637,11 @@ public:
|
|||||||
// you end up here if you try anyway.
|
// you end up here if you try anyway.
|
||||||
bool load(handle, bool) = delete;
|
bool load(handle, bool) = delete;
|
||||||
operator Type() = delete;
|
operator Type() = delete;
|
||||||
template <typename> using cast_op_type = Type;
|
template <typename>
|
||||||
|
using cast_op_type = Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template <typename Type>
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
||||||
using Scalar = typename Type::Scalar;
|
using Scalar = typename Type::Scalar;
|
||||||
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
|
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
|
||||||
@ -545,13 +649,13 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
static constexpr bool rowMajor = Type::IsRowMajor;
|
static constexpr bool rowMajor = Type::IsRowMajor;
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool) {
|
||||||
if (!src)
|
if (!src) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto obj = reinterpret_borrow<object>(src);
|
auto obj = reinterpret_borrow<object>(src);
|
||||||
object sparse_module = module_::import("scipy.sparse");
|
object sparse_module = module_::import("scipy.sparse");
|
||||||
object matrix_type = sparse_module.attr(
|
object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
rowMajor ? "csr_matrix" : "csc_matrix");
|
|
||||||
|
|
||||||
if (!type::handle_of(obj).is(matrix_type)) {
|
if (!type::handle_of(obj).is(matrix_type)) {
|
||||||
try {
|
try {
|
||||||
@ -567,41 +671,43 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
|
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
|
||||||
auto nnz = obj.attr("nnz").cast<Index>();
|
auto nnz = obj.attr("nnz").cast<Index>();
|
||||||
|
|
||||||
if (!values || !innerIndices || !outerIndices)
|
if (!values || !innerIndices || !outerIndices) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
|
value = EigenMapSparseMatrix<Scalar,
|
||||||
shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
|
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
|
||||||
outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
|
StorageIndex>(shape[0].cast<Index>(),
|
||||||
|
shape[1].cast<Index>(),
|
||||||
|
std::move(nnz),
|
||||||
|
outerIndices.mutable_data(),
|
||||||
|
innerIndices.mutable_data(),
|
||||||
|
values.mutable_data());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
const_cast<Type&>(src).makeCompressed();
|
const_cast<Type &>(src).makeCompressed();
|
||||||
|
|
||||||
object matrix_type = module_::import("scipy.sparse").attr(
|
object matrix_type
|
||||||
rowMajor ? "csr_matrix" : "csc_matrix");
|
= module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
|
|
||||||
array data(src.nonZeros(), src.valuePtr());
|
array data(src.nonZeros(), src.valuePtr());
|
||||||
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(
|
return matrix_type(pybind11::make_tuple(
|
||||||
std::make_tuple(data, innerIndices, outerIndices),
|
std::move(data), std::move(innerIndices), std::move(outerIndices)),
|
||||||
std::make_pair(src.rows(), src.cols())
|
pybind11::make_tuple(src.rows(), src.cols()))
|
||||||
).release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
|
PYBIND11_TYPE_CASTER(Type,
|
||||||
+ npy_format_descriptor<Scalar>::name + _("]"));
|
const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
|
||||||
|
"scipy.sparse.csc_matrix[")
|
||||||
|
+ npy_format_descriptor<Scalar>::name + const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
#if defined(__GNUG__) || defined(__clang__)
|
|
||||||
# pragma GCC diagnostic pop
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
# pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
158
3rdparty/pybind11/include/pybind11/embed.h
vendored
158
3rdparty/pybind11/include/pybind11/embed.h
vendored
@ -12,23 +12,16 @@
|
|||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
# 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() { \
|
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##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
|
||||||
@ -46,68 +39,142 @@
|
|||||||
}
|
}
|
||||||
\endrst */
|
\endrst */
|
||||||
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
||||||
static ::pybind11::module_::module_def \
|
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
|
||||||
PYBIND11_CONCAT(pybind11_module_def_, name); \
|
|
||||||
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
|
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
|
||||||
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
||||||
auto m = ::pybind11::module_::create_extension_module( \
|
auto m = ::pybind11::module_::create_extension_module( \
|
||||||
PYBIND11_TOSTRING(name), nullptr, \
|
PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
||||||
&PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
|
||||||
try { \
|
try { \
|
||||||
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||||
return m.ptr(); \
|
return m.ptr(); \
|
||||||
} PYBIND11_CATCH_INIT_EXCEPTIONS \
|
} \
|
||||||
|
PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
} \
|
} \
|
||||||
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||||
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \
|
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \
|
||||||
(PYBIND11_TOSTRING(name), \
|
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
||||||
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \
|
||||||
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &variable)
|
& variable) // NOLINT(bugprone-macro-parentheses)
|
||||||
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
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())
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
auto result = PyImport_AppendInittab(name, init);
|
auto result = PyImport_AppendInittab(name, init);
|
||||||
if (result == -1)
|
if (result == -1) {
|
||||||
pybind11_fail("Insufficient memory to add a new module");
|
pybind11_fail("Insufficient memory to add a new module");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wide_char_arg_deleter {
|
||||||
|
void operator()(wchar_t *ptr) const {
|
||||||
|
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
||||||
|
PyMem_RawFree(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline wchar_t *widen_chars(const char *safe_arg) {
|
||||||
|
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
||||||
|
return widened_arg;
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
||||||
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
||||||
optional parameter can be used to skip the registration of signal handlers (see the
|
optional `init_signal_handlers` parameter can be used to skip the registration of
|
||||||
`Python documentation`_ for details). Calling this function again after the interpreter
|
signal handlers (see the `Python documentation`_ for details). Calling this function
|
||||||
has already been initialized is a fatal error.
|
again after the interpreter has already been initialized is a fatal error.
|
||||||
|
|
||||||
If initializing the Python interpreter fails, then the program is terminated. (This
|
If initializing the Python interpreter fails, then the program is terminated. (This
|
||||||
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
||||||
of throwing exceptions on errors.)
|
of throwing exceptions on errors.)
|
||||||
|
|
||||||
|
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
|
||||||
|
used to populate ``sys.argv`` and ``sys.path``.
|
||||||
|
See the |PySys_SetArgvEx documentation|_ for details.
|
||||||
|
|
||||||
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
||||||
|
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
|
||||||
|
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
|
||||||
\endrst */
|
\endrst */
|
||||||
inline void initialize_interpreter(bool init_signal_handlers = true) {
|
inline void initialize_interpreter(bool init_signal_handlers = true,
|
||||||
if (Py_IsInitialized())
|
int argc = 0,
|
||||||
|
const char *const *argv = nullptr,
|
||||||
|
bool add_program_dir_to_path = true) {
|
||||||
|
if (Py_IsInitialized() != 0) {
|
||||||
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);
|
||||||
|
|
||||||
// Make .py files in the working directory available by default
|
// Before it was special-cased in python 3.8, passing an empty or null argv
|
||||||
module_::import("sys").attr("path").cast<list>().append(".");
|
// 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.isolated = 0;
|
||||||
|
config.use_environment = 1;
|
||||||
|
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
|
||||||
@ -154,8 +221,13 @@ inline void finalize_interpreter() {
|
|||||||
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
||||||
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
||||||
// It could also be stashed in builtins, so look there too:
|
// It could also be stashed in builtins, so look there too:
|
||||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
|
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
||||||
internals_ptr_ptr = capsule(builtins[id]);
|
internals_ptr_ptr = capsule(builtins[id]);
|
||||||
|
}
|
||||||
|
// Local internals contains data managed by the current interpreter, so we must clear them to
|
||||||
|
// avoid undefined behaviors when initializing another interpreter
|
||||||
|
detail::get_local_internals().registered_types_cpp.clear();
|
||||||
|
detail::get_local_internals().registered_exception_translators.clear();
|
||||||
|
|
||||||
Py_Finalize();
|
Py_Finalize();
|
||||||
|
|
||||||
@ -169,6 +241,8 @@ inline void finalize_interpreter() {
|
|||||||
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
||||||
This a move-only guard and only a single instance can exist.
|
This a move-only guard and only a single instance can exist.
|
||||||
|
|
||||||
|
See `initialize_interpreter` for a discussion of its constructor arguments.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
#include <pybind11/embed.h>
|
#include <pybind11/embed.h>
|
||||||
@ -180,8 +254,11 @@ inline void finalize_interpreter() {
|
|||||||
\endrst */
|
\endrst */
|
||||||
class scoped_interpreter {
|
class scoped_interpreter {
|
||||||
public:
|
public:
|
||||||
scoped_interpreter(bool init_signal_handlers = true) {
|
explicit scoped_interpreter(bool init_signal_handlers = true,
|
||||||
initialize_interpreter(init_signal_handlers);
|
int argc = 0,
|
||||||
|
const char *const *argv = nullptr,
|
||||||
|
bool add_program_dir_to_path = true) {
|
||||||
|
initialize_interpreter(init_signal_handlers, argc, argv, add_program_dir_to_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_interpreter(const scoped_interpreter &) = delete;
|
scoped_interpreter(const scoped_interpreter &) = delete;
|
||||||
@ -190,9 +267,10 @@ public:
|
|||||||
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
||||||
|
|
||||||
~scoped_interpreter() {
|
~scoped_interpreter() {
|
||||||
if (is_valid)
|
if (is_valid) {
|
||||||
finalize_interpreter();
|
finalize_interpreter();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_valid = true;
|
bool is_valid = true;
|
||||||
|
106
3rdparty/pybind11/include/pybind11/eval.h
vendored
106
3rdparty/pybind11/include/pybind11/eval.h
vendored
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
pybind11/exec.h: Support for evaluating Python expressions and statements
|
pybind11/eval.h: Support for evaluating Python expressions and statements
|
||||||
from strings and files
|
from strings and files
|
||||||
|
|
||||||
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
|
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
|
||||||
@ -13,20 +13,22 @@
|
|||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
inline void ensure_builtins_in_globals(object &global) {
|
inline void ensure_builtins_in_globals(object &global) {
|
||||||
#if 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.
|
// 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
|
||||||
(void) global;
|
(void) global;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
@ -43,9 +45,10 @@ enum eval_mode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <eval_mode mode = eval_expr>
|
template <eval_mode mode = eval_expr>
|
||||||
object eval(str expr, object global = globals(), object local = object()) {
|
object eval(const str &expr, object global = globals(), object local = object()) {
|
||||||
if (!local)
|
if (!local) {
|
||||||
local = global;
|
local = global;
|
||||||
|
}
|
||||||
|
|
||||||
detail::ensure_builtins_in_globals(global);
|
detail::ensure_builtins_in_globals(global);
|
||||||
|
|
||||||
@ -53,38 +56,45 @@ object eval(str expr, object global = globals(), object local = object()) {
|
|||||||
this seems to be the only alternative */
|
this seems to be the only alternative */
|
||||||
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
||||||
|
|
||||||
int start;
|
int start = 0;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case eval_expr: start = Py_eval_input; break;
|
case eval_expr:
|
||||||
case eval_single_statement: start = Py_single_input; break;
|
start = Py_eval_input;
|
||||||
case eval_statements: start = Py_file_input; break;
|
break;
|
||||||
default: pybind11_fail("invalid evaluation mode");
|
case eval_single_statement:
|
||||||
|
start = Py_single_input;
|
||||||
|
break;
|
||||||
|
case eval_statements:
|
||||||
|
start = Py_file_input;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pybind11_fail("invalid evaluation mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
||||||
if (!result)
|
if (!result) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
|
}
|
||||||
return reinterpret_steal<object>(result);
|
return reinterpret_steal<object>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <eval_mode mode = eval_expr, size_t N>
|
template <eval_mode mode = eval_expr, size_t N>
|
||||||
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
||||||
/* Support raw string literals by removing common leading whitespace */
|
/* Support raw string literals by removing common leading whitespace */
|
||||||
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s))
|
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
|
||||||
: str(s);
|
return eval<mode>(expr, std::move(global), std::move(local));
|
||||||
return eval<mode>(expr, global, local);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void exec(str expr, object global = globals(), object local = object()) {
|
inline void exec(const str &expr, object global = globals(), object local = object()) {
|
||||||
eval<eval_statements>(expr, global, local);
|
eval<eval_statements>(expr, std::move(global), std::move(local));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
||||||
eval<eval_statements>(s, global, 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");
|
||||||
@ -100,51 +110,45 @@ object eval_file(str) {
|
|||||||
#else
|
#else
|
||||||
template <eval_mode mode = eval_statements>
|
template <eval_mode mode = eval_statements>
|
||||||
object eval_file(str fname, object global = globals(), object local = object()) {
|
object eval_file(str fname, object global = globals(), object local = object()) {
|
||||||
if (!local)
|
if (!local) {
|
||||||
local = global;
|
local = global;
|
||||||
|
}
|
||||||
|
|
||||||
detail::ensure_builtins_in_globals(global);
|
detail::ensure_builtins_in_globals(global);
|
||||||
|
|
||||||
int start;
|
int start = 0;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case eval_expr: start = Py_eval_input; break;
|
case eval_expr:
|
||||||
case eval_single_statement: start = Py_single_input; break;
|
start = Py_eval_input;
|
||||||
case eval_statements: start = Py_file_input; break;
|
break;
|
||||||
default: pybind11_fail("invalid evaluation mode");
|
case eval_single_statement:
|
||||||
|
start = Py_single_input;
|
||||||
|
break;
|
||||||
|
case eval_statements:
|
||||||
|
start = Py_file_input;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pybind11_fail("invalid evaluation mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
if (!global.contains("__file__")) {
|
||||||
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
|
global["__file__"] = std::move(fname);
|
||||||
local.ptr());
|
}
|
||||||
(void) closeFile;
|
|
||||||
#else
|
|
||||||
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
|
|
||||||
local.ptr(), closeFile);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!result)
|
PyObject *result
|
||||||
|
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
|
}
|
||||||
return reinterpret_steal<object>(result);
|
return reinterpret_steal<object>(result);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
64
3rdparty/pybind11/include/pybind11/functional.h
vendored
64
3rdparty/pybind11/include/pybind11/functional.h
vendored
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
@ -19,18 +20,21 @@ template <typename Return, typename... Args>
|
|||||||
struct type_caster<std::function<Return(Args...)>> {
|
struct type_caster<std::function<Return(Args...)>> {
|
||||||
using type = std::function<Return(Args...)>;
|
using type = std::function<Return(Args...)>;
|
||||||
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||||
using function_type = Return (*) (Args...);
|
using function_type = Return (*)(Args...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (src.is_none()) {
|
if (src.is_none()) {
|
||||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||||
if (!convert) return false;
|
if (!convert) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isinstance<function>(src))
|
if (!isinstance<function>(src)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto func = reinterpret_borrow<function>(src);
|
auto func = reinterpret_borrow<function>(src);
|
||||||
|
|
||||||
@ -43,24 +47,44 @@ public:
|
|||||||
captured variables), in which case the roundtrip can be avoided.
|
captured variables), in which case the roundtrip can be avoided.
|
||||||
*/
|
*/
|
||||||
if (auto cfunc = func.cpp_function()) {
|
if (auto cfunc = func.cpp_function()) {
|
||||||
auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
|
auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
|
||||||
auto rec = (function_record *) c;
|
if (isinstance<capsule>(cfunc_self)) {
|
||||||
|
auto c = reinterpret_borrow<capsule>(cfunc_self);
|
||||||
|
auto *rec = (function_record *) c;
|
||||||
|
|
||||||
if (rec && rec->is_stateless &&
|
while (rec != nullptr) {
|
||||||
same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
if (rec->is_stateless
|
||||||
struct capture { function_type f; };
|
&& same_type(typeid(function_type),
|
||||||
|
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
||||||
|
struct capture {
|
||||||
|
function_type f;
|
||||||
|
};
|
||||||
value = ((capture *) &rec->data)->f;
|
value = ((capture *) &rec->data)->f;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
rec = rec->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// PYPY segfaults here when passing builtin function like sum.
|
||||||
|
// Raising an fail exception here works to prevent the segfault, but only on gcc.
|
||||||
|
// See PR #1413 for full details
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure GIL is held during functor destruction
|
// ensure GIL is held during functor destruction
|
||||||
struct func_handle {
|
struct func_handle {
|
||||||
function f;
|
function f;
|
||||||
func_handle(function&& f_) : f(std::move(f_)) {}
|
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
||||||
func_handle(const func_handle& f_) {
|
// This triggers a syntax error under very special conditions (very weird indeed).
|
||||||
|
explicit
|
||||||
|
#endif
|
||||||
|
func_handle(function &&f_) noexcept
|
||||||
|
: f(std::move(f_)) {
|
||||||
|
}
|
||||||
|
func_handle(const func_handle &f_) { operator=(f_); }
|
||||||
|
func_handle &operator=(const func_handle &f_) {
|
||||||
gil_scoped_acquire acq;
|
gil_scoped_acquire acq;
|
||||||
f = f_.f;
|
f = f_.f;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
~func_handle() {
|
~func_handle() {
|
||||||
gil_scoped_acquire acq;
|
gil_scoped_acquire acq;
|
||||||
@ -71,12 +95,11 @@ public:
|
|||||||
// to emulate 'move initialization capture' in C++11
|
// to emulate 'move initialization capture' in C++11
|
||||||
struct func_wrapper {
|
struct func_wrapper {
|
||||||
func_handle hfunc;
|
func_handle hfunc;
|
||||||
func_wrapper(func_handle&& hf): 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>());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -86,18 +109,21 @@ public:
|
|||||||
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
||||||
if (!f_)
|
if (!f_) {
|
||||||
return none().inc_ref();
|
return none().inc_ref();
|
||||||
|
}
|
||||||
|
|
||||||
auto result = f_.template target<function_type>();
|
auto result = f_.template target<function_type>();
|
||||||
if (result)
|
if (result) {
|
||||||
return cpp_function(*result, policy).release();
|
return cpp_function(*result, policy).release();
|
||||||
else
|
}
|
||||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")
|
PYBIND11_TYPE_CASTER(type,
|
||||||
+ make_caster<retval_type>::name + _("]"));
|
const_name("Callable[[") + concat(make_caster<Args>::name...)
|
||||||
|
+ const_name("], ") + make_caster<retval_type>::name
|
||||||
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
202
3rdparty/pybind11/include/pybind11/gil.h
vendored
Normal file
202
3rdparty/pybind11/include/pybind11/gil.h
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
pybind11/gil.h: RAII helpers for managing the GIL
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "detail/common.h"
|
||||||
|
#include "detail/internals.h"
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
PyThreadState *get_thread_state_unchecked();
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
|
||||||
|
|
||||||
|
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
||||||
|
* pattern, but there are a few important differences:
|
||||||
|
*
|
||||||
|
* 1. When acquiring the GIL from an non-main thread during the finalization
|
||||||
|
* phase, the GILState API blindly terminates the calling thread, which
|
||||||
|
* is often not what is wanted. This API does not do this.
|
||||||
|
*
|
||||||
|
* 2. The gil_scoped_release function can optionally cut the relationship
|
||||||
|
* of a PyThreadState and its associated thread, which allows moving it to
|
||||||
|
* another thread (this is a fairly rare/advanced use case).
|
||||||
|
*
|
||||||
|
* 3. The reference count of an acquired thread state can be controlled. This
|
||||||
|
* can be handy to prevent cases where callbacks issued from an external
|
||||||
|
* thread would otherwise constantly construct and destroy thread state data
|
||||||
|
* structures.
|
||||||
|
*
|
||||||
|
* See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
|
||||||
|
* example which uses features 2 and 3 to migrate the Python thread of
|
||||||
|
* execution to another thread (to run the event loop on the original thread,
|
||||||
|
* in this case).
|
||||||
|
*/
|
||||||
|
|
||||||
|
class gil_scoped_acquire {
|
||||||
|
public:
|
||||||
|
PYBIND11_NOINLINE gil_scoped_acquire() {
|
||||||
|
auto &internals = detail::get_internals();
|
||||||
|
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
|
||||||
|
|
||||||
|
if (!tstate) {
|
||||||
|
/* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
|
||||||
|
calling from a Python thread). Since we use a different key, this ensures
|
||||||
|
we don't create a new thread state and deadlock in PyEval_AcquireThread
|
||||||
|
below. Note we don't save this state with internals.tstate, since we don't
|
||||||
|
create it we would fail to clear it (its reference count should be > 0). */
|
||||||
|
tstate = PyGILState_GetThisThreadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tstate) {
|
||||||
|
tstate = PyThreadState_New(internals.istate);
|
||||||
|
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
|
if (!tstate) {
|
||||||
|
pybind11_fail("scoped_acquire: could not create thread state!");
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
tstate->gilstate_counter = 0;
|
||||||
|
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
|
||||||
|
} else {
|
||||||
|
release = detail::get_thread_state_unchecked() != tstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (release) {
|
||||||
|
PyEval_AcquireThread(tstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
inc_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc_ref() { ++tstate->gilstate_counter; }
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE void dec_ref() {
|
||||||
|
--tstate->gilstate_counter;
|
||||||
|
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
|
if (detail::get_thread_state_unchecked() != tstate) {
|
||||||
|
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
|
||||||
|
}
|
||||||
|
if (tstate->gilstate_counter < 0) {
|
||||||
|
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
if (tstate->gilstate_counter == 0) {
|
||||||
|
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
|
if (!release) {
|
||||||
|
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
PyThreadState_Clear(tstate);
|
||||||
|
if (active) {
|
||||||
|
PyThreadState_DeleteCurrent();
|
||||||
|
}
|
||||||
|
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
|
||||||
|
release = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
||||||
|
/// GIL won't be acquired. This method should be used if the interpreter
|
||||||
|
/// could be shutting down when this is called, as thread deletion is not
|
||||||
|
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
||||||
|
/// protect subsequent code.
|
||||||
|
PYBIND11_NOINLINE void disarm() { active = false; }
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE ~gil_scoped_acquire() {
|
||||||
|
dec_ref();
|
||||||
|
if (release) {
|
||||||
|
PyEval_SaveThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PyThreadState *tstate = nullptr;
|
||||||
|
bool release = true;
|
||||||
|
bool active = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class gil_scoped_release {
|
||||||
|
public:
|
||||||
|
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
|
||||||
|
// `get_internals()` must be called here unconditionally in order to initialize
|
||||||
|
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
|
||||||
|
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
|
||||||
|
auto &internals = detail::get_internals();
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
||||||
|
tstate = PyEval_SaveThread();
|
||||||
|
if (disassoc) {
|
||||||
|
// Python >= 3.7 can remove this, it's an int before 3.7
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto)
|
||||||
|
auto key = internals.tstate;
|
||||||
|
PYBIND11_TLS_DELETE_VALUE(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
||||||
|
/// GIL won't be acquired. This method should be used if the interpreter
|
||||||
|
/// could be shutting down when this is called, as thread deletion is not
|
||||||
|
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
||||||
|
/// protect subsequent code.
|
||||||
|
PYBIND11_NOINLINE void disarm() { active = false; }
|
||||||
|
|
||||||
|
~gil_scoped_release() {
|
||||||
|
if (!tstate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
|
||||||
|
if (active) {
|
||||||
|
PyEval_RestoreThread(tstate);
|
||||||
|
}
|
||||||
|
if (disassoc) {
|
||||||
|
// Python >= 3.7 can remove this, it's an int before 3.7
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto)
|
||||||
|
auto key = detail::get_internals().tstate;
|
||||||
|
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PyThreadState *tstate;
|
||||||
|
bool disassoc;
|
||||||
|
bool active = true;
|
||||||
|
};
|
||||||
|
#elif defined(PYPY_VERSION)
|
||||||
|
class gil_scoped_acquire {
|
||||||
|
PyGILState_STATE state;
|
||||||
|
|
||||||
|
public:
|
||||||
|
gil_scoped_acquire() { state = PyGILState_Ensure(); }
|
||||||
|
~gil_scoped_acquire() { PyGILState_Release(state); }
|
||||||
|
void disarm() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class gil_scoped_release {
|
||||||
|
PyThreadState *state;
|
||||||
|
|
||||||
|
public:
|
||||||
|
gil_scoped_release() { state = PyEval_SaveThread(); }
|
||||||
|
~gil_scoped_release() { PyEval_RestoreThread(state); }
|
||||||
|
void disarm() {}
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
class gil_scoped_acquire {
|
||||||
|
void disarm() {}
|
||||||
|
};
|
||||||
|
class gil_scoped_release {
|
||||||
|
void disarm() {}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
143
3rdparty/pybind11/include/pybind11/iostream.h
vendored
143
3rdparty/pybind11/include/pybind11/iostream.h
vendored
@ -5,17 +5,31 @@
|
|||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
All rights reserved. Use of this source code is governed by a
|
||||||
BSD-style license that can be found in the LICENSE file.
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
WARNING: The implementation in this file is NOT thread safe. Multiple
|
||||||
|
threads writing to a redirected ostream concurrently cause data races
|
||||||
|
and potentially buffer overflows. Therefore it is currently a requirement
|
||||||
|
that all (possibly) concurrent redirected ostream writes are protected by
|
||||||
|
a mutex.
|
||||||
|
#HelpAppreciated: Work on iostream.h thread safety.
|
||||||
|
For more background see the discussions under
|
||||||
|
https://github.com/pybind/pybind11/pull/2982 and
|
||||||
|
https://github.com/pybind/pybind11/pull/2995.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#include <streambuf>
|
#include <algorithm>
|
||||||
#include <ostream>
|
#include <cstring>
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
#include <streambuf>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
@ -38,50 +52,85 @@ private:
|
|||||||
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function must be non-virtual to be called in a destructor. If the
|
// Computes how many bytes at the end of the buffer are part of an
|
||||||
// rare MSVC test failure shows up with this version, then this should be
|
// incomplete sequence of UTF-8 bytes.
|
||||||
// simplified to a fully qualified call.
|
// Precondition: pbase() < pptr()
|
||||||
int _sync() {
|
size_t utf8_remainder() const {
|
||||||
if (pbase() != pptr()) {
|
const auto rbase = std::reverse_iterator<char *>(pbase());
|
||||||
// This subtraction cannot be negative, so dropping the sign
|
const auto rpptr = std::reverse_iterator<char *>(pptr());
|
||||||
str line(pbase(), static_cast<size_t>(pptr() - pbase()));
|
auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
|
||||||
|
auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };
|
||||||
|
auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };
|
||||||
|
auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
|
||||||
|
// If the last character is ASCII, there are no incomplete code points
|
||||||
|
if (is_ascii(*rpptr)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Otherwise, work back from the end of the buffer and find the first
|
||||||
|
// UTF-8 leading byte
|
||||||
|
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
|
||||||
|
const auto leading = std::find_if(rpptr, rpend, is_leading);
|
||||||
|
if (leading == rbase) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto dist = static_cast<size_t>(leading - rpptr);
|
||||||
|
size_t remainder = 0;
|
||||||
|
|
||||||
{
|
if (dist == 0) {
|
||||||
|
remainder = 1; // 1-byte code point is impossible
|
||||||
|
} else if (dist == 1) {
|
||||||
|
remainder = is_leading_2b(*leading) ? 0 : dist + 1;
|
||||||
|
} else if (dist == 2) {
|
||||||
|
remainder = is_leading_3b(*leading) ? 0 : dist + 1;
|
||||||
|
}
|
||||||
|
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8
|
||||||
|
// leading byte, either no remainder or invalid UTF-8.
|
||||||
|
// Invalid UTF-8 will cause an exception later when converting
|
||||||
|
// to a Python string, so that's not handled here.
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function must be non-virtual to be called in a destructor.
|
||||||
|
int _sync() {
|
||||||
|
if (pbase() != pptr()) { // If buffer is not empty
|
||||||
gil_scoped_acquire tmp;
|
gil_scoped_acquire tmp;
|
||||||
pywrite(line);
|
// This subtraction cannot be negative, so dropping the sign.
|
||||||
|
auto size = static_cast<size_t>(pptr() - pbase());
|
||||||
|
size_t remainder = utf8_remainder();
|
||||||
|
|
||||||
|
if (size > remainder) {
|
||||||
|
str line(pbase(), size - remainder);
|
||||||
|
pywrite(std::move(line));
|
||||||
pyflush();
|
pyflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the remainder at the end of the buffer to the beginning:
|
||||||
|
if (remainder > 0) {
|
||||||
|
std::memmove(pbase(), pptr() - remainder, remainder);
|
||||||
|
}
|
||||||
setp(pbase(), epptr());
|
setp(pbase(), epptr());
|
||||||
|
pbump(static_cast<int>(remainder));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sync() override {
|
int sync() override { return _sync(); }
|
||||||
return _sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
|
||||||
pythonbuf(object pyostream, size_t buffer_size = 1024)
|
: buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
|
||||||
: buf_size(buffer_size),
|
|
||||||
d_buffer(new char[buf_size]),
|
|
||||||
pywrite(pyostream.attr("write")),
|
|
||||||
pyflush(pyostream.attr("flush")) {
|
pyflush(pyostream.attr("flush")) {
|
||||||
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pythonbuf(pythonbuf&&) = default;
|
pythonbuf(pythonbuf &&) = default;
|
||||||
|
|
||||||
/// Sync before destroy
|
/// Sync before destroy
|
||||||
~pythonbuf() override {
|
~pythonbuf() override { _sync(); }
|
||||||
_sync();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
This a move-only guard that redirects output.
|
This a move-only guard that redirects output.
|
||||||
|
|
||||||
@ -102,8 +151,9 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
{
|
{
|
||||||
py::scoped_ostream_redirect output{std::cerr, py::module_::import("sys").attr("stderr")};
|
py::scoped_ostream_redirect output{
|
||||||
std::cerr << "Hello, World!";
|
std::cerr, py::module::import("sys").attr("stderr")};
|
||||||
|
std::cout << "Hello, World!";
|
||||||
}
|
}
|
||||||
\endrst */
|
\endrst */
|
||||||
class scoped_ostream_redirect {
|
class scoped_ostream_redirect {
|
||||||
@ -113,16 +163,14 @@ protected:
|
|||||||
detail::pythonbuf buffer;
|
detail::pythonbuf buffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
scoped_ostream_redirect(
|
explicit scoped_ostream_redirect(std::ostream &costream = std::cout,
|
||||||
std::ostream &costream = std::cout,
|
const object &pyostream
|
||||||
object pyostream = module_::import("sys").attr("stdout"))
|
= module_::import("sys").attr("stdout"))
|
||||||
: costream(costream), buffer(pyostream) {
|
: costream(costream), buffer(pyostream) {
|
||||||
old = costream.rdbuf(&buffer);
|
old = costream.rdbuf(&buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
~scoped_ostream_redirect() {
|
~scoped_ostream_redirect() { costream.rdbuf(old); }
|
||||||
costream.rdbuf(old);
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
||||||
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
||||||
@ -130,7 +178,6 @@ public:
|
|||||||
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
||||||
is provided primary to make ``py::call_guard`` easier to make.
|
is provided primary to make ``py::call_guard`` easier to make.
|
||||||
@ -144,13 +191,12 @@ public:
|
|||||||
\endrst */
|
\endrst */
|
||||||
class scoped_estream_redirect : public scoped_ostream_redirect {
|
class scoped_estream_redirect : public scoped_ostream_redirect {
|
||||||
public:
|
public:
|
||||||
scoped_estream_redirect(
|
explicit scoped_estream_redirect(std::ostream &costream = std::cerr,
|
||||||
std::ostream &costream = std::cerr,
|
const object &pyostream
|
||||||
object pyostream = module_::import("sys").attr("stderr"))
|
= module_::import("sys").attr("stderr"))
|
||||||
: scoped_ostream_redirect(costream,pyostream) {}
|
: scoped_ostream_redirect(costream, pyostream) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
// Class to redirect output as a context manager. C++ backend.
|
// Class to redirect output as a context manager. C++ backend.
|
||||||
@ -161,15 +207,17 @@ class OstreamRedirect {
|
|||||||
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
explicit OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
||||||
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
||||||
|
|
||||||
void enter() {
|
void enter() {
|
||||||
if (do_stdout_)
|
if (do_stdout_) {
|
||||||
redirect_stdout.reset(new scoped_ostream_redirect());
|
redirect_stdout.reset(new scoped_ostream_redirect());
|
||||||
if (do_stderr_)
|
}
|
||||||
|
if (do_stderr_) {
|
||||||
redirect_stderr.reset(new scoped_estream_redirect());
|
redirect_stderr.reset(new scoped_estream_redirect());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void exit() {
|
void exit() {
|
||||||
redirect_stdout.reset();
|
redirect_stdout.reset();
|
||||||
@ -206,11 +254,12 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
m.noisy_function_with_error_printing()
|
m.noisy_function_with_error_printing()
|
||||||
|
|
||||||
\endrst */
|
\endrst */
|
||||||
inline class_<detail::OstreamRedirect> add_ostream_redirect(module_ m, std::string name = "ostream_redirect") {
|
inline class_<detail::OstreamRedirect>
|
||||||
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
|
||||||
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
|
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
|
||||||
|
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
|
||||||
.def("__enter__", &detail::OstreamRedirect::enter)
|
.def("__enter__", &detail::OstreamRedirect::enter)
|
||||||
.def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); });
|
.def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
1374
3rdparty/pybind11/include/pybind11/numpy.h
vendored
1374
3rdparty/pybind11/include/pybind11/numpy.h
vendored
File diff suppressed because it is too large
Load Diff
144
3rdparty/pybind11/include/pybind11/operators.h
vendored
144
3rdparty/pybind11/include/pybind11/operators.h
vendored
@ -11,24 +11,55 @@
|
|||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#if defined(__clang__) && !defined(__INTEL_COMPILER)
|
|
||||||
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
/// Enumeration with all supported operator types
|
/// Enumeration with all supported operator types
|
||||||
enum op_id : int {
|
enum op_id : int {
|
||||||
op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift,
|
op_add,
|
||||||
op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert,
|
op_sub,
|
||||||
op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le,
|
op_mul,
|
||||||
op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
|
op_div,
|
||||||
op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero,
|
op_mod,
|
||||||
op_repr, op_truediv, op_itruediv, op_hash
|
op_divmod,
|
||||||
|
op_pow,
|
||||||
|
op_lshift,
|
||||||
|
op_rshift,
|
||||||
|
op_and,
|
||||||
|
op_xor,
|
||||||
|
op_or,
|
||||||
|
op_neg,
|
||||||
|
op_pos,
|
||||||
|
op_abs,
|
||||||
|
op_invert,
|
||||||
|
op_int,
|
||||||
|
op_long,
|
||||||
|
op_float,
|
||||||
|
op_str,
|
||||||
|
op_cmp,
|
||||||
|
op_gt,
|
||||||
|
op_ge,
|
||||||
|
op_lt,
|
||||||
|
op_le,
|
||||||
|
op_eq,
|
||||||
|
op_ne,
|
||||||
|
op_iadd,
|
||||||
|
op_isub,
|
||||||
|
op_imul,
|
||||||
|
op_idiv,
|
||||||
|
op_imod,
|
||||||
|
op_ilshift,
|
||||||
|
op_irshift,
|
||||||
|
op_iand,
|
||||||
|
op_ixor,
|
||||||
|
op_ior,
|
||||||
|
op_complex,
|
||||||
|
op_bool,
|
||||||
|
op_nonzero,
|
||||||
|
op_repr,
|
||||||
|
op_truediv,
|
||||||
|
op_itruediv,
|
||||||
|
op_hash
|
||||||
};
|
};
|
||||||
|
|
||||||
enum op_type : int {
|
enum op_type : int {
|
||||||
@ -37,95 +68,96 @@ enum op_type : int {
|
|||||||
op_u /* unary operator */
|
op_u /* unary operator */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct self_t { };
|
struct self_t {};
|
||||||
static const self_t self = self_t();
|
static const self_t self = self_t();
|
||||||
|
|
||||||
/// Type for an unused type slot
|
/// Type for an unused type slot
|
||||||
struct undefined_t { };
|
struct undefined_t {};
|
||||||
|
|
||||||
/// Don't warn about an unused variable
|
/// Don't warn about an unused variable
|
||||||
inline self_t __self() { return self; }
|
inline self_t __self() { return self; }
|
||||||
|
|
||||||
/// base template of operator implementations
|
/// base template of operator implementations
|
||||||
template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
|
template <op_id, op_type, typename B, typename L, typename R>
|
||||||
|
struct op_impl {};
|
||||||
|
|
||||||
/// Operator implementation generator
|
/// Operator implementation generator
|
||||||
template <op_id id, op_type ot, typename L, typename R> struct op_ {
|
template <op_id id, op_type ot, typename L, typename R>
|
||||||
template <typename Class, typename... Extra> void execute(Class &cl, const Extra&... extra) const {
|
struct op_ {
|
||||||
|
template <typename Class, typename... Extra>
|
||||||
|
void execute(Class &cl, const Extra &...extra) const {
|
||||||
using Base = typename Class::type;
|
using Base = typename Class::type;
|
||||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||||
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 (id == op_truediv || 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> void execute_cast(Class &cl, const Extra&... extra) const {
|
template <typename Class, typename... Extra>
|
||||||
|
void execute_cast(Class &cl, const Extra &...extra) const {
|
||||||
using Base = typename Class::type;
|
using Base = typename Class::type;
|
||||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
||||||
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
template <typename B, typename L, typename R> \
|
||||||
static char const* name() { return "__" #id "__"; } \
|
struct op_impl<op_##id, op_l, B, L, R> { \
|
||||||
|
static char const *name() { return "__" #id "__"; } \
|
||||||
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
||||||
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
||||||
}; \
|
}; \
|
||||||
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
|
template <typename B, typename L, typename R> \
|
||||||
static char const* name() { return "__" #rid "__"; } \
|
struct op_impl<op_##id, op_r, B, L, R> { \
|
||||||
|
static char const *name() { return "__" #rid "__"; } \
|
||||||
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
||||||
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
||||||
}; \
|
}; \
|
||||||
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
||||||
return op_<op_##id, op_l, self_t, self_t>(); \
|
return op_<op_##id, op_l, self_t, self_t>(); \
|
||||||
} \
|
} \
|
||||||
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
template <typename T> \
|
||||||
|
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||||
return op_<op_##id, op_l, self_t, T>(); \
|
return op_<op_##id, op_l, self_t, T>(); \
|
||||||
} \
|
} \
|
||||||
template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
template <typename T> \
|
||||||
|
op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
||||||
return op_<op_##id, op_r, T, self_t>(); \
|
return op_<op_##id, op_r, T, self_t>(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
||||||
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
template <typename B, typename L, typename R> \
|
||||||
static char const* name() { return "__" #id "__"; } \
|
struct op_impl<op_##id, op_l, B, L, R> { \
|
||||||
|
static char const *name() { return "__" #id "__"; } \
|
||||||
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
||||||
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
||||||
}; \
|
}; \
|
||||||
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
template <typename T> \
|
||||||
|
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||||
return op_<op_##id, op_l, self_t, T>(); \
|
return op_<op_##id, op_l, self_t, T>(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
||||||
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
template <typename B, typename L> \
|
||||||
static char const* name() { return "__" #id "__"; } \
|
struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
||||||
|
static char const *name() { return "__" #id "__"; } \
|
||||||
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
||||||
static B execute_cast(const L &l) { return B(expr); } \
|
static B execute_cast(const L &l) { return B(expr); } \
|
||||||
}; \
|
}; \
|
||||||
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
||||||
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
||||||
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
||||||
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r)
|
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l *r)
|
||||||
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
||||||
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
||||||
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
||||||
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
||||||
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r)
|
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l &r)
|
||||||
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
||||||
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
||||||
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
||||||
@ -134,7 +166,7 @@ PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
|
|||||||
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
||||||
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
||||||
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
||||||
//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
// PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
||||||
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
||||||
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
||||||
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
||||||
@ -167,7 +199,3 @@ using detail::self;
|
|||||||
using detail::hash;
|
using detail::hash;
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
39
3rdparty/pybind11/include/pybind11/options.h
vendored
39
3rdparty/pybind11/include/pybind11/options.h
vendored
@ -15,43 +15,54 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|||||||
|
|
||||||
class options {
|
class options {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Default RAII constructor, which leaves settings as they currently are.
|
// Default RAII constructor, which leaves settings as they currently are.
|
||||||
options() : previous_state(global_state()) {}
|
options() : previous_state(global_state()) {}
|
||||||
|
|
||||||
// Class is non-copyable.
|
// Class is non-copyable.
|
||||||
options(const options&) = delete;
|
options(const options &) = delete;
|
||||||
options& operator=(const options&) = delete;
|
options &operator=(const options &) = delete;
|
||||||
|
|
||||||
// Destructor, which restores settings that were in effect before.
|
// Destructor, which restores settings that were in effect before.
|
||||||
~options() {
|
~options() { global_state() = previous_state; }
|
||||||
global_state() = previous_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setter methods (affect the global state):
|
// Setter methods (affect the global state):
|
||||||
|
|
||||||
options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }
|
options &disable_user_defined_docstrings() & {
|
||||||
|
global_state().show_user_defined_docstrings = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }
|
options &enable_user_defined_docstrings() & {
|
||||||
|
global_state().show_user_defined_docstrings = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }
|
options &disable_function_signatures() & {
|
||||||
|
global_state().show_function_signatures = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }
|
options &enable_function_signatures() & {
|
||||||
|
global_state().show_function_signatures = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// Getter methods (return the global state):
|
// Getter methods (return the global state):
|
||||||
|
|
||||||
static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }
|
static bool show_user_defined_docstrings() {
|
||||||
|
return global_state().show_user_defined_docstrings;
|
||||||
|
}
|
||||||
|
|
||||||
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
||||||
|
|
||||||
// This type is not meant to be allocated on the heap.
|
// This type is not meant to be allocated on the heap.
|
||||||
void* operator new(size_t) = delete;
|
void *operator new(size_t) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct state {
|
struct state {
|
||||||
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
||||||
bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings.
|
bool show_function_signatures = true; //< Include auto-generated function signatures
|
||||||
|
// in docstrings.
|
||||||
};
|
};
|
||||||
|
|
||||||
static state &global_state() {
|
static state &global_state() {
|
||||||
|
2140
3rdparty/pybind11/include/pybind11/pybind11.h
vendored
2140
3rdparty/pybind11/include/pybind11/pybind11.h
vendored
File diff suppressed because it is too large
Load Diff
1633
3rdparty/pybind11/include/pybind11/pytypes.h
vendored
1633
3rdparty/pybind11/include/pybind11/pytypes.h
vendored
File diff suppressed because it is too large
Load Diff
275
3rdparty/pybind11/include/pybind11/stl.h
vendored
275
3rdparty/pybind11/include/pybind11/stl.h
vendored
@ -10,42 +10,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
#include <set>
|
#include "detail/common.h"
|
||||||
#include <unordered_set>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <iostream>
|
|
||||||
#include <list>
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <ostream>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <valarray>
|
#include <valarray>
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
// See `detail/common.h` for implementation of these guards.
|
||||||
#pragma warning(push)
|
#if defined(PYBIND11_HAS_OPTIONAL)
|
||||||
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
# include <optional>
|
||||||
|
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
|
||||||
|
# include <experimental/optional>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __has_include
|
#if defined(PYBIND11_HAS_VARIANT)
|
||||||
// std::optional (but including it in c++14 mode isn't allowed)
|
|
||||||
# if defined(PYBIND11_CPP17) && __has_include(<optional>)
|
|
||||||
# include <optional>
|
|
||||||
# define PYBIND11_HAS_OPTIONAL 1
|
|
||||||
# endif
|
|
||||||
// std::experimental::optional (but not allowed in c++11 mode)
|
|
||||||
# if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
|
|
||||||
!__has_include(<optional>))
|
|
||||||
# include <experimental/optional>
|
|
||||||
# define PYBIND11_HAS_EXP_OPTIONAL 1
|
|
||||||
# endif
|
|
||||||
// std::variant
|
|
||||||
# if defined(PYBIND11_CPP17) && __has_include(<variant>)
|
|
||||||
# include <variant>
|
# include <variant>
|
||||||
# define PYBIND11_HAS_VARIANT 1
|
|
||||||
# endif
|
|
||||||
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
|
|
||||||
# include <optional>
|
|
||||||
# include <variant>
|
|
||||||
# define PYBIND11_HAS_OPTIONAL 1
|
|
||||||
# define PYBIND11_HAS_VARIANT 1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
@ -54,29 +38,33 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
||||||
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
using forwarded_type = conditional_t<
|
using forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,
|
||||||
std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;
|
remove_reference_t<U> &,
|
||||||
|
remove_reference_t<U> &&>;
|
||||||
|
|
||||||
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
||||||
/// used for forwarding a container's elements.
|
/// used for forwarding a container's elements.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
forwarded_type<T, U> forward_like(U &&u) {
|
constexpr forwarded_type<T, U> forward_like(U &&u) {
|
||||||
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, typename Key> struct set_caster {
|
template <typename Type, typename Key>
|
||||||
|
struct set_caster {
|
||||||
using type = Type;
|
using type = Type;
|
||||||
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;
|
||||||
if (!conv.load(entry, convert))
|
if (!conv.load(entry, convert)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value.insert(cast_op<Key &&>(std::move(conv)));
|
value.insert(cast_op<Key &&>(std::move(conv)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -84,35 +72,40 @@ template <typename Type, typename Key> struct set_caster {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
if (!std::is_lvalue_reference<T>::value)
|
if (!std::is_lvalue_reference<T>::value) {
|
||||||
policy = return_value_policy_override<Key>::policy(policy);
|
policy = return_value_policy_override<Key>::policy(policy);
|
||||||
|
}
|
||||||
pybind11::set s;
|
pybind11::set s;
|
||||||
for (auto &&value : src) {
|
for (auto &&value : src) {
|
||||||
auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
|
auto value_ = reinterpret_steal<object>(
|
||||||
if (!value_ || !s.add(value_))
|
key_conv::cast(detail::forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_ || !s.add(std::move(value_))) {
|
||||||
return handle();
|
return handle();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return s.release();
|
return s.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]"));
|
PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, typename Key, typename Value> struct map_caster {
|
template <typename Type, typename Key, typename Value>
|
||||||
|
struct map_caster {
|
||||||
using key_conv = make_caster<Key>;
|
using key_conv = make_caster<Key>;
|
||||||
using value_conv = make_caster<Value>;
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!isinstance<dict>(src))
|
if (!isinstance<dict>(src)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
auto d = reinterpret_borrow<dict>(src);
|
auto d = reinterpret_borrow<dict>(src);
|
||||||
value.clear();
|
value.clear();
|
||||||
for (auto it : d) {
|
for (auto it : d) {
|
||||||
key_conv kconv;
|
key_conv kconv;
|
||||||
value_conv vconv;
|
value_conv vconv;
|
||||||
if (!kconv.load(it.first.ptr(), convert) ||
|
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
|
||||||
!vconv.load(it.second.ptr(), convert))
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -128,78 +121,94 @@ template <typename Type, typename Key, typename Value> struct map_caster {
|
|||||||
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
||||||
}
|
}
|
||||||
for (auto &&kv : src) {
|
for (auto &&kv : src) {
|
||||||
auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
|
auto key = reinterpret_steal<object>(
|
||||||
auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
|
key_conv::cast(detail::forward_like<T>(kv.first), policy_key, parent));
|
||||||
if (!key || !value)
|
auto value = reinterpret_steal<object>(
|
||||||
|
value_conv::cast(detail::forward_like<T>(kv.second), policy_value, parent));
|
||||||
|
if (!key || !value) {
|
||||||
return handle();
|
return handle();
|
||||||
d[key] = value;
|
}
|
||||||
|
d[std::move(key)] = std::move(value);
|
||||||
}
|
}
|
||||||
return d.release();
|
return d.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]"));
|
PYBIND11_TYPE_CASTER(Type,
|
||||||
|
const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name
|
||||||
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, typename Value> struct list_caster {
|
template <typename Type, typename Value>
|
||||||
|
struct list_caster {
|
||||||
using value_conv = make_caster<Value>;
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!isinstance<sequence>(src) || isinstance<str>(src))
|
if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
auto s = reinterpret_borrow<sequence>(src);
|
auto s = reinterpret_borrow<sequence>(src);
|
||||||
value.clear();
|
value.clear();
|
||||||
reserve_maybe(s, &value);
|
reserve_maybe(s, &value);
|
||||||
for (auto it : s) {
|
for (auto it : s) {
|
||||||
value_conv conv;
|
value_conv conv;
|
||||||
if (!conv.load(it, convert))
|
if (!conv.load(it, convert)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value.push_back(cast_op<Value &&>(std::move(conv)));
|
value.push_back(cast_op<Value &&>(std::move(conv)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T = Type,
|
template <
|
||||||
|
typename T = Type,
|
||||||
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
||||||
void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
|
void reserve_maybe(const sequence &s, Type *) {
|
||||||
void reserve_maybe(sequence, void *) { }
|
value.reserve(s.size());
|
||||||
|
}
|
||||||
|
void reserve_maybe(const sequence &, void *) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
if (!std::is_lvalue_reference<T>::value)
|
if (!std::is_lvalue_reference<T>::value) {
|
||||||
policy = return_value_policy_override<Value>::policy(policy);
|
policy = return_value_policy_override<Value>::policy(policy);
|
||||||
|
}
|
||||||
list l(src.size());
|
list l(src.size());
|
||||||
size_t index = 0;
|
ssize_t index = 0;
|
||||||
for (auto &&value : src) {
|
for (auto &&value : src) {
|
||||||
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
auto value_ = reinterpret_steal<object>(
|
||||||
if (!value_)
|
value_conv::cast(detail::forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_) {
|
||||||
return handle();
|
return handle();
|
||||||
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
}
|
||||||
|
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
||||||
}
|
}
|
||||||
return l.release();
|
return l.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]"));
|
PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
|
template <typename Type, typename Alloc>
|
||||||
: list_caster<std::vector<Type, Alloc>, Type> { };
|
struct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> {};
|
||||||
|
|
||||||
template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>>
|
template <typename Type, typename Alloc>
|
||||||
: list_caster<std::deque<Type, Alloc>, Type> { };
|
struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc>, Type> {};
|
||||||
|
|
||||||
template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
|
template <typename Type, typename Alloc>
|
||||||
: list_caster<std::list<Type, Alloc>, Type> { };
|
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
||||||
|
|
||||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
|
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
||||||
|
struct array_caster {
|
||||||
using value_conv = make_caster<Value>;
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <bool R = Resizable>
|
template <bool R = Resizable>
|
||||||
bool require_size(enable_if_t<R, size_t> size) {
|
bool require_size(enable_if_t<R, size_t> size) {
|
||||||
if (value.size() != size)
|
if (value.size() != size) {
|
||||||
value.resize(size);
|
value.resize(size);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template <bool R = Resizable>
|
template <bool R = Resizable>
|
||||||
@ -209,16 +218,19 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!isinstance<sequence>(src))
|
if (!isinstance<sequence>(src)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
auto l = reinterpret_borrow<sequence>(src);
|
auto l = reinterpret_borrow<sequence>(src);
|
||||||
if (!require_size(l.size()))
|
if (!require_size(l.size())) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
size_t ctr = 0;
|
size_t ctr = 0;
|
||||||
for (auto it : l) {
|
for (auto it : l) {
|
||||||
value_conv conv;
|
value_conv conv;
|
||||||
if (!conv.load(it, convert))
|
if (!conv.load(it, convert)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -227,81 +239,99 @@ public:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
list l(src.size());
|
list l(src.size());
|
||||||
size_t index = 0;
|
ssize_t index = 0;
|
||||||
for (auto &&value : src) {
|
for (auto &&value : src) {
|
||||||
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
auto value_ = reinterpret_steal<object>(
|
||||||
if (!value_)
|
value_conv::cast(detail::forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_) {
|
||||||
return handle();
|
return handle();
|
||||||
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
}
|
||||||
|
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
||||||
}
|
}
|
||||||
return l.release();
|
return l.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
|
PYBIND11_TYPE_CASTER(ArrayType,
|
||||||
|
const_name("List[") + value_conv::name
|
||||||
|
+ const_name<Resizable>(const_name(""),
|
||||||
|
const_name("[") + const_name<Size>()
|
||||||
|
+ const_name("]"))
|
||||||
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
|
template <typename Type, size_t Size>
|
||||||
: array_caster<std::array<Type, Size>, Type, false, Size> { };
|
struct type_caster<std::array<Type, Size>>
|
||||||
|
: array_caster<std::array<Type, Size>, Type, false, Size> {};
|
||||||
|
|
||||||
template <typename Type> struct type_caster<std::valarray<Type>>
|
template <typename Type>
|
||||||
: array_caster<std::valarray<Type>, Type, true> { };
|
struct type_caster<std::valarray<Type>> : array_caster<std::valarray<Type>, Type, true> {};
|
||||||
|
|
||||||
template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
|
template <typename Key, typename Compare, typename Alloc>
|
||||||
: set_caster<std::set<Key, Compare, Alloc>, Key> { };
|
struct type_caster<std::set<Key, Compare, Alloc>>
|
||||||
|
: set_caster<std::set<Key, Compare, Alloc>, Key> {};
|
||||||
|
|
||||||
template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
template <typename Key, typename Hash, typename Equal, typename Alloc>
|
||||||
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
|
struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
||||||
|
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};
|
||||||
|
|
||||||
template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
template <typename Key, typename Value, typename Compare, typename Alloc>
|
||||||
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
|
struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
||||||
|
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};
|
||||||
|
|
||||||
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc>
|
||||||
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
|
struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
||||||
|
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> {};
|
||||||
|
|
||||||
// This type caster is intended to be used for std::optional and std::experimental::optional
|
// This type caster is intended to be used for std::optional and std::experimental::optional
|
||||||
template<typename T> struct optional_caster {
|
template <typename Type, typename Value = typename Type::value_type>
|
||||||
using value_conv = make_caster<typename T::value_type>;
|
struct optional_caster {
|
||||||
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
template <typename T_>
|
template <typename T>
|
||||||
static handle cast(T_ &&src, return_value_policy policy, handle parent) {
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
if (!src)
|
if (!src) {
|
||||||
return none().inc_ref();
|
return none().inc_ref();
|
||||||
if (!std::is_lvalue_reference<T>::value) {
|
|
||||||
policy = return_value_policy_override<T>::policy(policy);
|
|
||||||
}
|
}
|
||||||
return value_conv::cast(*std::forward<T_>(src), policy, parent);
|
if (!std::is_lvalue_reference<T>::value) {
|
||||||
|
policy = return_value_policy_override<Value>::policy(policy);
|
||||||
|
}
|
||||||
|
return value_conv::cast(*std::forward<T>(src), policy, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!src) {
|
if (!src) {
|
||||||
return false;
|
return false;
|
||||||
} else if (src.is_none()) {
|
}
|
||||||
|
if (src.is_none()) {
|
||||||
return true; // default-constructed value is already empty
|
return true; // default-constructed value is already empty
|
||||||
}
|
}
|
||||||
value_conv inner_caster;
|
value_conv inner_caster;
|
||||||
if (!inner_caster.load(src, convert))
|
if (!inner_caster.load(src, convert)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
|
value.emplace(cast_op<Value &&>(std::move(inner_caster)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
|
PYBIND11_TYPE_CASTER(Type, const_name("Optional[") + value_conv::name + const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_OPTIONAL)
|
#if defined(PYBIND11_HAS_OPTIONAL)
|
||||||
template<typename T> struct type_caster<std::optional<T>>
|
template <typename T>
|
||||||
: public optional_caster<std::optional<T>> {};
|
struct type_caster<std::optional<T>> : public optional_caster<std::optional<T>> {};
|
||||||
|
|
||||||
template<> struct type_caster<std::nullopt_t>
|
template <>
|
||||||
: public void_caster<std::nullopt_t> {};
|
struct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
|
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
|
||||||
template<typename T> struct type_caster<std::experimental::optional<T>>
|
template <typename T>
|
||||||
|
struct type_caster<std::experimental::optional<T>>
|
||||||
: public optional_caster<std::experimental::optional<T>> {};
|
: public optional_caster<std::experimental::optional<T>> {};
|
||||||
|
|
||||||
template<> struct type_caster<std::experimental::nullopt_t>
|
template <>
|
||||||
|
struct type_caster<std::experimental::nullopt_t>
|
||||||
: public void_caster<std::experimental::nullopt_t> {};
|
: public void_caster<std::experimental::nullopt_t> {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -322,7 +352,7 @@ struct variant_caster_visitor {
|
|||||||
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
||||||
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
||||||
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
||||||
template <template<typename...> class Variant>
|
template <template <typename...> class Variant>
|
||||||
struct visit_helper {
|
struct visit_helper {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
||||||
@ -331,9 +361,10 @@ struct visit_helper {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Generic variant caster
|
/// Generic variant caster
|
||||||
template <typename Variant> struct variant_caster;
|
template <typename Variant>
|
||||||
|
struct variant_caster;
|
||||||
|
|
||||||
template <template<typename...> class V, typename... Ts>
|
template <template <typename...> class V, typename... Ts>
|
||||||
struct variant_caster<V<Ts...>> {
|
struct variant_caster<V<Ts...>> {
|
||||||
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
||||||
|
|
||||||
@ -341,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...>{});
|
||||||
@ -354,8 +385,9 @@ struct variant_caster<V<Ts...>> {
|
|||||||
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
||||||
// slot of the variant. Without two-pass loading `double` would be filled
|
// slot of the variant. Without two-pass loading `double` would be filled
|
||||||
// because it appears first and a conversion is possible.
|
// because it appears first and a conversion is possible.
|
||||||
if (convert && load_alternative(src, false, type_list<Ts...>{}))
|
if (convert && load_alternative(src, false, type_list<Ts...>{})) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return load_alternative(src, convert, type_list<Ts...>{});
|
return load_alternative(src, convert, type_list<Ts...>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,23 +398,28 @@ struct variant_caster<V<Ts...>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Type = V<Ts...>;
|
using Type = V<Ts...>;
|
||||||
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]"));
|
PYBIND11_TYPE_CASTER(Type,
|
||||||
|
const_name("Union[") + detail::concat(make_caster<Ts>::name...)
|
||||||
|
+ const_name("]"));
|
||||||
};
|
};
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
||||||
|
#ifdef PYBIND11_HAS_STRING_VIEW
|
||||||
|
os << str(obj).cast<std::string_view>();
|
||||||
|
#else
|
||||||
os << (std::string) str(obj);
|
os << (std::string) str(obj);
|
||||||
|
#endif
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
116
3rdparty/pybind11/include/pybind11/stl/filesystem.h
vendored
Normal file
116
3rdparty/pybind11/include/pybind11/stl/filesystem.h
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (c) 2021 The Pybind Development Team.
|
||||||
|
// All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../pybind11.h"
|
||||||
|
#include "../detail/common.h"
|
||||||
|
#include "../detail/descr.h"
|
||||||
|
#include "../cast.h"
|
||||||
|
#include "../pytypes.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
# if defined(PYBIND11_CPP17)
|
||||||
|
# if __has_include(<filesystem>) && \
|
||||||
|
PY_VERSION_HEX >= 0x03060000
|
||||||
|
# include <filesystem>
|
||||||
|
# define PYBIND11_HAS_FILESYSTEM 1
|
||||||
|
# elif __has_include(<experimental/filesystem>)
|
||||||
|
# include <experimental/filesystem>
|
||||||
|
# define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \
|
||||||
|
&& !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
||||||
|
# error \
|
||||||
|
"Neither #include <filesystem> nor #include <experimental/filesystem is available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
|
template <typename T>
|
||||||
|
struct path_caster {
|
||||||
|
|
||||||
|
private:
|
||||||
|
static PyObject *unicode_from_fs_native(const std::string &w) {
|
||||||
|
# if !defined(PYPY_VERSION)
|
||||||
|
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
|
||||||
|
# else
|
||||||
|
// PyPy mistakenly declares the first parameter as non-const.
|
||||||
|
return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *unicode_from_fs_native(const std::wstring &w) {
|
||||||
|
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static handle cast(const T &path, return_value_policy, handle) {
|
||||||
|
if (auto py_str = unicode_from_fs_native(path.native())) {
|
||||||
|
return module_::import("pathlib")
|
||||||
|
.attr("Path")(reinterpret_steal<object>(py_str))
|
||||||
|
.release();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(handle handle, bool) {
|
||||||
|
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
|
||||||
|
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
|
||||||
|
// issue #3168) so we do it ourselves instead.
|
||||||
|
PyObject *buf = PyOS_FSPath(handle.ptr());
|
||||||
|
if (!buf) {
|
||||||
|
PyErr_Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PyObject *native = nullptr;
|
||||||
|
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
||||||
|
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
||||||
|
if (auto *c_str = PyBytes_AsString(native)) {
|
||||||
|
// AsString returns a pointer to the internal buffer, which
|
||||||
|
// must not be free'd.
|
||||||
|
value = c_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
||||||
|
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
||||||
|
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
||||||
|
// AsWideCharString returns a new string that must be free'd.
|
||||||
|
value = c_str; // Copies the string.
|
||||||
|
PyMem_Free(c_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_XDECREF(native);
|
||||||
|
Py_DECREF(buf);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
PyErr_Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
|
|
||||||
|
#if defined(PYBIND11_HAS_FILESYSTEM)
|
||||||
|
template <>
|
||||||
|
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
|
||||||
|
#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(PYBIND11_NAMESPACE)
|
562
3rdparty/pybind11/include/pybind11/stl_bind.h
vendored
562
3rdparty/pybind11/include/pybind11/stl_bind.h
vendored
@ -19,140 +19,152 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
/* SFINAE helper class used by 'is_comparable */
|
/* SFINAE helper class used by 'is_comparable */
|
||||||
template <typename T> struct container_traits {
|
template <typename T>
|
||||||
template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
|
struct container_traits {
|
||||||
template <typename T2> static std::false_type test_comparable(...);
|
template <typename T2>
|
||||||
template <typename T2> static std::true_type test_value(typename T2::value_type *);
|
static std::true_type
|
||||||
template <typename T2> static std::false_type test_value(...);
|
test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);
|
||||||
template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
|
template <typename T2>
|
||||||
template <typename T2> static std::false_type test_pair(...);
|
static std::false_type test_comparable(...);
|
||||||
|
template <typename T2>
|
||||||
|
static std::true_type test_value(typename T2::value_type *);
|
||||||
|
template <typename T2>
|
||||||
|
static std::false_type test_value(...);
|
||||||
|
template <typename T2>
|
||||||
|
static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
|
||||||
|
template <typename T2>
|
||||||
|
static std::false_type test_pair(...);
|
||||||
|
|
||||||
static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
|
static constexpr const bool is_comparable
|
||||||
static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
|
= std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
|
||||||
static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
|
static constexpr const bool is_pair
|
||||||
|
= std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
|
||||||
|
static constexpr const bool is_vector
|
||||||
|
= std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
|
||||||
static constexpr const bool is_element = !is_pair && !is_vector;
|
static constexpr const bool is_element = !is_pair && !is_vector;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default: is_comparable -> std::false_type */
|
/* Default: is_comparable -> std::false_type */
|
||||||
template <typename T, typename SFINAE = void>
|
template <typename T, typename SFINAE = void>
|
||||||
struct is_comparable : std::false_type { };
|
struct is_comparable : std::false_type {};
|
||||||
|
|
||||||
/* For non-map data structures, check whether operator== can be instantiated */
|
/* For non-map data structures, check whether operator== can be instantiated */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_comparable<
|
struct is_comparable<
|
||||||
T, enable_if_t<container_traits<T>::is_element &&
|
T,
|
||||||
container_traits<T>::is_comparable>>
|
enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>
|
||||||
: std::true_type { };
|
: std::true_type {};
|
||||||
|
|
||||||
/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
|
/* For a vector/map data structure, recursively check the value type
|
||||||
|
(which is std::pair for maps) */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
|
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
|
||||||
static constexpr const bool value =
|
static constexpr const bool value = is_comparable<typename T::value_type>::value;
|
||||||
is_comparable<typename T::value_type>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For pairs, recursively check the two data types */
|
/* For pairs, recursively check the two data types */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
||||||
static constexpr const bool value =
|
static constexpr const bool value = is_comparable<typename T::first_type>::value
|
||||||
is_comparable<typename T::first_type>::value &&
|
&& is_comparable<typename T::second_type>::value;
|
||||||
is_comparable<typename T::second_type>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Fallback functions */
|
/* Fallback functions */
|
||||||
template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { }
|
template <typename, typename, typename... Args>
|
||||||
template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { }
|
void vector_if_copy_constructible(const Args &...) {}
|
||||||
template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { }
|
template <typename, typename, typename... Args>
|
||||||
template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { }
|
void vector_if_equal_operator(const Args &...) {}
|
||||||
|
template <typename, typename, typename... Args>
|
||||||
|
void vector_if_insertion_operator(const Args &...) {}
|
||||||
|
template <typename, typename, typename... Args>
|
||||||
|
void vector_modifiers(const Args &...) {}
|
||||||
|
|
||||||
template<typename Vector, typename Class_>
|
template <typename Vector, typename Class_>
|
||||||
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
|
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
|
||||||
cl.def(init<const Vector &>(), "Copy constructor");
|
cl.def(init<const Vector &>(), "Copy constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Vector, typename Class_>
|
template <typename Vector, typename Class_>
|
||||||
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
|
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
|
||||||
using T = typename Vector::value_type;
|
using T = typename Vector::value_type;
|
||||||
|
|
||||||
cl.def(self == self);
|
cl.def(self == self);
|
||||||
cl.def(self != self);
|
cl.def(self != self);
|
||||||
|
|
||||||
cl.def("count",
|
cl.def(
|
||||||
[](const Vector &v, const T &x) {
|
"count",
|
||||||
return std::count(v.begin(), v.end(), x);
|
[](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },
|
||||||
},
|
|
||||||
arg("x"),
|
arg("x"),
|
||||||
"Return the number of times ``x`` appears in the list"
|
"Return the number of times ``x`` appears in the list");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("remove", [](Vector &v, const T &x) {
|
cl.def(
|
||||||
|
"remove",
|
||||||
|
[](Vector &v, const T &x) {
|
||||||
auto p = std::find(v.begin(), v.end(), x);
|
auto p = std::find(v.begin(), v.end(), x);
|
||||||
if (p != v.end())
|
if (p != v.end()) {
|
||||||
v.erase(p);
|
v.erase(p);
|
||||||
else
|
} else {
|
||||||
throw value_error();
|
throw value_error();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
arg("x"),
|
arg("x"),
|
||||||
"Remove the first item from the list whose value is x. "
|
"Remove the first item from the list whose value is x. "
|
||||||
"It is an error if there is no such item."
|
"It is an error if there is no such item.");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__contains__",
|
cl.def(
|
||||||
[](const Vector &v, const T &x) {
|
"__contains__",
|
||||||
return std::find(v.begin(), v.end(), x) != v.end();
|
[](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },
|
||||||
},
|
|
||||||
arg("x"),
|
arg("x"),
|
||||||
"Return true the container contains ``x``"
|
"Return true the container contains ``x``");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vector modifiers -- requires a copyable vector_type:
|
// Vector modifiers -- requires a copyable vector_type:
|
||||||
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems
|
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it
|
||||||
// silly to allow deletion but not insertion, so include them here too.)
|
// seems silly to allow deletion but not insertion, so include them here too.)
|
||||||
template <typename Vector, typename Class_>
|
template <typename Vector, typename Class_>
|
||||||
void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
|
void vector_modifiers(
|
||||||
|
enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
|
||||||
using T = typename Vector::value_type;
|
using T = typename Vector::value_type;
|
||||||
using SizeType = typename Vector::size_type;
|
using SizeType = typename Vector::size_type;
|
||||||
using DiffType = typename Vector::difference_type;
|
using DiffType = typename Vector::difference_type;
|
||||||
|
|
||||||
auto wrap_i = [](DiffType i, SizeType n) {
|
auto wrap_i = [](DiffType i, SizeType n) {
|
||||||
if (i < 0)
|
if (i < 0) {
|
||||||
i += n;
|
i += n;
|
||||||
if (i < 0 || (SizeType)i >= n)
|
}
|
||||||
|
if (i < 0 || (SizeType) i >= n) {
|
||||||
throw index_error();
|
throw index_error();
|
||||||
|
}
|
||||||
return i;
|
return i;
|
||||||
};
|
};
|
||||||
|
|
||||||
cl.def("append",
|
cl.def(
|
||||||
|
"append",
|
||||||
[](Vector &v, const T &value) { v.push_back(value); },
|
[](Vector &v, const T &value) { v.push_back(value); },
|
||||||
arg("x"),
|
arg("x"),
|
||||||
"Add an item to the end of the list");
|
"Add an item to the end of the list");
|
||||||
|
|
||||||
cl.def(init([](iterable it) {
|
cl.def(init([](const iterable &it) {
|
||||||
auto v = std::unique_ptr<Vector>(new Vector());
|
auto v = std::unique_ptr<Vector>(new Vector());
|
||||||
v->reserve(len_hint(it));
|
v->reserve(len_hint(it));
|
||||||
for (handle h : it)
|
for (handle h : it) {
|
||||||
v->push_back(h.cast<T>());
|
v->push_back(h.cast<T>());
|
||||||
|
}
|
||||||
return v.release();
|
return v.release();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cl.def("clear",
|
cl.def(
|
||||||
[](Vector &v) {
|
"clear", [](Vector &v) { v.clear(); }, "Clear the contents");
|
||||||
v.clear();
|
|
||||||
},
|
|
||||||
"Clear the contents"
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("extend",
|
cl.def(
|
||||||
[](Vector &v, const Vector &src) {
|
"extend",
|
||||||
v.insert(v.end(), src.begin(), src.end());
|
[](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },
|
||||||
},
|
|
||||||
arg("L"),
|
arg("L"),
|
||||||
"Extend the list by appending all the items in the given list"
|
"Extend the list by appending all the items in the given list");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("extend",
|
cl.def(
|
||||||
[](Vector &v, iterable it) {
|
"extend",
|
||||||
|
[](Vector &v, const iterable &it) {
|
||||||
const size_t old_size = v.size();
|
const size_t old_size = v.size();
|
||||||
v.reserve(old_size + len_hint(it));
|
v.reserve(old_size + len_hint(it));
|
||||||
try {
|
try {
|
||||||
@ -160,7 +172,8 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||||||
v.push_back(h.cast<T>());
|
v.push_back(h.cast<T>());
|
||||||
}
|
}
|
||||||
} catch (const cast_error &) {
|
} catch (const cast_error &) {
|
||||||
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end());
|
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
|
||||||
|
v.end());
|
||||||
try {
|
try {
|
||||||
v.shrink_to_fit();
|
v.shrink_to_fit();
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
@ -170,103 +183,110 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
arg("L"),
|
arg("L"),
|
||||||
"Extend the list by appending all the items in the given list"
|
"Extend the list by appending all the items in the given list");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("insert",
|
cl.def(
|
||||||
|
"insert",
|
||||||
[](Vector &v, DiffType i, const T &x) {
|
[](Vector &v, DiffType i, const T &x) {
|
||||||
// Can't use wrap_i; i == v.size() is OK
|
// Can't use wrap_i; i == v.size() is OK
|
||||||
if (i < 0)
|
if (i < 0) {
|
||||||
i += v.size();
|
i += v.size();
|
||||||
if (i < 0 || (SizeType)i > v.size())
|
}
|
||||||
|
if (i < 0 || (SizeType) i > v.size()) {
|
||||||
throw index_error();
|
throw index_error();
|
||||||
|
}
|
||||||
v.insert(v.begin() + i, x);
|
v.insert(v.begin() + i, x);
|
||||||
},
|
},
|
||||||
arg("i") , arg("x"),
|
arg("i"),
|
||||||
"Insert an item at a given position."
|
arg("x"),
|
||||||
);
|
"Insert an item at a given position.");
|
||||||
|
|
||||||
cl.def("pop",
|
cl.def(
|
||||||
|
"pop",
|
||||||
[](Vector &v) {
|
[](Vector &v) {
|
||||||
if (v.empty())
|
if (v.empty()) {
|
||||||
throw index_error();
|
throw index_error();
|
||||||
T t = v.back();
|
}
|
||||||
|
T t = std::move(v.back());
|
||||||
v.pop_back();
|
v.pop_back();
|
||||||
return t;
|
return t;
|
||||||
},
|
},
|
||||||
"Remove and return the last item"
|
"Remove and return the last item");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("pop",
|
cl.def(
|
||||||
|
"pop",
|
||||||
[wrap_i](Vector &v, DiffType i) {
|
[wrap_i](Vector &v, DiffType i) {
|
||||||
i = wrap_i(i, v.size());
|
i = wrap_i(i, v.size());
|
||||||
T t = v[(SizeType) i];
|
T t = std::move(v[(SizeType) i]);
|
||||||
v.erase(v.begin() + i);
|
v.erase(std::next(v.begin(), i));
|
||||||
return t;
|
return t;
|
||||||
},
|
},
|
||||||
arg("i"),
|
arg("i"),
|
||||||
"Remove and return the item at index ``i``"
|
"Remove and return the item at index ``i``");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__setitem__",
|
cl.def("__setitem__", [wrap_i](Vector &v, DiffType i, const T &t) {
|
||||||
[wrap_i](Vector &v, DiffType i, const T &t) {
|
|
||||||
i = wrap_i(i, v.size());
|
i = wrap_i(i, v.size());
|
||||||
v[(SizeType)i] = t;
|
v[(SizeType) i] = t;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
/// Slicing protocol
|
/// Slicing protocol
|
||||||
cl.def("__getitem__",
|
cl.def(
|
||||||
[](const Vector &v, slice slice) -> Vector * {
|
"__getitem__",
|
||||||
size_t start, stop, step, slicelength;
|
[](const Vector &v, const slice &slice) -> Vector * {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
auto *seq = new Vector();
|
auto *seq = new Vector();
|
||||||
seq->reserve((size_t) slicelength);
|
seq->reserve((size_t) slicelength);
|
||||||
|
|
||||||
for (size_t i=0; i<slicelength; ++i) {
|
for (size_t i = 0; i < slicelength; ++i) {
|
||||||
seq->push_back(v[start]);
|
seq->push_back(v[start]);
|
||||||
start += step;
|
start += step;
|
||||||
}
|
}
|
||||||
return seq;
|
return seq;
|
||||||
},
|
},
|
||||||
arg("s"),
|
arg("s"),
|
||||||
"Retrieve list elements using a slice object"
|
"Retrieve list elements using a slice object");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__setitem__",
|
cl.def(
|
||||||
[](Vector &v, slice slice, const Vector &value) {
|
"__setitem__",
|
||||||
size_t start, stop, step, slicelength;
|
[](Vector &v, const slice &slice, const Vector &value) {
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||||
|
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
|
||||||
if (slicelength != value.size())
|
if (slicelength != value.size()) {
|
||||||
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
|
throw std::runtime_error(
|
||||||
|
"Left and right hand size of slice assignment have different sizes!");
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i=0; i<slicelength; ++i) {
|
for (size_t i = 0; i < slicelength; ++i) {
|
||||||
v[start] = value[i];
|
v[start] = value[i];
|
||||||
start += step;
|
start += step;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Assign list elements using a slice object"
|
"Assign list elements using a slice object");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__delitem__",
|
cl.def(
|
||||||
|
"__delitem__",
|
||||||
[wrap_i](Vector &v, DiffType i) {
|
[wrap_i](Vector &v, DiffType i) {
|
||||||
i = wrap_i(i, v.size());
|
i = wrap_i(i, v.size());
|
||||||
v.erase(v.begin() + i);
|
v.erase(v.begin() + i);
|
||||||
},
|
},
|
||||||
"Delete the list elements at index ``i``"
|
"Delete the list elements at index ``i``");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__delitem__",
|
cl.def(
|
||||||
[](Vector &v, slice slice) {
|
"__delitem__",
|
||||||
size_t start, stop, step, slicelength;
|
[](Vector &v, const slice &slice) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
if (step == 1 && false) {
|
if (step == 1 && false) {
|
||||||
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
|
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
|
||||||
@ -277,15 +297,15 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Delete list elements using a slice object"
|
"Delete list elements using a slice object");
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
||||||
// we have to access by copying; otherwise we return by reference.
|
// we have to access by copying; otherwise we return by reference.
|
||||||
template <typename Vector> using vector_needs_copy = negation<
|
template <typename Vector>
|
||||||
std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
|
using vector_needs_copy
|
||||||
|
= negation<std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]),
|
||||||
|
typename Vector::value_type &>>;
|
||||||
|
|
||||||
// The usual case: access and iterate by reference
|
// The usual case: access and iterate by reference
|
||||||
template <typename Vector, typename Class_>
|
template <typename Vector, typename Class_>
|
||||||
@ -296,25 +316,28 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
|
|||||||
using ItType = typename Vector::iterator;
|
using ItType = typename Vector::iterator;
|
||||||
|
|
||||||
auto wrap_i = [](DiffType i, SizeType n) {
|
auto wrap_i = [](DiffType i, SizeType n) {
|
||||||
if (i < 0)
|
if (i < 0) {
|
||||||
i += n;
|
i += n;
|
||||||
if (i < 0 || (SizeType)i >= n)
|
}
|
||||||
|
if (i < 0 || (SizeType) i >= n) {
|
||||||
throw index_error();
|
throw index_error();
|
||||||
|
}
|
||||||
return i;
|
return i;
|
||||||
};
|
};
|
||||||
|
|
||||||
cl.def("__getitem__",
|
cl.def(
|
||||||
|
"__getitem__",
|
||||||
[wrap_i](Vector &v, DiffType i) -> T & {
|
[wrap_i](Vector &v, DiffType i) -> T & {
|
||||||
i = wrap_i(i, v.size());
|
i = wrap_i(i, v.size());
|
||||||
return v[(SizeType)i];
|
return v[(SizeType) i];
|
||||||
},
|
},
|
||||||
return_value_policy::reference_internal // ref + keepalive
|
return_value_policy::reference_internal // ref + keepalive
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def("__iter__",
|
cl.def(
|
||||||
|
"__iter__",
|
||||||
[](Vector &v) {
|
[](Vector &v) {
|
||||||
return make_iterator<
|
return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(
|
||||||
return_value_policy::reference_internal, ItType, ItType, T&>(
|
|
||||||
v.begin(), v.end());
|
v.begin(), v.end());
|
||||||
},
|
},
|
||||||
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
||||||
@ -328,95 +351,128 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
|
|||||||
using SizeType = typename Vector::size_type;
|
using SizeType = typename Vector::size_type;
|
||||||
using DiffType = typename Vector::difference_type;
|
using DiffType = typename Vector::difference_type;
|
||||||
using ItType = typename Vector::iterator;
|
using ItType = typename Vector::iterator;
|
||||||
cl.def("__getitem__",
|
cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
|
||||||
[](const Vector &v, DiffType i) -> T {
|
if (i < 0 && (i += v.size()) < 0) {
|
||||||
if (i < 0 && (i += v.size()) < 0)
|
|
||||||
throw index_error();
|
throw index_error();
|
||||||
if ((SizeType)i >= v.size())
|
|
||||||
throw index_error();
|
|
||||||
return v[(SizeType)i];
|
|
||||||
}
|
}
|
||||||
);
|
if ((SizeType) i >= v.size()) {
|
||||||
|
throw index_error();
|
||||||
|
}
|
||||||
|
return v[(SizeType) i];
|
||||||
|
});
|
||||||
|
|
||||||
cl.def("__iter__",
|
cl.def(
|
||||||
|
"__iter__",
|
||||||
[](Vector &v) {
|
[](Vector &v) {
|
||||||
return make_iterator<
|
return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());
|
||||||
return_value_policy::copy, ItType, ItType, T>(
|
|
||||||
v.begin(), v.end());
|
|
||||||
},
|
},
|
||||||
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
|
template <typename Vector, typename Class_>
|
||||||
-> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) {
|
auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||||
|
-> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),
|
||||||
|
void()) {
|
||||||
using size_type = typename Vector::size_type;
|
using size_type = typename Vector::size_type;
|
||||||
|
|
||||||
cl.def("__repr__",
|
cl.def(
|
||||||
|
"__repr__",
|
||||||
[name](Vector &v) {
|
[name](Vector &v) {
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << name << '[';
|
s << name << '[';
|
||||||
for (size_type i=0; i < v.size(); ++i) {
|
for (size_type i = 0; i < v.size(); ++i) {
|
||||||
s << v[i];
|
s << v[i];
|
||||||
if (i != v.size() - 1)
|
if (i != v.size() - 1) {
|
||||||
s << ", ";
|
s << ", ";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
s << ']';
|
s << ']';
|
||||||
return s.str();
|
return s.str();
|
||||||
},
|
},
|
||||||
"Return the canonical string representation of this list."
|
"Return the canonical string representation of this list.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide the buffer interface for vectors if we have data() and we have a format for it
|
// Provide the buffer interface for vectors if we have data() and we have a format for it
|
||||||
// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer
|
// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data()
|
||||||
|
// is insufficient, we need to check it returns an appropriate pointer
|
||||||
template <typename Vector, typename = void>
|
template <typename Vector, typename = void>
|
||||||
struct vector_has_data_and_format : std::false_type {};
|
struct vector_has_data_and_format : std::false_type {};
|
||||||
template <typename Vector>
|
template <typename Vector>
|
||||||
struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
|
struct vector_has_data_and_format<
|
||||||
|
Vector,
|
||||||
|
enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(),
|
||||||
|
std::declval<Vector>().data()),
|
||||||
|
typename Vector::value_type *>::value>> : std::true_type {};
|
||||||
|
|
||||||
|
// [workaround(intel)] Separate function required here
|
||||||
|
// Workaround as the Intel compiler does not compile the enable_if_t part below
|
||||||
|
// (tested with icc (ICC) 2021.1 Beta 20200827)
|
||||||
|
template <typename... Args>
|
||||||
|
constexpr bool args_any_are_buffer() {
|
||||||
|
return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [workaround(intel)] Separate function required here
|
||||||
|
// [workaround(msvc)] Can't use constexpr bool in return type
|
||||||
|
|
||||||
// Add the buffer interface to a vector
|
// Add the buffer interface to a vector
|
||||||
template <typename Vector, typename Class_, typename... Args>
|
template <typename Vector, typename Class_, typename... Args>
|
||||||
enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value>
|
void vector_buffer_impl(Class_ &cl, std::true_type) {
|
||||||
vector_buffer(Class_& cl) {
|
|
||||||
using T = typename Vector::value_type;
|
using T = typename Vector::value_type;
|
||||||
|
|
||||||
static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
|
static_assert(vector_has_data_and_format<Vector>::value,
|
||||||
|
"There is not an appropriate format descriptor for this vector");
|
||||||
|
|
||||||
// numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
|
// numpy.h declares this for arbitrary types, but it may raise an exception and crash hard
|
||||||
|
// at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
|
||||||
format_descriptor<T>::format();
|
format_descriptor<T>::format();
|
||||||
|
|
||||||
cl.def_buffer([](Vector& v) -> buffer_info {
|
cl.def_buffer([](Vector &v) -> buffer_info {
|
||||||
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
|
return buffer_info(v.data(),
|
||||||
|
static_cast<ssize_t>(sizeof(T)),
|
||||||
|
format_descriptor<T>::format(),
|
||||||
|
1,
|
||||||
|
{v.size()},
|
||||||
|
{sizeof(T)});
|
||||||
});
|
});
|
||||||
|
|
||||||
cl.def(init([](buffer buf) {
|
cl.def(init([](const buffer &buf) {
|
||||||
auto info = buf.request();
|
auto info = buf.request();
|
||||||
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
|
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) {
|
||||||
throw type_error("Only valid 1D buffers can be copied to a vector");
|
throw type_error("Only valid 1D buffers can be copied to a vector");
|
||||||
if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
|
}
|
||||||
throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
|
if (!detail::compare_buffer_info<T>::compare(info)
|
||||||
|
|| (ssize_t) sizeof(T) != info.itemsize) {
|
||||||
|
throw type_error("Format mismatch (Python: " + info.format
|
||||||
|
+ " C++: " + format_descriptor<T>::format() + ")");
|
||||||
|
}
|
||||||
|
|
||||||
T *p = static_cast<T*>(info.ptr);
|
T *p = static_cast<T *>(info.ptr);
|
||||||
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
||||||
T *end = p + info.shape[0] * step;
|
T *end = p + info.shape[0] * step;
|
||||||
if (step == 1) {
|
if (step == 1) {
|
||||||
return Vector(p, end);
|
return Vector(p, end);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Vector vec;
|
Vector vec;
|
||||||
vec.reserve((size_t) info.shape[0]);
|
vec.reserve((size_t) info.shape[0]);
|
||||||
for (; p != end; p += step)
|
for (; p != end; p += step) {
|
||||||
vec.push_back(*p);
|
vec.push_back(*p);
|
||||||
return vec;
|
|
||||||
}
|
}
|
||||||
|
return vec;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Vector, typename Class_, typename... Args>
|
template <typename Vector, typename Class_, typename... Args>
|
||||||
enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {}
|
void vector_buffer_impl(Class_ &, std::false_type) {}
|
||||||
|
|
||||||
|
template <typename Vector, typename Class_, typename... Args>
|
||||||
|
void vector_buffer(Class_ &cl) {
|
||||||
|
vector_buffer_impl<Vector, Class_, Args...>(
|
||||||
|
cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
@ -424,13 +480,13 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
// std::vector
|
// std::vector
|
||||||
//
|
//
|
||||||
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
|
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
|
||||||
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
|
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {
|
||||||
using Class_ = class_<Vector, holder_type>;
|
using Class_ = class_<Vector, holder_type>;
|
||||||
|
|
||||||
// If the value_type is unregistered (e.g. a converting type) or is itself registered
|
// If the value_type is unregistered (e.g. a converting type) or is itself registered
|
||||||
// module-local then make the vector binding module-local as well:
|
// module-local then make the vector binding module-local as well:
|
||||||
using vtype = typename Vector::value_type;
|
using vtype = typename Vector::value_type;
|
||||||
auto vtype_info = detail::get_type_info(typeid(vtype));
|
auto *vtype_info = detail::get_type_info(typeid(vtype));
|
||||||
bool local = !vtype_info || vtype_info->module_local;
|
bool local = !vtype_info || vtype_info->module_local;
|
||||||
|
|
||||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||||
@ -455,18 +511,13 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
|
|||||||
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
|
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
|
||||||
detail::vector_accessor<Vector, Class_>(cl);
|
detail::vector_accessor<Vector, Class_>(cl);
|
||||||
|
|
||||||
cl.def("__bool__",
|
cl.def(
|
||||||
[](const Vector &v) -> bool {
|
"__bool__",
|
||||||
return !v.empty();
|
[](const Vector &v) -> bool { return !v.empty(); },
|
||||||
},
|
"Check whether the list is nonempty");
|
||||||
"Check whether the list is nonempty"
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__len__", &Vector::size);
|
cl.def("__len__", &Vector::size);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// C++ style functions deprecated, leaving it here as an example
|
// C++ style functions deprecated, leaving it here as an example
|
||||||
cl.def(init<size_type>());
|
cl.def(init<size_type>());
|
||||||
@ -510,8 +561,6 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
|
|||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// std::map, std::unordered_map
|
// std::map, std::unordered_map
|
||||||
//
|
//
|
||||||
@ -519,81 +568,104 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
|
|||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
/* Fallback functions */
|
/* Fallback functions */
|
||||||
template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { }
|
template <typename, typename, typename... Args>
|
||||||
template <typename, typename, typename... Args> void map_assignment(const Args &...) { }
|
void map_if_insertion_operator(const Args &...) {}
|
||||||
|
template <typename, typename, typename... Args>
|
||||||
|
void map_assignment(const Args &...) {}
|
||||||
|
|
||||||
// Map assignment when copy-assignable: just copy the value
|
// Map assignment when copy-assignable: just copy the value
|
||||||
template <typename Map, typename Class_>
|
template <typename Map, typename Class_>
|
||||||
void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
|
void map_assignment(
|
||||||
|
enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
|
||||||
using KeyType = typename Map::key_type;
|
using KeyType = typename Map::key_type;
|
||||||
using MappedType = typename Map::mapped_type;
|
using MappedType = typename Map::mapped_type;
|
||||||
|
|
||||||
cl.def("__setitem__",
|
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
|
||||||
[](Map &m, const KeyType &k, const MappedType &v) {
|
|
||||||
auto it = m.find(k);
|
auto it = m.find(k);
|
||||||
if (it != m.end()) it->second = v;
|
if (it != m.end()) {
|
||||||
else m.emplace(k, v);
|
it->second = v;
|
||||||
|
} else {
|
||||||
|
m.emplace(k, v);
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting
|
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and
|
||||||
template<typename Map, typename Class_>
|
// reinserting
|
||||||
void map_assignment(enable_if_t<
|
template <typename Map, typename Class_>
|
||||||
!is_copy_assignable<typename Map::mapped_type>::value &&
|
void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value
|
||||||
is_copy_constructible<typename Map::mapped_type>::value,
|
&& is_copy_constructible<typename Map::mapped_type>::value,
|
||||||
Class_> &cl) {
|
Class_> &cl) {
|
||||||
using KeyType = typename Map::key_type;
|
using KeyType = typename Map::key_type;
|
||||||
using MappedType = typename Map::mapped_type;
|
using MappedType = typename Map::mapped_type;
|
||||||
|
|
||||||
cl.def("__setitem__",
|
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
|
||||||
[](Map &m, const KeyType &k, const MappedType &v) {
|
|
||||||
// We can't use m[k] = v; because value type might not be default constructable
|
// We can't use m[k] = v; because value type might not be default constructable
|
||||||
auto r = m.emplace(k, v);
|
auto r = m.emplace(k, v);
|
||||||
if (!r.second) {
|
if (!r.second) {
|
||||||
// value type is not copy assignable so the only way to insert it is to erase it first...
|
// value type is not copy assignable so the only way to insert it is to erase it
|
||||||
|
// first...
|
||||||
m.erase(r.first);
|
m.erase(r.first);
|
||||||
m.emplace(k, v);
|
m.emplace(k, v);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Map, typename Class_>
|
||||||
|
auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||||
|
-> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()
|
||||||
|
<< std::declval<typename Map::mapped_type>(),
|
||||||
|
void()) {
|
||||||
|
|
||||||
template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
cl.def(
|
||||||
-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) {
|
"__repr__",
|
||||||
|
|
||||||
cl.def("__repr__",
|
|
||||||
[name](Map &m) {
|
[name](Map &m) {
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << name << '{';
|
s << name << '{';
|
||||||
bool f = false;
|
bool f = false;
|
||||||
for (auto const &kv : m) {
|
for (auto const &kv : m) {
|
||||||
if (f)
|
if (f) {
|
||||||
s << ", ";
|
s << ", ";
|
||||||
|
}
|
||||||
s << kv.first << ": " << kv.second;
|
s << kv.first << ": " << kv.second;
|
||||||
f = true;
|
f = true;
|
||||||
}
|
}
|
||||||
s << '}';
|
s << '}';
|
||||||
return s.str();
|
return s.str();
|
||||||
},
|
},
|
||||||
"Return the canonical string representation of this map."
|
"Return the canonical string representation of this map.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
struct keys_view {
|
||||||
|
Map ↦
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
struct values_view {
|
||||||
|
Map ↦
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
struct items_view {
|
||||||
|
Map ↦
|
||||||
|
};
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
|
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
|
||||||
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
|
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
||||||
using KeyType = typename Map::key_type;
|
using KeyType = typename Map::key_type;
|
||||||
using MappedType = typename Map::mapped_type;
|
using MappedType = typename Map::mapped_type;
|
||||||
|
using KeysView = detail::keys_view<Map>;
|
||||||
|
using ValuesView = detail::values_view<Map>;
|
||||||
|
using ItemsView = detail::items_view<Map>;
|
||||||
using Class_ = class_<Map, holder_type>;
|
using Class_ = class_<Map, holder_type>;
|
||||||
|
|
||||||
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
||||||
// otherwise (e.g. both types are either module-local or converting) the map will be
|
// otherwise (e.g. both types are either module-local or converting) the map will be
|
||||||
// module-local.
|
// module-local.
|
||||||
auto tinfo = detail::get_type_info(typeid(MappedType));
|
auto *tinfo = detail::get_type_info(typeid(MappedType));
|
||||||
bool local = !tinfo || tinfo->module_local;
|
bool local = !tinfo || tinfo->module_local;
|
||||||
if (local) {
|
if (local) {
|
||||||
tinfo = detail::get_type_info(typeid(KeyType));
|
tinfo = detail::get_type_info(typeid(KeyType));
|
||||||
@ -601,60 +673,112 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
|
|||||||
}
|
}
|
||||||
|
|
||||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||||
|
class_<KeysView> keys_view(
|
||||||
|
scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local));
|
||||||
|
class_<ValuesView> values_view(
|
||||||
|
scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local));
|
||||||
|
class_<ItemsView> items_view(
|
||||||
|
scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local));
|
||||||
|
|
||||||
cl.def(init<>());
|
cl.def(init<>());
|
||||||
|
|
||||||
// Register stream insertion operator (if possible)
|
// Register stream insertion operator (if possible)
|
||||||
detail::map_if_insertion_operator<Map, Class_>(cl, name);
|
detail::map_if_insertion_operator<Map, Class_>(cl, name);
|
||||||
|
|
||||||
cl.def("__bool__",
|
cl.def(
|
||||||
|
"__bool__",
|
||||||
[](const Map &m) -> bool { return !m.empty(); },
|
[](const Map &m) -> bool { return !m.empty(); },
|
||||||
"Check whether the map is nonempty"
|
"Check whether the map is nonempty");
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__iter__",
|
cl.def(
|
||||||
|
"__iter__",
|
||||||
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
|
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
|
||||||
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def("items",
|
cl.def(
|
||||||
[](Map &m) { return make_iterator(m.begin(), m.end()); },
|
"keys",
|
||||||
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
[](Map &m) { return KeysView{m}; },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def("__getitem__",
|
cl.def(
|
||||||
|
"values",
|
||||||
|
[](Map &m) { return ValuesView{m}; },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def(
|
||||||
|
"items",
|
||||||
|
[](Map &m) { return ItemsView{m}; },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
|
);
|
||||||
|
|
||||||
|
cl.def(
|
||||||
|
"__getitem__",
|
||||||
[](Map &m, const KeyType &k) -> MappedType & {
|
[](Map &m, const KeyType &k) -> MappedType & {
|
||||||
auto it = m.find(k);
|
auto it = m.find(k);
|
||||||
if (it == m.end())
|
if (it == m.end()) {
|
||||||
throw key_error();
|
throw key_error();
|
||||||
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
},
|
},
|
||||||
return_value_policy::reference_internal // ref + keepalive
|
return_value_policy::reference_internal // ref + keepalive
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def("__contains__",
|
cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
|
||||||
[](Map &m, const KeyType &k) -> bool {
|
|
||||||
auto it = m.find(k);
|
auto it = m.find(k);
|
||||||
if (it == m.end())
|
if (it == m.end()) {
|
||||||
return false;
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
);
|
return true;
|
||||||
|
});
|
||||||
|
// Fallback for when the object is not of the key type
|
||||||
|
cl.def("__contains__", [](Map &, const object &) -> bool { return false; });
|
||||||
|
|
||||||
// Assignment provided only if the type is copyable
|
// Assignment provided only if the type is copyable
|
||||||
detail::map_assignment<Map, Class_>(cl);
|
detail::map_assignment<Map, Class_>(cl);
|
||||||
|
|
||||||
cl.def("__delitem__",
|
cl.def("__delitem__", [](Map &m, const KeyType &k) {
|
||||||
[](Map &m, const KeyType &k) {
|
|
||||||
auto it = m.find(k);
|
auto it = m.find(k);
|
||||||
if (it == m.end())
|
if (it == m.end()) {
|
||||||
throw key_error();
|
throw key_error();
|
||||||
m.erase(it);
|
|
||||||
}
|
}
|
||||||
);
|
m.erase(it);
|
||||||
|
});
|
||||||
|
|
||||||
cl.def("__len__", &Map::size);
|
cl.def("__len__", &Map::size);
|
||||||
|
|
||||||
|
keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
|
||||||
|
keys_view.def(
|
||||||
|
"__iter__",
|
||||||
|
[](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||||
|
);
|
||||||
|
keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
|
||||||
|
auto it = view.map.find(k);
|
||||||
|
if (it == view.map.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
// Fallback for when the object is not of the key type
|
||||||
|
keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });
|
||||||
|
|
||||||
|
values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
|
||||||
|
values_view.def(
|
||||||
|
"__iter__",
|
||||||
|
[](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||||
|
);
|
||||||
|
|
||||||
|
items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
|
||||||
|
items_view.def(
|
||||||
|
"__iter__",
|
||||||
|
[](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
|
||||||
|
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||||
|
);
|
||||||
|
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
107
3rdparty/pybind11/noxfile.py
vendored
Normal file
107
3rdparty/pybind11/noxfile.py
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import nox
|
||||||
|
|
||||||
|
nox.needs_version = ">=2022.1.7"
|
||||||
|
nox.options.sessions = ["lint", "tests", "tests_packaging"]
|
||||||
|
|
||||||
|
PYTHON_VERSIONS = [
|
||||||
|
"3.6",
|
||||||
|
"3.7",
|
||||||
|
"3.8",
|
||||||
|
"3.9",
|
||||||
|
"3.10",
|
||||||
|
"3.11",
|
||||||
|
"pypy3.7",
|
||||||
|
"pypy3.8",
|
||||||
|
"pypy3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
if os.environ.get("CI", None):
|
||||||
|
nox.options.error_on_missing_interpreters = True
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(reuse_venv=True)
|
||||||
|
def lint(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Lint the codebase (except for clang-format/tidy).
|
||||||
|
"""
|
||||||
|
session.install("pre-commit")
|
||||||
|
session.run("pre-commit", "run", "-a", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(python=PYTHON_VERSIONS)
|
||||||
|
def tests(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Run the tests (requires a compiler).
|
||||||
|
"""
|
||||||
|
tmpdir = session.create_tmp()
|
||||||
|
session.install("cmake")
|
||||||
|
session.install("-r", "tests/requirements.txt")
|
||||||
|
session.run(
|
||||||
|
"cmake",
|
||||||
|
"-S.",
|
||||||
|
f"-B{tmpdir}",
|
||||||
|
"-DPYBIND11_WERROR=ON",
|
||||||
|
"-DDOWNLOAD_CATCH=ON",
|
||||||
|
"-DDOWNLOAD_EIGEN=ON",
|
||||||
|
*session.posargs,
|
||||||
|
)
|
||||||
|
session.run("cmake", "--build", tmpdir)
|
||||||
|
session.run("cmake", "--build", tmpdir, "--config=Release", "--target", "check")
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session
|
||||||
|
def tests_packaging(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Run the packaging tests.
|
||||||
|
"""
|
||||||
|
|
||||||
|
session.install("-r", "tests/requirements.txt", "--prefer-binary")
|
||||||
|
session.run("pytest", "tests/extra_python_package", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(reuse_venv=True)
|
||||||
|
def docs(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Build the docs. Pass "serve" to serve.
|
||||||
|
"""
|
||||||
|
|
||||||
|
session.install("-r", "docs/requirements.txt")
|
||||||
|
session.chdir("docs")
|
||||||
|
|
||||||
|
if "pdf" in session.posargs:
|
||||||
|
session.run("sphinx-build", "-M", "latexpdf", ".", "_build")
|
||||||
|
return
|
||||||
|
|
||||||
|
session.run("sphinx-build", "-M", "html", ".", "_build")
|
||||||
|
|
||||||
|
if "serve" in session.posargs:
|
||||||
|
session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit")
|
||||||
|
session.run("python", "-m", "http.server", "8000", "-d", "_build/html")
|
||||||
|
elif session.posargs:
|
||||||
|
session.error("Unsupported argument to docs")
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(reuse_venv=True)
|
||||||
|
def make_changelog(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Inspect the closed issues and make entries for a changelog.
|
||||||
|
"""
|
||||||
|
session.install("ghapi", "rich")
|
||||||
|
session.run("python", "tools/make_changelog.py")
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(reuse_venv=True)
|
||||||
|
def build(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Build SDists and wheels.
|
||||||
|
"""
|
||||||
|
|
||||||
|
session.install("build")
|
||||||
|
session.log("Building normal files")
|
||||||
|
session.run("python", "-m", "build", *session.posargs)
|
||||||
|
session.log("Building pybind11-global files (PYBIND11_GLOBAL_SDIST=1)")
|
||||||
|
session.run(
|
||||||
|
"python", "-m", "build", *session.posargs, env={"PYBIND11_GLOBAL_SDIST": "1"}
|
||||||
|
)
|
11
3rdparty/pybind11/pybind11/__init__.py
vendored
11
3rdparty/pybind11/pybind11/__init__.py
vendored
@ -1,12 +1,17 @@
|
|||||||
# -*- coding: utf-8 -*-
|
import sys
|
||||||
|
|
||||||
from ._version import version_info, __version__
|
if sys.version_info < (3, 6):
|
||||||
from .commands import get_include, get_cmake_dir
|
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 .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
"version_info",
|
"version_info",
|
||||||
"__version__",
|
"__version__",
|
||||||
"get_include",
|
"get_include",
|
||||||
"get_cmake_dir",
|
"get_cmake_dir",
|
||||||
|
"get_pkgconfig_dir",
|
||||||
)
|
)
|
||||||
|
18
3rdparty/pybind11/pybind11/__main__.py
vendored
18
3rdparty/pybind11/pybind11/__main__.py
vendored
@ -1,15 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# pylint: disable=missing-function-docstring
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
|
|
||||||
from .commands import get_include, get_cmake_dir
|
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
||||||
|
|
||||||
|
|
||||||
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(
|
||||||
@ -39,6 +36,11 @@ def main():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
|
help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--pkgconfigdir",
|
||||||
|
action="store_true",
|
||||||
|
help="Print the pkgconfig directory, ideal for setting $PKG_CONFIG_PATH.",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if not sys.argv[1:]:
|
if not sys.argv[1:]:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
@ -46,6 +48,8 @@ def main():
|
|||||||
print_includes()
|
print_includes()
|
||||||
if args.cmakedir:
|
if args.cmakedir:
|
||||||
print(get_cmake_dir())
|
print(get_cmake_dir())
|
||||||
|
if args.pkgconfigdir:
|
||||||
|
print(get_pkgconfig_dir())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
6
3rdparty/pybind11/pybind11/_version.py
vendored
6
3rdparty/pybind11/pybind11/_version.py
vendored
@ -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.6.1"
|
__version__ = "2.11.0.dev1"
|
||||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||||
|
29
3rdparty/pybind11/pybind11/commands.py
vendored
29
3rdparty/pybind11/pybind11/commands.py
vendored
@ -1,22 +1,37 @@
|
|||||||
# -*- 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)
|
||||||
|
|
||||||
|
|
||||||
|
def get_pkgconfig_dir() -> str:
|
||||||
|
"""
|
||||||
|
Return the path to the pybind11 pkgconfig directory.
|
||||||
|
"""
|
||||||
|
pkgconfig_installed_path = os.path.join(DIR, "share", "pkgconfig")
|
||||||
|
if os.path.exists(pkgconfig_installed_path):
|
||||||
|
return pkgconfig_installed_path
|
||||||
|
|
||||||
|
msg = "pybind11 not installed, installation required to access the pkgconfig files"
|
||||||
|
raise ImportError(msg)
|
||||||
|
276
3rdparty/pybind11/pybind11/setup_helpers.py
vendored
276
3rdparty/pybind11/pybind11/setup_helpers.py
vendored
@ -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.
|
||||||
|
|
||||||
@ -41,26 +39,40 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
import sysconfig
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import platform
|
|
||||||
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.command.build_ext import build_ext as _build_ext
|
|
||||||
from setuptools import Extension as _Extension
|
from setuptools import Extension as _Extension
|
||||||
|
from setuptools.command.build_ext import build_ext as _build_ext
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.command.build_ext import build_ext as _build_ext
|
from distutils.command.build_ext import build_ext as _build_ext
|
||||||
from distutils.extension import Extension as _Extension
|
from distutils.extension import Extension as _Extension
|
||||||
|
|
||||||
import distutils.errors
|
|
||||||
import distutils.ccompiler
|
import distutils.ccompiler
|
||||||
|
import distutils.errors
|
||||||
|
|
||||||
|
WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform()
|
||||||
WIN = sys.platform.startswith("win32")
|
|
||||||
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++{}"
|
||||||
|
|
||||||
@ -72,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
|
||||||
@ -84,7 +96,7 @@ class Pybind11Extension(_Extension):
|
|||||||
* ``stdlib=libc++`` on macOS
|
* ``stdlib=libc++`` on macOS
|
||||||
* ``visibility=hidden`` and ``-g0`` on Unix
|
* ``visibility=hidden`` and ``-g0`` on Unix
|
||||||
|
|
||||||
Finally, you can set ``cxx_std`` via constructor or afterwords to enable
|
Finally, you can set ``cxx_std`` via constructor or afterwards to enable
|
||||||
flags for C++ std, and a few extra helper flags related to the C++ standard
|
flags for C++ std, and a few extra helper flags related to the C++ standard
|
||||||
level. It is _highly_ recommended you either set this, or use the provided
|
level. It is _highly_ recommended you either set this, or use the provided
|
||||||
``build_ext``, which will search for the highest supported extension for
|
``build_ext``, which will search for the highest supported extension for
|
||||||
@ -94,22 +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.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _add_cflags(self, *flags):
|
# flags are prepended, so that they can be further overridden, e.g. by
|
||||||
for flag in flags:
|
# ``extra_compile_args=["-g"]``.
|
||||||
if flag not in self.extra_compile_args:
|
|
||||||
self.extra_compile_args.append(flag)
|
|
||||||
|
|
||||||
def _add_lflags(self, *flags):
|
def _add_cflags(self, flags: List[str]) -> None:
|
||||||
for flag in flags:
|
self.extra_compile_args[:0] = flags
|
||||||
if flag not in self.extra_link_args:
|
|
||||||
self.extra_link_args.append(flag)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def _add_ldflags(self, flags: List[str]) -> None:
|
||||||
|
self.extra_link_args[:0] = flags
|
||||||
|
|
||||||
|
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,33 +139,41 @@ 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 = []
|
||||||
|
ldflags = []
|
||||||
if WIN:
|
if WIN:
|
||||||
self._add_cflags("/EHsc", "/bigobj")
|
cflags += ["/EHsc", "/bigobj"]
|
||||||
else:
|
else:
|
||||||
self._add_cflags("-fvisibility=hidden", "-g0")
|
cflags += ["-fvisibility=hidden"]
|
||||||
|
env_cflags = os.environ.get("CFLAGS", "")
|
||||||
|
env_cppflags = os.environ.get("CPPFLAGS", "")
|
||||||
|
c_cpp_flags = shlex.split(env_cflags) + shlex.split(env_cppflags)
|
||||||
|
if not any(opt.startswith("-g") for opt in c_cpp_flags):
|
||||||
|
cflags += ["-g0"]
|
||||||
if MACOS:
|
if MACOS:
|
||||||
self._add_cflags("-stdlib=libc++")
|
cflags += ["-stdlib=libc++"]
|
||||||
self._add_lflags("-stdlib=libc++")
|
ldflags += ["-stdlib=libc++"]
|
||||||
|
self._add_cflags(cflags)
|
||||||
|
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!")
|
||||||
@ -174,7 +188,8 @@ class Pybind11Extension(_Extension):
|
|||||||
if not level:
|
if not level:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.extra_compile_args.append(STD_TMPL.format(level))
|
cflags = [STD_TMPL.format(level)]
|
||||||
|
ldflags = []
|
||||||
|
|
||||||
if MACOS and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
|
if MACOS and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
|
||||||
# C++17 requires a higher min version of macOS. An earlier version
|
# C++17 requires a higher min version of macOS. An earlier version
|
||||||
@ -185,28 +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}"
|
||||||
self.extra_compile_args.append(macosx_min)
|
cflags += [macosx_min]
|
||||||
self.extra_link_args.append(macosx_min)
|
ldflags += [macosx_min]
|
||||||
|
|
||||||
if PY2:
|
self._add_cflags(cflags)
|
||||||
if WIN:
|
self._add_ldflags(ldflags)
|
||||||
# Will be ignored on MSVC 2015, where C++17 is not supported so
|
|
||||||
# this flag is not valid.
|
|
||||||
self.extra_compile_args.append("/wd5033")
|
|
||||||
elif level >= 17:
|
|
||||||
self.extra_compile_args.append("-Wno-register")
|
|
||||||
elif level >= 14:
|
|
||||||
self.extra_compile_args.append("-Wno-deprecated-register")
|
|
||||||
|
|
||||||
|
|
||||||
# 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
|
||||||
@ -222,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).
|
||||||
@ -230,12 +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.
|
||||||
f.write("int main (int argc, char **argv) { return 0; }")
|
fname.write_text("int main (int, char **) { return 0; }", encoding="utf-8")
|
||||||
|
|
||||||
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
|
||||||
@ -245,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.
|
||||||
"""
|
"""
|
||||||
@ -253,48 +261,78 @@ 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 naive_recompile(obj, src):
|
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
|
||||||
|
source tree.
|
||||||
|
|
||||||
|
``package_dir`` behaves as in ``setuptools.setup``. If unset, the Python
|
||||||
|
package root parent is determined as the first parent directory that does
|
||||||
|
not contain an ``__init__.py`` file.
|
||||||
|
"""
|
||||||
|
exts = []
|
||||||
|
|
||||||
|
if package_dir is None:
|
||||||
|
for path in paths:
|
||||||
|
parent, _ = os.path.split(path)
|
||||||
|
while os.path.exists(os.path.join(parent, "__init__.py")):
|
||||||
|
parent, _ = os.path.split(parent)
|
||||||
|
relname, _ = os.path.splitext(os.path.relpath(path, parent))
|
||||||
|
qualified_name = relname.replace(os.path.sep, ".")
|
||||||
|
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:
|
||||||
|
msg = (
|
||||||
|
f"path {path} is not a child of any of the directories listed "
|
||||||
|
f"in 'package_dir' ({package_dir})"
|
||||||
|
)
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
return exts
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
@ -303,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.
|
||||||
@ -311,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:
|
||||||
@ -354,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
|
||||||
@ -391,17 +453,19 @@ 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:
|
||||||
import multiprocessing
|
# Importing .synchronize checks for platforms that have some multiprocessing
|
||||||
|
# capabilities but lack semaphores, such as AWS Lambda and Android Termux.
|
||||||
|
import multiprocessing.synchronize
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
except ImportError:
|
except ImportError:
|
||||||
threads = 1
|
threads = 1
|
||||||
@ -414,7 +478,8 @@ class ParallelCompile(object):
|
|||||||
threads = 1
|
threads = 1
|
||||||
|
|
||||||
if threads > 1:
|
if threads > 1:
|
||||||
for _ in ThreadPool(threads).imap_unordered(_single_compile, objects):
|
with ThreadPool(threads) as pool:
|
||||||
|
for _ in pool.imap_unordered(_single_compile, objects):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
for ob in objects:
|
for ob in objects:
|
||||||
@ -424,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]
|
||||||
|
60
3rdparty/pybind11/pyproject.toml
vendored
60
3rdparty/pybind11/pyproject.toml
vendored
@ -1,3 +1,61 @@
|
|||||||
[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]
|
||||||
|
ignore = [
|
||||||
|
"tests/**",
|
||||||
|
"docs/**",
|
||||||
|
"tools/**",
|
||||||
|
"include/**",
|
||||||
|
".*",
|
||||||
|
"pybind11/include/**",
|
||||||
|
"pybind11/share/**",
|
||||||
|
"CMakeLists.txt",
|
||||||
|
"noxfile.py",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
# Needs the compiled .so modules and env.py from tests
|
||||||
|
known_first_party = "env,pybind11_cross_module_tests,pybind11_tests,"
|
||||||
|
# For black compatibility
|
||||||
|
profile = "black"
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
files = ["pybind11"]
|
||||||
|
python_version = "3.6"
|
||||||
|
strict = true
|
||||||
|
show_error_codes = true
|
||||||
|
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
|
||||||
|
warn_unreachable = true
|
||||||
|
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = ["ghapi.*", "setuptools.*"]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
minversion = "6.0"
|
||||||
|
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
|
||||||
|
xfail_strict = true
|
||||||
|
filterwarnings = ["error"]
|
||||||
|
log_cli_level = "info"
|
||||||
|
testpaths = [
|
||||||
|
"tests",
|
||||||
|
]
|
||||||
|
timeout=300
|
||||||
|
|
||||||
|
|
||||||
|
[tool.pylint]
|
||||||
|
master.py-version = "3.6"
|
||||||
|
reports.output-format = "colorized"
|
||||||
|
messages_control.disable = [
|
||||||
|
"design",
|
||||||
|
"fixme",
|
||||||
|
"imports",
|
||||||
|
"line-too-long",
|
||||||
|
"imports",
|
||||||
|
"invalid-name",
|
||||||
|
"protected-access",
|
||||||
|
"missing-module-docstring",
|
||||||
|
]
|
||||||
|
49
3rdparty/pybind11/setup.cfg
vendored
49
3rdparty/pybind11/setup.cfg
vendored
@ -13,13 +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.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
|
||||||
@ -30,42 +30,21 @@ keywords =
|
|||||||
C++11
|
C++11
|
||||||
Python bindings
|
Python bindings
|
||||||
|
|
||||||
|
project_urls =
|
||||||
|
Documentation = https://pybind11.readthedocs.io/
|
||||||
|
Bug Tracker = https://github.com/pybind/pybind11/issues
|
||||||
|
Discussions = https://github.com/pybind/pybind11/discussions
|
||||||
|
Changelog = https://pybind11.readthedocs.io/en/latest/changelog.html
|
||||||
|
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
|
|
||||||
|
|
||||||
[check-manifest]
|
|
||||||
ignore =
|
|
||||||
tests/**
|
|
||||||
docs/**
|
|
||||||
tools/**
|
|
||||||
include/**
|
|
||||||
.appveyor.yml
|
|
||||||
.cmake-format.yaml
|
|
||||||
.gitmodules
|
|
||||||
.pre-commit-config.yaml
|
|
||||||
.readthedocs.yml
|
|
||||||
.clang-tidy
|
|
||||||
pybind11/include/**
|
|
||||||
pybind11/share/**
|
|
||||||
CMakeLists.txt
|
|
||||||
|
|
||||||
|
|
||||||
[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, B903, 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
|
|
||||||
|
|
||||||
[mypy]
|
|
||||||
files = pybind11
|
|
||||||
strict = True
|
|
||||||
|
121
3rdparty/pybind11/setup.py
vendored
121
3rdparty/pybind11/setup.py
vendored
@ -1,5 +1,4 @@
|
|||||||
#!/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
|
||||||
|
|
||||||
@ -10,87 +9,110 @@ 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: Dict[str, str]) -> str:
|
||||||
|
patch_level_serial = matches["PATCH"]
|
||||||
|
serial = None
|
||||||
|
major = int(matches["MAJOR"])
|
||||||
|
minor = int(matches["MINOR"])
|
||||||
|
flds = patch_level_serial.split(".")
|
||||||
|
if flds:
|
||||||
|
patch = int(flds[0])
|
||||||
|
if len(flds) == 1:
|
||||||
|
level = "0"
|
||||||
|
serial = 0
|
||||||
|
elif len(flds) == 2:
|
||||||
|
level_serial = flds[1]
|
||||||
|
for level in ("a", "b", "c", "dev"):
|
||||||
|
if level_serial.startswith(level):
|
||||||
|
serial = int(level_serial[len(level) :])
|
||||||
|
break
|
||||||
|
if serial is None:
|
||||||
|
msg = f'Invalid PYBIND11_VERSION_PATCH: "{patch_level_serial}"'
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
version_hex_str = f"{major:02x}{minor:02x}{patch:02x}{level[:1]}{serial:x}"
|
||||||
|
return f"0x{version_hex_str.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
|
||||||
# files, and the sys.prefix files (CMake and headers).
|
# files, and the sys.prefix files (CMake and headers).
|
||||||
|
|
||||||
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 open("include/pybind11/detail/common.h") 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)
|
||||||
)
|
|
||||||
|
version_hex = matches.get("HEX", "MISSING")
|
||||||
|
exp_version_hex = build_expected_version_hex(matches)
|
||||||
|
if version_hex != exp_version_hex:
|
||||||
|
msg = f"PYBIND11_VERSION_HEX {version_hex} does not match expected value {exp_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:
|
||||||
@ -105,10 +127,23 @@ with remove_output("pybind11/include", "pybind11/share"):
|
|||||||
"-DCMAKE_INSTALL_PREFIX=pybind11",
|
"-DCMAKE_INSTALL_PREFIX=pybind11",
|
||||||
"-DBUILD_TESTING=OFF",
|
"-DBUILD_TESTING=OFF",
|
||||||
"-DPYBIND11_NOPYTHON=ON",
|
"-DPYBIND11_NOPYTHON=ON",
|
||||||
|
"-Dprefix_for_pc_file=${pcfiledir}/../../",
|
||||||
]
|
]
|
||||||
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
if "CMAKE_ARGS" in os.environ:
|
||||||
subprocess.check_call(cmd, **cmake_opts)
|
fcommand = [
|
||||||
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
c
|
||||||
|
for c in os.environ["CMAKE_ARGS"].split()
|
||||||
|
if "DCMAKE_INSTALL_PREFIX" not in c
|
||||||
|
]
|
||||||
|
cmd += fcommand
|
||||||
|
subprocess.run(cmd, check=True, cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||||
|
subprocess.run(
|
||||||
|
["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")
|
||||||
|
323
3rdparty/pybind11/tests/CMakeLists.txt
vendored
323
3rdparty/pybind11/tests/CMakeLists.txt
vendored
@ -10,27 +10,34 @@ cmake_minimum_required(VERSION 3.4)
|
|||||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
|
||||||
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
|
||||||
# the behavior using the following workaround:
|
# the behavior using the following workaround:
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
if(${CMAKE_VERSION} VERSION_LESS 3.21)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
else()
|
||||||
cmake_policy(VERSION 3.18)
|
cmake_policy(VERSION 3.21)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Only needed for CMake < 3.5 support
|
# Only needed for CMake < 3.5 support
|
||||||
include(CMakeParseArguments)
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
# Filter out items; print an optional message if any items filtered
|
# Filter out items; print an optional message if any items filtered. This ignores extensions.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "")
|
# pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "")
|
||||||
#
|
#
|
||||||
macro(PYBIND11_FILTER_TESTS LISTNAME)
|
macro(pybind11_filter_tests LISTNAME)
|
||||||
cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN})
|
cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN})
|
||||||
set(PYBIND11_FILTER_TESTS_FOUND OFF)
|
set(PYBIND11_FILTER_TESTS_FOUND OFF)
|
||||||
|
# Make a list of the test without any extensions, for easier filtering.
|
||||||
|
set(_TMP_ACTUAL_LIST "${${LISTNAME}};") # enforce ';' at the end to allow matching last item.
|
||||||
|
string(REGEX REPLACE "\\.[^.;]*;" ";" LIST_WITHOUT_EXTENSIONS "${_TMP_ACTUAL_LIST}")
|
||||||
foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS)
|
foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS)
|
||||||
list(FIND ${LISTNAME} ${filename} _FILE_FOUND)
|
string(REGEX REPLACE "\\.[^.]*$" "" filename_no_ext ${filename})
|
||||||
|
# Search in the list without extensions.
|
||||||
|
list(FIND LIST_WITHOUT_EXTENSIONS ${filename_no_ext} _FILE_FOUND)
|
||||||
if(_FILE_FOUND GREATER -1)
|
if(_FILE_FOUND GREATER -1)
|
||||||
list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND})
|
list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND}) # And remove from the list with extensions.
|
||||||
|
list(REMOVE_AT LIST_WITHOUT_EXTENSIONS ${_FILE_FOUND}
|
||||||
|
)# And our search list, to ensure it is in sync.
|
||||||
set(PYBIND11_FILTER_TESTS_FOUND ON)
|
set(PYBIND11_FILTER_TESTS_FOUND ON)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
@ -39,6 +46,26 @@ macro(PYBIND11_FILTER_TESTS LISTNAME)
|
|||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
macro(possibly_uninitialized)
|
||||||
|
foreach(VARNAME ${ARGN})
|
||||||
|
if(NOT DEFINED "${VARNAME}")
|
||||||
|
set("${VARNAME}" "")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Function to add additional targets if any of the provided tests are found.
|
||||||
|
# Needles; Specifies the test names to look for.
|
||||||
|
# Additions; Specifies the additional test targets to add when any of the needles are found.
|
||||||
|
macro(tests_extra_targets needles additions)
|
||||||
|
# Add the index for this relation to the index extra targets map.
|
||||||
|
list(LENGTH PYBIND11_TEST_EXTRA_TARGETS PYBIND11_TEST_EXTRA_TARGETS_LEN)
|
||||||
|
list(APPEND PYBIND11_TEST_EXTRA_TARGETS ${PYBIND11_TEST_EXTRA_TARGETS_LEN})
|
||||||
|
# Add the test names to look for, and the associated test target additions.
|
||||||
|
set(PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${needles})
|
||||||
|
set(PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${additions})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
# New Python support
|
# New Python support
|
||||||
if(DEFINED Python_EXECUTABLE)
|
if(DEFINED Python_EXECUTABLE)
|
||||||
set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
|
set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
|
||||||
@ -67,7 +94,7 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
|||||||
find_package(pybind11 REQUIRED CONFIG)
|
find_package(pybind11 REQUIRED CONFIG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||||
message(STATUS "Setting tests build type to MinSizeRel as none was specified")
|
message(STATUS "Setting tests build type to MinSizeRel as none was specified")
|
||||||
set(CMAKE_BUILD_TYPE
|
set(CMAKE_BUILD_TYPE
|
||||||
MinSizeRel
|
MinSizeRel
|
||||||
@ -84,52 +111,67 @@ if(PYBIND11_CUDA_TESTS)
|
|||||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Full set of test files (you can override these; see below)
|
# Full set of test files (you can override these; see below, overrides ignore extension)
|
||||||
|
# Any test that has no extension is both .py and .cpp, so 'foo' will add 'foo.cpp' and 'foo.py'.
|
||||||
|
# Any test that has an extension is exclusively that and handled as such.
|
||||||
set(PYBIND11_TEST_FILES
|
set(PYBIND11_TEST_FILES
|
||||||
test_async.cpp
|
test_async
|
||||||
test_buffers.cpp
|
test_buffers
|
||||||
test_builtin_casters.cpp
|
test_builtin_casters
|
||||||
test_call_policies.cpp
|
test_call_policies
|
||||||
test_callbacks.cpp
|
test_callbacks
|
||||||
test_chrono.cpp
|
test_chrono
|
||||||
test_class.cpp
|
test_class
|
||||||
test_constants_and_functions.cpp
|
test_const_name
|
||||||
test_copy_move.cpp
|
test_constants_and_functions
|
||||||
test_custom_type_casters.cpp
|
test_copy_move
|
||||||
test_docstring_options.cpp
|
test_custom_type_casters
|
||||||
test_eigen.cpp
|
test_custom_type_setup
|
||||||
test_enum.cpp
|
test_docstring_options
|
||||||
test_eval.cpp
|
test_eigen
|
||||||
test_exceptions.cpp
|
test_enum
|
||||||
test_factory_constructors.cpp
|
test_eval
|
||||||
test_gil_scoped.cpp
|
test_exceptions
|
||||||
test_iostream.cpp
|
test_factory_constructors
|
||||||
test_kwargs_and_defaults.cpp
|
test_gil_scoped
|
||||||
test_local_bindings.cpp
|
test_iostream
|
||||||
test_methods_and_attributes.cpp
|
test_kwargs_and_defaults
|
||||||
test_modules.cpp
|
test_local_bindings
|
||||||
test_multiple_inheritance.cpp
|
test_methods_and_attributes
|
||||||
test_numpy_array.cpp
|
test_modules
|
||||||
test_numpy_dtypes.cpp
|
test_multiple_inheritance
|
||||||
test_numpy_vectorize.cpp
|
test_numpy_array
|
||||||
test_opaque_types.cpp
|
test_numpy_dtypes
|
||||||
test_operator_overloading.cpp
|
test_numpy_vectorize
|
||||||
test_pickling.cpp
|
test_opaque_types
|
||||||
test_pytypes.cpp
|
test_operator_overloading
|
||||||
test_sequences_and_iterators.cpp
|
test_pickling
|
||||||
test_smart_ptr.cpp
|
test_pytypes
|
||||||
test_stl.cpp
|
test_sequences_and_iterators
|
||||||
test_stl_binders.cpp
|
test_smart_ptr
|
||||||
test_tagbased_polymorphic.cpp
|
test_stl
|
||||||
test_union.cpp
|
test_stl_binders
|
||||||
test_virtual_functions.cpp)
|
test_tagbased_polymorphic
|
||||||
|
test_thread
|
||||||
|
test_union
|
||||||
|
test_virtual_functions)
|
||||||
|
|
||||||
# Invoking cmake with something like:
|
# Invoking cmake with something like:
|
||||||
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
|
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
|
||||||
# lets you override the tests that get compiled and run. You can restore to all tests with:
|
# lets you override the tests that get compiled and run. You can restore to all tests with:
|
||||||
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
||||||
if(PYBIND11_TEST_OVERRIDE)
|
if(PYBIND11_TEST_OVERRIDE)
|
||||||
set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
|
# Instead of doing a direct override here, we iterate over the overrides without extension and
|
||||||
|
# match them against entries from the PYBIND11_TEST_FILES, anything that not matches goes into the filter list.
|
||||||
|
string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_OVERRIDE_NO_EXT "${PYBIND11_TEST_OVERRIDE};")
|
||||||
|
string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_FILES_NO_EXT "${PYBIND11_TEST_FILES};")
|
||||||
|
# This allows the override to be done with extensions, preserving backwards compatibility.
|
||||||
|
foreach(test_name ${TEST_FILES_NO_EXT})
|
||||||
|
if(NOT ${test_name} IN_LIST TEST_OVERRIDE_NO_EXT
|
||||||
|
)# If not in the whitelist, add to be filtered out.
|
||||||
|
list(APPEND PYBIND11_TEST_FILTER ${test_name})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# You can also filter tests:
|
# You can also filter tests:
|
||||||
@ -137,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
|
||||||
@ -151,15 +188,47 @@ if(PYBIND11_CUDA_TESTS)
|
|||||||
"Skipping test_constants_and_functions due to incompatible exception specifications")
|
"Skipping test_constants_and_functions due to incompatible exception specifications")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
# Now that the test filtering is complete, we need to split the list into the test for PYTEST
|
||||||
|
# and the list for the cpp targets.
|
||||||
|
set(PYBIND11_CPPTEST_FILES "")
|
||||||
|
set(PYBIND11_PYTEST_FILES "")
|
||||||
|
|
||||||
|
foreach(test_name ${PYBIND11_TEST_FILES})
|
||||||
|
if(test_name MATCHES "\\.py$") # Ends in .py, purely python test.
|
||||||
|
list(APPEND PYBIND11_PYTEST_FILES ${test_name})
|
||||||
|
elseif(test_name MATCHES "\\.cpp$") # Ends in .cpp, purely cpp test.
|
||||||
|
list(APPEND PYBIND11_CPPTEST_FILES ${test_name})
|
||||||
|
elseif(NOT test_name MATCHES "\\.") # No extension specified, assume both, add extension.
|
||||||
|
list(APPEND PYBIND11_PYTEST_FILES ${test_name}.py)
|
||||||
|
list(APPEND PYBIND11_CPPTEST_FILES ${test_name}.cpp)
|
||||||
|
else()
|
||||||
|
message(WARNING "Unhanded test extension in test: ${test_name}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(PYBIND11_TEST_FILES ${PYBIND11_CPPTEST_FILES})
|
||||||
|
list(SORT PYBIND11_PYTEST_FILES)
|
||||||
|
|
||||||
# Contains the set of test files that require pybind11_cross_module_tests to be
|
# Contains the set of test files that require pybind11_cross_module_tests to be
|
||||||
# built; if none of these are built (i.e. because TEST_OVERRIDE is used and
|
# built; if none of these are built (i.e. because TEST_OVERRIDE is used and
|
||||||
# doesn't include them) the second module doesn't get built.
|
# doesn't include them) the second module doesn't get built.
|
||||||
set(PYBIND11_CROSS_MODULE_TESTS test_exceptions.py test_local_bindings.py test_stl.py
|
tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_stl_binders.py"
|
||||||
test_stl_binders.py)
|
"pybind11_cross_module_tests")
|
||||||
|
|
||||||
set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py)
|
# 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")
|
||||||
|
|
||||||
|
set(PYBIND11_EIGEN_REPO
|
||||||
|
"https://gitlab.com/libeigen/eigen.git"
|
||||||
|
CACHE STRING "Eigen repository to use for tests")
|
||||||
|
# Always use a hash for reconfigure speed and security reasons
|
||||||
|
# Include the version number for pretty printing (keep in sync)
|
||||||
|
set(PYBIND11_EIGEN_VERSION_AND_HASH
|
||||||
|
"3.4.0;929bc0e191d0927b1735b9a1ddc0e8b77e3a25ec"
|
||||||
|
CACHE STRING "Eigen version to use for tests, format: VERSION;HASH")
|
||||||
|
|
||||||
|
list(GET PYBIND11_EIGEN_VERSION_AND_HASH 0 PYBIND11_EIGEN_VERSION_STRING)
|
||||||
|
list(GET PYBIND11_EIGEN_VERSION_AND_HASH 1 PYBIND11_EIGEN_VERSION_HASH)
|
||||||
|
|
||||||
# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
|
# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
|
||||||
# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
|
# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
|
||||||
@ -174,22 +243,26 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
|||||||
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
|
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(EIGEN3_VERSION_STRING "3.3.8")
|
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
eigen
|
eigen
|
||||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}"
|
||||||
GIT_TAG ${EIGEN3_VERSION_STRING})
|
GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}")
|
||||||
|
|
||||||
FetchContent_GetProperties(eigen)
|
FetchContent_GetProperties(eigen)
|
||||||
if(NOT eigen_POPULATED)
|
if(NOT eigen_POPULATED)
|
||||||
message(STATUS "Downloading Eigen")
|
message(
|
||||||
|
STATUS
|
||||||
|
"Downloading Eigen ${PYBIND11_EIGEN_VERSION_STRING} (${PYBIND11_EIGEN_VERSION_HASH}) from ${PYBIND11_EIGEN_REPO}"
|
||||||
|
)
|
||||||
FetchContent_Populate(eigen)
|
FetchContent_Populate(eigen)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
|
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
|
||||||
set(EIGEN3_FOUND TRUE)
|
set(EIGEN3_FOUND TRUE)
|
||||||
|
# When getting locally, the version is not visible from a superprojet,
|
||||||
|
# so just force it.
|
||||||
|
set(EIGEN3_VERSION "${PYBIND11_EIGEN_VERSION_STRING}")
|
||||||
|
|
||||||
else()
|
else()
|
||||||
find_package(Eigen3 3.2.7 QUIET CONFIG)
|
find_package(Eigen3 3.2.7 QUIET CONFIG)
|
||||||
@ -217,7 +290,8 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
|||||||
message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
|
message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
|
||||||
else()
|
else()
|
||||||
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
||||||
message(STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN on CMake 3.11+ to download")
|
message(
|
||||||
|
STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -238,10 +312,47 @@ if(Boost_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Check if we need to add -lstdc++fs or -lc++fs or nothing
|
||||||
|
if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17)
|
||||||
|
set(STD_FS_NO_LIB_NEEDED TRUE)
|
||||||
|
elseif(MSVC)
|
||||||
|
set(STD_FS_NO_LIB_NEEDED TRUE)
|
||||||
|
else()
|
||||||
|
file(
|
||||||
|
WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||||
|
"#include <filesystem>\nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}"
|
||||||
|
)
|
||||||
|
try_compile(
|
||||||
|
STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||||
|
COMPILE_DEFINITIONS -std=c++17)
|
||||||
|
try_compile(
|
||||||
|
STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||||
|
COMPILE_DEFINITIONS -std=c++17
|
||||||
|
LINK_LIBRARIES stdc++fs)
|
||||||
|
try_compile(
|
||||||
|
STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||||
|
COMPILE_DEFINITIONS -std=c++17
|
||||||
|
LINK_LIBRARIES c++fs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(${STD_FS_NEEDS_STDCXXFS})
|
||||||
|
set(STD_FS_LIB stdc++fs)
|
||||||
|
elseif(${STD_FS_NEEDS_CXXFS})
|
||||||
|
set(STD_FS_LIB c++fs)
|
||||||
|
elseif(${STD_FS_NO_LIB_NEEDED})
|
||||||
|
set(STD_FS_LIB "")
|
||||||
|
else()
|
||||||
|
message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs")
|
||||||
|
set(STD_FS_LIB "")
|
||||||
|
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}
|
||||||
@ -259,40 +370,35 @@ function(pybind11_enable_warnings target_name)
|
|||||||
target_compile_options(${target_name} PRIVATE /WX)
|
target_compile_options(${target_name} PRIVATE /WX)
|
||||||
elseif(PYBIND11_CUDA_TESTS)
|
elseif(PYBIND11_CUDA_TESTS)
|
||||||
target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings")
|
target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings")
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|IntelLLVM)")
|
||||||
target_compile_options(${target_name} PRIVATE -Werror)
|
target_compile_options(${target_name} PRIVATE -Werror)
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||||
|
if(CMAKE_CXX_STANDARD EQUAL 17) # See PR #3570
|
||||||
|
target_compile_options(${target_name} PRIVATE -Wno-conversion)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
target_compile_options(
|
||||||
|
${target_name}
|
||||||
# Needs to be readded since the ordering requires these to be after the ones above
|
PRIVATE
|
||||||
if(CMAKE_CXX_STANDARD
|
-Werror-all
|
||||||
AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
# "Inlining inhibited by limit max-size", "Inlining inhibited by limit max-total-size"
|
||||||
AND PYTHON_VERSION VERSION_LESS 3.0)
|
-diag-disable 11074,11076)
|
||||||
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()
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
set(test_targets pybind11_tests)
|
set(test_targets pybind11_tests)
|
||||||
|
|
||||||
# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it
|
# Check if any tests need extra targets by iterating through the mappings registered.
|
||||||
foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
|
foreach(i ${PYBIND11_TEST_EXTRA_TARGETS})
|
||||||
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
foreach(needle ${PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${i}})
|
||||||
if(i GREATER -1)
|
if(needle IN_LIST PYBIND11_PYTEST_FILES)
|
||||||
list(APPEND test_targets pybind11_cross_module_tests)
|
# Add all the additional targets to the test list. List join in newer cmake.
|
||||||
break()
|
foreach(extra_target ${PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${i}})
|
||||||
endif()
|
list(APPEND test_targets ${extra_target})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
break() # Breaks out of the needle search, continues with the next mapping.
|
||||||
foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
|
|
||||||
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
|
||||||
if(i GREATER -1)
|
|
||||||
list(APPEND test_targets cross_module_gil_utils)
|
|
||||||
break()
|
|
||||||
endif()
|
endif()
|
||||||
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Support CUDA testing by forcing the target file to compile with NVCC
|
# Support CUDA testing by forcing the target file to compile with NVCC
|
||||||
@ -341,18 +447,31 @@ foreach(target ${test_targets})
|
|||||||
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
|
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(${target} PRIVATE ${STD_FS_LIB})
|
||||||
|
|
||||||
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
||||||
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
|
||||||
|
if(DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||||
string(TOUPPER ${config} config)
|
string(TOUPPER ${config} config)
|
||||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
|
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
# Provide nice organisation in IDEs
|
||||||
|
if(NOT CMAKE_VERSION VERSION_LESS 3.8)
|
||||||
|
source_group(
|
||||||
|
TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
||||||
|
PREFIX "Header Files"
|
||||||
|
FILES ${PYBIND11_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Make sure pytest is found or produce a warning
|
# Make sure pytest is found or produce a warning
|
||||||
pybind11_find_import(pytest VERSION 3.1)
|
pybind11_find_import(pytest VERSION 3.1)
|
||||||
|
|
||||||
@ -370,12 +489,17 @@ endif()
|
|||||||
string(REPLACE "test_" "${CMAKE_CURRENT_SOURCE_DIR}/test_" PYBIND11_ABS_PYTEST_FILES
|
string(REPLACE "test_" "${CMAKE_CURRENT_SOURCE_DIR}/test_" PYBIND11_ABS_PYTEST_FILES
|
||||||
"${PYBIND11_PYTEST_FILES}")
|
"${PYBIND11_PYTEST_FILES}")
|
||||||
|
|
||||||
|
set(PYBIND11_TEST_PREFIX_COMMAND
|
||||||
|
""
|
||||||
|
CACHE STRING "Put this before pytest, use for checkers and such")
|
||||||
|
|
||||||
# A single command to compile and run the tests
|
# A single command to compile and run the tests
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
pytest
|
pytest
|
||||||
COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES}
|
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
|
||||||
|
${PYBIND11_ABS_PYTEST_FILES}
|
||||||
DEPENDS ${test_targets}
|
DEPENDS ${test_targets}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
USES_TERMINAL)
|
USES_TERMINAL)
|
||||||
|
|
||||||
if(PYBIND11_TEST_OVERRIDE)
|
if(PYBIND11_TEST_OVERRIDE)
|
||||||
@ -386,6 +510,27 @@ if(PYBIND11_TEST_OVERRIDE)
|
|||||||
"Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
|
"Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# cmake-format: off
|
||||||
|
add_custom_target(
|
||||||
|
memcheck
|
||||||
|
COMMAND
|
||||||
|
PYTHONMALLOC=malloc
|
||||||
|
valgrind
|
||||||
|
--leak-check=full
|
||||||
|
--show-leak-kinds=definite,indirect
|
||||||
|
--errors-for-leak-kinds=definite,indirect
|
||||||
|
--error-exitcode=1
|
||||||
|
--read-var-info=yes
|
||||||
|
--track-origins=yes
|
||||||
|
--suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-python.supp"
|
||||||
|
--suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-numpy-scipy.supp"
|
||||||
|
--gen-suppressions=all
|
||||||
|
${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES}
|
||||||
|
DEPENDS ${test_targets}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
USES_TERMINAL)
|
||||||
|
# cmake-format: on
|
||||||
|
|
||||||
# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
|
# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
|
||||||
add_custom_target(check DEPENDS pytest)
|
add_custom_target(check DEPENDS pytest)
|
||||||
|
|
||||||
|
31
3rdparty/pybind11/tests/conftest.py
vendored
31
3rdparty/pybind11/tests/conftest.py
vendored
@ -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}"
|
||||||
|
)
|
||||||
|
141
3rdparty/pybind11/tests/constructor_stats.h
vendored
141
3rdparty/pybind11/tests/constructor_stats.h
vendored
@ -56,7 +56,8 @@ from the ConstructorStats instance `.values()` method.
|
|||||||
In some cases, when you need to track instances of a C++ class not registered with pybind11, you
|
In some cases, when you need to track instances of a C++ class not registered with pybind11, you
|
||||||
need to add a function returning the ConstructorStats for the C++ class; this can be done with:
|
need to add a function returning the ConstructorStats for the C++ class; this can be done with:
|
||||||
|
|
||||||
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference)
|
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>,
|
||||||
|
py::return_value_policy::reference)
|
||||||
|
|
||||||
Finally, you can suppress the output messages, but keep the constructor tracking (for
|
Finally, you can suppress the output messages, but keep the constructor tracking (for
|
||||||
inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
|
inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
|
||||||
@ -65,15 +66,18 @@ inspection/testing in python) by using the functions with `print_` replaced with
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
#include <unordered_map>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <typeindex>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class ConstructorStats {
|
class ConstructorStats {
|
||||||
protected:
|
protected:
|
||||||
std::unordered_map<void*, int> _instances; // Need a map rather than set because members can shared address with parents
|
std::unordered_map<void *, int> _instances; // Need a map rather than set because members can
|
||||||
std::list<std::string> _values; // Used to track values (e.g. of value constructors)
|
// shared address with parents
|
||||||
|
std::list<std::string> _values; // Used to track values
|
||||||
|
// (e.g. of value constructors)
|
||||||
public:
|
public:
|
||||||
int default_constructions = 0;
|
int default_constructions = 0;
|
||||||
int copy_constructions = 0;
|
int copy_constructions = 0;
|
||||||
@ -96,26 +100,26 @@ public:
|
|||||||
default_constructions++;
|
default_constructions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void created(void *inst) {
|
void created(void *inst) { ++_instances[inst]; }
|
||||||
++_instances[inst];
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroyed(void *inst) {
|
void destroyed(void *inst) {
|
||||||
if (--_instances[inst] < 0)
|
if (--_instances[inst] < 0) {
|
||||||
throw std::runtime_error("cstats.destroyed() called with unknown "
|
throw std::runtime_error("cstats.destroyed() called with unknown "
|
||||||
"instance; potential double-destruction "
|
"instance; potential double-destruction "
|
||||||
"or a missing cstats.created()");
|
"or a missing cstats.created()");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void gc() {
|
static void gc() {
|
||||||
// Force garbage collection to ensure any pending destructors are invoked:
|
// Force garbage collection to ensure any pending destructors are invoked:
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
PyObject *globals = PyEval_GetGlobals();
|
PyObject *globals = PyEval_GetGlobals();
|
||||||
PyObject *result = PyRun_String(
|
PyObject *result = PyRun_String("import gc\n"
|
||||||
"import gc\n"
|
"for i in range(2):\n"
|
||||||
"for i in range(2):"
|
|
||||||
" gc.collect()\n",
|
" gc.collect()\n",
|
||||||
Py_file_input, globals, globals);
|
Py_file_input,
|
||||||
|
globals,
|
||||||
|
globals);
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
@ -127,15 +131,18 @@ public:
|
|||||||
int alive() {
|
int alive() {
|
||||||
gc();
|
gc();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
for (const auto &p : _instances)
|
for (const auto &p : _instances) {
|
||||||
if (p.second > 0)
|
if (p.second > 0) {
|
||||||
total += p.second;
|
total += p.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
void value() {} // Recursion terminator
|
void value() {} // Recursion terminator
|
||||||
// Takes one or more values, converts them to strings, then stores them.
|
// Takes one or more values, converts them to strings, then stores them.
|
||||||
template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
|
template <typename T, typename... Tmore>
|
||||||
|
void value(const T &v, Tmore &&...args) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << v;
|
oss << v;
|
||||||
_values.push_back(oss.str());
|
_values.push_back(oss.str());
|
||||||
@ -145,19 +152,22 @@ public:
|
|||||||
// Move out stored values
|
// Move out stored values
|
||||||
py::list values() {
|
py::list values() {
|
||||||
py::list l;
|
py::list l;
|
||||||
for (const auto &v : _values) l.append(py::cast(v));
|
for (const auto &v : _values) {
|
||||||
|
l.append(py::cast(v));
|
||||||
|
}
|
||||||
_values.clear();
|
_values.clear();
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets constructor stats from a C++ type index
|
// Gets constructor stats from a C++ type index
|
||||||
static ConstructorStats& get(std::type_index type) {
|
static ConstructorStats &get(std::type_index type) {
|
||||||
static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
|
static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
|
||||||
return all_cstats[type];
|
return all_cstats[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets constructor stats from a C++ type
|
// Gets constructor stats from a C++ type
|
||||||
template <typename T> static ConstructorStats& get() {
|
template <typename T>
|
||||||
|
static ConstructorStats &get() {
|
||||||
#if defined(PYPY_VERSION)
|
#if defined(PYPY_VERSION)
|
||||||
gc();
|
gc();
|
||||||
#endif
|
#endif
|
||||||
@ -165,11 +175,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gets constructor stats from a Python class
|
// Gets constructor stats from a Python class
|
||||||
static ConstructorStats& get(py::object class_) {
|
static ConstructorStats &get(py::object class_) {
|
||||||
auto &internals = py::detail::get_internals();
|
auto &internals = py::detail::get_internals();
|
||||||
const std::type_index *t1 = nullptr, *t2 = nullptr;
|
const std::type_index *t1 = nullptr, *t2 = nullptr;
|
||||||
try {
|
try {
|
||||||
auto *type_info = internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
|
auto *type_info
|
||||||
|
= internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
|
||||||
for (auto &p : internals.registered_types_cpp) {
|
for (auto &p : internals.registered_types_cpp) {
|
||||||
if (p.second == type_info) {
|
if (p.second == type_info) {
|
||||||
if (t1) {
|
if (t1) {
|
||||||
@ -179,17 +190,23 @@ public:
|
|||||||
t1 = &p.first;
|
t1 = &p.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (const std::out_of_range &) {
|
||||||
|
}
|
||||||
|
if (!t1) {
|
||||||
|
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
||||||
}
|
}
|
||||||
catch (const std::out_of_range&) {}
|
|
||||||
if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
|
||||||
auto &cs1 = get(*t1);
|
auto &cs1 = get(*t1);
|
||||||
// If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
|
// If we have both a t1 and t2 match, one is probably the trampoline class; return
|
||||||
// has more constructions (typically one or the other will be 0)
|
// whichever has more constructions (typically one or the other will be 0)
|
||||||
if (t2) {
|
if (t2) {
|
||||||
auto &cs2 = get(*t2);
|
auto &cs2 = get(*t2);
|
||||||
int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
|
int cs1_total = cs1.default_constructions + cs1.copy_constructions
|
||||||
int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
|
+ cs1.move_constructions + (int) cs1._values.size();
|
||||||
if (cs2_total > cs1_total) return cs2;
|
int cs2_total = cs2.default_constructions + cs2.copy_constructions
|
||||||
|
+ cs2.move_constructions + (int) cs2._values.size();
|
||||||
|
if (cs2_total > cs1_total) {
|
||||||
|
return cs2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cs1;
|
return cs1;
|
||||||
}
|
}
|
||||||
@ -198,78 +215,108 @@ public:
|
|||||||
// To track construction/destruction, you need to call these methods from the various
|
// To track construction/destruction, you need to call these methods from the various
|
||||||
// constructors/operators. The ones that take extra values record the given values in the
|
// constructors/operators. The ones that take extra values record the given values in the
|
||||||
// constructor stats values for later inspection.
|
// constructor stats values for later inspection.
|
||||||
template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
|
template <class T>
|
||||||
template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
|
void track_copy_created(T *inst) {
|
||||||
template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
|
ConstructorStats::get<T>().copy_created(inst);
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
void track_move_created(T *inst) {
|
||||||
|
ConstructorStats::get<T>().move_created(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values>
|
||||||
|
void track_copy_assigned(T *, Values &&...values) {
|
||||||
auto &cst = ConstructorStats::get<T>();
|
auto &cst = ConstructorStats::get<T>();
|
||||||
cst.copy_assignments++;
|
cst.copy_assignments++;
|
||||||
cst.value(std::forward<Values>(values)...);
|
cst.value(std::forward<Values>(values)...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void track_move_assigned(T *, Values &&...values) {
|
||||||
auto &cst = ConstructorStats::get<T>();
|
auto &cst = ConstructorStats::get<T>();
|
||||||
cst.move_assignments++;
|
cst.move_assignments++;
|
||||||
cst.value(std::forward<Values>(values)...);
|
cst.value(std::forward<Values>(values)...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void track_default_created(T *inst, Values &&...values) {
|
||||||
auto &cst = ConstructorStats::get<T>();
|
auto &cst = ConstructorStats::get<T>();
|
||||||
cst.default_created(inst);
|
cst.default_created(inst);
|
||||||
cst.value(std::forward<Values>(values)...);
|
cst.value(std::forward<Values>(values)...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void track_created(T *inst, Values &&...values) {
|
||||||
auto &cst = ConstructorStats::get<T>();
|
auto &cst = ConstructorStats::get<T>();
|
||||||
cst.created(inst);
|
cst.created(inst);
|
||||||
cst.value(std::forward<Values>(values)...);
|
cst.value(std::forward<Values>(values)...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void track_destroyed(T *inst) {
|
template <class T, typename... Values>
|
||||||
|
void track_destroyed(T *inst) {
|
||||||
ConstructorStats::get<T>().destroyed(inst);
|
ConstructorStats::get<T>().destroyed(inst);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void track_values(T *, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void track_values(T *, Values &&...values) {
|
||||||
ConstructorStats::get<T>().value(std::forward<Values>(values)...);
|
ConstructorStats::get<T>().value(std::forward<Values>(values)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Don't cast pointers to Python, print them as strings
|
/// Don't cast pointers to Python, print them as strings
|
||||||
inline const char *format_ptrs(const char *p) { return p; }
|
inline const char *format_ptrs(const char *p) { return p; }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p)); }
|
py::str format_ptrs(T *p) {
|
||||||
|
return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p));
|
||||||
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) { return std::forward<T>(x); }
|
auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) {
|
||||||
|
return std::forward<T>(x);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T, typename... Output>
|
template <class T, typename... Output>
|
||||||
void print_constr_details(T *inst, const std::string &action, Output &&...output) {
|
void print_constr_details(T *inst, const std::string &action, Output &&...output) {
|
||||||
py::print("###", py::type_id<T>(), "@", format_ptrs(inst), action,
|
py::print("###",
|
||||||
|
py::type_id<T>(),
|
||||||
|
"@",
|
||||||
|
format_ptrs(inst),
|
||||||
|
action,
|
||||||
format_ptrs(std::forward<Output>(output))...);
|
format_ptrs(std::forward<Output>(output))...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verbose versions of the above:
|
// Verbose versions of the above:
|
||||||
template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
template <class T, typename... Values>
|
||||||
|
void print_copy_created(T *inst,
|
||||||
|
Values &&...values) { // NB: this prints, but doesn't store, given values
|
||||||
print_constr_details(inst, "created via copy constructor", values...);
|
print_constr_details(inst, "created via copy constructor", values...);
|
||||||
track_copy_created(inst);
|
track_copy_created(inst);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
template <class T, typename... Values>
|
||||||
|
void print_move_created(T *inst,
|
||||||
|
Values &&...values) { // NB: this prints, but doesn't store, given values
|
||||||
print_constr_details(inst, "created via move constructor", values...);
|
print_constr_details(inst, "created via move constructor", values...);
|
||||||
track_move_created(inst);
|
track_move_created(inst);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void print_copy_assigned(T *inst, Values &&...values) {
|
||||||
print_constr_details(inst, "assigned via copy assignment", values...);
|
print_constr_details(inst, "assigned via copy assignment", values...);
|
||||||
track_copy_assigned(inst, values...);
|
track_copy_assigned(inst, values...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void print_move_assigned(T *inst, Values &&...values) {
|
||||||
print_constr_details(inst, "assigned via move assignment", values...);
|
print_constr_details(inst, "assigned via move assignment", values...);
|
||||||
track_move_assigned(inst, values...);
|
track_move_assigned(inst, values...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void print_default_created(T *inst, Values &&...values) {
|
||||||
print_constr_details(inst, "created via default constructor", values...);
|
print_constr_details(inst, "created via default constructor", values...);
|
||||||
track_default_created(inst, values...);
|
track_default_created(inst, values...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void print_created(T *inst, Values &&...values) {
|
||||||
print_constr_details(inst, "created", values...);
|
print_constr_details(inst, "created", values...);
|
||||||
track_created(inst, values...);
|
track_created(inst, values...);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
|
template <class T, typename... Values>
|
||||||
|
void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
|
||||||
print_constr_details(inst, "destroyed", values...);
|
print_constr_details(inst, "destroyed", values...);
|
||||||
track_destroyed(inst);
|
track_destroyed(inst);
|
||||||
}
|
}
|
||||||
template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
|
template <class T, typename... Values>
|
||||||
|
void print_values(T *inst, Values &&...values) {
|
||||||
print_constr_details(inst, ":", values...);
|
print_constr_details(inst, ":", values...);
|
||||||
track_values(inst, values...);
|
track_values(inst, values...);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
BSD-style license that can be found in the LICENSE file.
|
BSD-style license that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
// This file mimics a DSO that makes pybind11 calls but does not define a
|
// This file mimics a DSO that makes pybind11 calls but does not define a
|
||||||
@ -24,50 +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,
|
PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||||
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(
|
static_assert(sizeof(&gil_acquire) == sizeof(void *),
|
||||||
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(m, "gil_acquire_funcaddr",
|
PyModule_AddObject(
|
||||||
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
3rdparty/pybind11/tests/cross_module_interleaved_error_already_set.cpp
vendored
Normal file
51
3rdparty/pybind11/tests/cross_module_interleaved_error_already_set.cpp
vendored
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;
|
||||||
|
}
|
20
3rdparty/pybind11/tests/env.py
vendored
20
3rdparty/pybind11/tests/env.py
vendored
@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
LINUX = sys.platform.startswith("linux")
|
LINUX = sys.platform.startswith("linux")
|
||||||
MACOS = sys.platform.startswith("darwin")
|
MACOS = sys.platform.startswith("darwin")
|
||||||
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
||||||
@ -9,6 +10,19 @@ 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():
|
||||||
|
"""
|
||||||
|
pytest.deprecated_call() seems broken in pytest<3.9.x; concretely, it
|
||||||
|
doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922).
|
||||||
|
|
||||||
|
This is a narrowed reimplementation of the following PR :(
|
||||||
|
https://github.com/pytest-dev/pytest/pull/4104
|
||||||
|
"""
|
||||||
|
# TODO: Remove this when testing requires pytest>=3.9.
|
||||||
|
pieces = pytest.__version__.split(".")
|
||||||
|
pytest_major_minor = (int(pieces[0]), int(pieces[1]))
|
||||||
|
if pytest_major_minor < (3, 9):
|
||||||
|
return pytest.warns((DeprecationWarning, PendingDeprecationWarning))
|
||||||
|
else:
|
||||||
|
return pytest.deprecated_call()
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
@ -13,6 +12,16 @@ import zipfile
|
|||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
||||||
|
|
||||||
|
PKGCONFIG = """\
|
||||||
|
prefix=${{pcfiledir}}/../../
|
||||||
|
includedir=${{prefix}}/include
|
||||||
|
|
||||||
|
Name: pybind11
|
||||||
|
Description: Seamless operability between C++11 and Python
|
||||||
|
Version: {VERSION}
|
||||||
|
Cflags: -I${{includedir}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
main_headers = {
|
main_headers = {
|
||||||
"include/pybind11/attr.h",
|
"include/pybind11/attr.h",
|
||||||
@ -25,6 +34,7 @@ main_headers = {
|
|||||||
"include/pybind11/embed.h",
|
"include/pybind11/embed.h",
|
||||||
"include/pybind11/eval.h",
|
"include/pybind11/eval.h",
|
||||||
"include/pybind11/functional.h",
|
"include/pybind11/functional.h",
|
||||||
|
"include/pybind11/gil.h",
|
||||||
"include/pybind11/iostream.h",
|
"include/pybind11/iostream.h",
|
||||||
"include/pybind11/numpy.h",
|
"include/pybind11/numpy.h",
|
||||||
"include/pybind11/operators.h",
|
"include/pybind11/operators.h",
|
||||||
@ -41,9 +51,14 @@ detail_headers = {
|
|||||||
"include/pybind11/detail/descr.h",
|
"include/pybind11/detail/descr.h",
|
||||||
"include/pybind11/detail/init.h",
|
"include/pybind11/detail/init.h",
|
||||||
"include/pybind11/detail/internals.h",
|
"include/pybind11/detail/internals.h",
|
||||||
|
"include/pybind11/detail/type_caster_base.h",
|
||||||
"include/pybind11/detail/typeid.h",
|
"include/pybind11/detail/typeid.h",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stl_headers = {
|
||||||
|
"include/pybind11/stl/filesystem.h",
|
||||||
|
}
|
||||||
|
|
||||||
cmake_files = {
|
cmake_files = {
|
||||||
"share/cmake/pybind11/FindPythonLibsNew.cmake",
|
"share/cmake/pybind11/FindPythonLibsNew.cmake",
|
||||||
"share/cmake/pybind11/pybind11Common.cmake",
|
"share/cmake/pybind11/pybind11Common.cmake",
|
||||||
@ -54,19 +69,21 @@ cmake_files = {
|
|||||||
"share/cmake/pybind11/pybind11Tools.cmake",
|
"share/cmake/pybind11/pybind11Tools.cmake",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pkgconfig_files = {
|
||||||
|
"share/pkgconfig/pybind11.pc",
|
||||||
|
}
|
||||||
|
|
||||||
py_files = {
|
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
|
headers = main_headers | detail_headers | stl_headers
|
||||||
src_files = headers | cmake_files
|
src_files = headers | cmake_files | pkgconfig_files
|
||||||
all_files = src_files | py_files
|
all_files = src_files | py_files
|
||||||
|
|
||||||
|
|
||||||
@ -75,9 +92,11 @@ sdist_files = {
|
|||||||
"pybind11/include",
|
"pybind11/include",
|
||||||
"pybind11/include/pybind11",
|
"pybind11/include/pybind11",
|
||||||
"pybind11/include/pybind11/detail",
|
"pybind11/include/pybind11/detail",
|
||||||
|
"pybind11/include/pybind11/stl",
|
||||||
"pybind11/share",
|
"pybind11/share",
|
||||||
"pybind11/share/cmake",
|
"pybind11/share/cmake",
|
||||||
"pybind11/share/cmake/pybind11",
|
"pybind11/share/cmake/pybind11",
|
||||||
|
"pybind11/share/pkgconfig",
|
||||||
"pyproject.toml",
|
"pyproject.toml",
|
||||||
"setup.cfg",
|
"setup.cfg",
|
||||||
"setup.py",
|
"setup.py",
|
||||||
@ -97,52 +116,57 @@ local_sdist_files = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def read_tz_file(tar: tarfile.TarFile, name: str) -> bytes:
|
||||||
|
start = tar.getnames()[0] + "/"
|
||||||
|
inner_file = tar.extractfile(tar.getmember(f"{start}{name}"))
|
||||||
|
assert inner_file
|
||||||
|
with contextlib.closing(inner_file) as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_line_endings(value: bytes) -> bytes:
|
||||||
|
return value.replace(os.linesep.encode("utf-8"), b"\n")
|
||||||
|
|
||||||
|
|
||||||
def test_build_sdist(monkeypatch, tmpdir):
|
def test_build_sdist(monkeypatch, tmpdir):
|
||||||
|
|
||||||
monkeypatch.chdir(MAIN_DIR)
|
monkeypatch.chdir(MAIN_DIR)
|
||||||
|
|
||||||
out = subprocess.check_output(
|
subprocess.run(
|
||||||
[
|
[sys.executable, "-m", "build", "--sdist", f"--outdir={tmpdir}"], check=True
|
||||||
sys.executable,
|
|
||||||
"setup.py",
|
|
||||||
"sdist",
|
|
||||||
"--formats=tar",
|
|
||||||
"--dist-dir",
|
|
||||||
str(tmpdir),
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
if hasattr(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 = set(n.split("/", 1)[-1] for n in tar.getnames()[1:])
|
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
||||||
|
|
||||||
with contextlib.closing(
|
setup_py = read_tz_file(tar, "setup.py")
|
||||||
tar.extractfile(tar.getmember(start + "setup.py"))
|
pyproject_toml = read_tz_file(tar, "pyproject.toml")
|
||||||
) as f:
|
pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc")
|
||||||
setup_py = f.read()
|
cmake_cfg = read_tz_file(
|
||||||
|
tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake"
|
||||||
|
)
|
||||||
|
|
||||||
with contextlib.closing(
|
assert (
|
||||||
tar.extractfile(tar.getmember(start + "pyproject.toml"))
|
'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")'
|
||||||
) as f:
|
in cmake_cfg.decode("utf-8")
|
||||||
pyproject_toml = f.read()
|
)
|
||||||
|
|
||||||
files = set("pybind11/{}".format(n) for n in all_files)
|
files = {f"pybind11/{n}" for n in all_files}
|
||||||
files |= sdist_files
|
files |= sdist_files
|
||||||
files |= set("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
|
||||||
|
|
||||||
with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f:
|
with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f:
|
||||||
contents = (
|
contents = (
|
||||||
string.Template(f.read().decode())
|
string.Template(f.read().decode("utf-8"))
|
||||||
.substitute(version=version, extra_cmd="")
|
.substitute(version=version, extra_cmd="")
|
||||||
.encode()
|
.encode("utf-8")
|
||||||
)
|
)
|
||||||
assert setup_py == contents
|
assert setup_py == contents
|
||||||
|
|
||||||
@ -150,52 +174,48 @@ def test_build_sdist(monkeypatch, tmpdir):
|
|||||||
contents = f.read()
|
contents = f.read()
|
||||||
assert pyproject_toml == contents
|
assert pyproject_toml == contents
|
||||||
|
|
||||||
|
simple_version = ".".join(version.split(".")[:3])
|
||||||
|
pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8")
|
||||||
|
assert normalize_line_endings(pkgconfig) == pkgconfig_expected
|
||||||
|
|
||||||
|
|
||||||
def test_build_global_dist(monkeypatch, tmpdir):
|
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")
|
||||||
|
subprocess.run(
|
||||||
out = subprocess.check_output(
|
[sys.executable, "-m", "build", "--sdist", "--outdir", str(tmpdir)], check=True
|
||||||
[
|
|
||||||
sys.executable,
|
|
||||||
"setup.py",
|
|
||||||
"sdist",
|
|
||||||
"--formats=tar",
|
|
||||||
"--dist-dir",
|
|
||||||
str(tmpdir),
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
if hasattr(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 = set(n.split("/", 1)[-1] for n in tar.getnames()[1:])
|
simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
|
||||||
|
|
||||||
with contextlib.closing(
|
setup_py = read_tz_file(tar, "setup.py")
|
||||||
tar.extractfile(tar.getmember(start + "setup.py"))
|
pyproject_toml = read_tz_file(tar, "pyproject.toml")
|
||||||
) as f:
|
pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc")
|
||||||
setup_py = f.read()
|
cmake_cfg = read_tz_file(
|
||||||
|
tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake"
|
||||||
|
)
|
||||||
|
|
||||||
with contextlib.closing(
|
assert (
|
||||||
tar.extractfile(tar.getmember(start + "pyproject.toml"))
|
'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")'
|
||||||
) as f:
|
in cmake_cfg.decode("utf-8")
|
||||||
pyproject_toml = f.read()
|
)
|
||||||
|
|
||||||
files = set("pybind11/{}".format(n) for n in all_files)
|
files = {f"pybind11/{n}" for n in all_files}
|
||||||
files |= sdist_files
|
files |= sdist_files
|
||||||
files |= set("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:
|
||||||
contents = (
|
contents = (
|
||||||
string.Template(f.read().decode())
|
string.Template(f.read().decode())
|
||||||
.substitute(version=version, extra_cmd="")
|
.substitute(version=version, extra_cmd="")
|
||||||
.encode()
|
.encode("utf-8")
|
||||||
)
|
)
|
||||||
assert setup_py == contents
|
assert setup_py == contents
|
||||||
|
|
||||||
@ -203,17 +223,21 @@ def test_build_global_dist(monkeypatch, tmpdir):
|
|||||||
contents = f.read()
|
contents = f.read()
|
||||||
assert pyproject_toml == contents
|
assert pyproject_toml == contents
|
||||||
|
|
||||||
|
simple_version = ".".join(version.split(".")[:3])
|
||||||
|
pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8")
|
||||||
|
assert normalize_line_endings(pkgconfig) == pkgconfig_expected
|
||||||
|
|
||||||
|
|
||||||
def tests_build_wheel(monkeypatch, tmpdir):
|
def tests_build_wheel(monkeypatch, tmpdir):
|
||||||
monkeypatch.chdir(MAIN_DIR)
|
monkeypatch.chdir(MAIN_DIR)
|
||||||
|
|
||||||
subprocess.check_output(
|
subprocess.run(
|
||||||
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
|
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True
|
||||||
)
|
)
|
||||||
|
|
||||||
(wheel,) = tmpdir.visit("*.whl")
|
(wheel,) = tmpdir.visit("*.whl")
|
||||||
|
|
||||||
files = set("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",
|
||||||
@ -226,10 +250,8 @@ def tests_build_wheel(monkeypatch, tmpdir):
|
|||||||
with zipfile.ZipFile(str(wheel)) as z:
|
with zipfile.ZipFile(str(wheel)) as z:
|
||||||
names = z.namelist()
|
names = z.namelist()
|
||||||
|
|
||||||
trimmed = set(n for n in names if "dist-info" not in n)
|
trimmed = {n for n in names if "dist-info" not in n}
|
||||||
trimmed |= set(
|
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
|
||||||
|
|
||||||
|
|
||||||
@ -237,14 +259,14 @@ def tests_build_global_wheel(monkeypatch, tmpdir):
|
|||||||
monkeypatch.chdir(MAIN_DIR)
|
monkeypatch.chdir(MAIN_DIR)
|
||||||
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
||||||
|
|
||||||
subprocess.check_output(
|
subprocess.run(
|
||||||
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
|
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True
|
||||||
)
|
)
|
||||||
|
|
||||||
(wheel,) = tmpdir.visit("*.whl")
|
(wheel,) = tmpdir.visit("*.whl")
|
||||||
|
|
||||||
files = set("data/data/{}".format(n) for n in src_files)
|
files = {f"data/data/{n}" for n in src_files}
|
||||||
files |= set("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",
|
||||||
@ -257,6 +279,6 @@ def tests_build_global_wheel(monkeypatch, tmpdir):
|
|||||||
names = z.namelist()
|
names = z.namelist()
|
||||||
|
|
||||||
beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0]
|
beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0]
|
||||||
trimmed = set(n[len(beginning) + 1 :] for n in names)
|
trimmed = {n[len(beginning) + 1 :] for n in names}
|
||||||
|
|
||||||
assert files == trimmed
|
assert files == trimmed
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
||||||
|
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("parallel", [False, True])
|
@pytest.mark.parametrize("parallel", [False, True])
|
||||||
@ -18,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})
|
||||||
|
|
||||||
@ -51,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) {
|
||||||
@ -71,13 +71,20 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
encoding="ascii",
|
encoding="ascii",
|
||||||
)
|
)
|
||||||
|
|
||||||
subprocess.check_call(
|
out = subprocess.check_output(
|
||||||
[sys.executable, "setup.py", "build_ext", "--inplace"],
|
[sys.executable, "setup.py", "build_ext", "--inplace"],
|
||||||
stdout=sys.stdout,
|
|
||||||
stderr=sys.stderr,
|
|
||||||
)
|
)
|
||||||
|
if not WIN:
|
||||||
|
assert b"-g0" in out
|
||||||
|
out = subprocess.check_output(
|
||||||
|
[sys.executable, "setup.py", "build_ext", "--inplace", "--force"],
|
||||||
|
env=dict(os.environ, CFLAGS="-g"),
|
||||||
|
)
|
||||||
|
if not WIN:
|
||||||
|
assert b"-g0" not in out
|
||||||
|
|
||||||
# Debug helper printout, normally hidden
|
# Debug helper printout, normally hidden
|
||||||
|
print(out)
|
||||||
for item in tmpdir.listdir():
|
for item in tmpdir.listdir():
|
||||||
print(item.basename)
|
print(item.basename)
|
||||||
|
|
||||||
@ -88,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
|
||||||
"""
|
"""
|
||||||
@ -99,3 +106,46 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
|
|||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
[sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr
|
[sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_intree_extensions(monkeypatch, tmpdir):
|
||||||
|
monkeypatch.syspath_prepend(MAIN_DIR)
|
||||||
|
|
||||||
|
from pybind11.setup_helpers import intree_extensions
|
||||||
|
|
||||||
|
monkeypatch.chdir(tmpdir)
|
||||||
|
root = tmpdir
|
||||||
|
root.ensure_dir()
|
||||||
|
subdir = root / "dir"
|
||||||
|
subdir.ensure_dir()
|
||||||
|
src = subdir / "ext.cpp"
|
||||||
|
src.ensure()
|
||||||
|
relpath = src.relto(tmpdir)
|
||||||
|
(ext,) = intree_extensions([relpath])
|
||||||
|
assert ext.name == "ext"
|
||||||
|
subdir.ensure("__init__.py")
|
||||||
|
(ext,) = intree_extensions([relpath])
|
||||||
|
assert ext.name == "dir.ext"
|
||||||
|
|
||||||
|
|
||||||
|
def test_intree_extensions_package_dir(monkeypatch, tmpdir):
|
||||||
|
monkeypatch.syspath_prepend(MAIN_DIR)
|
||||||
|
|
||||||
|
from pybind11.setup_helpers import intree_extensions
|
||||||
|
|
||||||
|
monkeypatch.chdir(tmpdir)
|
||||||
|
root = tmpdir / "src"
|
||||||
|
root.ensure_dir()
|
||||||
|
subdir = root / "dir"
|
||||||
|
subdir.ensure_dir()
|
||||||
|
src = subdir / "ext.cpp"
|
||||||
|
src.ensure()
|
||||||
|
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"})
|
||||||
|
assert ext.name == "dir.ext"
|
||||||
|
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"})
|
||||||
|
assert ext.name == "foo.dir.ext"
|
||||||
|
subdir.ensure("__init__.py")
|
||||||
|
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"})
|
||||||
|
assert ext.name == "dir.ext"
|
||||||
|
(ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"})
|
||||||
|
assert ext.name == "foo.dir.ext"
|
||||||
|
52
3rdparty/pybind11/tests/local_bindings.h
vendored
52
3rdparty/pybind11/tests/local_bindings.h
vendored
@ -1,10 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
/// Simple class used to test py::local:
|
/// Simple class used to test py::local:
|
||||||
template <int> class LocalBase {
|
template <int>
|
||||||
|
class LocalBase {
|
||||||
public:
|
public:
|
||||||
LocalBase(int i) : i(i) { }
|
explicit LocalBase(int i) : i(i) {}
|
||||||
int i = -1;
|
int i = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,32 +36,57 @@ using NonLocalVec2 = std::vector<NonLocal2>;
|
|||||||
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
|
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
|
||||||
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
|
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
|
||||||
|
|
||||||
|
// Exception that will be caught via the module local translator.
|
||||||
|
class LocalException : public std::exception {
|
||||||
|
public:
|
||||||
|
explicit LocalException(const char *m) : message{m} {}
|
||||||
|
const char *what() const noexcept override { return message.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exception that will be registered with register_local_exception_translator
|
||||||
|
class LocalSimpleException : public std::exception {
|
||||||
|
public:
|
||||||
|
explicit LocalSimpleException(const char *m) : message{m} {}
|
||||||
|
const char *what() const noexcept override { return message.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message = "";
|
||||||
|
};
|
||||||
|
|
||||||
PYBIND11_MAKE_OPAQUE(LocalVec);
|
PYBIND11_MAKE_OPAQUE(LocalVec);
|
||||||
PYBIND11_MAKE_OPAQUE(LocalVec2);
|
PYBIND11_MAKE_OPAQUE(LocalVec2);
|
||||||
PYBIND11_MAKE_OPAQUE(LocalMap);
|
PYBIND11_MAKE_OPAQUE(LocalMap);
|
||||||
PYBIND11_MAKE_OPAQUE(NonLocalVec);
|
PYBIND11_MAKE_OPAQUE(NonLocalVec);
|
||||||
//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
|
// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
|
||||||
PYBIND11_MAKE_OPAQUE(NonLocalMap);
|
PYBIND11_MAKE_OPAQUE(NonLocalMap);
|
||||||
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
|
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
|
||||||
|
|
||||||
|
|
||||||
// Simple bindings (used with the above):
|
// Simple bindings (used with the above):
|
||||||
template <typename T, int Adjust = 0, typename... Args>
|
template <typename T, int Adjust = 0, typename... Args>
|
||||||
py::class_<T> bind_local(Args && ...args) {
|
py::class_<T> bind_local(Args &&...args) {
|
||||||
return py::class_<T>(std::forward<Args>(args)...)
|
return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
|
||||||
.def(py::init<int>())
|
return i.i + Adjust;
|
||||||
.def("get", [](T &i) { return i.i + Adjust; });
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simulate a foreign library base class (to match the example in the docs):
|
// Simulate a foreign library base class (to match the example in the docs):
|
||||||
namespace pets {
|
namespace pets {
|
||||||
class Pet {
|
class Pet {
|
||||||
public:
|
public:
|
||||||
Pet(std::string name) : name_(name) {}
|
explicit Pet(std::string name) : name_(std::move(name)) {}
|
||||||
std::string name_;
|
std::string name_;
|
||||||
const std::string &name() { return name_; }
|
const std::string &name() const { return name_; }
|
||||||
};
|
};
|
||||||
} // namespace pets
|
} // namespace pets
|
||||||
|
|
||||||
struct MixGL { int i; MixGL(int i) : i{i} {} };
|
struct MixGL {
|
||||||
struct MixGL2 { int i; MixGL2(int i) : i{i} {} };
|
int i;
|
||||||
|
explicit MixGL(int i) : i{i} {}
|
||||||
|
};
|
||||||
|
struct MixGL2 {
|
||||||
|
int i;
|
||||||
|
explicit MixGL2(int i) : i{i} {}
|
||||||
|
};
|
||||||
|
114
3rdparty/pybind11/tests/object.h
vendored
114
3rdparty/pybind11/tests/object.h
vendored
@ -1,8 +1,9 @@
|
|||||||
#if !defined(__OBJECT_H)
|
#if !defined(__OBJECT_H)
|
||||||
#define __OBJECT_H
|
# define __OBJECT_H
|
||||||
|
|
||||||
#include <atomic>
|
# include "constructor_stats.h"
|
||||||
#include "constructor_stats.h"
|
|
||||||
|
# include <atomic>
|
||||||
|
|
||||||
/// Reference counted object base class
|
/// Reference counted object base class
|
||||||
class Object {
|
class Object {
|
||||||
@ -27,20 +28,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
void decRef(bool dealloc = true) const {
|
void decRef(bool dealloc = true) const {
|
||||||
--m_refCount;
|
--m_refCount;
|
||||||
if (m_refCount == 0 && dealloc)
|
if (m_refCount == 0 && dealloc) {
|
||||||
delete this;
|
delete this;
|
||||||
else if (m_refCount < 0)
|
} else if (m_refCount < 0) {
|
||||||
throw std::runtime_error("Internal error: reference count < 0!");
|
throw std::runtime_error("Internal error: reference count < 0!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string toString() const = 0;
|
virtual std::string toString() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** \brief Virtual protected deconstructor.
|
/** \brief Virtual protected deconstructor.
|
||||||
* (Will only be called by \ref ref)
|
* (Will only be called by \ref ref)
|
||||||
*/
|
*/
|
||||||
virtual ~Object() { print_destroyed(this); }
|
virtual ~Object() { print_destroyed(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable std::atomic<int> m_refCount { 0 };
|
mutable std::atomic<int> m_refCount{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tag class used to track constructions of ref objects. When we track constructors, below, we
|
// Tag class used to track constructions of ref objects. When we track constructors, below, we
|
||||||
@ -59,80 +63,105 @@ class ref_tag {};
|
|||||||
*
|
*
|
||||||
* \ingroup libcore
|
* \ingroup libcore
|
||||||
*/
|
*/
|
||||||
template <typename T> class ref {
|
template <typename T>
|
||||||
|
class ref {
|
||||||
public:
|
public:
|
||||||
/// Create a nullptr reference
|
/// Create a nullptr reference
|
||||||
ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
|
ref() : m_ptr(nullptr) {
|
||||||
|
print_default_created(this);
|
||||||
|
track_default_created((ref_tag *) this);
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a reference from a pointer
|
/// Construct a reference from a pointer
|
||||||
ref(T *ptr) : m_ptr(ptr) {
|
explicit ref(T *ptr) : m_ptr(ptr) {
|
||||||
if (m_ptr) ((Object *) m_ptr)->incRef();
|
if (m_ptr) {
|
||||||
|
((Object *) m_ptr)->incRef();
|
||||||
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
|
}
|
||||||
|
|
||||||
|
print_created(this, "from pointer", m_ptr);
|
||||||
|
track_created((ref_tag *) this, "from pointer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
ref(const ref &r) : m_ptr(r.m_ptr) {
|
ref(const ref &r) : m_ptr(r.m_ptr) {
|
||||||
if (m_ptr)
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->incRef();
|
((Object *) m_ptr)->incRef();
|
||||||
|
}
|
||||||
|
|
||||||
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
|
print_copy_created(this, "with pointer", m_ptr);
|
||||||
|
track_copy_created((ref_tag *) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
ref(ref &&r) : m_ptr(r.m_ptr) {
|
ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
|
|
||||||
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
|
print_move_created(this, "with pointer", m_ptr);
|
||||||
|
track_move_created((ref_tag *) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroy this reference
|
/// Destroy this reference
|
||||||
~ref() {
|
~ref() {
|
||||||
if (m_ptr)
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->decRef();
|
((Object *) m_ptr)->decRef();
|
||||||
|
}
|
||||||
|
|
||||||
print_destroyed(this); track_destroyed((ref_tag*) this);
|
print_destroyed(this);
|
||||||
|
track_destroyed((ref_tag *) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move another reference into the current one
|
/// Move another reference into the current one
|
||||||
ref& operator=(ref&& r) {
|
ref &operator=(ref &&r) noexcept {
|
||||||
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
|
print_move_assigned(this, "pointer", r.m_ptr);
|
||||||
|
track_move_assigned((ref_tag *) this);
|
||||||
|
|
||||||
if (*this == r)
|
if (*this == r) {
|
||||||
return *this;
|
return *this;
|
||||||
if (m_ptr)
|
}
|
||||||
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->decRef();
|
((Object *) m_ptr)->decRef();
|
||||||
|
}
|
||||||
m_ptr = r.m_ptr;
|
m_ptr = r.m_ptr;
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overwrite this reference with another reference
|
/// Overwrite this reference with another reference
|
||||||
ref& operator=(const ref& r) {
|
ref &operator=(const ref &r) {
|
||||||
print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
|
if (this == &r) {
|
||||||
|
|
||||||
if (m_ptr == r.m_ptr)
|
|
||||||
return *this;
|
return *this;
|
||||||
if (m_ptr)
|
}
|
||||||
|
print_copy_assigned(this, "pointer", r.m_ptr);
|
||||||
|
track_copy_assigned((ref_tag *) this);
|
||||||
|
|
||||||
|
if (m_ptr == r.m_ptr) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->decRef();
|
((Object *) m_ptr)->decRef();
|
||||||
|
}
|
||||||
m_ptr = r.m_ptr;
|
m_ptr = r.m_ptr;
|
||||||
if (m_ptr)
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->incRef();
|
((Object *) m_ptr)->incRef();
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overwrite this reference with a pointer to another object
|
/// Overwrite this reference with a pointer to another object
|
||||||
ref& operator=(T *ptr) {
|
ref &operator=(T *ptr) {
|
||||||
print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
|
print_values(this, "assigned pointer");
|
||||||
|
track_values((ref_tag *) this, "assigned pointer");
|
||||||
|
|
||||||
if (m_ptr == ptr)
|
if (m_ptr == ptr) {
|
||||||
return *this;
|
return *this;
|
||||||
if (m_ptr)
|
}
|
||||||
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->decRef();
|
((Object *) m_ptr)->decRef();
|
||||||
|
}
|
||||||
m_ptr = ptr;
|
m_ptr = ptr;
|
||||||
if (m_ptr)
|
if (m_ptr) {
|
||||||
((Object *) m_ptr)->incRef();
|
((Object *) m_ptr)->incRef();
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,31 +172,32 @@ public:
|
|||||||
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
|
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
|
||||||
|
|
||||||
/// Compare this reference with a pointer
|
/// Compare this reference with a pointer
|
||||||
bool operator==(const T* ptr) const { return m_ptr == ptr; }
|
bool operator==(const T *ptr) const { return m_ptr == ptr; }
|
||||||
|
|
||||||
/// Compare this reference with a pointer
|
/// Compare this reference with a pointer
|
||||||
bool operator!=(const T* ptr) const { return m_ptr != ptr; }
|
bool operator!=(const T *ptr) const { return m_ptr != ptr; }
|
||||||
|
|
||||||
/// Access the object referenced by this reference
|
/// Access the object referenced by this reference
|
||||||
T* operator->() { return m_ptr; }
|
T *operator->() { return m_ptr; }
|
||||||
|
|
||||||
/// Access the object referenced by this reference
|
/// Access the object referenced by this reference
|
||||||
const T* operator->() const { return m_ptr; }
|
const T *operator->() const { return m_ptr; }
|
||||||
|
|
||||||
/// Return a C++ reference to the referenced object
|
/// Return a C++ reference to the referenced object
|
||||||
T& operator*() { return *m_ptr; }
|
T &operator*() { return *m_ptr; }
|
||||||
|
|
||||||
/// Return a const C++ reference to the referenced object
|
/// Return a const C++ reference to the referenced object
|
||||||
const T& operator*() const { return *m_ptr; }
|
const T &operator*() const { return *m_ptr; }
|
||||||
|
|
||||||
/// Return a pointer to the referenced object
|
/// Return a pointer to the referenced object
|
||||||
operator T* () { return m_ptr; }
|
explicit operator T *() { return m_ptr; }
|
||||||
|
|
||||||
/// Return a const pointer to the referenced object
|
/// Return a const pointer to the referenced object
|
||||||
T* get_ptr() { return m_ptr; }
|
T *get_ptr() { return m_ptr; }
|
||||||
|
|
||||||
/// Return a pointer to the referenced object
|
/// Return a pointer to the referenced object
|
||||||
const T* get_ptr() const { return m_ptr; }
|
const T *get_ptr() const { return m_ptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T *m_ptr;
|
T *m_ptr;
|
||||||
};
|
};
|
||||||
|
@ -7,10 +7,14 @@
|
|||||||
BSD-style license that can be found in the LICENSE file.
|
BSD-style license that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pybind11_tests.h"
|
|
||||||
#include "local_bindings.h"
|
|
||||||
#include <pybind11/stl_bind.h>
|
#include <pybind11/stl_bind.h>
|
||||||
|
|
||||||
|
#include "local_bindings.h"
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
#include "test_exceptions.h"
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||||
m.doc() = "pybind11 cross-module test module";
|
m.doc() = "pybind11 cross-module test module";
|
||||||
@ -25,17 +29,46 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
|||||||
bind_local<ExternalType2>(m, "ExternalType2", py::module_local());
|
bind_local<ExternalType2>(m, "ExternalType2", py::module_local());
|
||||||
|
|
||||||
// test_exceptions.py
|
// test_exceptions.py
|
||||||
m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); });
|
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
|
||||||
m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); });
|
m.def("raise_runtime_error", []() {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "My runtime error");
|
||||||
|
throw py::error_already_set();
|
||||||
|
});
|
||||||
|
m.def("raise_value_error", []() {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "My value error");
|
||||||
|
throw py::error_already_set();
|
||||||
|
});
|
||||||
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
||||||
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
|
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
|
||||||
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
|
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
|
||||||
|
m.def("throw_local_error", []() { throw LocalException("just local"); });
|
||||||
|
m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); });
|
||||||
|
py::register_exception_translator([](std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) {
|
||||||
|
std::rethrow_exception(p);
|
||||||
|
}
|
||||||
|
} catch (const shared_exception &e) {
|
||||||
|
PyErr_SetString(PyExc_KeyError, e.what());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// translate the local exception into a key error but only in this module
|
||||||
|
py::register_local_exception_translator([](std::exception_ptr p) {
|
||||||
|
try {
|
||||||
|
if (p) {
|
||||||
|
std::rethrow_exception(p);
|
||||||
|
}
|
||||||
|
} catch (const LocalException &e) {
|
||||||
|
PyErr_SetString(PyExc_KeyError, e.what());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// test_local_bindings.py
|
// test_local_bindings.py
|
||||||
// Local to both:
|
// Local to both:
|
||||||
bind_local<LocalType, 1>(m, "LocalType", py::module_local())
|
bind_local<LocalType, 1>(m, "LocalType", py::module_local()).def("get2", [](LocalType &t) {
|
||||||
.def("get2", [](LocalType &t) { return t.i + 2; })
|
return t.i + 2;
|
||||||
;
|
});
|
||||||
|
|
||||||
// Can only be called with our python type:
|
// Can only be called with our python type:
|
||||||
m.def("local_value", [](LocalType &l) { return l.i; });
|
m.def("local_value", [](LocalType &l) { return l.i; });
|
||||||
@ -43,9 +76,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
|||||||
// test_nonlocal_failure
|
// test_nonlocal_failure
|
||||||
// This registration will fail (global registration when LocalFail is already registered
|
// This registration will fail (global registration when LocalFail is already registered
|
||||||
// globally in the main test module):
|
// globally in the main test module):
|
||||||
m.def("register_nonlocal", [m]() {
|
m.def("register_nonlocal", [m]() { bind_local<NonLocalType, 0>(m, "NonLocalType"); });
|
||||||
bind_local<NonLocalType, 0>(m, "NonLocalType");
|
|
||||||
});
|
|
||||||
|
|
||||||
// test_stl_bind_local
|
// test_stl_bind_local
|
||||||
// stl_bind.h binders defaults to py::module_local if the types are local or converting:
|
// stl_bind.h binders defaults to py::module_local if the types are local or converting:
|
||||||
@ -55,27 +86,21 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
|||||||
// test_stl_bind_global
|
// test_stl_bind_global
|
||||||
// and global if the type (or one of the types, for the map) is global (so these will fail,
|
// and global if the type (or one of the types, for the map) is global (so these will fail,
|
||||||
// assuming pybind11_tests is already loaded):
|
// assuming pybind11_tests is already loaded):
|
||||||
m.def("register_nonlocal_vec", [m]() {
|
m.def("register_nonlocal_vec", [m]() { py::bind_vector<NonLocalVec>(m, "NonLocalVec"); });
|
||||||
py::bind_vector<NonLocalVec>(m, "NonLocalVec");
|
m.def("register_nonlocal_map", [m]() { py::bind_map<NonLocalMap>(m, "NonLocalMap"); });
|
||||||
});
|
|
||||||
m.def("register_nonlocal_map", [m]() {
|
|
||||||
py::bind_map<NonLocalMap>(m, "NonLocalMap");
|
|
||||||
});
|
|
||||||
// The default can, however, be overridden to global using `py::module_local()` or
|
// The default can, however, be overridden to global using `py::module_local()` or
|
||||||
// `py::module_local(false)`.
|
// `py::module_local(false)`.
|
||||||
// Explicitly made local:
|
// Explicitly made local:
|
||||||
py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
|
py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
|
||||||
// Explicitly made global (and so will fail to bind):
|
// Explicitly made global (and so will fail to bind):
|
||||||
m.def("register_nonlocal_map2", [m]() {
|
m.def("register_nonlocal_map2",
|
||||||
py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
|
[m]() { py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false)); });
|
||||||
});
|
|
||||||
|
|
||||||
// test_mixed_local_global
|
// test_mixed_local_global
|
||||||
// We try this both with the global type registered first and vice versa (the order shouldn't
|
// We try this both with the global type registered first and vice versa (the order shouldn't
|
||||||
// matter).
|
// matter).
|
||||||
m.def("register_mixed_global_local", [m]() {
|
m.def("register_mixed_global_local",
|
||||||
bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local());
|
[m]() { bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local()); });
|
||||||
});
|
|
||||||
m.def("register_mixed_local_global", [m]() {
|
m.def("register_mixed_local_global", [m]() {
|
||||||
bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
|
bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
|
||||||
});
|
});
|
||||||
@ -83,25 +108,26 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
|||||||
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
|
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
|
||||||
|
|
||||||
// test_internal_locals_differ
|
// test_internal_locals_differ
|
||||||
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
|
m.def("local_cpp_types_addr",
|
||||||
|
[]() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
|
||||||
|
|
||||||
// test_stl_caster_vs_stl_bind
|
// test_stl_caster_vs_stl_bind
|
||||||
py::bind_vector<std::vector<int>>(m, "VectorInt");
|
py::bind_vector<std::vector<int>>(m, "VectorInt");
|
||||||
|
|
||||||
m.def("load_vector_via_binding", [](std::vector<int> &v) {
|
m.def("load_vector_via_binding",
|
||||||
return std::accumulate(v.begin(), v.end(), 0);
|
[](std::vector<int> &v) { return std::accumulate(v.begin(), v.end(), 0); });
|
||||||
});
|
|
||||||
|
|
||||||
// test_cross_module_calls
|
// test_cross_module_calls
|
||||||
m.def("return_self", [](LocalVec *v) { return v; });
|
m.def("return_self", [](LocalVec *v) { return v; });
|
||||||
m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
|
m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
|
||||||
|
|
||||||
class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; };
|
class Dog : public pets::Pet {
|
||||||
py::class_<pets::Pet>(m, "Pet", py::module_local())
|
public:
|
||||||
.def("name", &pets::Pet::name);
|
explicit Dog(std::string name) : Pet(std::move(name)) {}
|
||||||
|
};
|
||||||
|
py::class_<pets::Pet>(m, "Pet", py::module_local()).def("name", &pets::Pet::name);
|
||||||
// Binding for local extending class:
|
// Binding for local extending class:
|
||||||
py::class_<Dog, pets::Pet>(m, "Dog")
|
py::class_<Dog, pets::Pet>(m, "Dog").def(py::init<std::string>());
|
||||||
.def(py::init<std::string>());
|
|
||||||
m.def("pet_name", [](pets::Pet &p) { return p.name(); });
|
m.def("pet_name", [](pets::Pet &p) { return p.name(); });
|
||||||
|
|
||||||
py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
|
py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
|
||||||
@ -118,6 +144,6 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
|||||||
// test_missing_header_message
|
// test_missing_header_message
|
||||||
// The main module already includes stl.h, but we need to test the error message
|
// The main module already includes stl.h, but we need to test the error message
|
||||||
// which appears when this header is missing.
|
// which appears when this header is missing.
|
||||||
m.def("missing_header_arg", [](std::vector<float>) { });
|
m.def("missing_header_arg", [](const std::vector<float> &) {});
|
||||||
m.def("missing_header_return", []() { return std::vector<float>(); });
|
m.def("missing_header_return", []() { return std::vector<float>(); });
|
||||||
}
|
}
|
||||||
|
54
3rdparty/pybind11/tests/pybind11_tests.cpp
vendored
54
3rdparty/pybind11/tests/pybind11_tests.cpp
vendored
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
#include "constructor_stats.h"
|
#include "constructor_stats.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -31,9 +32,7 @@ std::list<std::function<void(py::module_ &)>> &initializers() {
|
|||||||
return inits;
|
return inits;
|
||||||
}
|
}
|
||||||
|
|
||||||
test_initializer::test_initializer(Initializer init) {
|
test_initializer::test_initializer(Initializer init) { initializers().emplace_back(init); }
|
||||||
initializers().emplace_back(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
||||||
initializers().emplace_back([=](py::module_ &parent) {
|
initializers().emplace_back([=](py::module_ &parent) {
|
||||||
@ -51,26 +50,52 @@ void bind_ConstructorStats(py::module_ &m) {
|
|||||||
.def_readwrite("move_assignments", &ConstructorStats::move_assignments)
|
.def_readwrite("move_assignments", &ConstructorStats::move_assignments)
|
||||||
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
|
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
|
||||||
.def_readwrite("move_constructions", &ConstructorStats::move_constructions)
|
.def_readwrite("move_constructions", &ConstructorStats::move_constructions)
|
||||||
.def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
|
.def_static("get",
|
||||||
|
(ConstructorStats & (*) (py::object)) & ConstructorStats::get,
|
||||||
|
py::return_value_policy::reference_internal)
|
||||||
|
|
||||||
// Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
|
// Not exactly ConstructorStats, but related: expose the internal pybind number of
|
||||||
// to allow instance cleanup checks (invokes a GC first)
|
// registered instances to allow instance cleanup checks (invokes a GC first)
|
||||||
.def_static("detail_reg_inst", []() {
|
.def_static("detail_reg_inst", []() {
|
||||||
ConstructorStats::gc();
|
ConstructorStats::gc();
|
||||||
return py::detail::get_internals().registered_instances.size();
|
return py::detail::get_internals().registered_instances.size();
|
||||||
})
|
});
|
||||||
;
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
@ -79,13 +104,14 @@ PYBIND11_MODULE(pybind11_tests, m) {
|
|||||||
.def("get_value", &UserType::value, "Get value using a method")
|
.def("get_value", &UserType::value, "Get value using a method")
|
||||||
.def("set_value", &UserType::set, "Set value using a method")
|
.def("set_value", &UserType::set, "Set value using a method")
|
||||||
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
|
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
|
||||||
.def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
|
.def("__repr__", [](const UserType &u) { return "UserType({})"_s.format(u.value()); });
|
||||||
|
|
||||||
py::class_<IncType, UserType>(m, "IncType")
|
py::class_<IncType, UserType>(m, "IncType")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def(py::init<int>())
|
.def(py::init<int>())
|
||||||
.def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
|
.def("__repr__", [](const IncType &u) { return "IncType({})"_s.format(u.value()); });
|
||||||
|
|
||||||
for (const auto &initializer : initializers())
|
for (const auto &initializer : initializers()) {
|
||||||
initializer(m);
|
initializer(m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
48
3rdparty/pybind11/tests/pybind11_tests.h
vendored
48
3rdparty/pybind11/tests/pybind11_tests.h
vendored
@ -1,10 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <pybind11/pybind11.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
#include <pybind11/eval.h>
|
||||||
// We get some really long type names here which causes MSVC 2015 to emit warnings
|
#include <pybind11/pybind11.h>
|
||||||
# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
using namespace pybind11::literals;
|
using namespace pybind11::literals;
|
||||||
@ -13,24 +10,23 @@ class test_initializer {
|
|||||||
using Initializer = void (*)(py::module_ &);
|
using Initializer = void (*)(py::module_ &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
test_initializer(Initializer init);
|
explicit test_initializer(Initializer init);
|
||||||
test_initializer(const char *submodule_name, Initializer init);
|
test_initializer(const char *submodule_name, Initializer init);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TEST_SUBMODULE(name, variable) \
|
#define TEST_SUBMODULE(name, variable) \
|
||||||
void test_submodule_##name(py::module_ &); \
|
void test_submodule_##name(py::module_ &); \
|
||||||
test_initializer name(#name, test_submodule_##name); \
|
test_initializer name(#name, test_submodule_##name); \
|
||||||
void test_submodule_##name(py::module_ &variable)
|
void test_submodule_##name(py::module_ &(variable))
|
||||||
|
|
||||||
|
|
||||||
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
|
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
|
||||||
struct UnregisteredType { };
|
struct UnregisteredType {};
|
||||||
|
|
||||||
/// A user-defined type which is exported and can be used by any test
|
/// A user-defined type which is exported and can be used by any test
|
||||||
class UserType {
|
class UserType {
|
||||||
public:
|
public:
|
||||||
UserType() = default;
|
UserType() = default;
|
||||||
UserType(int i) : i(i) { }
|
explicit UserType(int i) : i(i) {}
|
||||||
|
|
||||||
int value() const { return i; }
|
int value() const { return i; }
|
||||||
void set(int set) { i = set; }
|
void set(int set) { i = set; }
|
||||||
@ -44,7 +40,7 @@ class IncType : public UserType {
|
|||||||
public:
|
public:
|
||||||
using UserType::UserType;
|
using UserType::UserType;
|
||||||
IncType() = default;
|
IncType() = default;
|
||||||
IncType(const IncType &other) : IncType(other.value() + 1) { }
|
IncType(const IncType &other) : IncType(other.value() + 1) {}
|
||||||
IncType(IncType &&) = delete;
|
IncType(IncType &&) = delete;
|
||||||
IncType &operator=(const IncType &) = delete;
|
IncType &operator=(const IncType &) = delete;
|
||||||
IncType &operator=(IncType &&) = delete;
|
IncType &operator=(IncType &&) = delete;
|
||||||
@ -56,16 +52,34 @@ union IntFloat {
|
|||||||
float f;
|
float f;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context.
|
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast
|
||||||
/// Used to test recursive casters (e.g. std::tuple, stl containers).
|
/// context. Used to test recursive casters (e.g. std::tuple, stl containers).
|
||||||
struct RValueCaster {};
|
struct RValueCaster {};
|
||||||
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
PYBIND11_NAMESPACE_BEGIN(pybind11)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
template<> class type_caster<RValueCaster> {
|
template <>
|
||||||
|
class type_caster<RValueCaster> {
|
||||||
public:
|
public:
|
||||||
PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster"));
|
PYBIND11_TYPE_CASTER(RValueCaster, const_name("RValueCaster"));
|
||||||
static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); }
|
static handle cast(RValueCaster &&, return_value_policy, handle) {
|
||||||
static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); }
|
return py::str("rvalue").release();
|
||||||
|
}
|
||||||
|
static handle cast(const RValueCaster &, return_value_policy, handle) {
|
||||||
|
return py::str("lvalue").release();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
PYBIND11_NAMESPACE_END(pybind11)
|
PYBIND11_NAMESPACE_END(pybind11)
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void ignoreOldStyleInitWarnings(F &&body) {
|
||||||
|
py::exec(R"(
|
||||||
|
message = "pybind11-bound class '.+' is using an old-style placement-new '(?:__init__|__setstate__)' which has been deprecated"
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.filterwarnings("ignore", message=message, category=FutureWarning)
|
||||||
|
body()
|
||||||
|
)",
|
||||||
|
py::dict(py::arg("body") = py::cpp_function(body)));
|
||||||
|
}
|
||||||
|
13
3rdparty/pybind11/tests/pytest.ini
vendored
13
3rdparty/pybind11/tests/pytest.ini
vendored
@ -1,17 +1,20 @@
|
|||||||
[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
|
||||||
# enable all warnings
|
# Show local info when a failure occurs
|
||||||
-Wa
|
--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
|
||||||
|
# somehow, some DeprecationWarnings do not get turned into errors
|
||||||
|
always::DeprecationWarning
|
||||||
# importing scipy submodules on some version of Python
|
# importing scipy submodules on some version of Python
|
||||||
ignore::ImportWarning
|
ignore::ImportWarning
|
||||||
# bogus numpy ABI warning (see numpy/#432)
|
# bogus numpy ABI warning (see numpy/#432)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user