commit
0043120a8a
|
@ -27,15 +27,24 @@ set(PYBIND11_PYTHON_VERSION ${WRAP_PYTHON_VERSION})
|
|||
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../pybind11 pybind11)
|
||||
|
||||
# User-friendly Pybind11 wrapping and installing function. Builds a Pybind11
|
||||
# module from the provided interface_header. For example, for the interface
|
||||
# header gtsam.h, this will build the wrap module 'gtsam_py.cc'.
|
||||
# User-friendly Pybind11 wrapping and installing function.
|
||||
# Builds a Pybind11 module from the provided interface_header.
|
||||
# For example, for the interface header gtsam.h, this will
|
||||
# build the wrap module 'gtsam_py.cc'.
|
||||
#
|
||||
# Arguments:
|
||||
# ~~~
|
||||
# target: The Make target
|
||||
# interface_header: The relative path to the wrapper interface definition file.
|
||||
# install_path: destination to install the library libs: libraries to link with
|
||||
# dependencies: Dependencies which need to be built before the wrapper
|
||||
# generated_cpp: The name of the cpp file which is generated from the tpl file.
|
||||
# module_name: The name of the Python module to use.
|
||||
# top_namespace: The C++ namespace under which the code to be wrapped exists.
|
||||
# ignore_classes: CMake list of classes to ignore from wrapping.
|
||||
# install_path: Destination to install the library.
|
||||
# module_template: The template file (.tpl) from which to generate the Pybind11 module.
|
||||
# libs: Libraries to link with.
|
||||
# dependencies: Dependencies which need to be built before the wrapper.
|
||||
# use_boost (optional): Flag indicating whether to include Boost.
|
||||
function(pybind_wrap
|
||||
target
|
||||
interface_header
|
||||
|
|
|
@ -1,64 +1,32 @@
|
|||
version: 1.0.{build}
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2015
|
||||
test: off
|
||||
skip_branch_with_pr: true
|
||||
build:
|
||||
parallel: true
|
||||
platform:
|
||||
- x64
|
||||
- x86
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: 36
|
||||
CPP: 14
|
||||
CONFIG: Debug
|
||||
- PYTHON: 27
|
||||
CPP: 14
|
||||
CONFIG: Debug
|
||||
- CONDA: 36
|
||||
CPP: latest
|
||||
CONFIG: Release
|
||||
matrix:
|
||||
exclude:
|
||||
- image: Visual Studio 2015
|
||||
platform: x86
|
||||
- image: Visual Studio 2015
|
||||
CPP: latest
|
||||
- image: Visual Studio 2017
|
||||
CPP: latest
|
||||
platform: x86
|
||||
install:
|
||||
- ps: |
|
||||
if ($env:PLATFORM -eq "x64") { $env:CMAKE_ARCH = "x64" }
|
||||
if ($env:APPVEYOR_JOB_NAME -like "*Visual Studio 2017*") {
|
||||
$env:CMAKE_GENERATOR = "Visual Studio 15 2017"
|
||||
$env:CMAKE_INCLUDE_PATH = "C:\Libraries\boost_1_64_0"
|
||||
$env:CXXFLAGS = "-permissive-"
|
||||
} else {
|
||||
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
||||
}
|
||||
if ($env:PYTHON) {
|
||||
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
||||
$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 pytest numpy --no-warn-script-location
|
||||
} elseif ($env:CONDA) {
|
||||
if ($env:CONDA -eq "27") { $env:CONDA = "" }
|
||||
if ($env:PLATFORM -eq "x64") { $env:CONDA = "$env:CONDA-x64" }
|
||||
$env:PATH = "C:\Miniconda$env:CONDA\;C:\Miniconda$env:CONDA\Scripts\;$env:PATH"
|
||||
$env:PYTHONHOME = "C:\Miniconda$env:CONDA"
|
||||
conda --version
|
||||
conda install -y -q pytest numpy scipy
|
||||
}
|
||||
$env:CMAKE_GENERATOR = "Visual Studio 14 2015"
|
||||
if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" }
|
||||
$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 pytest numpy --no-warn-script-location
|
||||
- ps: |
|
||||
Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.3.3.zip'
|
||||
7z x 3.3.3.zip -y > $null
|
||||
$env:CMAKE_INCLUDE_PATH = "eigen-eigen-67e894c6cd8f;$env:CMAKE_INCLUDE_PATH"
|
||||
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
|
||||
$env:CMAKE_INCLUDE_PATH = "eigen-3.3.7;$env:CMAKE_INCLUDE_PATH"
|
||||
build_script:
|
||||
- cmake -G "%CMAKE_GENERATOR%" -A "%CMAKE_ARCH%"
|
||||
-DPYBIND11_CPP_STANDARD=/std:c++%CPP%
|
||||
-DCMAKE_CXX_STANDARD=14
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DCMAKE_SUPPRESS_REGENERATION=1
|
||||
|
@ -66,5 +34,4 @@ build_script:
|
|||
- set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
- cmake --build . --config %CONFIG% --target pytest -- /m /v:m /logger:%MSBuildLogger%
|
||||
- cmake --build . --config %CONFIG% --target cpptest -- /m /v:m /logger:%MSBuildLogger%
|
||||
- if "%CPP%"=="latest" (cmake --build . --config %CONFIG% --target test_cmake_build -- /m /v:m /logger:%MSBuildLogger%)
|
||||
on_failure: if exist "tests\test_cmake_build" type tests\test_cmake_build\*.log*
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
FormatStyle: file
|
||||
|
||||
Checks: '
|
||||
llvm-namespace-comment,
|
||||
modernize-use-override,
|
||||
readability-container-size-empty,
|
||||
modernize-use-using,
|
||||
modernize-use-equals-default,
|
||||
modernize-use-auto,
|
||||
modernize-use-emplace,
|
||||
'
|
||||
|
||||
HeaderFilterRegex: 'pybind11/.*h'
|
|
@ -0,0 +1,73 @@
|
|||
parse:
|
||||
additional_commands:
|
||||
pybind11_add_module:
|
||||
flags:
|
||||
- THIN_LTO
|
||||
- MODULE
|
||||
- SHARED
|
||||
- NO_EXTRAS
|
||||
- EXCLUDE_FROM_ALL
|
||||
- SYSTEM
|
||||
|
||||
format:
|
||||
line_width: 99
|
||||
tab_size: 2
|
||||
|
||||
# If an argument group contains more than this many sub-groups
|
||||
# (parg or kwarg groups) then force it to a vertical layout.
|
||||
max_subgroups_hwrap: 2
|
||||
|
||||
# If a positional argument group contains more than this many
|
||||
# arguments, then force it to a vertical layout.
|
||||
max_pargs_hwrap: 6
|
||||
|
||||
# If a cmdline positional group consumes more than this many
|
||||
# lines without nesting, then invalidate the layout (and nest)
|
||||
max_rows_cmdline: 2
|
||||
separate_ctrl_name_with_space: false
|
||||
separate_fn_name_with_space: false
|
||||
dangle_parens: false
|
||||
|
||||
# If the trailing parenthesis must be 'dangled' on its on
|
||||
# 'line, then align it to this reference: `prefix`: the start'
|
||||
# 'of the statement, `prefix-indent`: the start of the'
|
||||
# 'statement, plus one indentation level, `child`: align to'
|
||||
# the column of the arguments
|
||||
dangle_align: prefix
|
||||
# If the statement spelling length (including space and
|
||||
# parenthesis) is smaller than this amount, then force reject
|
||||
# nested layouts.
|
||||
min_prefix_chars: 4
|
||||
|
||||
# If the statement spelling length (including space and
|
||||
# parenthesis) is larger than the tab width by more than this
|
||||
# amount, then force reject un-nested layouts.
|
||||
max_prefix_chars: 10
|
||||
|
||||
# If a candidate layout is wrapped horizontally but it exceeds
|
||||
# this many lines, then reject the layout.
|
||||
max_lines_hwrap: 2
|
||||
|
||||
line_ending: unix
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case: canonical
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
# unchanged is valid too
|
||||
keyword_case: 'upper'
|
||||
|
||||
# A list of command names which should always be wrapped
|
||||
always_wrap: []
|
||||
|
||||
# If true, the argument lists which are known to be sortable
|
||||
# will be sorted lexicographically
|
||||
enable_sort: true
|
||||
|
||||
# If true, the parsers may infer whether or not an argument
|
||||
# list is sortable (without annotation).
|
||||
autosort: false
|
||||
|
||||
# Causes a few issues - can be solved later, possibly.
|
||||
markup:
|
||||
enable_markup: false
|
|
@ -0,0 +1,319 @@
|
|||
Thank you for your interest in this project! Please refer to the following
|
||||
sections on how to contribute code and bug reports.
|
||||
|
||||
### Reporting bugs
|
||||
|
||||
Before submitting a question or bug report, please take a moment of your time
|
||||
and ensure that your issue isn't already discussed in the project documentation
|
||||
provided at [pybind11.readthedocs.org][] or in the [issue tracker][]. You can
|
||||
also check [gitter][] to see if it came up before.
|
||||
|
||||
Assuming that you have identified a previously unknown problem or an important
|
||||
question, it's essential that you submit a self-contained and minimal piece of
|
||||
code that reproduces the problem. In other words: 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 in isolation; or
|
||||
ideally make a small PR with a failing test case that can be used as a starting
|
||||
point.
|
||||
|
||||
## Pull requests
|
||||
|
||||
Contributions are submitted, reviewed, and accepted using GitHub pull requests.
|
||||
Please refer to [this article][using pull requests] for details and adhere to
|
||||
the following rules to make the process as smooth as possible:
|
||||
|
||||
* Make a new branch for every feature you're working on.
|
||||
* Make small and clean pull requests that are easy to review but make sure they
|
||||
do add value by themselves.
|
||||
* Add tests for any new functionality and run the test suite (`cmake --build
|
||||
build --target pytest`) to ensure that no existing features break.
|
||||
* Please run [`pre-commit`][pre-commit] to check your code matches the
|
||||
project style. (Note that `gawk` is required.) Use `pre-commit run
|
||||
--all-files` before committing (or use installed-mode, check pre-commit docs)
|
||||
to verify your code passes before pushing to save time.
|
||||
* This project has a strong focus on providing general solutions using a
|
||||
minimal amount of code, thus small pull requests are greatly preferred.
|
||||
|
||||
### Licensing of contributions
|
||||
|
||||
pybind11 is provided under a BSD-style license that can be found in the
|
||||
``LICENSE`` file. By using, distributing, or contributing to this project, you
|
||||
agree to the terms and conditions of this license.
|
||||
|
||||
You are under no obligation whatsoever to provide any bug fixes, patches, or
|
||||
upgrades to the features, functionality or performance of the source code
|
||||
("Enhancements") to anyone; however, if you choose to make your Enhancements
|
||||
available either publicly, or directly to the author of this software, without
|
||||
imposing a separate written license agreement for such Enhancements, then you
|
||||
hereby grant the following license: a non-exclusive, royalty-free perpetual
|
||||
license to install, use, modify, prepare derivative works, incorporate into
|
||||
other computer software, distribute, and sublicense such enhancements or
|
||||
derivative works thereof, in binary and source code form.
|
||||
|
||||
|
||||
## Development of pybind11
|
||||
|
||||
To setup an ideal development environment, run the following commands on a
|
||||
system with CMake 3.14+:
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r tests/requirements.txt
|
||||
cmake -S . -B build -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON
|
||||
cmake --build build -j4
|
||||
```
|
||||
|
||||
Tips:
|
||||
|
||||
* You can use `virtualenv` (from PyPI) instead of `venv` (which is Python 3
|
||||
only).
|
||||
* You can select any name for your environment folder; if it contains "env" it
|
||||
will be ignored by git.
|
||||
* 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+
|
||||
* In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`.
|
||||
FindPython uses `-DPython_ROOT_DIR=/path/to` or
|
||||
`-DPython_EXECUTABLE=/path/to/python`.
|
||||
|
||||
### Configuration options
|
||||
|
||||
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. Two selections are special - the generator, given with `-G`,
|
||||
and the compiler, which is selected based on environment variables `CXX` and
|
||||
similar, or `-DCMAKE_CXX_COMPILER=`. Unlike the others, these cannot be changed
|
||||
after the initial run.
|
||||
|
||||
The valid options are:
|
||||
|
||||
* `-DCMAKE_BUILD_TYPE`: Release, Debug, MinSizeRel, RelWithDebInfo
|
||||
* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+’s FindPython instead of the
|
||||
classic, deprecated, custom FindPythonLibs
|
||||
* `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests)
|
||||
* `-DBUILD_TESTING=ON`: Enable the tests
|
||||
* `-DDOWNLOAD_CATCH=ON`: Download catch to build the C++ tests
|
||||
* `-DOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests
|
||||
* `-DPYBIND11_INSTALL=ON/OFF`: Enable the install target (on by default for the
|
||||
master project)
|
||||
* `-DUSE_PYTHON_INSTALL_DIR=ON`: Try to install into the python dir
|
||||
|
||||
|
||||
<details><summary>A few standard CMake tricks: (click to expand)</summary><p>
|
||||
|
||||
* Use `cmake --build build -v` to see the commands used to build the files.
|
||||
* Use `cmake build -LH` to list the CMake options with help.
|
||||
* Use `ccmake` if available to see a curses (terminal) gui, or `cmake-gui` for
|
||||
a completely graphical interface (not present in the PyPI package).
|
||||
* Use `cmake --build build -j12` to build with 12 cores (for example).
|
||||
* Use `-G` and the name of a generator to use something different. `cmake
|
||||
--help` lists the generators available.
|
||||
- On Unix, setting `CMAKE_GENERATER=Ninja` in your environment will give
|
||||
you automatic mulithreading on all your CMake projects!
|
||||
* Open the `CMakeLists.txt` with QtCreator to generate for that IDE.
|
||||
* You can use `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` to generate the `.json` file
|
||||
that some tools expect.
|
||||
|
||||
</p></details>
|
||||
|
||||
|
||||
To run the tests, you can "build" the check target:
|
||||
|
||||
```bash
|
||||
cmake --build build --target check
|
||||
```
|
||||
|
||||
`--target` can be spelled `-t` in CMake 3.15+. You can also run individual
|
||||
tests with these targets:
|
||||
|
||||
* `pytest`: Python tests only
|
||||
* `cpptest`: C++ tests only
|
||||
* `test_cmake_build`: Install / subdirectory tests
|
||||
|
||||
If you want to build just a subset of tests, use
|
||||
`-DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp"`. If this is
|
||||
empty, all tests will be built.
|
||||
|
||||
### Formatting
|
||||
|
||||
All formatting is handled by pre-commit.
|
||||
|
||||
Install with brew (macOS) or pip (any OS):
|
||||
|
||||
```bash
|
||||
# Any OS
|
||||
python3 -m pip install pre-commit
|
||||
|
||||
# OR macOS with homebrew:
|
||||
brew install pre-commit
|
||||
```
|
||||
|
||||
Then, you can run it on the items you've added to your staging area, or all
|
||||
files:
|
||||
|
||||
```bash
|
||||
pre-commit run
|
||||
# OR
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
And, if you want to always use it, you can install it as a git hook (hence the
|
||||
name, pre-commit):
|
||||
|
||||
```bash
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
### Clang-Tidy
|
||||
|
||||
To run Clang tidy, the following recipe should work. Files will be modified in
|
||||
place, so you can use git to monitor the changes.
|
||||
|
||||
```bash
|
||||
docker run --rm -v $PWD:/pybind11 -it silkeh/clang:10
|
||||
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
|
||||
```
|
||||
|
||||
### Include what you use
|
||||
|
||||
To run include what you use, install (`brew install include-what-you-use` on
|
||||
macOS), then run:
|
||||
|
||||
```bash
|
||||
cmake -S . -B build-iwyu -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=$(which include-what-you-use)
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
The report is sent to stderr; you can pip it into a file if you wish.
|
||||
|
||||
### Build recipes
|
||||
|
||||
This builds with the Intel compiler (assuming it is in your path, along with a
|
||||
recent CMake and Python 3):
|
||||
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip install pytest
|
||||
cmake -S . -B build-intel -DCMAKE_CXX_COMPILER=$(which icpc) -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DPYBIND11_WERROR=ON
|
||||
```
|
||||
|
||||
This will test the PGI compilers:
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $PWD:/pybind11 nvcr.io/hpc/pgi-compilers:ce
|
||||
apt-get update && apt-get install -y python3-dev python3-pip python3-pytest
|
||||
wget -qO- "https://cmake.org/files/v3.18/cmake-3.18.2-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /usr/local
|
||||
cmake -S pybind11/ -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
### Explanation of the SDist/wheel building design
|
||||
|
||||
> These details below are _only_ for packaging the Python sources from git. The
|
||||
> SDists and wheels created do not have any extra requirements at all and are
|
||||
> completely normal.
|
||||
|
||||
The main objective of the packaging system is to create SDists (Python's source
|
||||
distribution packages) and wheels (Python's binary distribution packages) that
|
||||
include everything that is needed to work with pybind11, and which can be
|
||||
installed without any additional dependencies. This is more complex than it
|
||||
appears: in order to support CMake as a first class language even when using
|
||||
the PyPI package, they must include the _generated_ CMake files (so as not to
|
||||
require CMake when installing the `pybind11` package itself). They should also
|
||||
provide the option to install to the "standard" location
|
||||
(`<ENVROOT>/include/pybind11` and `<ENVROOT>/share/cmake/pybind11`) so they are
|
||||
easy to find with CMake, but this can cause problems if you are not an
|
||||
environment or using ``pyproject.toml`` requirements. This was solved by having
|
||||
two packages; the "nice" pybind11 package that stores the includes and CMake
|
||||
files inside the package, that you get access to via functions in the package,
|
||||
and a `pybind11-global` package that can be included via `pybind11[global]` if
|
||||
you want the more invasive but discoverable file locations.
|
||||
|
||||
If you want to install or package the GitHub source, it is best to have Pip 10
|
||||
or newer on Windows, macOS, or Linux (manylinux1 compatible, includes most
|
||||
distributions). You can then build the SDists, or run any procedure that makes
|
||||
SDists internally, like making wheels or installing.
|
||||
|
||||
|
||||
```bash
|
||||
# Editable development install example
|
||||
python3 -m pip install -e .
|
||||
```
|
||||
|
||||
Since Pip itself does not have an `sdist` command (it does have `wheel` and
|
||||
`install`), you may want to use the upcoming `build` package:
|
||||
|
||||
```bash
|
||||
python3 -m pip install build
|
||||
|
||||
# Normal package
|
||||
python3 -m build -s .
|
||||
|
||||
# Global extra
|
||||
PYBIND11_GLOBAL_SDIST=1 python3 -m build -s .
|
||||
```
|
||||
|
||||
If you want to use the classic "direct" usage of `python setup.py`, you will
|
||||
need CMake 3.15+ and either `make` or `ninja` preinstalled (possibly via `pip
|
||||
install cmake ninja`), since directly running Python on `setup.py` cannot pick
|
||||
up and install `pyproject.toml` requirements. As long as you have those two
|
||||
things, though, everything works the way you would expect:
|
||||
|
||||
```bash
|
||||
# Normal package
|
||||
python3 setup.py sdist
|
||||
|
||||
# Global extra
|
||||
PYBIND11_GLOBAL_SDIST=1 python3 setup.py sdist
|
||||
```
|
||||
|
||||
A detailed explanation of the build procedure design for developers wanting to
|
||||
work on or maintain the packaging system is as follows:
|
||||
|
||||
#### 1. Building from the source directory
|
||||
|
||||
When you invoke any `setup.py` command from the source directory, including
|
||||
`pip wheel .` and `pip install .`, you will activate a full source build. This
|
||||
is made of the following steps:
|
||||
|
||||
1. If the tool is PEP 518 compliant, like Pip 10+, it will create a temporary
|
||||
virtual environment and install the build requirements (mostly CMake) into
|
||||
it. (if you are not on Windows, macOS, or a manylinux compliant system, you
|
||||
can disable this with `--no-build-isolation` as long as you have CMake 3.15+
|
||||
installed)
|
||||
2. The environment variable `PYBIND11_GLOBAL_SDIST` is checked - if it is set
|
||||
and truthy, this will be make the accessory `pybind11-global` package,
|
||||
instead of the normal `pybind11` package. This package is used for
|
||||
installing the files directly to your environment root directory, using
|
||||
`pybind11[global]`.
|
||||
2. `setup.py` reads the version from `pybind11/_version.py` and verifies it
|
||||
matches `includes/pybind11/detail/common.h`.
|
||||
3. CMake is run with `-DCMAKE_INSTALL_PREIFX=pybind11`. Since the CMake install
|
||||
procedure uses only relative paths and is identical on all platforms, these
|
||||
files are valid as long as they stay in the correct relative position to the
|
||||
includes. `pybind11/share/cmake/pybind11` has the CMake files, and
|
||||
`pybind11/include` has the includes. The build directory is discarded.
|
||||
4. Simpler files are placed in the SDist: `tools/setup_*.py.in`,
|
||||
`tools/pyproject.toml` (`main` or `global`)
|
||||
5. The package is created by running the setup function in the
|
||||
`tools/setup_*.py`. `setup_main.py` fills in Python packages, and
|
||||
`setup_global.py` fills in only the data/header slots.
|
||||
6. A context manager cleans up the temporary CMake install directory (even if
|
||||
an error is thrown).
|
||||
|
||||
### 2. Building from SDist
|
||||
|
||||
Since the SDist has the rendered template files in `tools` along with the
|
||||
includes and CMake files in the correct locations, the builds are completely
|
||||
trivial and simple. No extra requirements are required. You can even use Pip 9
|
||||
if you really want to.
|
||||
|
||||
|
||||
[pre-commit]: https://pre-commit.com
|
||||
[pybind11.readthedocs.org]: http://pybind11.readthedocs.org/en/latest
|
||||
[issue tracker]: https://github.com/pybind/pybind11/issues
|
||||
[gitter]: https://gitter.im/pybind/Lobby
|
||||
[using pull requests]: https://help.github.com/articles/using-pull-requests
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
name: Bug Report
|
||||
about: File an issue about a bug
|
||||
title: "[BUG] "
|
||||
---
|
||||
|
||||
|
||||
Make sure you've completed the following steps before submitting your issue -- thank you!
|
||||
|
||||
1. Make sure you've read the [documentation][]. Your issue may be addressed there.
|
||||
2. Search the [issue tracker][] to verify that this hasn't already been reported. +1 or comment there if it has.
|
||||
3. Consider asking first in the [Gitter chat room][].
|
||||
4. Include a self-contained and minimal piece of code that reproduces the problem. If that's not possible, try to make the description as clear as possible.
|
||||
a. If possible, make a PR with a new, failing test to give us a starting point to work on!
|
||||
|
||||
[documentation]: https://pybind11.readthedocs.io
|
||||
[issue tracker]: https://github.com/pybind/pybind11/issues
|
||||
[Gitter chat room]: https://gitter.im/pybind/Lobby
|
||||
|
||||
*After reading, remove this checklist and the template text in parentheses below.*
|
||||
|
||||
## Issue description
|
||||
|
||||
(Provide a short description, state the expected behavior and what actually happens.)
|
||||
|
||||
## Reproducible example code
|
||||
|
||||
(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.)
|
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Gitter room
|
||||
url: https://gitter.im/pybind/Lobby
|
||||
about: A room for discussing pybind11 with an active community
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
name: Feature Request
|
||||
about: File an issue about adding a feature
|
||||
title: "[FEAT] "
|
||||
---
|
||||
|
||||
|
||||
Make sure you've completed the following steps before submitting your issue -- thank you!
|
||||
|
||||
1. Check if your feature has already been mentioned / rejected / planned in other issues.
|
||||
2. If those resources didn't help, consider asking in the [Gitter chat room][] to see if this is interesting / useful to a larger audience and possible to implement reasonably,
|
||||
4. If you have a useful feature that passes the previous items (or not suitable for chat), please fill in the details below.
|
||||
|
||||
[Gitter chat room]: https://gitter.im/pybind/Lobby
|
||||
|
||||
*After reading, remove this checklist.*
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
name: Question
|
||||
about: File an issue about unexplained behavior
|
||||
title: "[QUESTION] "
|
||||
---
|
||||
|
||||
If you have a question, please check the following first:
|
||||
|
||||
1. Check if your question has already been answered in the [FAQ][] section.
|
||||
2. Make sure you've read the [documentation][]. Your issue may be addressed there.
|
||||
3. If those resources didn't help and you only have a short question (not a bug report), consider asking in the [Gitter chat room][]
|
||||
4. Search the [issue tracker][], including the closed issues, to see if your question has already been asked/answered. +1 or comment if it has been asked but has no answer.
|
||||
5. If you have a more complex question which is not answered in the previous items (or not suitable for chat), please fill in the details below.
|
||||
6. Include a self-contained and minimal piece of code that illustrates your question. If that's not possible, try to make the description as clear as possible.
|
||||
|
||||
[FAQ]: http://pybind11.readthedocs.io/en/latest/faq.html
|
||||
[documentation]: https://pybind11.readthedocs.io
|
||||
[issue tracker]: https://github.com/pybind/pybind11/issues
|
||||
[Gitter chat room]: https://gitter.im/pybind/Lobby
|
||||
|
||||
*After reading, remove this checklist.*
|
|
@ -0,0 +1,519 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- stable
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
# This is the "main" test suite, which tests a large number of different
|
||||
# versions of default compilers and Python versions in GitHub Actions.
|
||||
standard:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
runs-on: [ubuntu-latest, windows-latest, macos-latest]
|
||||
arch: [x64]
|
||||
python:
|
||||
- 2.7
|
||||
- 3.5
|
||||
- 3.8
|
||||
- pypy2
|
||||
- pypy3
|
||||
|
||||
# Items in here will either be added to the build matrix (if not
|
||||
# present), or add new keys to an existing matrix element if all the
|
||||
# existing keys match.
|
||||
#
|
||||
# We support three optional keys: args (both build), args1 (first
|
||||
# build), and args2 (second build).
|
||||
include:
|
||||
- runs-on: ubuntu-latest
|
||||
python: 3.6
|
||||
arch: x64
|
||||
args: >
|
||||
-DPYBIND11_FINDPYTHON=ON
|
||||
- runs-on: windows-2016
|
||||
python: 3.7
|
||||
arch: x86
|
||||
args2: >
|
||||
-DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR"
|
||||
- runs-on: windows-latest
|
||||
python: 3.6
|
||||
arch: x64
|
||||
args: >
|
||||
-DPYBIND11_FINDPYTHON=ON
|
||||
- runs-on: windows-latest
|
||||
python: 3.7
|
||||
arch: x64
|
||||
|
||||
- runs-on: ubuntu-latest
|
||||
python: 3.9-dev
|
||||
arch: x64
|
||||
- runs-on: macos-latest
|
||||
python: 3.9-dev
|
||||
arch: x64
|
||||
args: >
|
||||
-DPYBIND11_FINDPYTHON=ON
|
||||
|
||||
# These items will be removed from the build matrix, keys must match.
|
||||
exclude:
|
||||
# Currently 32bit only, and we build 64bit
|
||||
- runs-on: windows-latest
|
||||
python: pypy2
|
||||
arch: x64
|
||||
- runs-on: windows-latest
|
||||
python: pypy3
|
||||
arch: x64
|
||||
|
||||
# Currently broken on embed_test
|
||||
- runs-on: windows-latest
|
||||
python: 3.8
|
||||
arch: x64
|
||||
- runs-on: windows-latest
|
||||
python: 3.9-dev
|
||||
arch: x64
|
||||
|
||||
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • ${{ matrix.arch }} ${{ matrix.args }}"
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
continue-on-error: ${{ endsWith(matrix.python, 'dev') }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
architecture: ${{ matrix.arch }}
|
||||
|
||||
- name: Setup Boost (Windows / Linux latest)
|
||||
run: echo "::set-env name=BOOST_ROOT::$BOOST_ROOT_1_72_0"
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.3
|
||||
|
||||
- name: Cache wheels
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
# This path is specific to macOS - we really only need it for PyPy NumPy wheels
|
||||
# See https://github.com/actions/cache/blob/master/examples.md#python---pip
|
||||
# for ways to do this more generally
|
||||
path: ~/Library/Caches/pip
|
||||
# Look to see if there is a cache hit for the corresponding requirements file
|
||||
key: ${{ runner.os }}-pip-${{ matrix.python }}-${{ matrix.arch }}-${{ hashFiles('tests/requirements.txt') }}
|
||||
|
||||
- name: Prepare env
|
||||
run: python -m pip install -r tests/requirements.txt --prefer-binary
|
||||
|
||||
- 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 ${{ matrix.args }}
|
||||
run: >
|
||||
cmake -S . -B .
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DDOWNLOAD_EIGEN=ON
|
||||
-DCMAKE_CXX_STANDARD=11
|
||||
${{ matrix.args }}
|
||||
|
||||
- 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 ${{ matrix.args2 }}
|
||||
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
|
||||
|
||||
- name: Interface test
|
||||
run: cmake --build build2 --target test_cmake_build
|
||||
|
||||
# Eventually Microsoft might have an action for setting up
|
||||
# MSVC, but for now, this action works:
|
||||
- name: Prepare compiler environment for Windows 🐍 2.7
|
||||
if: matrix.python == 2.7 && runner.os == 'Windows'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
# This makes two environment variables available in the following step(s)
|
||||
- name: Set Windows 🐍 2.7 environment variables
|
||||
if: matrix.python == 2.7 && runner.os == 'Windows'
|
||||
run: |
|
||||
echo "::set-env name=DISTUTILS_USE_SDK::1"
|
||||
echo "::set-env name=MSSdk::1"
|
||||
|
||||
# This makes sure the setup_helpers module can build packages using
|
||||
# setuptools
|
||||
- name: Setuptools helpers test
|
||||
run: pytest tests/extra_setuptools
|
||||
|
||||
|
||||
# Testing on clang using the excellent silkeh clang docker images
|
||||
clang:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
clang:
|
||||
- 3.6
|
||||
- 3.7
|
||||
- 3.9
|
||||
- 5
|
||||
- 7
|
||||
- 9
|
||||
- dev
|
||||
|
||||
name: "🐍 3 • Clang ${{ matrix.clang }} • x64"
|
||||
container: "silkeh/clang:${{ matrix.clang }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Add wget and python3
|
||||
run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: >
|
||||
cmake -S . -B build
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -j 2
|
||||
|
||||
- name: Python tests
|
||||
run: cmake --build build --target pytest
|
||||
|
||||
- name: C++ tests
|
||||
run: cmake --build build --target cpptest
|
||||
|
||||
- name: Interface test
|
||||
run: cmake --build build --target test_cmake_build
|
||||
|
||||
|
||||
# Testing NVCC; forces sources to behave like .cu files
|
||||
cuda:
|
||||
runs-on: ubuntu-latest
|
||||
name: "🐍 3.8 • CUDA 11 • Ubuntu 20.04"
|
||||
container: nvidia/cuda:11.0-devel-ubuntu20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
|
||||
- name: Install 🐍 3
|
||||
run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake git python3-dev python3-pytest python3-numpy
|
||||
|
||||
- name: Configure
|
||||
run: cmake -S . -B build -DPYBIND11_CUDA_TESTS=ON -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -j2 --verbose
|
||||
|
||||
- name: Python tests
|
||||
run: cmake --build build --target pytest
|
||||
|
||||
|
||||
# Testing CentOS 8 + PGI compilers
|
||||
centos-nvhpc8:
|
||||
runs-on: ubuntu-latest
|
||||
name: "🐍 3 • CentOS8 / PGI 20.7 • x64"
|
||||
container: centos:8
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Add Python 3 and a few requirements
|
||||
run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules
|
||||
|
||||
- name: Install CMake with pip
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install cmake --prefer-binary
|
||||
|
||||
- name: Install NVidia HPC SDK
|
||||
run: yum -y install https://developer.download.nvidia.com/hpc-sdk/nvhpc-20-7-20.7-1.x86_64.rpm https://developer.download.nvidia.com/hpc-sdk/nvhpc-2020-20.7-1.x86_64.rpm
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: |
|
||||
source /etc/profile.d/modules.sh
|
||||
module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/20.7
|
||||
cmake -S . -B build -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=14 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -j 2 --verbose
|
||||
|
||||
- name: Python tests
|
||||
run: cmake --build build --target pytest
|
||||
|
||||
- name: C++ tests
|
||||
run: cmake --build build --target cpptest
|
||||
|
||||
- name: Interface test
|
||||
run: cmake --build build --target test_cmake_build
|
||||
|
||||
|
||||
# Testing on CentOS 7 + PGI compilers, which seems to require more workarounds
|
||||
centos-nvhpc7:
|
||||
runs-on: ubuntu-latest
|
||||
name: "🐍 3 • CentOS7 / PGI 20.7 • x64"
|
||||
container: centos:7
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Add Python 3 and a few requirements
|
||||
run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3
|
||||
|
||||
- name: Install NVidia HPC SDK
|
||||
run: yum -y install https://developer.download.nvidia.com/hpc-sdk/nvhpc-20-7-20.7-1.x86_64.rpm https://developer.download.nvidia.com/hpc-sdk/nvhpc-2020-20.7-1.x86_64.rpm
|
||||
|
||||
# On CentOS 7, we have to filter a few tests (compiler internal error)
|
||||
# and allow deeper templete recursion (not needed on CentOS 8 with a newer
|
||||
# standard library). On some systems, you many need further workarounds:
|
||||
# https://github.com/pybind/pybind11/pull/2475
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: |
|
||||
source /etc/profile.d/modules.sh
|
||||
module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/20.7
|
||||
cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \
|
||||
-DCMAKE_CXX_STANDARD=11 \
|
||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
|
||||
-DCMAKE_CXX_FLAGS="-Wc,--pending_instantiations=0" \
|
||||
-DPYBIND11_TEST_FILTER="test_smart_ptr.cpp;test_virtual_functions.cpp"
|
||||
|
||||
# Building before installing Pip should produce a warning but not an error
|
||||
- name: Build
|
||||
run: cmake3 --build build -j 2 --verbose
|
||||
|
||||
- name: Install CMake with pip
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install pytest
|
||||
|
||||
- name: Python tests
|
||||
run: cmake3 --build build --target pytest
|
||||
|
||||
- name: C++ tests
|
||||
run: cmake3 --build build --target cpptest
|
||||
|
||||
- name: Interface test
|
||||
run: cmake3 --build build --target test_cmake_build
|
||||
|
||||
# Testing on GCC using the GCC docker images (only recent images supported)
|
||||
gcc:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
gcc:
|
||||
- 7
|
||||
- latest
|
||||
|
||||
name: "🐍 3 • GCC ${{ matrix.gcc }} • x64"
|
||||
container: "gcc:${{ matrix.gcc }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Add Python 3
|
||||
run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev
|
||||
|
||||
- name: Update pip
|
||||
run: python3 -m pip install --upgrade pip
|
||||
|
||||
- name: Setup CMake 3.18
|
||||
uses: jwlawson/actions-setup-cmake@v1.3
|
||||
with:
|
||||
cmake-version: 3.18
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: >
|
||||
cmake -S . -B build
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DCMAKE_CXX_STANDARD=11
|
||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -j 2
|
||||
|
||||
- name: Python tests
|
||||
run: cmake --build build --target pytest
|
||||
|
||||
- name: C++ tests
|
||||
run: cmake --build build --target cpptest
|
||||
|
||||
- name: Interface test
|
||||
run: cmake --build build --target test_cmake_build
|
||||
|
||||
|
||||
# Testing on CentOS (manylinux uses a centos base, and this is an easy way
|
||||
# to get GCC 4.8, which is the manylinux1 compiler).
|
||||
centos:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
centos:
|
||||
- 7 # GCC 4.8
|
||||
- 8
|
||||
|
||||
name: "🐍 3 • CentOS ${{ matrix.centos }} • x64"
|
||||
container: "centos:${{ matrix.centos }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Add Python 3
|
||||
run: yum update -y && yum install -y python3-devel gcc-c++ make git
|
||||
|
||||
- name: Update pip
|
||||
run: python3 -m pip install --upgrade pip
|
||||
|
||||
- name: Install dependencies
|
||||
run: python3 -m pip install cmake -r tests/requirements.txt --prefer-binary
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: >
|
||||
cmake -S . -B build
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DDOWNLOAD_EIGEN=ON
|
||||
-DCMAKE_CXX_STANDARD=11
|
||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -j 2
|
||||
|
||||
- name: Python tests
|
||||
run: cmake --build build --target pytest
|
||||
|
||||
- name: C++ tests
|
||||
run: cmake --build build --target cpptest
|
||||
|
||||
- name: Interface test
|
||||
run: cmake --build build --target test_cmake_build
|
||||
|
||||
|
||||
# This tests an "install" with the CMake tools
|
||||
install-classic:
|
||||
name: "🐍 3.5 • Debian • x86 • Install"
|
||||
runs-on: ubuntu-latest
|
||||
container: i386/debian:stretch
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Install requirements
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y git make cmake g++ libeigen3-dev python3-dev python3-pip
|
||||
pip3 install "pytest==3.1.*"
|
||||
|
||||
- name: Configure for install
|
||||
run: >
|
||||
cmake .
|
||||
-DPYBIND11_INSTALL=1 -DPYBIND11_TEST=0
|
||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
|
||||
|
||||
- name: Make and install
|
||||
run: make install
|
||||
|
||||
- name: Copy tests to new directory
|
||||
run: cp -a tests /pybind11-tests
|
||||
|
||||
- name: Make a new test directory
|
||||
run: mkdir /build-tests
|
||||
|
||||
- name: Configure tests
|
||||
run: >
|
||||
cmake ../pybind11-tests
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
|
||||
working-directory: /build-tests
|
||||
|
||||
- name: Run tests
|
||||
run: make pytest -j 2
|
||||
working-directory: /build-tests
|
||||
|
||||
|
||||
# This verifies that the documentation is not horribly broken, and does a
|
||||
# basic sanity check on the SDist.
|
||||
doxygen:
|
||||
name: "Documentation build test"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
|
||||
- name: Install Doxygen
|
||||
run: sudo apt install -y doxygen
|
||||
|
||||
- name: Install docs & setup requirements
|
||||
run: python3 -m pip install -r docs/requirements.txt
|
||||
|
||||
- name: Build docs
|
||||
run: python3 -m sphinx -W -b html docs docs/.build
|
||||
|
||||
- name: Make SDist
|
||||
run: python3 setup.py sdist
|
||||
|
||||
- run: git status --ignored
|
||||
|
||||
- name: Check local include dir
|
||||
run: >
|
||||
ls pybind11;
|
||||
python3 -c "import pybind11, pathlib; assert (a := pybind11.get_include()) == (b := str(pathlib.Path('include').resolve())), f'{a} != {b}'"
|
||||
|
||||
- name: Compare Dists (headers only)
|
||||
working-directory: include
|
||||
run: |
|
||||
python3 -m pip install --user -U ../dist/*
|
||||
installed=$(python3 -c "import pybind11; print(pybind11.get_include() + '/pybind11')")
|
||||
diff -rq $installed ./pybind11
|
|
@ -0,0 +1,138 @@
|
|||
name: Config
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- stable
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
# This tests various versions of CMake in various combinations, to make sure
|
||||
# the configure step passes.
|
||||
cmake:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
runs-on: [ubuntu-latest, macos-latest, windows-latest]
|
||||
arch: [x64]
|
||||
cmake: [3.18]
|
||||
|
||||
include:
|
||||
- runs-on: ubuntu-latest
|
||||
arch: x64
|
||||
cmake: 3.4
|
||||
|
||||
- runs-on: macos-latest
|
||||
arch: x64
|
||||
cmake: 3.7
|
||||
|
||||
- runs-on: windows-2016
|
||||
arch: x86
|
||||
cmake: 3.8
|
||||
|
||||
- runs-on: windows-2016
|
||||
arch: x86
|
||||
cmake: 3.18
|
||||
|
||||
name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python 3.7
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.7
|
||||
architecture: ${{ matrix.arch }}
|
||||
|
||||
- name: Prepare env
|
||||
run: python -m pip install -r tests/requirements.txt
|
||||
|
||||
# An action for adding a specific version of CMake:
|
||||
# https://github.com/jwlawson/actions-setup-cmake
|
||||
- name: Setup CMake ${{ matrix.cmake }}
|
||||
uses: jwlawson/actions-setup-cmake@v1.3
|
||||
with:
|
||||
cmake-version: ${{ matrix.cmake }}
|
||||
|
||||
# These steps use a directory with a space in it intentionally
|
||||
- name: Make build directories
|
||||
run: mkdir "build dir"
|
||||
|
||||
- name: Configure
|
||||
working-directory: build dir
|
||||
shell: bash
|
||||
run: >
|
||||
cmake ..
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)")
|
||||
|
||||
# Only build and test if this was manually triggered in the GitHub UI
|
||||
- name: Build
|
||||
working-directory: build dir
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: cmake --build . --config Release
|
||||
|
||||
- name: Test
|
||||
working-directory: build dir
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: cmake --build . --config Release --target check
|
||||
|
||||
# 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
|
||||
# challenging matrix element.
|
||||
test-packaging:
|
||||
name: 🐍 2.7 • 📦 tests • windows-latest
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup 🐍 2.7
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 2.7
|
||||
|
||||
- name: Prepare env
|
||||
run: python -m pip install -r tests/requirements.txt --prefer-binary
|
||||
|
||||
- name: Python Packaging tests
|
||||
run: pytest tests/extra_python_package/
|
||||
|
||||
|
||||
# This runs the packaging tests and also builds and saves the packages as
|
||||
# artifacts.
|
||||
packaging:
|
||||
name: 🐍 3.8 • 📦 & 📦 tests • ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup 🐍 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Prepare env
|
||||
run: python -m pip install -r tests/requirements.txt build twine --prefer-binary
|
||||
|
||||
- name: Python Packaging tests
|
||||
run: pytest tests/extra_python_package/
|
||||
|
||||
- name: Build SDist and wheels
|
||||
run: |
|
||||
python -m build -s -w .
|
||||
PYBIND11_GLOBAL_SDIST=1 python -m build -s -w .
|
||||
|
||||
- name: Check metadata
|
||||
run: twine check dist/*
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: dist/*
|
|
@ -1,3 +1,6 @@
|
|||
# This is a format job. Pre-commit has a first-party GitHub action, so we use
|
||||
# that: https://github.com/pre-commit/action
|
||||
|
||||
name: Format
|
||||
|
||||
on:
|
||||
|
@ -17,3 +20,22 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: pre-commit/action@v2.0.0
|
||||
with:
|
||||
# Slow hooks are marked with manual - slow is okay here, run them too
|
||||
extra_args: --hook-stage manual
|
||||
|
||||
clang-tidy:
|
||||
name: Clang-Tidy
|
||||
runs-on: ubuntu-latest
|
||||
container: silkeh/clang:10
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install requirements
|
||||
run: apt-get update && apt-get install -y python3-dev python3-pytest
|
||||
|
||||
- name: Configure
|
||||
run: cmake -S . -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--warnings-as-errors=*"
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -j 2
|
||||
|
|
|
@ -2,6 +2,7 @@ CMakeCache.txt
|
|||
CMakeFiles
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
cmake_uninstall.cmake
|
||||
.DS_Store
|
||||
*.so
|
||||
*.pyd
|
||||
|
@ -31,9 +32,12 @@ MANIFEST
|
|||
.*.swp
|
||||
.DS_Store
|
||||
/dist
|
||||
/build
|
||||
/cmake/
|
||||
/*build*
|
||||
.cache/
|
||||
sosize-*.txt
|
||||
pybind11Config*.cmake
|
||||
pybind11Targets.cmake
|
||||
/*env*
|
||||
/.vscode
|
||||
/pybind11/include/*
|
||||
/pybind11/share/*
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "tools/clang"]
|
||||
path = tools/clang
|
||||
url = ../../wjakob/clang-cindex-python3
|
|
@ -1,6 +1,21 @@
|
|||
# To use:
|
||||
#
|
||||
# pre-commit run -a
|
||||
#
|
||||
# Or:
|
||||
#
|
||||
# pre-commit install # (runs every time you commit in git)
|
||||
#
|
||||
# To update this file:
|
||||
#
|
||||
# pre-commit autoupdate
|
||||
#
|
||||
# See https://github.com/pre-commit/pre-commit
|
||||
|
||||
repos:
|
||||
# Standard hooks
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.1.0
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
|
@ -14,15 +29,60 @@ repos:
|
|||
- id: trailing-whitespace
|
||||
- id: fix-encoding-pragma
|
||||
|
||||
# Black, the code formatter, natively supports pre-commit
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 20.8b1
|
||||
hooks:
|
||||
- id: black
|
||||
# Not all Python files are Blacked, yet
|
||||
files: ^(setup.py|pybind11|tests/extra)
|
||||
|
||||
# Changes tabs to spaces
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.1.7
|
||||
rev: v1.1.9
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
exclude: (Makefile|debian/rules|.gitmodules)(\.in)?$
|
||||
|
||||
# Flake8 also supports pre-commit natively (same author)
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.2
|
||||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [flake8-bugbear]
|
||||
additional_dependencies: [flake8-bugbear, pep8-naming]
|
||||
exclude: ^(docs/.*|tools/.*)$
|
||||
|
||||
# CMake formatting
|
||||
- repo: https://github.com/cheshirekow/cmake-format-precommit
|
||||
rev: v0.6.11
|
||||
hooks:
|
||||
- id: cmake-format
|
||||
additional_dependencies: [pyyaml]
|
||||
types: [file]
|
||||
files: (\.cmake|CMakeLists.txt)(.in)?$
|
||||
|
||||
# Checks the manifest for missing files (native support)
|
||||
- repo: https://github.com/mgedmin/check-manifest
|
||||
rev: "0.42"
|
||||
hooks:
|
||||
- id: check-manifest
|
||||
# This is a slow hook, so only run this if --hook-stage manual is passed
|
||||
stages: [manual]
|
||||
additional_dependencies: [cmake, ninja]
|
||||
|
||||
# The original pybind11 checks for a few C++ style items
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: disallow-caps
|
||||
name: Disallow improper capitalization
|
||||
language: pygrep
|
||||
entry: PyBind|Numpy|Cmake
|
||||
exclude: .pre-commit-config.yaml
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-style
|
||||
name: Classic check-style
|
||||
language: system
|
||||
types:
|
||||
- c++
|
||||
entry: ./tools/check-style.sh
|
||||
|
|
|
@ -1,333 +0,0 @@
|
|||
language: cpp
|
||||
matrix:
|
||||
include:
|
||||
# This config does a few things:
|
||||
# - Checks C++ and Python code styles (check-style.sh and flake8).
|
||||
# - Makes sure sphinx can build the docs without any errors or warnings.
|
||||
# - Tests setup.py sdist and install (all header files should be present).
|
||||
# - Makes sure that everything still works without optional deps (numpy/scipy/eigen) and
|
||||
# also tests the automatic discovery functions in CMake (Python version, C++ standard).
|
||||
- os: linux
|
||||
dist: xenial # Necessary to run doxygen 1.8.15
|
||||
name: Style, docs, and pip
|
||||
cache: false
|
||||
before_install:
|
||||
- pyenv global $(pyenv whence 2to3) # activate all python versions
|
||||
- PY_CMD=python3
|
||||
- $PY_CMD -m pip install --user --upgrade pip wheel setuptools
|
||||
install:
|
||||
# breathe 4.14 doesn't work with bit fields. See https://github.com/michaeljones/breathe/issues/462
|
||||
# Latest breathe + Sphinx causes warnings and errors out
|
||||
- $PY_CMD -m pip install --user --upgrade "sphinx<3" sphinx_rtd_theme breathe==4.13.1 flake8 pep8-naming pytest
|
||||
- curl -fsSL https://sourceforge.net/projects/doxygen/files/rel-1.8.15/doxygen-1.8.15.linux.bin.tar.gz/download | tar xz
|
||||
- export PATH="$PWD/doxygen-1.8.15/bin:$PATH"
|
||||
script:
|
||||
- tools/check-style.sh
|
||||
- flake8
|
||||
- $PY_CMD -m sphinx -W -b html docs docs/.build
|
||||
- |
|
||||
# Make sure setup.py distributes and installs all the headers
|
||||
$PY_CMD setup.py sdist
|
||||
$PY_CMD -m pip install --user -U ./dist/*
|
||||
installed=$($PY_CMD -c "import pybind11; print(pybind11.get_include(True) + '/pybind11')")
|
||||
diff -rq $installed ./include/pybind11
|
||||
- |
|
||||
# Barebones build
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) .
|
||||
make pytest -j 2 && make cpptest -j 2
|
||||
# The following are regular test configurations, including optional dependencies.
|
||||
# With regard to each other they differ in Python version, C++ standard and compiler.
|
||||
- os: linux
|
||||
dist: trusty
|
||||
name: Python 2.7, c++11, gcc 4.8
|
||||
env: PYTHON=2.7 CPP=11 GCC=4.8
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cmake=2.\*
|
||||
- cmake-data=2.\*
|
||||
- os: linux
|
||||
dist: trusty
|
||||
name: Python 3.6, c++11, gcc 4.8
|
||||
env: PYTHON=3.6 CPP=11 GCC=4.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
packages:
|
||||
- python3.6-dev
|
||||
- python3.6-venv
|
||||
- cmake=2.\*
|
||||
- cmake-data=2.\*
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env: PYTHON=2.7 CPP=14 GCC=6 CMAKE=1
|
||||
name: Python 2.7, c++14, gcc 6, CMake test
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-6
|
||||
- os: linux
|
||||
dist: trusty
|
||||
name: Python 3.5, c++14, gcc 6, Debug build
|
||||
# N.B. `ensurepip` could be installed transitively by `python3.5-venv`, but
|
||||
# seems to have apt conflicts (at least for Trusty). Use Docker instead.
|
||||
services: docker
|
||||
env: DOCKER=debian:stretch PYTHON=3.5 CPP=14 GCC=6 DEBUG=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env: PYTHON=3.6 CPP=17 GCC=7
|
||||
name: Python 3.6, c++17, gcc 7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
- python3.6-dev
|
||||
- python3.6-venv
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env: PYTHON=3.6 CPP=17 CLANG=7
|
||||
name: Python 3.6, c++17, Clang 7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
- llvm-toolchain-xenial-7
|
||||
packages:
|
||||
- python3.6-dev
|
||||
- python3.6-venv
|
||||
- clang-7
|
||||
- libclang-7-dev
|
||||
- llvm-7-dev
|
||||
- lld-7
|
||||
- libc++-7-dev
|
||||
- libc++abi-7-dev # Why is this necessary???
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env: PYTHON=3.8 CPP=17 GCC=7
|
||||
name: Python 3.8, c++17, gcc 7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
- python3.8-dev
|
||||
- python3.8-venv
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env: PYTHON=3.9 CPP=17 GCC=7
|
||||
name: Python 3.9 beta, c++17, gcc 7 (w/o numpy/scipy) # TODO: update build name when the numpy/scipy wheels become available
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
- python3.9-dev
|
||||
- python3.9-venv
|
||||
# Currently there are no numpy/scipy wheels available for python3.9
|
||||
# TODO: remove next install and script clause when the wheels become available
|
||||
install:
|
||||
- $PY_CMD -m pip install --user --upgrade pytest
|
||||
script:
|
||||
- |
|
||||
# Barebones build
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) .
|
||||
make pytest -j 2 && make cpptest -j 2
|
||||
- os: osx
|
||||
name: Python 2.7, c++14, AppleClang 7.3, CMake test
|
||||
osx_image: xcode7.3
|
||||
env: PYTHON=2.7 CPP=14 CLANG CMAKE=1
|
||||
- os: osx
|
||||
name: Python 3.8, c++14, AppleClang 9, Debug build
|
||||
osx_image: xcode9.4
|
||||
env: PYTHON=3.8 CPP=14 CLANG DEBUG=1
|
||||
# Test a PyPy 2.7 build
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env: PYPY=7.3.1 PYTHON=2.7 CPP=11 GCC=4.8
|
||||
name: PyPy 7.3, Python 2.7, c++11, gcc 4.8
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libblas-dev
|
||||
- liblapack-dev
|
||||
- gfortran
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env: PYPY=7.3.1 PYTHON=3.6 CPP=11 GCC=5
|
||||
name: PyPy 7.3, Python 3.6, c++11, gcc 5
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libblas-dev
|
||||
- liblapack-dev
|
||||
- gfortran
|
||||
- g++-5
|
||||
# Build in 32-bit mode and tests against the CMake-installed version
|
||||
- os: linux
|
||||
dist: trusty
|
||||
services: docker
|
||||
env: DOCKER=i386/debian:stretch PYTHON=3.5 CPP=14 GCC=6 INSTALL=1
|
||||
name: Python 3.5, c++14, gcc 6, 32-bit
|
||||
script:
|
||||
- |
|
||||
# Consolidated 32-bit Docker Build + Install
|
||||
set -ex
|
||||
$SCRIPT_RUN_PREFIX sh -c "
|
||||
set -ex
|
||||
cmake ${CMAKE_EXTRA_ARGS} -DPYBIND11_INSTALL=1 -DPYBIND11_TEST=0 .
|
||||
make install
|
||||
cp -a tests /pybind11-tests
|
||||
mkdir /build-tests && cd /build-tests
|
||||
cmake ../pybind11-tests ${CMAKE_EXTRA_ARGS} -DPYBIND11_WERROR=ON
|
||||
make pytest -j 2"
|
||||
set +ex
|
||||
allow_failures:
|
||||
- name: Python 3.9 beta, c++17, gcc 7 (w/o numpy/scipy)
|
||||
- name: PyPy 7.3, Python 2.7, c++11, gcc 4.8
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.local/bin
|
||||
- $HOME/.local/lib
|
||||
- $HOME/.local/include
|
||||
- $HOME/Library/Python
|
||||
before_install:
|
||||
- |
|
||||
# Configure build variables
|
||||
set -ex
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ -n "$CLANG" ]; then
|
||||
export CXX=clang++-$CLANG CC=clang-$CLANG
|
||||
EXTRA_PACKAGES+=" clang-$CLANG llvm-$CLANG-dev"
|
||||
else
|
||||
if [ -z "$GCC" ]; then GCC=4.8
|
||||
else EXTRA_PACKAGES+=" g++-$GCC"
|
||||
fi
|
||||
export CXX=g++-$GCC CC=gcc-$GCC
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export CXX=clang++ CC=clang;
|
||||
fi
|
||||
if [ -n "$CPP" ]; then CPP=-std=c++$CPP; fi
|
||||
if [ "${PYTHON:0:1}" = "3" ]; then PY=3; fi
|
||||
if [ -n "$DEBUG" ]; then CMAKE_EXTRA_ARGS+=" -DCMAKE_BUILD_TYPE=Debug"; fi
|
||||
set +ex
|
||||
- |
|
||||
# Initialize environment
|
||||
set -ex
|
||||
if [ -n "$DOCKER" ]; then
|
||||
docker pull $DOCKER
|
||||
|
||||
containerid=$(docker run --detach --tty \
|
||||
--volume="$PWD":/pybind11 --workdir=/pybind11 \
|
||||
--env="CC=$CC" --env="CXX=$CXX" --env="DEBIAN_FRONTEND=$DEBIAN_FRONTEND" \
|
||||
--env=GCC_COLORS=\ \
|
||||
$DOCKER)
|
||||
SCRIPT_RUN_PREFIX="docker exec --tty $containerid"
|
||||
$SCRIPT_RUN_PREFIX sh -c 'for s in 0 15; do sleep $s; apt-get update && apt-get -qy dist-upgrade && break; done'
|
||||
else
|
||||
if [ -n "$PYPY" ]; then
|
||||
curl -fSL https://bitbucket.org/pypy/pypy/downloads/pypy$PYTHON-v$PYPY-linux64.tar.bz2 | tar xj
|
||||
PY_CMD=$(echo `pwd`/pypy$PYTHON-v$PYPY-linux64/bin/pypy$PY)
|
||||
CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE:FILEPATH=$PY_CMD"
|
||||
else
|
||||
PY_CMD=python$PYTHON
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$PY" = "3" ]; then
|
||||
brew update && brew unlink python@2 && (brew upgrade python || brew install python)
|
||||
else
|
||||
curl -fsSL https://bootstrap.pypa.io/get-pip.py | $PY_CMD - --user
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$PY" = 3 ] || [ -n "$PYPY" ]; then
|
||||
$PY_CMD -m ensurepip --user
|
||||
fi
|
||||
$PY_CMD --version
|
||||
$PY_CMD -m pip install --user --upgrade pip wheel
|
||||
fi
|
||||
set +ex
|
||||
install:
|
||||
- |
|
||||
# Install dependencies
|
||||
set -ex
|
||||
cmake --version
|
||||
if [ -n "$DOCKER" ]; then
|
||||
if [ -n "$DEBUG" ]; then
|
||||
PY_DEBUG="python$PYTHON-dbg python$PY-scipy-dbg"
|
||||
CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE=/usr/bin/python${PYTHON}dm"
|
||||
fi
|
||||
$SCRIPT_RUN_PREFIX sh -c "for s in 0 15; do sleep \$s; \
|
||||
apt-get -qy --no-install-recommends install \
|
||||
$PY_DEBUG python$PYTHON-dev python$PY-pytest python$PY-scipy \
|
||||
libeigen3-dev libboost-dev cmake make ${EXTRA_PACKAGES} && break; done"
|
||||
else
|
||||
|
||||
if [ "$CLANG" = "7" ]; then
|
||||
export CXXFLAGS="-stdlib=libc++"
|
||||
fi
|
||||
|
||||
export NPY_NUM_BUILD_JOBS=2
|
||||
local PIP_CMD=""
|
||||
if [ -n "$PYPY" ]; then
|
||||
# For expediency, install only versions that are available on the extra index.
|
||||
echo "Not installing numpy, scipy as working wheels are not available"
|
||||
# travis_wait 30 $PY_CMD -m pip install --user --upgrade --extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010 \
|
||||
# numpy scipy
|
||||
echo "Installing pytest"
|
||||
travis_wait 30 \
|
||||
$PY_CMD -m pip install --user --upgrade pytest
|
||||
else
|
||||
echo "Installing pytest, numpy, scipy..."
|
||||
$PY_CMD -m pip install --user --upgrade pytest numpy scipy
|
||||
fi
|
||||
echo "done."
|
||||
|
||||
mkdir eigen
|
||||
curl -fsSL https://bitbucket.org/eigen/eigen/get/3.3.4.tar.bz2 | \
|
||||
tar --extract -j --directory=eigen --strip-components=1
|
||||
export CMAKE_INCLUDE_PATH="${CMAKE_INCLUDE_PATH:+$CMAKE_INCLUDE_PATH:}$PWD/eigen"
|
||||
fi
|
||||
set +ex
|
||||
script:
|
||||
- |
|
||||
# CMake Configuration
|
||||
set -ex
|
||||
$SCRIPT_RUN_PREFIX cmake ${CMAKE_EXTRA_ARGS} \
|
||||
-DPYBIND11_PYTHON_VERSION=$PYTHON \
|
||||
-DPYBIND11_CPP_STANDARD=$CPP \
|
||||
-DPYBIND11_WERROR=${WERROR:-ON} \
|
||||
-DDOWNLOAD_CATCH=${DOWNLOAD_CATCH:-ON} \
|
||||
.
|
||||
set +ex
|
||||
- |
|
||||
# pytest
|
||||
set -ex
|
||||
$SCRIPT_RUN_PREFIX make pytest -j 2 VERBOSE=1
|
||||
set +ex
|
||||
- |
|
||||
# cpptest
|
||||
set -ex
|
||||
$SCRIPT_RUN_PREFIX make cpptest -j 2
|
||||
set +ex
|
||||
- |
|
||||
# CMake Build Interface
|
||||
set -ex
|
||||
if [ -n "$CMAKE" ]; then $SCRIPT_RUN_PREFIX make test_cmake_build; fi
|
||||
set +ex
|
||||
after_failure: cat tests/test_cmake_build/*.log*
|
||||
after_script:
|
||||
- |
|
||||
# Cleanup (Docker)
|
||||
set -ex
|
||||
if [ -n "$DOCKER" ]; then docker stop "$containerid"; docker rm "$containerid"; fi
|
||||
set +ex
|
|
@ -5,153 +5,263 @@
|
|||
# All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
if (POLICY CMP0048)
|
||||
# cmake warns if loaded from a min-3.0-required parent dir, so silence the warning:
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
# CMake versions < 3.4.0 do not support try_compile/pthread checks without C as active language.
|
||||
if(CMAKE_VERSION VERSION_LESS 3.4.0)
|
||||
project(pybind11)
|
||||
else()
|
||||
project(pybind11 CXX)
|
||||
# Extract project version from source
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h"
|
||||
pybind11_version_defines REGEX "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) ")
|
||||
|
||||
foreach(ver ${pybind11_version_defines})
|
||||
if(ver MATCHES [[#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$]])
|
||||
set(PYBIND11_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(PYBIND11_VERSION_PATCH MATCHES [[\.([a-zA-Z0-9]+)$]])
|
||||
set(pybind11_VERSION_TYPE "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
string(REGEX MATCH "^[0-9]+" PYBIND11_VERSION_PATCH "${PYBIND11_VERSION_PATCH}")
|
||||
|
||||
project(
|
||||
pybind11
|
||||
LANGUAGES CXX
|
||||
VERSION "${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH}")
|
||||
|
||||
# Standard includes
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
if(NOT pybind11_FIND_QUIETLY)
|
||||
message(STATUS "pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}")
|
||||
endif()
|
||||
|
||||
# Check if pybind11 is being used directly or via add_subdirectory
|
||||
set(PYBIND11_MASTER_PROJECT OFF)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
### Warn if not an out-of-source builds
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
set(lines
|
||||
"You are building in-place. If that is not what you intended to "
|
||||
"do, you can clean the source directory with:\n"
|
||||
"rm -r CMakeCache.txt CMakeFiles/ cmake_uninstall.cmake pybind11Config.cmake "
|
||||
"pybind11ConfigVersion.cmake tests/CMakeFiles/\n")
|
||||
message(AUTHOR_WARNING ${lines})
|
||||
endif()
|
||||
|
||||
set(PYBIND11_MASTER_PROJECT ON)
|
||||
|
||||
if(OSX AND CMAKE_VERSION VERSION_LESS 3.7)
|
||||
# Bug in macOS CMake < 3.7 is unable to download catch
|
||||
message(WARNING "CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended")
|
||||
elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8)
|
||||
# Only tested with 3.8+ in CI.
|
||||
message(WARNING "CMAKE 3.8+ tested on Windows, previous versions untested")
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake ${CMAKE_VERSION}")
|
||||
|
||||
if(CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
else()
|
||||
set(PYBIND11_MASTER_PROJECT OFF)
|
||||
set(pybind11_system SYSTEM)
|
||||
endif()
|
||||
|
||||
# Options
|
||||
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)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools")
|
||||
cmake_dependent_option(
|
||||
USE_PYTHON_INCLUDE_DIR
|
||||
"Install pybind11 headers in Python include directory instead of default installation prefix"
|
||||
OFF "PYBIND11_INSTALL" OFF)
|
||||
|
||||
include(pybind11Tools)
|
||||
|
||||
# Cache variables so pybind11_add_module can be used in parent projects
|
||||
set(PYBIND11_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "")
|
||||
set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE INTERNAL "")
|
||||
set(PYTHON_LIBRARIES ${PYTHON_LIBRARIES} CACHE INTERNAL "")
|
||||
set(PYTHON_MODULE_PREFIX ${PYTHON_MODULE_PREFIX} CACHE INTERNAL "")
|
||||
set(PYTHON_MODULE_EXTENSION ${PYTHON_MODULE_EXTENSION} CACHE INTERNAL "")
|
||||
set(PYTHON_VERSION_MAJOR ${PYTHON_VERSION_MAJOR} CACHE INTERNAL "")
|
||||
set(PYTHON_VERSION_MINOR ${PYTHON_VERSION_MINOR} CACHE INTERNAL "")
|
||||
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" OFF
|
||||
"NOT CMAKE_VERSION VERSION_LESS 3.12" OFF)
|
||||
|
||||
# NB: when adding a header don't forget to also add it to setup.py
|
||||
set(PYBIND11_HEADERS
|
||||
include/pybind11/detail/class.h
|
||||
include/pybind11/detail/common.h
|
||||
include/pybind11/detail/descr.h
|
||||
include/pybind11/detail/init.h
|
||||
include/pybind11/detail/internals.h
|
||||
include/pybind11/detail/typeid.h
|
||||
include/pybind11/attr.h
|
||||
include/pybind11/buffer_info.h
|
||||
include/pybind11/cast.h
|
||||
include/pybind11/chrono.h
|
||||
include/pybind11/common.h
|
||||
include/pybind11/complex.h
|
||||
include/pybind11/options.h
|
||||
include/pybind11/eigen.h
|
||||
include/pybind11/embed.h
|
||||
include/pybind11/eval.h
|
||||
include/pybind11/functional.h
|
||||
include/pybind11/numpy.h
|
||||
include/pybind11/operators.h
|
||||
include/pybind11/pybind11.h
|
||||
include/pybind11/pytypes.h
|
||||
include/pybind11/stl.h
|
||||
include/pybind11/stl_bind.h
|
||||
)
|
||||
string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||
PYBIND11_HEADERS "${PYBIND11_HEADERS}")
|
||||
include/pybind11/detail/class.h
|
||||
include/pybind11/detail/common.h
|
||||
include/pybind11/detail/descr.h
|
||||
include/pybind11/detail/init.h
|
||||
include/pybind11/detail/internals.h
|
||||
include/pybind11/detail/typeid.h
|
||||
include/pybind11/attr.h
|
||||
include/pybind11/buffer_info.h
|
||||
include/pybind11/cast.h
|
||||
include/pybind11/chrono.h
|
||||
include/pybind11/common.h
|
||||
include/pybind11/complex.h
|
||||
include/pybind11/options.h
|
||||
include/pybind11/eigen.h
|
||||
include/pybind11/embed.h
|
||||
include/pybind11/eval.h
|
||||
include/pybind11/iostream.h
|
||||
include/pybind11/functional.h
|
||||
include/pybind11/numpy.h
|
||||
include/pybind11/operators.h
|
||||
include/pybind11/pybind11.h
|
||||
include/pybind11/pytypes.h
|
||||
include/pybind11/stl.h
|
||||
include/pybind11/stl_bind.h)
|
||||
|
||||
if (PYBIND11_TEST)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
# extract project version from source
|
||||
file(STRINGS "${PYBIND11_INCLUDE_DIR}/pybind11/detail/common.h" pybind11_version_defines
|
||||
REGEX "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) ")
|
||||
foreach(ver ${pybind11_version_defines})
|
||||
if (ver MATCHES "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
|
||||
set(PYBIND11_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
|
||||
# Compare with grep and warn if mismatched
|
||||
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||
file(
|
||||
GLOB_RECURSE _pybind11_header_check
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
CONFIGURE_DEPENDS "include/pybind11/*.h")
|
||||
set(_pybind11_here_only ${PYBIND11_HEADERS})
|
||||
set(_pybind11_disk_only ${_pybind11_header_check})
|
||||
list(REMOVE_ITEM _pybind11_here_only ${_pybind11_header_check})
|
||||
list(REMOVE_ITEM _pybind11_disk_only ${PYBIND11_HEADERS})
|
||||
if(_pybind11_here_only)
|
||||
message(AUTHOR_WARNING "PYBIND11_HEADERS has extra files:" ${_pybind11_here_only})
|
||||
endif()
|
||||
if(_pybind11_disk_only)
|
||||
message(AUTHOR_WARNING "PYBIND11_HEADERS is missing files:" ${_pybind11_disk_only})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${PROJECT_NAME}_VERSION ${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH})
|
||||
message(STATUS "pybind11 v${${PROJECT_NAME}_VERSION}")
|
||||
|
||||
option (USE_PYTHON_INCLUDE_DIR "Install pybind11 headers in Python include directory instead of default installation prefix" OFF)
|
||||
if (USE_PYTHON_INCLUDE_DIR)
|
||||
file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0
|
||||
# Build an interface library target:
|
||||
add_library(pybind11 INTERFACE)
|
||||
add_library(pybind11::pybind11 ALIAS pybind11) # to match exported target
|
||||
target_include_directories(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_INCLUDE_DIR}>
|
||||
$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>
|
||||
# CMake 3.12 added list(TRANSFORM <list> PREPEND
|
||||
# But we can't use it yet
|
||||
string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" PYBIND11_HEADERS
|
||||
"${PYBIND11_HEADERS}")
|
||||
|
||||
# Cache variables so pybind11_add_module can be used in parent projects
|
||||
set(PYBIND11_INCLUDE_DIR
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include"
|
||||
CACHE INTERNAL "")
|
||||
|
||||
# Note: when creating targets, you cannot use if statements at configure time -
|
||||
# you need generator expressions, because those will be placed in the target file.
|
||||
# You can also place ifs *in* the Config.in, but not here.
|
||||
|
||||
# This section builds targets, but does *not* touch Python
|
||||
|
||||
# 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
|
||||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake")
|
||||
|
||||
# Relative directory setting
|
||||
if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS)
|
||||
file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${Python_INCLUDE_DIRS})
|
||||
elseif(USE_PYTHON_INCLUDE_DIR AND DEFINED PYTHON_INCLUDE_DIR)
|
||||
file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS})
|
||||
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_options(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_CPP_STANDARD}>)
|
||||
|
||||
add_library(module INTERFACE)
|
||||
add_library(pybind11::module ALIAS module)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(module INTERFACE -fvisibility=hidden)
|
||||
endif()
|
||||
target_link_libraries(module INTERFACE pybind11::pybind11)
|
||||
if(WIN32 OR CYGWIN)
|
||||
target_link_libraries(module INTERFACE $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
|
||||
elseif(APPLE)
|
||||
target_link_libraries(module INTERFACE "-undefined dynamic_lookup")
|
||||
endif()
|
||||
target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals
|
||||
cxx_right_angle_brackets)
|
||||
|
||||
add_library(embed INTERFACE)
|
||||
add_library(pybind11::embed ALIAS embed)
|
||||
target_link_libraries(embed INTERFACE pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
|
||||
endif()
|
||||
|
||||
if (PYBIND11_INSTALL)
|
||||
if(PYBIND11_INSTALL)
|
||||
install(DIRECTORY ${PYBIND11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
# GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share".
|
||||
set(PYBIND11_CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11Config.cmake")
|
||||
set(PYBIND11_CMAKECONFIG_INSTALL_DIR
|
||||
"share/cmake/${PROJECT_NAME}"
|
||||
CACHE STRING "install path for pybind11Config.cmake")
|
||||
|
||||
configure_package_config_file(tools/${PROJECT_NAME}Config.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||
# Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does
|
||||
# not depend on architecture specific settings or libraries.
|
||||
set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||
unset(CMAKE_SIZEOF_VOID_P)
|
||||
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
tools/FindPythonLibsNew.cmake
|
||||
tools/pybind11Tools.cmake
|
||||
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||
configure_package_config_file(
|
||||
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||
|
||||
if(NOT (CMAKE_VERSION VERSION_LESS 3.0))
|
||||
if(NOT PYBIND11_EXPORT_NAME)
|
||||
set(PYBIND11_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
if(CMAKE_VERSION VERSION_LESS 3.14)
|
||||
# Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does
|
||||
# not depend on architecture specific settings or libraries.
|
||||
set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||
unset(CMAKE_SIZEOF_VOID_P)
|
||||
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P})
|
||||
else()
|
||||
# CMake 3.14+ natively supports header-only libraries
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
tools/FindPythonLibsNew.cmake
|
||||
tools/pybind11Common.cmake
|
||||
tools/pybind11Tools.cmake
|
||||
tools/pybind11NewTools.cmake
|
||||
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||
|
||||
if(NOT PYBIND11_EXPORT_NAME)
|
||||
set(PYBIND11_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
endif()
|
||||
|
||||
install(TARGETS pybind11_headers EXPORT "${PYBIND11_EXPORT_NAME}")
|
||||
|
||||
install(
|
||||
EXPORT "${PYBIND11_EXPORT_NAME}"
|
||||
NAMESPACE "pybind11::"
|
||||
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||
|
||||
# Uninstall target
|
||||
if(PYBIND11_MASTER_PROJECT)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# BUILD_TESTING takes priority, but only if this is the master project
|
||||
if(PYBIND11_MASTER_PROJECT AND DEFINED BUILD_TESTING)
|
||||
if(BUILD_TESTING)
|
||||
if(_pybind11_nopython)
|
||||
message(FATAL_ERROR "Cannot activate tests in NOPYTHON mode")
|
||||
else()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
install(TARGETS pybind11 module embed
|
||||
EXPORT "${PYBIND11_EXPORT_NAME}")
|
||||
if(PYBIND11_MASTER_PROJECT)
|
||||
install(EXPORT "${PYBIND11_EXPORT_NAME}"
|
||||
NAMESPACE "${PROJECT_NAME}::"
|
||||
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
|
||||
endif()
|
||||
else()
|
||||
if(PYBIND11_TEST)
|
||||
if(_pybind11_nopython)
|
||||
message(FATAL_ERROR "Cannot activate tests in NOPYTHON mode")
|
||||
else()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Better symmetry with find_package(pybind11 CONFIG) mode.
|
||||
if(NOT PYBIND11_MASTER_PROJECT)
|
||||
set(pybind11_FOUND
|
||||
TRUE
|
||||
CACHE INTERNAL "true if pybind11 and all required components found on the system")
|
||||
set(pybind11_INCLUDE_DIR
|
||||
"${PYBIND11_INCLUDE_DIR}"
|
||||
CACHE INTERNAL "Directory where pybind11 headers are located")
|
||||
endif()
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
Thank you for your interest in this project! Please refer to the following
|
||||
sections on how to contribute code and bug reports.
|
||||
|
||||
### Reporting bugs
|
||||
|
||||
At the moment, this project is run in the spare time of a single person
|
||||
([Wenzel Jakob](http://rgl.epfl.ch/people/wjakob)) with very limited resources
|
||||
for issue tracker tickets. Thus, before submitting a question or bug report,
|
||||
please take a moment of your time and ensure that your issue isn't already
|
||||
discussed in the project documentation provided at
|
||||
[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest).
|
||||
|
||||
Assuming that you have identified a previously unknown problem or an important
|
||||
question, it's essential that you submit a self-contained and minimal piece of
|
||||
code that reproduces the problem. In other words: 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 on my end.
|
||||
|
||||
## Pull requests
|
||||
Contributions are submitted, reviewed, and accepted using Github pull requests.
|
||||
Please refer to [this
|
||||
article](https://help.github.com/articles/using-pull-requests) for details and
|
||||
adhere to the following rules to make the process as smooth as possible:
|
||||
|
||||
* Make a new branch for every feature you're working on.
|
||||
* Make small and clean pull requests that are easy to review but make sure they
|
||||
do add value by themselves.
|
||||
* Add tests for any new functionality and run the test suite (``make pytest``)
|
||||
to ensure that no existing features break.
|
||||
* Please run [``pre-commit``][pre-commit] and ``tools/check-style.sh`` to check
|
||||
your code matches the project style. (Note that ``check-style.sh`` requires
|
||||
``gawk``.) Use `pre-commit run --all-files` before committing (or use
|
||||
installed-mode, check pre-commit docs) to verify your code passes before
|
||||
pushing to save time.
|
||||
* This project has a strong focus on providing general solutions using a
|
||||
minimal amount of code, thus small pull requests are greatly preferred.
|
||||
|
||||
[pre-commit]: https://pre-commit.com
|
||||
|
||||
### Licensing of contributions
|
||||
|
||||
pybind11 is provided under a BSD-style license that can be found in the
|
||||
``LICENSE`` file. By using, distributing, or contributing to this project, you
|
||||
agree to the terms and conditions of this license.
|
||||
|
||||
You are under no obligation whatsoever to provide any bug fixes, patches, or
|
||||
upgrades to the features, functionality or performance of the source code
|
||||
("Enhancements") to anyone; however, if you choose to make your Enhancements
|
||||
available either publicly, or directly to the author of this software, without
|
||||
imposing a separate written license agreement for such Enhancements, then you
|
||||
hereby grant the following license: a non-exclusive, royalty-free perpetual
|
||||
license to install, use, modify, prepare derivative works, incorporate into
|
||||
other computer software, distribute, and sublicense such enhancements or
|
||||
derivative works thereof, in binary and source code form.
|
|
@ -1,17 +0,0 @@
|
|||
Make sure you've completed the following steps before submitting your issue -- thank you!
|
||||
|
||||
1. Check if your question has already been answered in the [FAQ](http://pybind11.readthedocs.io/en/latest/faq.html) section.
|
||||
2. Make sure you've read the [documentation](http://pybind11.readthedocs.io/en/latest/). Your issue may be addressed there.
|
||||
3. If those resources didn't help and you only have a short question (not a bug report), consider asking in the [Gitter chat room](https://gitter.im/pybind/Lobby).
|
||||
4. If you have a genuine bug report or a more complex question which is not answered in the previous items (or not suitable for chat), please fill in the details below.
|
||||
5. Include a self-contained and minimal piece of code that reproduces the problem. If that's not possible, try to make the description as clear as possible.
|
||||
|
||||
*After reading, remove this checklist and the template text in parentheses below.*
|
||||
|
||||
## Issue description
|
||||
|
||||
(Provide a short description, state the expected behavior and what actually happens.)
|
||||
|
||||
## Reproducible example code
|
||||
|
||||
(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.)
|
|
@ -25,5 +25,5 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Please also refer to the file CONTRIBUTING.md, which clarifies licensing of
|
||||
Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of
|
||||
external contributions to this project including patches, pull requests, etc.
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
recursive-include include/pybind11 *.h
|
||||
include LICENSE README.md CONTRIBUTING.md
|
||||
recursive-include pybind11/include/pybind11 *.h
|
||||
recursive-include pybind11 *.py
|
||||
include pybind11/share/cmake/pybind11/*.cmake
|
||||
include LICENSE README.md pyproject.toml setup.py setup.cfg
|
||||
|
|
|
@ -5,15 +5,14 @@
|
|||
[](http://pybind11.readthedocs.org/en/master/?badge=master)
|
||||
[](http://pybind11.readthedocs.org/en/stable/?badge=stable)
|
||||
[](https://gitter.im/pybind/Lobby)
|
||||
[](https://travis-ci.org/pybind/pybind11)
|
||||
[](https://github.com/pybind/pybind11/actions)
|
||||
[](https://ci.appveyor.com/project/wjakob/pybind11)
|
||||
|
||||
**pybind11** is a lightweight header-only library that exposes C++ types in Python
|
||||
and vice versa, mainly to create Python bindings of existing C++ code. Its
|
||||
goals and syntax are similar to the excellent
|
||||
[Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library
|
||||
by David Abrahams: to minimize boilerplate code in traditional extension
|
||||
modules by inferring type information using compile-time introspection.
|
||||
**pybind11** is a lightweight header-only library that exposes C++ types in
|
||||
Python and vice versa, mainly to create Python bindings of existing C++ code.
|
||||
Its goals and syntax are similar to the excellent [Boost.Python][] library by
|
||||
David Abrahams: to minimize boilerplate code in traditional extension modules
|
||||
by inferring type information using compile-time introspection.
|
||||
|
||||
The main issue with Boost.Python—and the reason for creating such a similar
|
||||
project—is Boost. Boost is an enormously large and complex suite of utility
|
||||
|
@ -26,19 +25,18 @@ become an excessively large and unnecessary dependency.
|
|||
Think of this library as a tiny self-contained version of Boost.Python with
|
||||
everything stripped away that isn't relevant for binding generation. Without
|
||||
comments, the core header files only require ~4K lines of code and depend on
|
||||
Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
|
||||
compact implementation was possible thanks to some of the new C++11 language
|
||||
features (specifically: tuples, lambda functions and variadic templates). Since
|
||||
its creation, this library has grown beyond Boost.Python in many ways, leading
|
||||
to dramatically simpler binding code in many common situations.
|
||||
Python (2.7 or 3.5+, or PyPy) and the C++ standard library. This compact
|
||||
implementation was possible thanks to some of the new C++11 language features
|
||||
(specifically: tuples, lambda functions and variadic templates). Since its
|
||||
creation, this library has grown beyond Boost.Python in many ways, leading to
|
||||
dramatically simpler binding code in many common situations.
|
||||
|
||||
Tutorial and reference documentation is provided at
|
||||
[http://pybind11.readthedocs.org/en/master](http://pybind11.readthedocs.org/en/master).
|
||||
A PDF version of the manual is available
|
||||
[here](https://media.readthedocs.org/pdf/pybind11/master/pybind11.pdf).
|
||||
[pybind11.readthedocs.org][]. A PDF version of the manual is available
|
||||
[here][docs-pdf].
|
||||
|
||||
## Core features
|
||||
pybind11 can map the following core C++ features to Python
|
||||
pybind11 can map the following core C++ features to Python:
|
||||
|
||||
- Functions accepting and returning custom data structures per value, reference, or pointer
|
||||
- Instance methods and static methods
|
||||
|
@ -51,15 +49,15 @@ pybind11 can map the following core C++ features to Python
|
|||
- Custom operators
|
||||
- Single and multiple inheritance
|
||||
- STL data structures
|
||||
- Smart pointers with reference counting like ``std::shared_ptr``
|
||||
- Smart pointers with reference counting like `std::shared_ptr`
|
||||
- Internal references with correct reference counting
|
||||
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
||||
|
||||
## Goodies
|
||||
In addition to the core functionality, pybind11 provides some extra goodies:
|
||||
|
||||
- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an
|
||||
implementation-agnostic interface.
|
||||
- Python 2.7, 3.5+, and PyPy (tested on 7.3) are supported with an implementation-agnostic
|
||||
interface.
|
||||
|
||||
- It is possible to bind C++11 lambda functions with captured variables. The
|
||||
lambda capture data is stored inside the resulting Python function object.
|
||||
|
@ -83,10 +81,10 @@ In addition to the core functionality, pybind11 provides some extra goodies:
|
|||
- Binaries are generally smaller by a factor of at least 2 compared to
|
||||
equivalent bindings generated by Boost.Python. A recent pybind11 conversion
|
||||
of PyRosetta, an enormous Boost.Python binding project,
|
||||
[reported](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary
|
||||
size reduction of **5.4x** and compile time reduction by **5.8x**.
|
||||
[reported][pyrosetta-report] a binary size reduction of **5.4x** and compile
|
||||
time reduction by **5.8x**.
|
||||
|
||||
- Function signatures are precomputed at compile time (using ``constexpr``),
|
||||
- Function signatures are precomputed at compile time (using `constexpr`),
|
||||
leading to smaller binaries.
|
||||
|
||||
- With little extra effort, C++ types can be pickled and unpickled similar to
|
||||
|
@ -97,8 +95,11 @@ In addition to the core functionality, pybind11 provides some extra goodies:
|
|||
1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer)
|
||||
2. GCC 4.8 or newer
|
||||
3. Microsoft Visual Studio 2015 Update 3 or newer
|
||||
4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11 v2.0 and a [workaround](https://github.com/pybind/pybind11/issues/276))
|
||||
4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11
|
||||
v2.0 and a [workaround][intel-15-workaround])
|
||||
5. Cygwin/GCC (tested on 2.5.1)
|
||||
6. NVCC (CUDA 11 tested)
|
||||
7. NVIDIA PGI (20.7 tested)
|
||||
|
||||
## About
|
||||
|
||||
|
@ -122,8 +123,23 @@ Henry Schreiner,
|
|||
Ivan Smirnov, and
|
||||
Patrick Stewart.
|
||||
|
||||
### Contributing
|
||||
|
||||
See the [contributing guide][] for information on building and contributing to
|
||||
pybind11.
|
||||
|
||||
|
||||
### License
|
||||
|
||||
pybind11 is provided under a BSD-style license that can be found in the
|
||||
``LICENSE`` file. By using, distributing, or contributing to this project,
|
||||
[`LICENSE`][] file. By using, distributing, or contributing to this project,
|
||||
you agree to the terms and conditions of this license.
|
||||
|
||||
|
||||
[pybind11.readthedocs.org]: http://pybind11.readthedocs.org/en/master
|
||||
[docs-pdf]: https://media.readthedocs.org/pdf/pybind11/master/pybind11.pdf
|
||||
[Boost.Python]: http://www.boost.org/doc/libs/1_58_0/libs/python/doc/
|
||||
[pyrosetta-report]: http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf
|
||||
[contributing guide]: https://github.com/pybind/pybind11/blob/master/.github/CONTRIBUTING.md
|
||||
[`LICENSE`]: https://github.com/pybind/pybind11/blob/master/LICENSE
|
||||
[intel-15-workaround]: https://github.com/pybind/pybind11/issues/276
|
||||
|
|
|
@ -29,9 +29,9 @@ The following Python snippet demonstrates the intended usage from the Python sid
|
|||
from example import print
|
||||
print(A())
|
||||
|
||||
To register the necessary conversion routines, it is necessary to add
|
||||
a partial overload to the ``pybind11::detail::type_caster<T>`` template.
|
||||
Although this is an implementation detail, adding partial overloads to this
|
||||
To register the necessary conversion routines, it is necessary to add an
|
||||
instantiation of the ``pybind11::detail::type_caster<T>`` template.
|
||||
Although this is an implementation detail, adding an instantiation of this
|
||||
type is explicitly allowed.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
|
|
@ -274,7 +274,7 @@ Vectors versus column/row matrices
|
|||
|
||||
Eigen and numpy have fundamentally different notions of a vector. In Eigen, a
|
||||
vector is simply a matrix with the number of columns or rows set to 1 at
|
||||
compile time (for a column vector or row vector, respectively). Numpy, in
|
||||
compile time (for a column vector or row vector, respectively). NumPy, in
|
||||
contrast, has comparable 2-dimensional 1xN and Nx1 arrays, but *also* has
|
||||
1-dimensional arrays of size N.
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _type-conversions:
|
||||
|
||||
Type conversions
|
||||
################
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ the declaration
|
|||
|
||||
before any binding code (e.g. invocations to ``class_::def()``, etc.). This
|
||||
macro must be specified at the top level (and outside of any namespaces), since
|
||||
it instantiates a partial template overload. If your binding code consists of
|
||||
it adds a template instantiation of ``type_caster``. If your binding code consists of
|
||||
multiple compilation units, it must be present in every file (typically via a
|
||||
common header) preceding any usage of ``std::vector<int>``. Opaque types must
|
||||
also have a corresponding ``class_`` declaration to associate them with a name
|
||||
|
|
|
@ -71,7 +71,7 @@ helper class that is defined as follows:
|
|||
|
||||
/* Trampoline (need one for each virtual function) */
|
||||
std::string go(int n_times) override {
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
std::string, /* Return type */
|
||||
Animal, /* Parent class */
|
||||
go, /* Name of function in C++ (must match Python name) */
|
||||
|
@ -80,10 +80,10 @@ helper class that is defined as follows:
|
|||
}
|
||||
};
|
||||
|
||||
The macro :c:macro:`PYBIND11_OVERLOAD_PURE` should be used for pure virtual
|
||||
functions, and :c:macro:`PYBIND11_OVERLOAD` should be used for functions which have
|
||||
The macro :c:macro:`PYBIND11_OVERRIDE_PURE` should be used for pure virtual
|
||||
functions, and :c:macro:`PYBIND11_OVERRIDE` should be used for functions which have
|
||||
a default implementation. There are also two alternate macros
|
||||
:c:macro:`PYBIND11_OVERLOAD_PURE_NAME` and :c:macro:`PYBIND11_OVERLOAD_NAME` which
|
||||
:c:macro:`PYBIND11_OVERRIDE_PURE_NAME` and :c:macro:`PYBIND11_OVERRIDE_NAME` which
|
||||
take a string-valued name argument between the *Parent class* and *Name of the
|
||||
function* slots, which defines the name of function in Python. This is required
|
||||
when the C++ and Python versions of the
|
||||
|
@ -122,7 +122,7 @@ Bindings should be made against the actual class, not the trampoline helper clas
|
|||
|
||||
Note, however, that the above is sufficient for allowing python classes to
|
||||
extend ``Animal``, but not ``Dog``: see :ref:`virtual_and_inheritance` for the
|
||||
necessary steps required to providing proper overload support for inherited
|
||||
necessary steps required to providing proper overriding support for inherited
|
||||
classes.
|
||||
|
||||
The Python session below shows how to override ``Animal::go`` and invoke it via
|
||||
|
@ -149,8 +149,7 @@ memory for the C++ portion of the instance will be left uninitialized, which
|
|||
will generally leave the C++ instance in an invalid state and cause undefined
|
||||
behavior if the C++ instance is subsequently used.
|
||||
|
||||
.. versionadded:: 2.5.1
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
The default pybind11 metaclass will throw a ``TypeError`` when it detects
|
||||
that ``__init__`` was not called by a derived class.
|
||||
|
||||
|
@ -160,7 +159,7 @@ Here is an example:
|
|||
|
||||
class Dachshund(Dog):
|
||||
def __init__(self, name):
|
||||
Dog.__init__(self) # Without this, undefined behavior may occur if the C++ portions are referenced.
|
||||
Dog.__init__(self) # Without this, a TypeError is raised.
|
||||
self.name = name
|
||||
def bark(self):
|
||||
return "yap!"
|
||||
|
@ -182,15 +181,24 @@ Please take a look at the :ref:`macro_notes` before using this feature.
|
|||
|
||||
- because in these cases there is no C++ variable to reference (the value
|
||||
is stored in the referenced Python variable), pybind11 provides one in
|
||||
the PYBIND11_OVERLOAD macros (when needed) with static storage duration.
|
||||
Note that this means that invoking the overloaded method on *any*
|
||||
the PYBIND11_OVERRIDE macros (when needed) with static storage duration.
|
||||
Note that this means that invoking the overridden method on *any*
|
||||
instance will change the referenced value stored in *all* instances of
|
||||
that type.
|
||||
|
||||
- Attempts to modify a non-const reference will not have the desired
|
||||
effect: it will change only the static cache variable, but this change
|
||||
will not propagate to underlying Python instance, and the change will be
|
||||
replaced the next time the overload is invoked.
|
||||
replaced the next time the override is invoked.
|
||||
|
||||
.. warning::
|
||||
|
||||
The :c:macro:`PYBIND11_OVERRIDE` and accompanying macros used to be called
|
||||
``PYBIND11_OVERLOAD`` up until pybind11 v2.5.0, and :func:`get_override`
|
||||
used to be called ``get_overload``. This naming was corrected and the older
|
||||
macro and function names may soon be deprecated, in order to reduce
|
||||
confusion with overloaded functions and methods and ``py::overload_cast``
|
||||
(see :ref:`classes`).
|
||||
|
||||
.. seealso::
|
||||
|
||||
|
@ -238,20 +246,20 @@ override the ``name()`` method):
|
|||
class PyAnimal : public Animal {
|
||||
public:
|
||||
using Animal::Animal; // Inherit constructors
|
||||
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, Animal, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERLOAD(std::string, Animal, name, ); }
|
||||
std::string go(int n_times) override { PYBIND11_OVERRIDE_PURE(std::string, Animal, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERRIDE(std::string, Animal, name, ); }
|
||||
};
|
||||
class PyDog : public Dog {
|
||||
public:
|
||||
using Dog::Dog; // Inherit constructors
|
||||
std::string go(int n_times) override { PYBIND11_OVERLOAD(std::string, Dog, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERLOAD(std::string, Dog, name, ); }
|
||||
std::string bark() override { PYBIND11_OVERLOAD(std::string, Dog, bark, ); }
|
||||
std::string go(int n_times) override { PYBIND11_OVERRIDE(std::string, Dog, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERRIDE(std::string, Dog, name, ); }
|
||||
std::string bark() override { PYBIND11_OVERRIDE(std::string, Dog, bark, ); }
|
||||
};
|
||||
|
||||
.. note::
|
||||
|
||||
Note the trailing commas in the ``PYBIND11_OVERLOAD`` calls to ``name()``
|
||||
Note the trailing commas in the ``PYBIND11_OVERIDE`` calls to ``name()``
|
||||
and ``bark()``. These are needed to portably implement a trampoline for a
|
||||
function that does not take any arguments. For functions that take
|
||||
a nonzero number of arguments, the trailing comma must be omitted.
|
||||
|
@ -266,9 +274,9 @@ declare or override any virtual methods itself:
|
|||
class PyHusky : public Husky {
|
||||
public:
|
||||
using Husky::Husky; // Inherit constructors
|
||||
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, Husky, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERLOAD(std::string, Husky, name, ); }
|
||||
std::string bark() override { PYBIND11_OVERLOAD(std::string, Husky, bark, ); }
|
||||
std::string go(int n_times) override { PYBIND11_OVERRIDE_PURE(std::string, Husky, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERRIDE(std::string, Husky, name, ); }
|
||||
std::string bark() override { PYBIND11_OVERRIDE(std::string, Husky, bark, ); }
|
||||
};
|
||||
|
||||
There is, however, a technique that can be used to avoid this duplication
|
||||
|
@ -281,15 +289,15 @@ follows:
|
|||
template <class AnimalBase = Animal> class PyAnimal : public AnimalBase {
|
||||
public:
|
||||
using AnimalBase::AnimalBase; // Inherit constructors
|
||||
std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, AnimalBase, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERLOAD(std::string, AnimalBase, name, ); }
|
||||
std::string go(int n_times) override { PYBIND11_OVERRIDE_PURE(std::string, AnimalBase, go, n_times); }
|
||||
std::string name() override { PYBIND11_OVERRIDE(std::string, AnimalBase, name, ); }
|
||||
};
|
||||
template <class DogBase = Dog> class PyDog : public PyAnimal<DogBase> {
|
||||
public:
|
||||
using PyAnimal<DogBase>::PyAnimal; // Inherit constructors
|
||||
// Override PyAnimal's pure virtual go() with a non-pure one:
|
||||
std::string go(int n_times) override { PYBIND11_OVERLOAD(std::string, DogBase, go, n_times); }
|
||||
std::string bark() override { PYBIND11_OVERLOAD(std::string, DogBase, bark, ); }
|
||||
std::string go(int n_times) override { PYBIND11_OVERRIDE(std::string, DogBase, go, n_times); }
|
||||
std::string bark() override { PYBIND11_OVERRIDE(std::string, DogBase, bark, ); }
|
||||
};
|
||||
|
||||
This technique has the advantage of requiring just one trampoline method to be
|
||||
|
@ -342,7 +350,7 @@ valid for the trampoline class but not the registered class. This is primarily
|
|||
for performance reasons: when the trampoline class is not needed for anything
|
||||
except virtual method dispatching, not initializing the trampoline class
|
||||
improves performance by avoiding needing to do a run-time check to see if the
|
||||
inheriting python instance has an overloaded method.
|
||||
inheriting python instance has an overridden method.
|
||||
|
||||
Sometimes, however, it is useful to always initialize a trampoline class as an
|
||||
intermediate class that does more than just handle virtual method dispatching.
|
||||
|
@ -373,7 +381,7 @@ references (See also :ref:`faq_reference_arguments`). Another way of solving
|
|||
this is to use the method body of the trampoline class to do conversions to the
|
||||
input and return of the Python method.
|
||||
|
||||
The main building block to do so is the :func:`get_overload`, this function
|
||||
The main building block to do so is the :func:`get_override`, this function
|
||||
allows retrieving a method implemented in Python from within the trampoline's
|
||||
methods. Consider for example a C++ method which has the signature
|
||||
``bool myMethod(int32_t& value)``, where the return indicates whether
|
||||
|
@ -385,10 +393,10 @@ Python side by allowing the Python function to return ``None`` or an ``int``:
|
|||
bool MyClass::myMethod(int32_t& value)
|
||||
{
|
||||
pybind11::gil_scoped_acquire gil; // Acquire the GIL while in this scope.
|
||||
// Try to look up the overloaded method on the Python side.
|
||||
pybind11::function overload = pybind11::get_overload(this, "myMethod");
|
||||
if (overload) { // method is found
|
||||
auto obj = overload(value); // Call the Python function.
|
||||
// Try to look up the overridden method on the Python side.
|
||||
pybind11::function override = pybind11::get_override(this, "myMethod");
|
||||
if (override) { // method is found
|
||||
auto obj = override(value); // Call the Python function.
|
||||
if (py::isinstance<py::int_>(obj)) { // check if it returned a Python integer type
|
||||
value = obj.cast<int32_t>(); // Cast it and assign it to the value.
|
||||
return true; // Return true; value should be used.
|
||||
|
@ -559,6 +567,46 @@ crucial that instances are deallocated on the C++ side to avoid memory leaks.
|
|||
py::class_<MyClass, std::unique_ptr<MyClass, py::nodelete>>(m, "MyClass")
|
||||
.def(py::init<>())
|
||||
|
||||
.. _destructors_that_call_python:
|
||||
|
||||
Destructors that call Python
|
||||
============================
|
||||
|
||||
If a Python function is invoked from a C++ destructor, an exception may be thrown
|
||||
of type :class:`error_already_set`. If this error is thrown out of a class destructor,
|
||||
``std::terminate()`` will be called, terminating the process. Class destructors
|
||||
must catch all exceptions of type :class:`error_already_set` to discard the Python
|
||||
exception using :func:`error_already_set::discard_as_unraisable`.
|
||||
|
||||
Every Python function should be treated as *possibly throwing*. When a Python generator
|
||||
stops yielding items, Python will throw a ``StopIteration`` exception, which can pass
|
||||
though C++ destructors if the generator's stack frame holds the last reference to C++
|
||||
objects.
|
||||
|
||||
For more information, see :ref:`the documentation on exceptions <unraisable_exceptions>`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
class MyClass {
|
||||
public:
|
||||
~MyClass() {
|
||||
try {
|
||||
py::print("Even printing is dangerous in a destructor");
|
||||
py::exec("raise ValueError('This is an unraisable exception')");
|
||||
} catch (py::error_already_set &e) {
|
||||
// error_context should be information about where/why the occurred,
|
||||
// e.g. use __func__ to get the name of the current function
|
||||
e.discard_as_unraisable(__func__);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
.. note::
|
||||
|
||||
pybind11 does not support C++ destructors marked ``noexcept(false)``.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
.. _implicit_conversions:
|
||||
|
||||
Implicit conversions
|
||||
|
@ -1065,7 +1113,7 @@ described trampoline:
|
|||
|
||||
class Trampoline : public A {
|
||||
public:
|
||||
int foo() const override { PYBIND11_OVERLOAD(int, A, foo, ); }
|
||||
int foo() const override { PYBIND11_OVERRIDE(int, A, foo, ); }
|
||||
};
|
||||
|
||||
class Publicist : public A {
|
||||
|
@ -1109,6 +1157,8 @@ error:
|
|||
|
||||
.. note:: This attribute is currently ignored on PyPy
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
Custom automatic downcasters
|
||||
============================
|
||||
|
||||
|
@ -1191,3 +1241,21 @@ appropriate derived-class pointer (e.g. using
|
|||
more complete example, including a demonstration of how to provide
|
||||
automatic downcasting for an entire class hierarchy without
|
||||
writing one get() function for each class.
|
||||
|
||||
Accessing the type object
|
||||
=========================
|
||||
|
||||
You can get the type object from a C++ class that has already been registered using:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
py::type T_py = py::type::of<T>();
|
||||
|
||||
You can directly use ``py::type::of(ob)`` to get the type object from any python
|
||||
object, just like ``type(ob)`` in Python.
|
||||
|
||||
.. note::
|
||||
|
||||
Other types, like ``py::type::of<int>()``, do not work, see :ref:`type-conversions`.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
|
|
@ -18,7 +18,7 @@ information, see :doc:`/compiling`.
|
|||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
project(example)
|
||||
|
||||
find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)`
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
Exceptions
|
||||
##########
|
||||
|
||||
Built-in exception translation
|
||||
==============================
|
||||
Built-in C++ to Python exception translation
|
||||
============================================
|
||||
|
||||
When C++ code invoked from Python throws an ``std::exception``, it is
|
||||
automatically converted into a Python ``Exception``. pybind11 defines multiple
|
||||
special exception classes that will map to different types of Python
|
||||
exceptions:
|
||||
When Python calls C++ code through pybind11, pybind11 provides a C++ exception handler
|
||||
that will trap C++ exceptions, translate them to the corresponding Python exception,
|
||||
and raise them so that Python code can handle them.
|
||||
|
||||
pybind11 defines translations for ``std::exception`` and its standard
|
||||
subclasses, and several special exception classes that translate to specific
|
||||
Python exceptions. Note that these are not actually Python exceptions, so they
|
||||
cannot be examined using the Python C API. Instead, they are pure C++ objects
|
||||
that pybind11 will translate the corresponding Python exception when they arrive
|
||||
at its exception handler.
|
||||
|
||||
.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
|
||||
|
||||
+--------------------------------------+--------------------------------------+
|
||||
| C++ exception type | Python exception type |
|
||||
| Exception thrown by C++ | Translated to Python exception type |
|
||||
+======================================+======================================+
|
||||
| :class:`std::exception` | ``RuntimeError`` |
|
||||
+--------------------------------------+--------------------------------------+
|
||||
|
@ -46,16 +52,11 @@ exceptions:
|
|||
| | ``__setitem__`` in dict-like |
|
||||
| | objects, etc.) |
|
||||
+--------------------------------------+--------------------------------------+
|
||||
| :class:`pybind11::error_already_set` | Indicates that the Python exception |
|
||||
| | flag has already been set via Python |
|
||||
| | API calls from C++ code; this C++ |
|
||||
| | exception is used to propagate such |
|
||||
| | a Python exception back to Python. |
|
||||
+--------------------------------------+--------------------------------------+
|
||||
|
||||
When a Python function invoked from C++ throws an exception, it is converted
|
||||
into a C++ exception of type :class:`error_already_set` whose string payload
|
||||
contains a textual summary.
|
||||
Exception translation is not bidirectional. That is, *catching* the C++
|
||||
exceptions defined above above will not trap exceptions that originate from
|
||||
Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below
|
||||
<handling_python_exceptions_cpp>` for further details.
|
||||
|
||||
There is also a special exception :class:`cast_error` that is thrown by
|
||||
:func:`handle::call` when the input arguments cannot be converted to Python
|
||||
|
@ -78,6 +79,19 @@ This call creates a Python exception class with the name ``PyExp`` in the given
|
|||
module and automatically converts any encountered exceptions of type ``CppExp``
|
||||
into Python exceptions of type ``PyExp``.
|
||||
|
||||
It is possible to specify base class for the exception using the third
|
||||
parameter, a `handle`:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
py::register_exception<CppExp>(module, "PyExp", PyExc_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
|
||||
documentation on `Standard Exceptions <https://docs.python.org/3/c-api/exceptions.html#standard-exceptions>`_.
|
||||
The default base class is `PyExc_Exception`.
|
||||
|
||||
When more advanced exception translation is needed, the function
|
||||
``py::register_exception_translator(translator)`` can be used to register
|
||||
functions that can translate arbitrary exception types (and which may include
|
||||
|
@ -100,7 +114,6 @@ and use this in the associated exception translator (note: it is often useful
|
|||
to make this a static declaration when using it inside a lambda expression
|
||||
without requiring capturing).
|
||||
|
||||
|
||||
The following example demonstrates this for a hypothetical exception classes
|
||||
``MyCustomException`` and ``OtherException``: the first is translated to a
|
||||
custom python exception ``MyCustomError``, while the second is translated to a
|
||||
|
@ -134,7 +147,7 @@ section.
|
|||
|
||||
.. note::
|
||||
|
||||
You must call either ``PyErr_SetString`` or a custom exception's call
|
||||
Call either ``PyErr_SetString`` or a custom exception's call
|
||||
operator (``exc(string)``) for every exception caught in a custom exception
|
||||
translator. Failure to do so will cause Python to crash with ``SystemError:
|
||||
error return without exception set``.
|
||||
|
@ -142,3 +155,144 @@ section.
|
|||
Exceptions that you do not plan to handle should simply not be caught, or
|
||||
may be explicitly (re-)thrown to delegate it to the other,
|
||||
previously-declared existing exception translators.
|
||||
|
||||
.. _handling_python_exceptions_cpp:
|
||||
|
||||
Handling exceptions from Python in C++
|
||||
======================================
|
||||
|
||||
When C++ calls Python functions, such as in a callback function or when
|
||||
manipulating Python objects, and Python raises an ``Exception``, pybind11
|
||||
converts the Python exception into a C++ exception of type
|
||||
:class:`pybind11::error_already_set` whose payload contains a C++ string textual
|
||||
summary and the actual Python exception. ``error_already_set`` is used to
|
||||
propagate Python exception back to Python (or possibly, handle them in C++).
|
||||
|
||||
.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
|
||||
|
||||
+--------------------------------------+--------------------------------------+
|
||||
| Exception raised in Python | Thrown as C++ exception type |
|
||||
+======================================+======================================+
|
||||
| Any Python ``Exception`` | :class:`pybind11::error_already_set` |
|
||||
+--------------------------------------+--------------------------------------+
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
try {
|
||||
// open("missing.txt", "r")
|
||||
auto file = py::module::import("io").attr("open")("missing.txt", "r");
|
||||
auto text = file.attr("read")();
|
||||
file.attr("close")();
|
||||
} catch (py::error_already_set &e) {
|
||||
if (e.matches(PyExc_FileNotFoundError)) {
|
||||
py::print("missing.txt not found");
|
||||
} else if (e.match(PyExc_PermissionError)) {
|
||||
py::print("missing.txt found but not accessible");
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
Note that C++ to Python exception translation does not apply here, since that is
|
||||
a method for translating C++ exceptions to Python, not vice versa. The error raised
|
||||
from Python is always ``error_already_set``.
|
||||
|
||||
This example illustrates this behavior:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
try {
|
||||
py::eval("raise ValueError('The Ring')");
|
||||
} catch (py::value_error &boromir) {
|
||||
// Boromir never gets the ring
|
||||
assert(false);
|
||||
} catch (py::error_already_set &frodo) {
|
||||
// Frodo gets the ring
|
||||
py::print("I will take the ring");
|
||||
}
|
||||
|
||||
try {
|
||||
// py::value_error is a request for pybind11 to raise a Python exception
|
||||
throw py::value_error("The ball");
|
||||
} catch (py::error_already_set &cat) {
|
||||
// cat won't catch the ball since
|
||||
// py::value_error is not a Python exception
|
||||
assert(false);
|
||||
} catch (py::value_error &dog) {
|
||||
// dog will catch the ball
|
||||
py::print("Run Spot run");
|
||||
throw; // Throw it again (pybind11 will raise ValueError)
|
||||
}
|
||||
|
||||
Handling errors from the Python C API
|
||||
=====================================
|
||||
|
||||
Where possible, use :ref:`pybind11 wrappers <wrappers>` instead of calling
|
||||
the Python C API directly. When calling the Python C API directly, in
|
||||
addition to manually managing reference counts, one must follow the pybind11
|
||||
error protocol, which is outlined here.
|
||||
|
||||
After calling the Python C API, if Python returns an error,
|
||||
``throw py::error_already_set();``, which allows pybind11 to deal with the
|
||||
exception and pass it back to the Python interpreter. This includes calls to
|
||||
the error setting functions such as ``PyErr_SetString``.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "C API type error demo");
|
||||
throw py::error_already_set();
|
||||
|
||||
// But it would be easier to simply...
|
||||
throw py::type_error("pybind11 wrapper type error");
|
||||
|
||||
Alternately, to ignore the error, call `PyErr_Clear
|
||||
<https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear>`_.
|
||||
|
||||
Any Python error must be thrown or cleared, or Python/pybind11 will be left in
|
||||
an invalid state.
|
||||
|
||||
.. _unraisable_exceptions:
|
||||
|
||||
Handling unraisable exceptions
|
||||
==============================
|
||||
|
||||
If a Python function invoked from a C++ destructor or any function marked
|
||||
``noexcept(true)`` (collectively, "noexcept functions") throws an exception, there
|
||||
is no way to propagate the exception, as such functions may not throw.
|
||||
Should they throw or fail to catch any exceptions in their call graph,
|
||||
the C++ runtime calls ``std::terminate()`` to abort immediately.
|
||||
|
||||
Similarly, Python exceptions raised in a class's ``__del__`` method do not
|
||||
propagate, but are logged by Python as an unraisable error. In Python 3.8+, a
|
||||
`system hook is triggered
|
||||
<https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_
|
||||
and an auditing event is logged.
|
||||
|
||||
Any noexcept function should have a try-catch block that traps
|
||||
class:`error_already_set` (or any other exception that can occur). Note that
|
||||
pybind11 wrappers around Python exceptions such as
|
||||
:class:`pybind11::value_error` are *not* Python exceptions; they are C++
|
||||
exceptions that pybind11 catches and converts to Python exceptions. Noexcept
|
||||
functions cannot propagate these exceptions either. A useful approach is to
|
||||
convert them to Python exceptions and then ``discard_as_unraisable`` as shown
|
||||
below.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void nonthrowing_func() noexcept(true) {
|
||||
try {
|
||||
// ...
|
||||
} catch (py::error_already_set &eas) {
|
||||
// Discard the Python error using Python APIs, using the C++ magic
|
||||
// variable __func__. Python already knows the type and value and of the
|
||||
// exception object.
|
||||
eas.discard_as_unraisable(__func__);
|
||||
} catch (const std::exception &e) {
|
||||
// Log and discard C++ exceptions.
|
||||
third_party::log(e);
|
||||
}
|
||||
}
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
|
|
@ -360,7 +360,7 @@ like so:
|
|||
.. code-block:: cpp
|
||||
|
||||
py::class_<MyClass>("MyClass")
|
||||
.def("myFunction", py::arg("arg") = (SomeType *) nullptr);
|
||||
.def("myFunction", py::arg("arg") = static_cast<SomeType *>(nullptr));
|
||||
|
||||
Keyword-only arguments
|
||||
======================
|
||||
|
@ -378,17 +378,37 @@ argument in a function definition:
|
|||
f(1, b=2) # good
|
||||
f(1, 2) # TypeError: f() takes 1 positional argument but 2 were given
|
||||
|
||||
Pybind11 provides a ``py::kwonly`` object that allows you to implement
|
||||
Pybind11 provides a ``py::kw_only`` object that allows you to implement
|
||||
the same behaviour by specifying the object between positional and keyword-only
|
||||
argument annotations when registering the function:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
m.def("f", [](int a, int b) { /* ... */ },
|
||||
py::arg("a"), py::kwonly(), py::arg("b"));
|
||||
py::arg("a"), py::kw_only(), py::arg("b"));
|
||||
|
||||
Note that, as in Python, you cannot combine this with a ``py::args`` argument.
|
||||
This feature does *not* require Python 3 to work.
|
||||
Note that you currently cannot combine this with a ``py::args`` argument. This
|
||||
feature does *not* require Python 3 to work.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
Positional-only arguments
|
||||
=========================
|
||||
|
||||
Python 3.8 introduced a new positional-only argument syntax, using ``/`` in the
|
||||
function definition (note that this has been a convention for CPython
|
||||
positional arguments, such as in ``pow()``, since Python 2). You can
|
||||
do the same thing in any version of Python using ``py::pos_only()``:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
m.def("f", [](int a, int b) { /* ... */ },
|
||||
py::arg("a"), py::pos_only(), py::arg("b"));
|
||||
|
||||
You now cannot give argument ``a`` by keyword. This can be combined with
|
||||
keyword-only arguments, as well.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
.. _nonconverting_arguments:
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@ General notes regarding convenience macros
|
|||
==========================================
|
||||
|
||||
pybind11 provides a few convenience macros such as
|
||||
:func:`PYBIND11_DECLARE_HOLDER_TYPE` and ``PYBIND11_OVERLOAD_*``. Since these
|
||||
:func:`PYBIND11_DECLARE_HOLDER_TYPE` and ``PYBIND11_OVERRIDE_*``. Since these
|
||||
are "just" macros that are evaluated in the preprocessor (which has no concept
|
||||
of types), they *will* get confused by commas in a template argument; for
|
||||
example, consider:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PYBIND11_OVERLOAD(MyReturnType<T1, T2>, Class<T3, T4>, func)
|
||||
PYBIND11_OVERRIDE(MyReturnType<T1, T2>, Class<T3, T4>, func)
|
||||
|
||||
The limitation of the C preprocessor interprets this as five arguments (with new
|
||||
arguments beginning after each comma) rather than three. To get around this,
|
||||
|
@ -26,10 +26,10 @@ using the ``PYBIND11_TYPE`` macro:
|
|||
// Version 1: using a type alias
|
||||
using ReturnType = MyReturnType<T1, T2>;
|
||||
using ClassType = Class<T3, T4>;
|
||||
PYBIND11_OVERLOAD(ReturnType, ClassType, func);
|
||||
PYBIND11_OVERRIDE(ReturnType, ClassType, func);
|
||||
|
||||
// Version 2: using the PYBIND11_TYPE macro:
|
||||
PYBIND11_OVERLOAD(PYBIND11_TYPE(MyReturnType<T1, T2>),
|
||||
PYBIND11_OVERRIDE(PYBIND11_TYPE(MyReturnType<T1, T2>),
|
||||
PYBIND11_TYPE(Class<T3, T4>), func)
|
||||
|
||||
The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds.
|
||||
|
@ -59,7 +59,7 @@ could be realized as follows (important changes highlighted):
|
|||
/* Acquire GIL before calling Python code */
|
||||
py::gil_scoped_acquire acquire;
|
||||
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
std::string, /* Return type */
|
||||
Animal, /* Parent class */
|
||||
go, /* Name of function */
|
||||
|
@ -176,9 +176,9 @@ pybind11 version. Consider the following example:
|
|||
|
||||
.. code-block:: cpp
|
||||
|
||||
auto data = (MyData *) py::get_shared_data("mydata");
|
||||
auto data = reinterpret_cast<MyData *>(py::get_shared_data("mydata"));
|
||||
if (!data)
|
||||
data = (MyData *) py::set_shared_data("mydata", new MyData(42));
|
||||
data = static_cast<MyData *>(py::set_shared_data("mydata", new MyData(42)));
|
||||
|
||||
If the above snippet was used in several separately compiled extension modules,
|
||||
the first one to be imported would create a ``MyData`` instance and associate
|
||||
|
@ -304,3 +304,34 @@ the default settings are restored to prevent unwanted side effects.
|
|||
|
||||
.. [#f4] http://www.sphinx-doc.org
|
||||
.. [#f5] http://github.com/pybind/python_example
|
||||
|
||||
.. _avoiding-cpp-types-in-docstrings:
|
||||
|
||||
Avoiding C++ types in docstrings
|
||||
================================
|
||||
|
||||
Docstrings are generated at the time of the declaration, e.g. when ``.def(...)`` is called.
|
||||
At this point parameter and return types should be known to pybind11.
|
||||
If a custom type is not exposed yet through a ``py::class_`` constructor or a custom type caster,
|
||||
its C++ type name will be used instead to generate the signature in the docstring:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
| __init__(...)
|
||||
| __init__(self: example.Foo, arg0: ns::Bar) -> None
|
||||
^^^^^^^
|
||||
|
||||
|
||||
This limitation can be circumvented by ensuring that C++ classes are registered with pybind11
|
||||
before they are used as a parameter or return type of a function:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PYBIND11_MODULE(example, m) {
|
||||
|
||||
auto pyFoo = py::class_<ns::Foo>(m, "Foo");
|
||||
auto pyBar = py::class_<ns::Bar>(m, "Bar");
|
||||
|
||||
pyFoo.def(py::init<const ns::Bar&>());
|
||||
pyBar.def(py::init<const ns::Foo&>());
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ buffer objects (e.g. a NumPy matrix).
|
|||
constexpr bool rowMajor = Matrix::Flags & Eigen::RowMajorBit;
|
||||
|
||||
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
|
||||
.def("__init__", [](py::buffer b) {
|
||||
.def(py::init([](py::buffer b) {
|
||||
typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
|
||||
|
||||
/* Request a buffer descriptor from Python */
|
||||
|
@ -101,8 +101,8 @@ buffer objects (e.g. a NumPy matrix).
|
|||
auto map = Eigen::Map<Matrix, 0, Strides>(
|
||||
static_cast<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);
|
||||
|
||||
return Matrix(m);
|
||||
});
|
||||
return Matrix(map);
|
||||
}));
|
||||
|
||||
For reference, the ``def_buffer()`` call for this Eigen data type should look
|
||||
as follows:
|
||||
|
@ -274,9 +274,9 @@ simply using ``vectorize``).
|
|||
|
||||
py::buffer_info buf3 = result.request();
|
||||
|
||||
double *ptr1 = (double *) buf1.ptr,
|
||||
*ptr2 = (double *) buf2.ptr,
|
||||
*ptr3 = (double *) buf3.ptr;
|
||||
double *ptr1 = static_cast<double *>(buf1.ptr);
|
||||
double *ptr2 = static_cast<double *>(buf2.ptr);
|
||||
double *ptr3 = static_cast<double *>(buf3.ptr);
|
||||
|
||||
for (size_t idx = 0; idx < buf1.shape[0]; idx++)
|
||||
ptr3[idx] = ptr1[idx] + ptr2[idx];
|
||||
|
@ -371,6 +371,8 @@ Ellipsis
|
|||
Python 3 provides a convenient ``...`` ellipsis notation that is often used to
|
||||
slice multidimensional arrays. For instance, the following snippet extracts the
|
||||
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
|
||||
|
||||
|
@ -385,6 +387,9 @@ operation on the C++ side:
|
|||
py::array a = /* A NumPy array */;
|
||||
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
|
||||
===========
|
||||
|
||||
|
@ -426,3 +431,6 @@ We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer:
|
|||
.. note::
|
||||
|
||||
``memoryview::from_memory`` is not available in Python 2.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
``memoryview::from_memory`` added.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Python types
|
||||
############
|
||||
|
||||
.. _wrappers:
|
||||
|
||||
Available wrappers
|
||||
==================
|
||||
|
||||
|
@ -13,6 +15,13 @@ Available types include :class:`handle`, :class:`object`, :class:`bool_`,
|
|||
:class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`,
|
||||
:class:`array`, and :class:`array_t`.
|
||||
|
||||
.. warning::
|
||||
|
||||
Be sure to review the :ref:`pytypes_gotchas` before using this heavily in
|
||||
your C++ API.
|
||||
|
||||
.. _casting_back_and_forth:
|
||||
|
||||
Casting back and forth
|
||||
======================
|
||||
|
||||
|
@ -55,6 +64,7 @@ This example obtains a reference to the Python ``Decimal`` class.
|
|||
py::object scipy = py::module::import("scipy");
|
||||
return scipy.attr("__version__");
|
||||
|
||||
|
||||
.. _calling_python_functions:
|
||||
|
||||
Calling Python functions
|
||||
|
@ -168,3 +178,74 @@ Generalized unpacking according to PEP448_ is also supported:
|
|||
Python functions from C++, including keywords arguments and unpacking.
|
||||
|
||||
.. _PEP448: https://www.python.org/dev/peps/pep-0448/
|
||||
|
||||
.. _implicit_casting:
|
||||
|
||||
Implicit casting
|
||||
================
|
||||
|
||||
When using the C++ interface for Python types, or calling Python functions,
|
||||
objects of type :class:`object` are returned. It is possible to invoke implicit
|
||||
conversions to subclasses like :class:`dict`. The same holds for the proxy objects
|
||||
returned by ``operator[]`` or ``obj.attr()``.
|
||||
Casting to subtypes improves code readability and allows values to be passed to
|
||||
C++ functions that require a specific subtype rather than a generic :class:`object`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <pybind11/numpy.h>
|
||||
using namespace pybind11::literals;
|
||||
|
||||
py::module os = py::module::import("os");
|
||||
py::module path = py::module::import("os.path"); // like 'import os.path as path'
|
||||
py::module np = py::module::import("numpy"); // like 'import numpy as np'
|
||||
|
||||
py::str curdir_abs = path.attr("abspath")(path.attr("curdir"));
|
||||
py::print(py::str("Current directory: ") + curdir_abs);
|
||||
py::dict environ = os.attr("environ");
|
||||
py::print(environ["HOME"]);
|
||||
py::array_t<float> arr = np.attr("ones")(3, "dtype"_a="float32");
|
||||
py::print(py::repr(arr + py::int_(1)));
|
||||
|
||||
These implicit conversions are available for subclasses of :class:`object`; there
|
||||
is no need to call ``obj.cast()`` explicitly as for custom classes, see
|
||||
:ref:`casting_back_and_forth`.
|
||||
|
||||
.. note::
|
||||
If a trivial conversion via move constructor is not possible, both implicit and
|
||||
explicit casting (calling ``obj.cast()``) will attempt a "rich" conversion.
|
||||
For instance, ``py::list env = os.attr("environ");`` will succeed and is
|
||||
equivalent to the Python code ``env = list(os.environ)`` that produces a
|
||||
list of the dict keys.
|
||||
|
||||
.. TODO: Adapt text once PR #2349 has landed
|
||||
|
||||
Handling exceptions
|
||||
===================
|
||||
|
||||
Python exceptions from wrapper classes will be thrown as a ``py::error_already_set``.
|
||||
See :ref:`Handling exceptions from Python in C++
|
||||
<handling_python_exceptions_cpp>` for more information on handling exceptions
|
||||
raised when calling C++ wrapper classes.
|
||||
|
||||
.. _pytypes_gotchas:
|
||||
|
||||
Gotchas
|
||||
=======
|
||||
|
||||
Default-Constructed Wrappers
|
||||
----------------------------
|
||||
|
||||
When a wrapper type is default-constructed, it is **not** a valid Python object (i.e. it is not ``py::none()``). It is simply the same as
|
||||
``PyObject*`` null pointer. To check for this, use
|
||||
``static_cast<bool>(my_wrapper)``.
|
||||
|
||||
Assigning py::none() to wrappers
|
||||
--------------------------------
|
||||
|
||||
You may be tempted to use types like ``py::str`` and ``py::dict`` in C++
|
||||
signatures (either pure C++, or in bound signatures), and assign them default
|
||||
values of ``py::none()``. However, in a best case scenario, it will fail fast
|
||||
because ``None`` is not convertible to that type (e.g. ``py::dict``), or in a
|
||||
worse case scenario, it will silently work but corrupt the types you want to
|
||||
work with (e.g. ``py::str(py::none())`` will yield ``"None"`` in Python).
|
||||
|
|
|
@ -11,11 +11,11 @@ included set of test cases.
|
|||
Compiling the test cases
|
||||
========================
|
||||
|
||||
Linux/MacOS
|
||||
Linux/macOS
|
||||
-----------
|
||||
|
||||
On Linux you'll need to install the **python-dev** or **python3-dev** packages as
|
||||
well as **cmake**. On Mac OS, the included python version works out of the box,
|
||||
well as **cmake**. On macOS, the included python version works out of the box,
|
||||
but **cmake** must still be installed.
|
||||
|
||||
After installing the prerequisites, run
|
||||
|
@ -35,6 +35,14 @@ Windows
|
|||
On Windows, only **Visual Studio 2015** and newer are supported since pybind11 relies
|
||||
on various C++11 language features that break older versions of Visual Studio.
|
||||
|
||||
.. Note::
|
||||
|
||||
To use the C++17 in Visual Studio 2017 (MSVC 14.1), pybind11 requires the flag
|
||||
``/permissive-`` to be passed to the compiler `to enforce standard conformance`_. When
|
||||
building with Visual Studio 2019, this is not strictly necessary, but still adviced.
|
||||
|
||||
.. _`to enforce standard conformance`: https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=vs-2017
|
||||
|
||||
To compile and run the tests:
|
||||
|
||||
.. code-block:: batch
|
||||
|
@ -130,7 +138,7 @@ On Linux, the above example can be compiled using the following command:
|
|||
|
||||
$ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
|
||||
|
||||
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,
|
||||
refer to the :ref:`compiling` page.
|
||||
|
||||
|
|
|
@ -6,6 +6,165 @@ Changelog
|
|||
Starting with version 1.8.0, pybind11 releases use a `semantic versioning
|
||||
<http://semver.org>`_ policy.
|
||||
|
||||
v2.6.0 (IN PROGRESS)
|
||||
--------------------
|
||||
|
||||
See :ref:`upgrade-guide-2.6` for help upgrading to the new version.
|
||||
|
||||
* Provide an additional spelling of ``py::module`` - ``py::module_`` (with a
|
||||
trailing underscore), for C++20 compatibility. Only relevant when used
|
||||
unqualified.
|
||||
`#2489 <https://github.com/pybind/pybind11/pull/2489>`_
|
||||
|
||||
* ``pybind11_add_module()`` now accepts an optional ``OPT_SIZE`` flag that
|
||||
switches the binding target to size-based optimization regardless global
|
||||
CMake build type (except in debug mode, where optimizations remain disabled).
|
||||
This reduces binary size quite substantially (~25%).
|
||||
`#2463 <https://github.com/pybind/pybind11/pull/2463>`_
|
||||
|
||||
* Keyword-only arguments supported in Python 2 or 3 with ``py::kw_only()``.
|
||||
`#2100 <https://github.com/pybind/pybind11/pull/2100>`_
|
||||
|
||||
* Positional-only arguments supported in Python 2 or 3 with ``py::pos_only()``.
|
||||
`#2459 <https://github.com/pybind/pybind11/pull/2459>`_
|
||||
|
||||
* Access to the type object now provided with ``py::type::of<T>()`` and
|
||||
``py::type::of(h)``.
|
||||
`#2364 <https://github.com/pybind/pybind11/pull/2364>`_
|
||||
|
||||
|
||||
* Perfect forwarding support for methods.
|
||||
`#2048 <https://github.com/pybind/pybind11/pull/2048>`_
|
||||
|
||||
* Added ``py::error_already_set::discard_as_unraisable()``.
|
||||
`#2372 <https://github.com/pybind/pybind11/pull/2372>`_
|
||||
|
||||
* ``py::hash`` is now public.
|
||||
`#2217 <https://github.com/pybind/pybind11/pull/2217>`_
|
||||
|
||||
* ``py::is_final()`` class modifier to block subclassing (CPython only).
|
||||
`#2151 <https://github.com/pybind/pybind11/pull/2151>`_
|
||||
|
||||
* ``py::memoryview`` update and documentation.
|
||||
`#2223 <https://github.com/pybind/pybind11/pull/2223>`_
|
||||
|
||||
* The Python package was reworked to be more powerful and useful.
|
||||
`#2433 <https://github.com/pybind/pybind11/pull/2433>`_
|
||||
|
||||
* :ref:`build-setuptools` is easier thanks to a new
|
||||
``pybind11.setup_helpers`` module, which provides utilities to use
|
||||
setuptools with pybind11. It can be used via PEP 518, ``setup_requires``,
|
||||
or by directly copying ``setup_helpers.py`` into your project.
|
||||
|
||||
* CMake configuration files are now included in the Python package. Use
|
||||
``pybind11.get_cmake_dir()`` or ``python -m pybind11 --cmakedir`` to get
|
||||
the directory with the CMake configuration files, or include the
|
||||
site-packages location in your ``CMAKE_MODULE_PATH``. Or you can use the
|
||||
new ``pybind11[global]`` extra when you install ``pybind11``, which
|
||||
installs the CMake files and headers into your base environment in the
|
||||
standard location
|
||||
|
||||
* ``pybind11-config`` is another way to write ``python -m pybind11`` if you
|
||||
have your PATH set up.
|
||||
|
||||
* Minimum CMake required increased to 3.4.
|
||||
`#2338 <https://github.com/pybind/pybind11/pull/2338>`_ and
|
||||
`#2370 <https://github.com/pybind/pybind11/pull/2370>`_
|
||||
|
||||
* Full integration with CMake’s C++ standard system replaces
|
||||
``PYBIND11_CPP_STANDARD``.
|
||||
|
||||
* Generated config file is now portable to different Python/compiler/CMake
|
||||
versions.
|
||||
|
||||
* Virtual environments prioritized if ``PYTHON_EXECUTABLE`` is not set
|
||||
(``venv``, ``virtualenv``, and ``conda``) (similar to the new FindPython
|
||||
mode).
|
||||
|
||||
* Other CMake features now natively supported, like
|
||||
``CMAKE_INTERPROCEDURAL_OPTIMIZATION``, ``set(CMAKE_CXX_VISIBILITY_PRESET
|
||||
hidden)``.
|
||||
|
||||
* Optional :ref:`find-python-mode` and :ref:`nopython-mode` with CMake.
|
||||
`#2370 <https://github.com/pybind/pybind11/pull/2370>`_
|
||||
|
||||
* Uninstall target added.
|
||||
`#2265 <https://github.com/pybind/pybind11/pull/2265>`_ and
|
||||
`#2346 <https://github.com/pybind/pybind11/pull/2346>`_
|
||||
|
||||
* ``PYBIND11_OVERLOAD*`` macros and ``get_overload`` function replaced by
|
||||
correctly-named ``PYBIND11_OVERRIDE*`` and ``get_override``, fixing
|
||||
inconsistencies in the presene of a closing ``;`` in these macros.
|
||||
``get_type_overload`` is deprecated.
|
||||
`#2325 <https://github.com/pybind/pybind11/pull/2325>`_
|
||||
|
||||
Smaller or developer focused features:
|
||||
|
||||
* Moved ``mkdoc.py`` to a new repo, `pybind11-mkdoc`_.
|
||||
|
||||
.. _pybind11-mkdoc: https://github.com/pybind/pybind11-mkdoc
|
||||
|
||||
* Error now thrown when ``__init__`` is forgotten on subclasses.
|
||||
`#2152 <https://github.com/pybind/pybind11/pull/2152>`_
|
||||
|
||||
* If ``__eq__`` defined but not ``__hash__``, ``__hash__`` is now set to
|
||||
``None``.
|
||||
`#2291 <https://github.com/pybind/pybind11/pull/2291>`_
|
||||
|
||||
* ``py::ellipsis`` now also works on Python 2.
|
||||
`#2360 <https://github.com/pybind/pybind11/pull/2360>`_
|
||||
|
||||
* Throw if conversion to ``str`` fails.
|
||||
`#2477 <https://github.com/pybind/pybind11/pull/2477>`_
|
||||
|
||||
* Added missing signature for ``py::array``.
|
||||
`#2363 <https://github.com/pybind/pybind11/pull/2363>`_
|
||||
|
||||
* Pointer to ``std::tuple`` & ``std::pair`` supported in cast.
|
||||
`#2334 <https://github.com/pybind/pybind11/pull/2334>`_
|
||||
|
||||
* Small fixes in NumPy support. ``py::array`` now uses ``py::ssize_t`` as first
|
||||
argument type.
|
||||
`#2293 <https://github.com/pybind/pybind11/pull/2293>`_
|
||||
|
||||
* Bugfixes related to more extensive testing
|
||||
`#2321 <https://github.com/pybind/pybind11/pull/2321>`_
|
||||
|
||||
* Bug in timezone issue in Eastern hemisphere midnight fixed.
|
||||
`#2438 <https://github.com/pybind/pybind11/pull/2438>`_
|
||||
|
||||
* ``std::chrono::time_point`` now works when the resolution is not the same as
|
||||
the system.
|
||||
`#2481 <https://github.com/pybind/pybind11/pull/2481>`_
|
||||
|
||||
* Bug fixed where ``py::array_t`` could accept arrays that did not match the
|
||||
requested ordering.
|
||||
`#2484 <https://github.com/pybind/pybind11/pull/2484>`_
|
||||
|
||||
* PyPy fixes, including support for PyPy3 and PyPy 7.
|
||||
`#2146 <https://github.com/pybind/pybind11/pull/2146>`_
|
||||
|
||||
* CPython 3.9 fixes.
|
||||
`#2253 <https://github.com/pybind/pybind11/pull/2253>`_
|
||||
|
||||
* More C++20 support.
|
||||
`#2489 <https://github.com/pybind/pybind11/pull/2489>`_
|
||||
|
||||
* Debug Python interpreter support.
|
||||
`#2025 <https://github.com/pybind/pybind11/pull/2025>`_
|
||||
|
||||
* NVCC (CUDA 11) now supported and tested in CI.
|
||||
`#2461 <https://github.com/pybind/pybind11/pull/2461>`_
|
||||
|
||||
* NVIDIA PGI compilers now supported and tested in CI.
|
||||
`#2475 <https://github.com/pybind/pybind11/pull/2475>`_
|
||||
|
||||
* Extensive style checking in CI, with `pre-commit`_ support.
|
||||
|
||||
.. _pre-commit: https://pre-commit.com
|
||||
|
||||
|
||||
|
||||
v2.5.0 (Mar 31, 2020)
|
||||
-----------------------------------------------------
|
||||
|
||||
|
@ -536,7 +695,7 @@ v2.2.0 (August 31, 2017)
|
|||
in reference cycles.
|
||||
`#856 <https://github.com/pybind/pybind11/pull/856>`_.
|
||||
|
||||
* Numpy and buffer protocol related improvements:
|
||||
* NumPy and buffer protocol related improvements:
|
||||
|
||||
1. Support for negative strides in Python buffer objects/numpy arrays. This
|
||||
required changing integers from unsigned to signed for the related C++ APIs.
|
||||
|
@ -1267,7 +1426,7 @@ Happy Christmas!
|
|||
* Improved support for ``std::shared_ptr<>`` conversions
|
||||
* Initial support for ``std::set<>`` conversions
|
||||
* Fixed type resolution issue for types defined in a separate plugin module
|
||||
* Cmake build system improvements
|
||||
* CMake build system improvements
|
||||
* Factored out generic functionality to non-templated code (smaller code size)
|
||||
* Added a code size / compile time benchmark vs Boost.Python
|
||||
* Added an appveyor CI script
|
||||
|
|
|
@ -74,7 +74,7 @@ Note how ``print(p)`` produced a rather useless summary of our data structure in
|
|||
>>> print(p)
|
||||
<example.Pet object at 0x10cd98060>
|
||||
|
||||
To address this, we could bind an utility function that returns a human-readable
|
||||
To address this, we could bind a utility function that returns a human-readable
|
||||
summary to the special method slot named ``__repr__``. Unfortunately, there is no
|
||||
suitable functionality in the ``Pet`` data structure, and it would be nice if
|
||||
we did not have to change it. This can easily be accomplished by binding a
|
||||
|
@ -373,8 +373,8 @@ sequence.
|
|||
|
||||
py::class_<Pet>(m, "Pet")
|
||||
.def(py::init<const std::string &, int>())
|
||||
.def("set", (void (Pet::*)(int)) &Pet::set, "Set the pet's age")
|
||||
.def("set", (void (Pet::*)(const std::string &)) &Pet::set, "Set the pet's name");
|
||||
.def("set", static_cast<void (Pet::*)(int)>(&Pet::set), "Set the pet's age")
|
||||
.def("set", static_cast<void (Pet::*)(const std::string &)>(&Pet::set), "Set the pet's name");
|
||||
|
||||
The overload signatures are also visible in the method's docstring:
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
Build systems
|
||||
#############
|
||||
|
||||
.. _build-setuptools:
|
||||
|
||||
Building with setuptools
|
||||
========================
|
||||
|
||||
|
@ -13,6 +15,135 @@ the [python_example]_ repository.
|
|||
|
||||
.. [python_example] https://github.com/pybind/python_example
|
||||
|
||||
A helper file is provided with pybind11 that can simplify usage with setuptools.
|
||||
|
||||
To use pybind11 inside your ``setup.py``, you have to have some system to
|
||||
ensure that ``pybind11`` is installed when you build your package. There are
|
||||
four possible ways to do this, and pybind11 supports all four: You can ask all
|
||||
users to install pybind11 beforehand (bad), you can use
|
||||
:ref:`setup_helpers-pep518` (good, but very new and requires Pip 10),
|
||||
:ref:`setup_helpers-setup_requires` (discouraged by Python packagers now that
|
||||
PEP 518 is available, but it still works everywhere), or you can
|
||||
:ref:`setup_helpers-copy-manually` (always works but you have to manually sync
|
||||
your copy to get updates).
|
||||
|
||||
An example of a ``setup.py`` using pybind11's helpers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from setuptools import setup
|
||||
from pybind11.setup_helpers import Pybind11Extension
|
||||
|
||||
ext_modules = [
|
||||
Pybind11Extension(
|
||||
"python_example",
|
||||
["src/main.cpp"],
|
||||
),
|
||||
]
|
||||
|
||||
setup(
|
||||
...,
|
||||
ext_modules=ext_modules
|
||||
)
|
||||
|
||||
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
|
||||
``Pybind11Extensions``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from setuptools import setup
|
||||
from pybind11.setup_helpers import Pybind11Extension, build_ext
|
||||
|
||||
ext_modules = [
|
||||
Pybind11Extension(
|
||||
"python_example",
|
||||
["src/main.cpp"],
|
||||
),
|
||||
]
|
||||
|
||||
setup(
|
||||
...,
|
||||
cmdclass={"build_ext": build_ext},
|
||||
ext_modules=ext_modules
|
||||
)
|
||||
|
||||
.. _setup_helpers-pep518:
|
||||
|
||||
PEP 518 requirements (Pip 10+ required)
|
||||
---------------------------------------
|
||||
|
||||
If you use `PEP 518's <https://www.python.org/dev/peps/pep-0518/>`_
|
||||
``pyproject.toml`` file, you can ensure that ``pybind11`` is available during
|
||||
the compilation of your project. When this file exists, Pip will make a new
|
||||
virtual environment, download just the packages listed here in ``requires=``,
|
||||
and build a wheel (binary Python package). It will then throw away the
|
||||
environment, and install your wheel.
|
||||
|
||||
Your ``pyproject.toml`` file will likely look something like this:
|
||||
|
||||
.. code-block:: toml
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools", "wheel", "pybind11==2.6.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
.. note::
|
||||
|
||||
The main drawback to this method is that a `PEP 517`_ compliant build tool,
|
||||
such as Pip 10+, is required for this approach to work; older versions of
|
||||
Pip completely ignore this file. If you distribute binaries (called wheels
|
||||
in Python) using something like `cibuildwheel`_, remember that ``setup.py``
|
||||
and ``pyproject.toml`` are not even contained in the wheel, so this high
|
||||
Pip requirement is only for source builds, and will not affect users of
|
||||
your binary wheels.
|
||||
|
||||
.. _PEP 517: https://www.python.org/dev/peps/pep-0517/
|
||||
.. _cibuildwheel: https://cibuildwheel.readthedocs.io
|
||||
|
||||
.. _setup_helpers-setup_requires:
|
||||
|
||||
Classic ``setup_requires``
|
||||
--------------------------
|
||||
|
||||
If you want to support old versions of Pip with the classic
|
||||
``setup_requires=["pybind11"]`` keyword argument to setup, which triggers a
|
||||
two-phase ``setup.py`` run, then you will need to use something like this to
|
||||
ensure the first pass works (which has not yet installed the ``setup_requires``
|
||||
packages, since it can't install something it does not know about):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from pybind11.setup_helpers import Pybind11Extension
|
||||
except ImportError:
|
||||
from setuptools import Extension as Pybind11Extension
|
||||
|
||||
|
||||
It doesn't matter that the Extension class is not the enhanced subclass for the
|
||||
first pass run; and the second pass will have the ``setup_requires``
|
||||
requirements.
|
||||
|
||||
This is obviously more of a hack than the PEP 518 method, but it supports
|
||||
ancient versions of Pip.
|
||||
|
||||
.. _setup_helpers-copy-manually:
|
||||
|
||||
Copy manually
|
||||
-------------
|
||||
|
||||
You can also copy ``setup_helpers.py`` directly to your project; it was
|
||||
designed to be usable standalone, like the old example ``setup.py``. You can
|
||||
set ``include_pybind11=False`` to skip including the pybind11 package headers,
|
||||
so you can use it with git submodules and a specific git version. If you use
|
||||
this, you will need to import from a local file in ``setup.py`` and ensure the
|
||||
helper file is part of your MANIFEST.
|
||||
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
|
||||
Added ``setup_helpers`` file.
|
||||
|
||||
Building with cppimport
|
||||
========================
|
||||
|
||||
|
@ -33,8 +164,8 @@ extension module can be created with just a few lines of code:
|
|||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(example)
|
||||
cmake_minimum_required(VERSION 3.4...3.18)
|
||||
project(example LANGUAGES CXX)
|
||||
|
||||
add_subdirectory(pybind11)
|
||||
pybind11_add_module(example example.cpp)
|
||||
|
@ -50,6 +181,9 @@ PyPI integration, can be found in the [cmake_example]_ repository.
|
|||
|
||||
.. [cmake_example] https://github.com/pybind/cmake_example
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
CMake 3.4+ is required.
|
||||
|
||||
pybind11_add_module
|
||||
-------------------
|
||||
|
||||
|
@ -59,7 +193,7 @@ function with the following signature:
|
|||
.. code-block:: cmake
|
||||
|
||||
pybind11_add_module(<name> [MODULE | SHARED] [EXCLUDE_FROM_ALL]
|
||||
[NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...])
|
||||
[NO_EXTRAS] [THIN_LTO] [OPT_SIZE] source1 [source2 ...])
|
||||
|
||||
This function behaves very much like CMake's builtin ``add_library`` (in fact,
|
||||
it's a wrapper function around that command). It will add a library target
|
||||
|
@ -86,49 +220,62 @@ latter optimizations are never applied in ``Debug`` mode. If ``NO_EXTRAS`` is
|
|||
given, they will always be disabled, even in ``Release`` mode. However, this
|
||||
will result in code bloat and is generally not recommended.
|
||||
|
||||
By default, pybind11 and Python headers will be included with ``-I``. In order
|
||||
to include pybind11 as system library, e.g. to avoid warnings in downstream
|
||||
code with warn-levels outside of pybind11's scope, set the option ``SYSTEM``.
|
||||
|
||||
As stated above, LTO is enabled by default. Some newer compilers also support
|
||||
different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause
|
||||
the function to prefer this flavor if available. The function falls back to
|
||||
regular LTO if ``-flto=thin`` is not available.
|
||||
regular LTO if ``-flto=thin`` is not available. If
|
||||
``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` is set (either ON or OFF), then that
|
||||
will be respected instead of the built-in flag search.
|
||||
|
||||
The ``OPT_SIZE`` flag enables size-based optimization equivalent to the
|
||||
standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type,
|
||||
which avoid optimizations that that can substantially increase the size of the
|
||||
resulting binary. This flag is particularly useful in projects that are split
|
||||
into performance-critical parts and associated bindings. In this case, we can
|
||||
compile the project in release mode (and hence, optimize performance globally),
|
||||
and specify ``OPT_SIZE`` for the binding target, where size might be the main
|
||||
concern as performance is often less critical here. A ~25% size reduction has
|
||||
been observed in practice. This flag only changes the optimization behavior at
|
||||
a per-target level and takes precedence over the global CMake build type
|
||||
(``Release``, ``RelWithDebInfo``) except for ``Debug`` builds, where
|
||||
optimizations remain disabled.
|
||||
|
||||
.. _ThinLTO: http://clang.llvm.org/docs/ThinLTO.html
|
||||
|
||||
Configuration variables
|
||||
-----------------------
|
||||
|
||||
By default, pybind11 will compile modules with the C++14 standard, if available
|
||||
on the target compiler, falling back to C++11 if C++14 support is not
|
||||
available. Note, however, that this default is subject to change: future
|
||||
pybind11 releases are expected to migrate to newer C++ standards as they become
|
||||
available. To override this, the standard flag can be given explicitly in
|
||||
`CMAKE_CXX_STANDARD <https://cmake.org/cmake/help/v3.17/variable/CMAKE_CXX_STANDARD.html>`_:
|
||||
By default, pybind11 will compile modules with the compiler default or the
|
||||
minimum standard required by pybind11, whichever is higher. You can set the
|
||||
standard explicitly with
|
||||
`CMAKE_CXX_STANDARD <https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_STANDARD.html>`_:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
# Use just one of these:
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD 17) # Experimental C++17 support
|
||||
set(CMAKE_CXX_STANDARD 14) # or 11, 14, 17, 20
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # optional, ensure standard is supported
|
||||
set(CMAKE_CXX_EXTENSIONS OFF) # optional, keep compiler extensionsn off
|
||||
|
||||
add_subdirectory(pybind11) # or find_package(pybind11)
|
||||
|
||||
Note that this and all other configuration variables must be set **before** the
|
||||
call to ``add_subdirectory`` or ``find_package``. The variables can also be set
|
||||
when calling CMake from the command line using the ``-D<variable>=<value>`` flag.
|
||||
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``
|
||||
on a target or use ``target_compile_features`` on your targets - anything that
|
||||
CMake supports.
|
||||
|
||||
The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION``
|
||||
or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``.
|
||||
For example:
|
||||
Classic Python support: The target Python version can be selected by setting
|
||||
``PYBIND11_PYTHON_VERSION`` or an exact Python installation can be specified
|
||||
with ``PYTHON_EXECUTABLE``. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DPYBIND11_PYTHON_VERSION=3.6 ..
|
||||
# or
|
||||
cmake -DPYTHON_EXECUTABLE=path/to/python ..
|
||||
|
||||
# Another method:
|
||||
cmake -DPYTHON_EXECUTABLE=/path/to/python ..
|
||||
|
||||
# This often is a good way to get the current Python, works in environments:
|
||||
cmake -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") ..
|
||||
|
||||
|
||||
find_package vs. add_subdirectory
|
||||
---------------------------------
|
||||
|
@ -139,8 +286,8 @@ See the `Config file`_ docstring for details of relevant CMake variables.
|
|||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(example)
|
||||
cmake_minimum_required(VERSION 3.4...3.18)
|
||||
project(example LANGUAGES CXX)
|
||||
|
||||
find_package(pybind11 REQUIRED)
|
||||
pybind11_add_module(example example.cpp)
|
||||
|
@ -151,12 +298,19 @@ the pybind11 repository :
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
# Classic CMake
|
||||
cd pybind11
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make install
|
||||
|
||||
# CMake 3.15+
|
||||
cd pybind11
|
||||
cmake -S . -B build
|
||||
cmake --build build -j 2 # Build on 2 cores
|
||||
cmake --install build
|
||||
|
||||
Once detected, the aforementioned ``pybind11_add_module`` can be employed as
|
||||
before. The function usage and configuration variables are identical no matter
|
||||
if pybind11 is added as a subdirectory or found as an installed package. You
|
||||
|
@ -165,41 +319,134 @@ can refer to the same [cmake_example]_ repository for a full sample project
|
|||
|
||||
.. _Config file: https://github.com/pybind/pybind11/blob/master/tools/pybind11Config.cmake.in
|
||||
|
||||
Advanced: interface library target
|
||||
----------------------------------
|
||||
|
||||
When using a version of CMake greater than 3.0, pybind11 can additionally
|
||||
be used as a special *interface library* . The target ``pybind11::module``
|
||||
is available with pybind11 headers, Python headers and libraries as needed,
|
||||
and C++ compile definitions attached. This target is suitable for linking
|
||||
to an independently constructed (through ``add_library``, not
|
||||
``pybind11_add_module``) target in the consuming project.
|
||||
.. _find-python-mode:
|
||||
|
||||
FindPython mode
|
||||
---------------
|
||||
|
||||
CMake 3.12+ (3.15+ recommended) added a new module called FindPython that had a
|
||||
highly improved search algorithm and modern targets and tools. If you use
|
||||
FindPython, pybind11 will detect this and use the existing targets instead:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(example)
|
||||
cmake_minumum_required(VERSION 3.15...3.18)
|
||||
project(example LANGUAGES CXX)
|
||||
|
||||
find_package(Python COMPONENTS Interpreter Development REQUIRED)
|
||||
find_package(pybind11 CONFIG REQUIRED)
|
||||
# or add_subdirectory(pybind11)
|
||||
|
||||
pybind11_add_module(example example.cpp)
|
||||
|
||||
You can also use the targets (as listed below) with FindPython. If you define
|
||||
``PYBIND11_FINDPYTHON``, pybind11 will perform the FindPython step for you
|
||||
(mostly useful when building pybind11's own tests, or as a way to change search
|
||||
algorithms from the CMake invocation, with ``-DPYBIND11_FINDPYTHON=ON``.
|
||||
|
||||
.. warning::
|
||||
|
||||
If you use FindPython2 and FindPython3 to dual-target Python, use the
|
||||
individual targets listed below, and avoid targets that directly include
|
||||
Python parts.
|
||||
|
||||
There are `many ways to hint or force a discovery of a specific Python
|
||||
installation <https://cmake.org/cmake/help/latest/module/FindPython.html>`_),
|
||||
setting ``Python_ROOT_DIR`` may be the most common one (though with
|
||||
virtualenv/venv support, and Conda support, this tends to find the correct
|
||||
Python version more often than the old system did).
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
Advanced: interface library targets
|
||||
-----------------------------------
|
||||
|
||||
Pybind11 supports modern CMake usage patterns with a set of interface targets,
|
||||
available in all modes. The targets provided are:
|
||||
|
||||
``pybind11::headers``
|
||||
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``
|
||||
Python headers + ``pybind11::headers`` + ``pybind11::python2_no_register`` (Python 2 only)
|
||||
|
||||
``pybind11::python_link_helper``
|
||||
Just the "linking" part of pybind11:module
|
||||
|
||||
``pybind11::module``
|
||||
Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper``
|
||||
|
||||
``pybind11::embed``
|
||||
Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Embed`` (FindPython) or Python libs
|
||||
|
||||
``pybind11::lto`` / ``pybind11::thin_lto``
|
||||
An alternative to `INTERPROCEDURAL_OPTIMIZATION` for adding link-time optimization.
|
||||
|
||||
``pybind11::windows_extras``
|
||||
``/bigobj`` and ``/mp`` for MSVC.
|
||||
|
||||
``pybind11::opt_size``
|
||||
``/Os`` for MSVC, ``-Os`` for other compilers. Does nothing for debug builds.
|
||||
|
||||
Two helper functions are also provided:
|
||||
|
||||
``pybind11_strip(target)``
|
||||
Strips a target (uses ``CMAKE_STRIP`` after the target is built)
|
||||
|
||||
``pybind11_extension(target)``
|
||||
Sets the correct extension (with SOABI) for a target.
|
||||
|
||||
You can use these targets to build complex applications. For example, the
|
||||
``add_python_module`` function is identical to:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
project(example LANGUAGES CXX)
|
||||
|
||||
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
||||
|
||||
add_library(example MODULE main.cpp)
|
||||
target_link_libraries(example PRIVATE pybind11::module)
|
||||
set_target_properties(example PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
|
||||
SUFFIX "${PYTHON_MODULE_EXTENSION}")
|
||||
|
||||
target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras)
|
||||
|
||||
pybind11_extension(example)
|
||||
pybind11_strip(example)
|
||||
|
||||
set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden"
|
||||
CUDA_VISIBILITY_PRESET "hidden")
|
||||
|
||||
Instead of setting properties, you can set ``CMAKE_*`` variables to initialize these correctly.
|
||||
|
||||
.. warning::
|
||||
|
||||
Since pybind11 is a metatemplate library, it is crucial that certain
|
||||
compiler flags are provided to ensure high quality code generation. In
|
||||
contrast to the ``pybind11_add_module()`` command, the CMake interface
|
||||
library only provides the *minimal* set of parameters to ensure that the
|
||||
code using pybind11 compiles, but it does **not** pass these extra compiler
|
||||
flags (i.e. this is up to you).
|
||||
provides a *composable* set of targets to ensure that you retain flexibility.
|
||||
It can be expecially important to provide or set these properties; the
|
||||
:ref:`FAQ <faq:symhidden>` contains an explanation on why these are needed.
|
||||
|
||||
These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL``
|
||||
and ``/LTCG`` on Visual Studio) and .OBJ files with many sections on Visual
|
||||
Studio (``/bigobj``). The :ref:`FAQ <faq:symhidden>` contains an
|
||||
explanation on why these are needed.
|
||||
.. versionadded:: 2.6
|
||||
|
||||
.. _nopython-mode:
|
||||
|
||||
Advanced: NOPYTHON mode
|
||||
-----------------------
|
||||
|
||||
If you want complete control, you can set ``PYBIND11_NOPYTHON`` to completely
|
||||
disable Python integration (this also happens if you run ``FindPython2`` and
|
||||
``FindPython3`` without running ``FindPython``). This gives you complete
|
||||
freedom to integrate into an existing system (like `Scikit-Build's
|
||||
<https://scikit-build.readthedocs.io>`_ ``PythonExtensions``).
|
||||
``pybind11_add_module`` and ``pybind11_extension`` will be unavailable, and the
|
||||
targets will be missing any Python specific behavior.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
Embedding the Python interpreter
|
||||
--------------------------------
|
||||
|
@ -213,8 +460,8 @@ information about usage in C++, see :doc:`/advanced/embedding`.
|
|||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(example)
|
||||
cmake_minimum_required(VERSION 3.4...3.18)
|
||||
project(example LANGUAGES CXX)
|
||||
|
||||
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
|
||||
|
||||
|
@ -251,7 +498,7 @@ Besides, the ``--extension-suffix`` option may or may not be available, dependin
|
|||
on the distribution; in the latter case, the module extension can be manually
|
||||
set to ``.so``.
|
||||
|
||||
On Mac OS: 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
|
||||
building the module:
|
||||
|
||||
|
@ -275,6 +522,25 @@ build system that works on all platforms including Windows.
|
|||
of possibly importing a second Python library into a process that already
|
||||
contains one (which will lead to a segfault).
|
||||
|
||||
|
||||
Building with vcpkg
|
||||
===================
|
||||
You can download and install pybind11 using the Microsoft `vcpkg
|
||||
<https://github.com/Microsoft/vcpkg/>`_ dependency manager:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
vcpkg install pybind11
|
||||
|
||||
The pybind11 port in vcpkg is kept up to date by Microsoft team members and
|
||||
community contributors. If the version is out of date, please `create an issue
|
||||
or pull request <https://github.com/Microsoft/vcpkg/>`_ on the vcpkg
|
||||
repository.
|
||||
|
||||
Generating binding code automatically
|
||||
=====================================
|
||||
|
||||
|
@ -291,3 +557,10 @@ extensible, and applies to very complex C++ libraries, composed of thousands of
|
|||
classes or incorporating modern meta-programming constructs.
|
||||
|
||||
.. [AutoWIG] https://github.com/StatisKit/AutoWIG
|
||||
|
||||
[robotpy-build]_ is a is a pure python, cross platform build tool that aims to
|
||||
simplify creation of python wheels for pybind11 projects, and provide
|
||||
cross-project dependency management. Additionally, it is able to autogenerate
|
||||
customizable pybind11-based wrappers by parsing C++ header files.
|
||||
|
||||
.. [robotpy-build] https://robotpy-build.readthedocs.io
|
||||
|
|
|
@ -285,7 +285,7 @@ CMake code. Conflicts can arise, however, when using pybind11 in a project that
|
|||
Python detection in a system with several Python versions installed.
|
||||
|
||||
This difference may cause inconsistencies and errors if *both* mechanisms are used in the same project. Consider the following
|
||||
Cmake code executed in a system with Python 2.7 and 3.x installed:
|
||||
CMake code executed in a system with Python 2.7 and 3.x installed:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ With reference counting
|
|||
Convenience classes for specific Python types
|
||||
=============================================
|
||||
|
||||
.. doxygenclass:: module
|
||||
.. doxygenclass:: module_
|
||||
:members:
|
||||
|
||||
.. doxygengroup:: pytypes
|
||||
|
@ -91,15 +91,15 @@ Inheritance
|
|||
|
||||
See :doc:`/classes` and :doc:`/advanced/classes` for more detail.
|
||||
|
||||
.. doxygendefine:: PYBIND11_OVERLOAD
|
||||
.. doxygendefine:: PYBIND11_OVERRIDE
|
||||
|
||||
.. doxygendefine:: PYBIND11_OVERLOAD_PURE
|
||||
.. doxygendefine:: PYBIND11_OVERRIDE_PURE
|
||||
|
||||
.. doxygendefine:: PYBIND11_OVERLOAD_NAME
|
||||
.. doxygendefine:: PYBIND11_OVERRIDE_NAME
|
||||
|
||||
.. doxygendefine:: PYBIND11_OVERLOAD_PURE_NAME
|
||||
.. doxygendefine:: PYBIND11_OVERRIDE_PURE_NAME
|
||||
|
||||
.. doxygenfunction:: get_overload
|
||||
.. doxygenfunction:: get_override
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
breathe == 4.5.0
|
||||
breathe==4.20.0
|
||||
commonmark==0.9.1
|
||||
recommonmark==0.6.0
|
||||
sphinx==3.2.1
|
||||
sphinx_rtd_theme==0.5.0
|
||||
|
|
|
@ -8,6 +8,92 @@ to a new version. But it goes into more detail. This includes things like
|
|||
deprecated APIs and their replacements, build system changes, general code
|
||||
modernization and other useful information.
|
||||
|
||||
.. _upgrade-guide-2.6:
|
||||
|
||||
v2.6
|
||||
====
|
||||
|
||||
The ``tools/clang`` submodule and ``tools/mkdoc.py`` have been moved to a
|
||||
standalone package, `pybind11-mkdoc`_. If you were using those tools, please
|
||||
use them via a pip install from the new location.
|
||||
|
||||
.. _pybind11-mkdoc: https://github.com/pybind/pybind11-mkdoc
|
||||
|
||||
An error is now thrown when ``__init__`` is forgotten on subclasses. This was
|
||||
incorrect before, but was not checked. Add a call to ``__init__`` if it is
|
||||
missing.
|
||||
|
||||
The undocumented ``h.get_type()`` method has been deprecated and replaced by
|
||||
``py::type::of(h)``.
|
||||
|
||||
If ``__eq__`` defined but not ``__hash__``, ``__hash__`` is now set to
|
||||
``None``, as in normal CPython. You should add ``__hash__`` if you intended the
|
||||
class to be hashable, possibly using the new ``py::hash`` shortcut.
|
||||
|
||||
Usage of the ``PYBIND11_OVERLOAD*`` macros and ``get_overload`` function should
|
||||
be replaced by ``PYBIND11_OVERRIDE*`` and ``get_override``. In the future, the
|
||||
old macros may be deprecated and removed.
|
||||
|
||||
The ``pybind11`` package on PyPI no longer fills the wheel "headers" slot - if
|
||||
you were using the headers from this slot, they are available by requesting the
|
||||
``global`` extra, that is, ``pip install "pybind11[global]"``. (Most users will
|
||||
be unaffected, as the ``pybind11/include`` location is reported by ``python -m
|
||||
pybind11 --includes`` and ``pybind11.get_include()`` is still correct and has
|
||||
not changed since 2.5).
|
||||
|
||||
CMake support:
|
||||
--------------
|
||||
|
||||
The minimum required version of CMake is now 3.4. Several details of the CMake
|
||||
support have been deprecated; warnings will be shown if you need to change
|
||||
something. The changes are:
|
||||
|
||||
* ``PYBIND11_CPP_STANDARD=<platform-flag>`` is deprecated, please use
|
||||
``CMAKE_CXX_STANDARD=<number>`` instead, or any other valid CMake CXX or CUDA
|
||||
standard selection method, like ``target_compile_features``.
|
||||
|
||||
* If you do not request a standard, pybind11 targets will compile with the
|
||||
compiler default, but not less than C++11, instead of forcing C++14 always.
|
||||
If you depend on the old behavior, please use ``set(CMAKE_CXX_STANDARD 14)``
|
||||
instead.
|
||||
|
||||
* Direct ``pybind11::module`` usage should always be accompanied by at least
|
||||
``set(CMAKE_CXX_VISIBILITY_PRESET hidden)`` or similar - it used to try to
|
||||
manually force this compiler flag (but not correctly on all compilers or with
|
||||
CUDA).
|
||||
|
||||
* ``pybind11_add_module``'s ``SYSTEM`` argument is deprecated and does nothing;
|
||||
linking now behaves like other imported libraries consistently in both
|
||||
config and submodule mode, and behaves like a ``SYSTEM`` library by
|
||||
default.
|
||||
|
||||
* If ``PYTHON_EXECUTABLE`` is not set, virtual environments (``venv``,
|
||||
``virtualenv``, and ``conda``) are prioritized over the standard search
|
||||
(similar to the new FindPython mode).
|
||||
|
||||
In addition, the following changes may be of interest:
|
||||
|
||||
* ``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` will be respected by
|
||||
``pybind11_add_module`` if set instead of linking to ``pybind11::lto`` or
|
||||
``pybind11::thin_lto``.
|
||||
|
||||
* Using ``find_package(Python COMPONENTS Interpreter Development)`` before
|
||||
pybind11 will cause pybind11 to use the new Python mechanisms instead of its
|
||||
own custom search, based on a patched version of classic ``FindPythonInterp``
|
||||
/ ``FindPythonLibs``. In the future, this may become the default.
|
||||
|
||||
|
||||
|
||||
v2.5
|
||||
====
|
||||
|
||||
The Python package now includes the headers as data in the package itself, as
|
||||
well as in the "headers" wheel slot. ``pybind11 --includes`` and
|
||||
``pybind11.get_include()`` report the new location, which is always correct
|
||||
regardless of how pybind11 was installed, making the old ``user=`` argument
|
||||
meaningless. If you are not using the function to get the location already, you
|
||||
are encouraged to switch to the package location.
|
||||
|
||||
|
||||
v2.2
|
||||
====
|
||||
|
|
|
@ -40,8 +40,9 @@ struct sibling { handle value; sibling(const handle &value) : value(value.ptr())
|
|||
|
||||
/// Annotation indicating that a class derives from another given type
|
||||
template <typename T> struct base {
|
||||
|
||||
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
||||
base() { }
|
||||
base() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
|
||||
};
|
||||
|
||||
/// Keep patient alive while nurse lives
|
||||
|
@ -61,7 +62,7 @@ struct metaclass {
|
|||
handle value;
|
||||
|
||||
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
|
||||
metaclass() {}
|
||||
metaclass() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
|
||||
|
||||
/// Override pybind11's default metaclass
|
||||
explicit metaclass(handle value) : value(value) { }
|
||||
|
@ -138,7 +139,7 @@ struct function_record {
|
|||
function_record()
|
||||
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
|
||||
is_operator(false), is_method(false),
|
||||
has_args(false), has_kwargs(false), has_kwonly_args(false) { }
|
||||
has_args(false), has_kwargs(false), has_kw_only_args(false) { }
|
||||
|
||||
/// Function name
|
||||
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
||||
|
@ -185,14 +186,17 @@ struct function_record {
|
|||
/// True if the function has a '**kwargs' argument
|
||||
bool has_kwargs : 1;
|
||||
|
||||
/// True once a 'py::kwonly' is encountered (any following args are keyword-only)
|
||||
bool has_kwonly_args : 1;
|
||||
/// True once a 'py::kw_only' is encountered (any following args are keyword-only)
|
||||
bool has_kw_only_args : 1;
|
||||
|
||||
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
||||
std::uint16_t nargs;
|
||||
|
||||
/// Number of trailing arguments (counted in `nargs`) that are keyword-only
|
||||
std::uint16_t nargs_kwonly = 0;
|
||||
std::uint16_t nargs_kw_only = 0;
|
||||
|
||||
/// Number of leading arguments (counted in `nargs`) that are positional-only
|
||||
std::uint16_t nargs_pos_only = 0;
|
||||
|
||||
/// Python method object
|
||||
PyMethodDef *def = nullptr;
|
||||
|
@ -366,10 +370,10 @@ template <> struct process_attribute<is_new_style_constructor> : process_attribu
|
|||
static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; }
|
||||
};
|
||||
|
||||
inline void process_kwonly_arg(const arg &a, function_record *r) {
|
||||
inline void process_kw_only_arg(const arg &a, function_record *r) {
|
||||
if (!a.name || strlen(a.name) == 0)
|
||||
pybind11_fail("arg(): cannot specify an unnamed argument after an kwonly() annotation");
|
||||
++r->nargs_kwonly;
|
||||
pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation");
|
||||
++r->nargs_kw_only;
|
||||
}
|
||||
|
||||
/// Process a keyword argument attribute (*without* a default value)
|
||||
|
@ -379,7 +383,7 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
|||
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);
|
||||
|
||||
if (r->has_kwonly_args) process_kwonly_arg(a, r);
|
||||
if (r->has_kw_only_args) process_kw_only_arg(a, r);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -412,14 +416,21 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
|||
}
|
||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
||||
|
||||
if (r->has_kwonly_args) process_kwonly_arg(a, r);
|
||||
if (r->has_kw_only_args) process_kw_only_arg(a, r);
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a keyword-only-arguments-follow pseudo argument
|
||||
template <> struct process_attribute<kwonly> : process_attribute_default<kwonly> {
|
||||
static void init(const kwonly &, function_record *r) {
|
||||
r->has_kwonly_args = true;
|
||||
template <> struct process_attribute<kw_only> : process_attribute_default<kw_only> {
|
||||
static void init(const kw_only &, function_record *r) {
|
||||
r->has_kw_only_args = true;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a positional-only-argument maker
|
||||
template <> struct process_attribute<pos_only> : process_attribute_default<pos_only> {
|
||||
static void init(const pos_only &, function_record *r) {
|
||||
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ struct buffer_info {
|
|||
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
|
||||
|
||||
buffer_info() { }
|
||||
buffer_info() = default;
|
||||
|
||||
buffer_info(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=false)
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
Py_CLEAR(ptr);
|
||||
|
||||
// A heuristic to reduce the stack's capacity (e.g. after long recursive calls)
|
||||
if (stack.capacity() > 16 && stack.size() != 0 && stack.capacity() / stack.size() > 2)
|
||||
if (stack.capacity() > 16 && !stack.empty() && stack.capacity() / stack.size() > 2)
|
||||
stack.shrink_to_fit();
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type)
|
|||
*/
|
||||
PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
|
||||
auto &bases = all_type_info(type);
|
||||
if (bases.size() == 0)
|
||||
if (bases.empty())
|
||||
return nullptr;
|
||||
if (bases.size() > 1)
|
||||
pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases");
|
||||
|
@ -220,7 +220,7 @@ struct value_and_holder {
|
|||
{}
|
||||
|
||||
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
||||
value_and_holder() {}
|
||||
value_and_holder() = default;
|
||||
|
||||
// Used for past-the-end iterator
|
||||
value_and_holder(size_t index) : index{index} {}
|
||||
|
@ -432,7 +432,7 @@ PYBIND11_NOINLINE inline std::string error_string() {
|
|||
|
||||
#if !defined(PYPY_VERSION)
|
||||
if (scope.trace) {
|
||||
PyTracebackObject *trace = (PyTracebackObject *) scope.trace;
|
||||
auto *trace = (PyTracebackObject *) scope.trace;
|
||||
|
||||
/* Get the deepest trace possible */
|
||||
while (trace->tb_next)
|
||||
|
@ -458,7 +458,7 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail:
|
|||
auto &instances = get_internals().registered_instances;
|
||||
auto range = instances.equal_range(ptr);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
for (auto vh : values_and_holders(it->second)) {
|
||||
for (const auto &vh : values_and_holders(it->second)) {
|
||||
if (vh.type == type)
|
||||
return handle((PyObject *) it->second);
|
||||
}
|
||||
|
@ -636,7 +636,7 @@ public:
|
|||
/// native typeinfo, or when the native one wasn't able to produce a value.
|
||||
PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {
|
||||
constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;
|
||||
const auto pytype = src.get_type();
|
||||
const auto pytype = type::handle_of(src);
|
||||
if (!hasattr(pytype, local_key))
|
||||
return false;
|
||||
|
||||
|
@ -1006,6 +1006,7 @@ template <typename CharT> using is_std_char_type = any_of<
|
|||
std::is_same<CharT, wchar_t> /* std::wstring */
|
||||
>;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
|
||||
using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
|
||||
|
@ -1034,12 +1035,12 @@ public:
|
|||
: (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
|
||||
}
|
||||
|
||||
// Python API reported an error
|
||||
bool py_err = py_value == (py_type) -1 && PyErr_Occurred();
|
||||
|
||||
// Protect std::numeric_limits::min/max with parentheses
|
||||
if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) &&
|
||||
(py_value < (py_type) (std::numeric_limits<T>::min)() ||
|
||||
py_value > (py_type) (std::numeric_limits<T>::max)()))) {
|
||||
// Check to see if the conversion is valid (integers should match exactly)
|
||||
// Signed/unsigned checks happen elsewhere
|
||||
if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) {
|
||||
bool type_error = py_err && PyErr_ExceptionMatches(
|
||||
#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION)
|
||||
PyExc_SystemError
|
||||
|
@ -1129,7 +1130,7 @@ public:
|
|||
}
|
||||
|
||||
/* Check if this is a C++ type */
|
||||
auto &bases = all_type_info((PyTypeObject *) h.get_type().ptr());
|
||||
auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr());
|
||||
if (bases.size() == 1) { // Only allowing loading from a single-value type
|
||||
value = values_and_holders(reinterpret_cast<instance *>(h.ptr())).begin()->value_ptr();
|
||||
return true;
|
||||
|
@ -1243,7 +1244,7 @@ template <typename StringType, bool IsView = false> struct string_caster {
|
|||
load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr));
|
||||
if (!utfNbytes) { PyErr_Clear(); return false; }
|
||||
|
||||
const CharT *buffer = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
|
||||
const auto *buffer = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
|
||||
size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);
|
||||
if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32
|
||||
value = StringType(buffer, length);
|
||||
|
@ -1257,7 +1258,7 @@ template <typename StringType, bool IsView = false> struct string_caster {
|
|||
|
||||
static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
const char *buffer = reinterpret_cast<const char *>(src.data());
|
||||
ssize_t nbytes = ssize_t(src.size() * sizeof(CharT));
|
||||
auto nbytes = ssize_t(src.size() * sizeof(CharT));
|
||||
handle s = decode_utfN(buffer, nbytes);
|
||||
if (!s) throw error_already_set();
|
||||
return s;
|
||||
|
@ -1363,7 +1364,7 @@ public:
|
|||
// errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those
|
||||
// can fit into a single char value.
|
||||
if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {
|
||||
unsigned char v0 = static_cast<unsigned char>(value[0]);
|
||||
auto v0 = static_cast<unsigned char>(value[0]);
|
||||
size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127
|
||||
(v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence
|
||||
(v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence
|
||||
|
@ -1421,6 +1422,17 @@ public:
|
|||
return cast_impl(std::forward<T>(src), policy, parent, indices{});
|
||||
}
|
||||
|
||||
// copied from the PYBIND11_TYPE_CASTER macro
|
||||
template <typename T>
|
||||
static handle cast(T *src, return_value_policy policy, handle parent) {
|
||||
if (!src) return none().release();
|
||||
if (policy == return_value_policy::take_ownership) {
|
||||
auto h = cast(std::move(*src), policy, parent); delete src; return h;
|
||||
} else {
|
||||
return cast(*src, policy, parent);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto name = _("Tuple[") + concat(make_caster<Ts>::name...) + _("]");
|
||||
|
||||
template <typename T> using cast_op_type = type;
|
||||
|
@ -1696,7 +1708,7 @@ template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_ca
|
|||
throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)");
|
||||
#else
|
||||
throw cast_error("Unable to cast Python instance of type " +
|
||||
(std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "'");
|
||||
(std::string) str(type::handle_of(handle)) + " to C++ type '" + type_id<T>() + "'");
|
||||
#endif
|
||||
}
|
||||
return conv;
|
||||
|
@ -1747,7 +1759,7 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
|
|||
throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references"
|
||||
" (compile in debug mode for details)");
|
||||
#else
|
||||
throw cast_error("Unable to move from Python " + (std::string) str(obj.get_type()) +
|
||||
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) +
|
||||
" instance to C++ " + type_id<T>() + " instance: instance has multiple references");
|
||||
#endif
|
||||
|
||||
|
@ -1756,7 +1768,7 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Calling cast() on an rvalue calls pybind::cast with the object rvalue, which does:
|
||||
// Calling cast() on an rvalue calls pybind11::cast with the object rvalue, which does:
|
||||
// - If we have to move (because T has no copy constructor), do it. This will fail if the moved
|
||||
// object has multiple references, but trying to copy will fail to compile.
|
||||
// - If both movable and copyable, check ref count: if 1, move; otherwise copy
|
||||
|
@ -1785,16 +1797,16 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||
template <typename T, enable_if_t<!is_pyobject<T>::value, int>>
|
||||
object object_or_cast(T &&o) { return pybind11::cast(std::forward<T>(o)); }
|
||||
|
||||
struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro
|
||||
template <typename ret_type> using overload_caster_t = conditional_t<
|
||||
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, overload_unused>;
|
||||
struct override_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the PYBIND11_OVERRIDE_OVERRIDE macro
|
||||
template <typename ret_type> using override_caster_t = conditional_t<
|
||||
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, override_unused>;
|
||||
|
||||
// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then
|
||||
// store the result in the given variable. For other types, this is a no-op.
|
||||
template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o, make_caster<T> &caster) {
|
||||
return cast_op<T>(load_type(caster, o));
|
||||
}
|
||||
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, overload_unused &) {
|
||||
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, override_unused &) {
|
||||
pybind11_fail("Internal error: cast_ref fallback invoked"); }
|
||||
|
||||
// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even
|
||||
|
@ -1899,7 +1911,12 @@ public:
|
|||
/// \ingroup annotations
|
||||
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of an
|
||||
/// unnamed '*' argument (in Python 3)
|
||||
struct kwonly {};
|
||||
struct kw_only {};
|
||||
|
||||
/// \ingroup annotations
|
||||
/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of an
|
||||
/// unnamed '/' argument (in Python 3.8)
|
||||
struct pos_only {};
|
||||
|
||||
template <typename T>
|
||||
arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward<T>(value)}; }
|
||||
|
@ -1912,7 +1929,7 @@ inline namespace literals {
|
|||
String literal version of `arg`
|
||||
\endrst */
|
||||
constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
|
@ -2187,13 +2204,25 @@ object object_api<Derived>::call(Args &&...args) const {
|
|||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
|
||||
template<typename T>
|
||||
handle type::handle_of() {
|
||||
static_assert(
|
||||
std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
|
||||
"py::type::of<T> only supports the case where T is a registered C++ types."
|
||||
);
|
||||
|
||||
return detail::get_type_handle(typeid(T), true);
|
||||
}
|
||||
|
||||
|
||||
#define PYBIND11_MAKE_OPAQUE(...) \
|
||||
namespace pybind11 { namespace detail { \
|
||||
template<> class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> { }; \
|
||||
}}
|
||||
|
||||
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate
|
||||
/// typedef, e.g.: `PYBIND11_OVERLOAD(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`
|
||||
/// typedef, e.g.: `PYBIND11_OVERRIDE(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`
|
||||
#define PYBIND11_TYPE(...) __VA_ARGS__
|
||||
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
|
|
@ -33,9 +33,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||
template <typename type> class duration_caster {
|
||||
public:
|
||||
typedef typename type::rep rep;
|
||||
typedef typename type::period period;
|
||||
using period = typename type::period;
|
||||
|
||||
typedef std::chrono::duration<uint_fast32_t, std::ratio<86400>> days;
|
||||
using days = std::chrono::duration<uint_fast32_t, std::ratio<86400>>;
|
||||
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
// 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>> {
|
||||
public:
|
||||
typedef std::chrono::time_point<std::chrono::system_clock, Duration> type;
|
||||
using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
||||
|
@ -140,7 +140,7 @@ public:
|
|||
}
|
||||
else return false;
|
||||
|
||||
value = 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;
|
||||
}
|
||||
|
||||
|
@ -150,21 +150,28 @@ public:
|
|||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src));
|
||||
// Get out microseconds, and make sure they are positive, to avoid bug in eastern hemisphere time zones
|
||||
// (cfr. https://github.com/pybind/pybind11/issues/2417)
|
||||
using us_t = duration<int, std::micro>;
|
||||
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
|
||||
if (us.count() < 0)
|
||||
us += seconds(1);
|
||||
|
||||
// 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.
|
||||
// (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));
|
||||
// this function uses static memory so it's best to copy it out asap just in case
|
||||
// otherwise other code that is using localtime may break this (not just python code)
|
||||
std::tm localtime = *std::localtime(&tt);
|
||||
|
||||
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
||||
localtime.tm_mon + 1,
|
||||
localtime.tm_mday,
|
||||
localtime.tm_hour,
|
||||
localtime.tm_min,
|
||||
localtime.tm_sec,
|
||||
(duration_cast<us_t>(src.time_since_epoch() % seconds(1))).count());
|
||||
us.count());
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
|
||||
};
|
||||
|
|
|
@ -169,7 +169,7 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
|||
auto instance = reinterpret_cast<detail::instance *>(self);
|
||||
|
||||
// Ensure that the base __init__ function(s) were called
|
||||
for (auto vh : values_and_holders(instance)) {
|
||||
for (const auto &vh : values_and_holders(instance)) {
|
||||
if (!vh.holder_constructed()) {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__",
|
||||
vh.type->type->tp_name);
|
||||
|
@ -592,7 +592,7 @@ inline PyObject* make_new_python_type(const type_record &rec) {
|
|||
|
||||
auto &internals = get_internals();
|
||||
auto bases = tuple(rec.bases);
|
||||
auto base = (bases.size() == 0) ? internals.instance_base
|
||||
auto base = (bases.empty()) ? internals.instance_base
|
||||
: bases[0].ptr();
|
||||
|
||||
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||
|
@ -616,7 +616,7 @@ inline PyObject* make_new_python_type(const type_record &rec) {
|
|||
type->tp_doc = tp_doc;
|
||||
type->tp_base = type_incref((PyTypeObject *)base);
|
||||
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
||||
if (bases.size() > 0)
|
||||
if (!bases.empty())
|
||||
type->tp_bases = bases.release().ptr();
|
||||
|
||||
/* Don't inherit base __init__ */
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define PYBIND11_VERSION_MAJOR 2
|
||||
#define PYBIND11_VERSION_MINOR 6
|
||||
#define PYBIND11_VERSION_PATCH 0.dev1
|
||||
|
||||
#define PYBIND11_NAMESPACE_BEGIN(name) namespace name {
|
||||
#define PYBIND11_NAMESPACE_END(name) }
|
||||
|
||||
|
@ -96,10 +100,6 @@
|
|||
# define PYBIND11_MAYBE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#define PYBIND11_VERSION_MAJOR 2
|
||||
#define PYBIND11_VERSION_MINOR 5
|
||||
#define PYBIND11_VERSION_PATCH dev1
|
||||
|
||||
/* Don't let Python.h #define (v)snprintf as macro because they are implemented
|
||||
properly in Visual Studio since 2015. */
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
|
@ -154,6 +154,7 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <exception>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
@ -501,8 +502,16 @@ template <bool... Bs> using select_indices = typename select_indices_impl<index_
|
|||
template <bool B> using bool_constant = std::integral_constant<bool, B>;
|
||||
template <typename T> struct negation : bool_constant<!T::value> { };
|
||||
|
||||
// PGI cannot detect operator delete with the "compatible" void_t impl, so
|
||||
// using the new one (C++14 defect, so generally works on newer compilers, even
|
||||
// if not in C++17 mode)
|
||||
#if defined(__PGIC__)
|
||||
template<typename... > using void_t = void;
|
||||
#else
|
||||
template <typename...> struct void_t_impl { using type = void; };
|
||||
template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type;
|
||||
#endif
|
||||
|
||||
|
||||
/// Compile-time all/any/none of that check the boolean value of all template types
|
||||
#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916))
|
||||
|
@ -528,17 +537,17 @@ template <class T, template<class> class... Predicates> using satisfies_none_of
|
|||
|
||||
/// Strip the class from a method type
|
||||
template <typename T> struct remove_class { };
|
||||
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
|
||||
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
|
||||
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { using type = R (A...); };
|
||||
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { using type = R (A...); };
|
||||
|
||||
/// Helper template to strip away type modifiers
|
||||
template <typename T> struct intrinsic_type { typedef T type; };
|
||||
template <typename T> struct intrinsic_type<const T> { typedef typename intrinsic_type<T>::type type; };
|
||||
template <typename T> struct intrinsic_type<T*> { typedef typename intrinsic_type<T>::type type; };
|
||||
template <typename T> struct intrinsic_type<T&> { typedef typename intrinsic_type<T>::type type; };
|
||||
template <typename T> struct intrinsic_type<T&&> { typedef typename intrinsic_type<T>::type type; };
|
||||
template <typename T, size_t N> struct intrinsic_type<const T[N]> { typedef typename intrinsic_type<T>::type type; };
|
||||
template <typename T, size_t N> struct intrinsic_type<T[N]> { typedef typename intrinsic_type<T>::type type; };
|
||||
template <typename T> struct intrinsic_type { using type = T; };
|
||||
template <typename T> struct intrinsic_type<const T> { using type = typename intrinsic_type<T>::type; };
|
||||
template <typename T> struct intrinsic_type<T*> { using type = typename intrinsic_type<T>::type; };
|
||||
template <typename T> struct intrinsic_type<T&> { using type = typename intrinsic_type<T>::type; };
|
||||
template <typename T> struct intrinsic_type<T&&> { using type = typename intrinsic_type<T>::type; };
|
||||
template <typename T, size_t N> struct intrinsic_type<const T[N]> { using type = typename intrinsic_type<T>::type; };
|
||||
template <typename T, size_t N> struct intrinsic_type<T[N]> { using type = typename intrinsic_type<T>::type; };
|
||||
template <typename T> using intrinsic_t = typename intrinsic_type<T>::type;
|
||||
|
||||
/// Helper type to replace 'void' in some expressions
|
||||
|
@ -752,7 +761,7 @@ struct nodelete { template <typename T> void operator()(T*) { } };
|
|||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
template <typename... Args>
|
||||
struct overload_cast_impl {
|
||||
constexpr overload_cast_impl() {} // MSVC 2015 needs this
|
||||
constexpr overload_cast_impl() {}; // NOLINT(modernize-use-equals-default): MSVC 2015 needs this
|
||||
|
||||
template <typename Return>
|
||||
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
|
||||
|
|
|
@ -132,6 +132,7 @@ void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
|
|||
template <typename Class>
|
||||
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
||||
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
||||
no_nullptr(ptr);
|
||||
// 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))
|
||||
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
|
||||
|
|
|
@ -82,10 +82,10 @@ struct type_equal_to {
|
|||
template <typename value_type>
|
||||
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
||||
|
||||
struct overload_hash {
|
||||
struct override_hash {
|
||||
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
@ -97,7 +97,7 @@ struct internals {
|
|||
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
|
||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
|
||||
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
|
||||
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
|
||||
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
|
||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
||||
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
|
||||
|
|
|
@ -553,7 +553,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||
object matrix_type = sparse_module.attr(
|
||||
rowMajor ? "csr_matrix" : "csc_matrix");
|
||||
|
||||
if (!obj.get_type().is(matrix_type)) {
|
||||
if (!type::handle_of(obj).is(matrix_type)) {
|
||||
try {
|
||||
obj = matrix_type(obj);
|
||||
} catch (const error_already_set &) {
|
||||
|
|
|
@ -30,7 +30,7 @@ private:
|
|||
object pywrite;
|
||||
object pyflush;
|
||||
|
||||
int overflow(int c) {
|
||||
int overflow(int c) override {
|
||||
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
*pptr() = traits_type::to_char_type(c);
|
||||
pbump(1);
|
||||
|
@ -38,7 +38,10 @@ private:
|
|||
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
||||
}
|
||||
|
||||
int sync() {
|
||||
// This function must be non-virtual to be called in a destructor. If the
|
||||
// rare MSVC test failure shows up with this version, then this should be
|
||||
// simplified to a fully qualified call.
|
||||
int _sync() {
|
||||
if (pbase() != pptr()) {
|
||||
// This subtraction cannot be negative, so dropping the sign
|
||||
str line(pbase(), static_cast<size_t>(pptr() - pbase()));
|
||||
|
@ -54,6 +57,10 @@ private:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sync() override {
|
||||
return _sync();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
pythonbuf(object pyostream, size_t buffer_size = 1024)
|
||||
|
@ -67,8 +74,8 @@ public:
|
|||
pythonbuf(pythonbuf&&) = default;
|
||||
|
||||
/// Sync before destroy
|
||||
~pythonbuf() {
|
||||
sync();
|
||||
~pythonbuf() override {
|
||||
_sync();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ private:
|
|||
};
|
||||
|
||||
static npy_api lookup() {
|
||||
module m = module::import("numpy.core.multiarray");
|
||||
module_ m = module::import("numpy.core.multiarray");
|
||||
auto c = m.attr("_ARRAY_API");
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
||||
|
@ -281,7 +281,7 @@ template <typename T> struct is_complex : std::false_type { };
|
|||
template <typename T> struct is_complex<std::complex<T>> : std::true_type { };
|
||||
|
||||
template <typename T> struct array_info_scalar {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
static constexpr bool is_array = false;
|
||||
static constexpr bool is_empty = false;
|
||||
static constexpr auto extents = _("");
|
||||
|
@ -550,7 +550,7 @@ public:
|
|||
forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
|
||||
};
|
||||
|
||||
array() : array({{0}}, static_cast<const double *>(nullptr)) {}
|
||||
array() : array(0, static_cast<const double *>(nullptr)) {}
|
||||
|
||||
using ShapeContainer = detail::any_container<ssize_t>;
|
||||
using StridesContainer = detail::any_container<ssize_t>;
|
||||
|
@ -611,8 +611,8 @@ public:
|
|||
template <typename T>
|
||||
explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { }
|
||||
|
||||
explicit array(const buffer_info &info)
|
||||
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { }
|
||||
explicit array(const buffer_info &info, handle base = handle())
|
||||
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr, base) { }
|
||||
|
||||
/// Array descriptor (dtype)
|
||||
pybind11::dtype dtype() const {
|
||||
|
@ -858,7 +858,7 @@ public:
|
|||
if (!m_ptr) throw error_already_set();
|
||||
}
|
||||
|
||||
explicit array_t(const buffer_info& info) : array(info) { }
|
||||
explicit array_t(const buffer_info& info, handle base = handle()) : array(info, base) { }
|
||||
|
||||
array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle())
|
||||
: array(std::move(shape), std::move(strides), ptr, base) { }
|
||||
|
@ -934,7 +934,8 @@ public:
|
|||
static bool check_(handle h) {
|
||||
const auto &api = detail::npy_api::get();
|
||||
return api.PyArray_Check_(h.ptr())
|
||||
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr());
|
||||
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr())
|
||||
&& detail::check_flags(h.ptr(), ExtraFlags & (array::c_style | array::f_style));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -1295,7 +1296,7 @@ public:
|
|||
m_strides.back() = static_cast<value_type>(strides.back());
|
||||
for (size_type i = m_strides.size() - 1; i != 0; --i) {
|
||||
size_type j = i - 1;
|
||||
value_type s = static_cast<value_type>(shape[i]);
|
||||
auto s = static_cast<value_type>(shape[i]);
|
||||
m_strides[j] = strides[j] + m_strides[i] - strides[i] * s;
|
||||
}
|
||||
}
|
||||
|
@ -1483,7 +1484,14 @@ struct vectorize_arg {
|
|||
|
||||
template <typename Func, typename Return, typename... Args>
|
||||
struct vectorize_helper {
|
||||
|
||||
// NVCC for some reason breaks if NVectorized is private
|
||||
#ifdef __CUDACC__
|
||||
public:
|
||||
#else
|
||||
private:
|
||||
#endif
|
||||
|
||||
static constexpr size_t N = sizeof...(Args);
|
||||
static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);
|
||||
static_assert(NVectorized >= 1,
|
||||
|
@ -1531,7 +1539,7 @@ private:
|
|||
ssize_t nd = 0;
|
||||
std::vector<ssize_t> shape(0);
|
||||
auto trivial = broadcast(buffers, nd, shape);
|
||||
size_t ndim = (size_t) nd;
|
||||
auto ndim = (size_t) nd;
|
||||
|
||||
size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|||
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
|
||||
class cpp_function : public function {
|
||||
public:
|
||||
cpp_function() { }
|
||||
cpp_function() = default;
|
||||
cpp_function(std::nullptr_t) { }
|
||||
|
||||
/// Construct a cpp_function from a vanilla function pointer
|
||||
|
@ -165,7 +165,7 @@ protected:
|
|||
/* Get a pointer to the capture object */
|
||||
auto data = (sizeof(capture) <= sizeof(call.func.data)
|
||||
? &call.func.data : call.func.data[0]);
|
||||
capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
|
||||
auto *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
|
||||
|
||||
/* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
|
||||
return_value_policy policy = return_value_policy_override<Return>::policy(call.func.policy);
|
||||
|
@ -187,11 +187,13 @@ protected:
|
|||
process_attributes<Extra...>::init(extra..., rec);
|
||||
|
||||
{
|
||||
constexpr bool has_kwonly_args = any_of<std::is_same<kwonly, Extra>...>::value,
|
||||
constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,
|
||||
has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,
|
||||
has_args = any_of<std::is_same<args, Args>...>::value,
|
||||
has_arg_annotations = any_of<is_keyword<Extra>...>::value;
|
||||
static_assert(has_arg_annotations || !has_kwonly_args, "py::kwonly requires the use of argument annotations");
|
||||
static_assert(!(has_args && has_kwonly_args), "py::kwonly cannot be combined with a py::args argument");
|
||||
static_assert(has_arg_annotations || !has_kw_only_args, "py::kw_only requires the use of argument annotations");
|
||||
static_assert(has_arg_annotations || !has_pos_only_args, "py::pos_only requires the use of argument annotations (for docstrings and aligning the annotations to the argument)");
|
||||
static_assert(!(has_args && has_kw_only_args), "py::kw_only cannot be combined with a py::args argument");
|
||||
}
|
||||
|
||||
/* Generate a readable signature describing the function's arguments and return value types */
|
||||
|
@ -228,7 +230,7 @@ protected:
|
|||
if (a.descr)
|
||||
a.descr = strdup(a.descr);
|
||||
else if (a.value)
|
||||
a.descr = strdup(a.value.attr("__repr__")().cast<std::string>().c_str());
|
||||
a.descr = strdup(repr(a.value).cast<std::string>().c_str());
|
||||
}
|
||||
|
||||
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
|
||||
|
@ -257,7 +259,10 @@ protected:
|
|||
// Write arg name for everything except *args and **kwargs.
|
||||
if (*(pc + 1) == '*')
|
||||
continue;
|
||||
|
||||
// Separator for keyword-only arguments, placed before the kw
|
||||
// arguments start
|
||||
if (rec->nargs_kw_only > 0 && arg_index + rec->nargs_kw_only == args)
|
||||
signature += "*, ";
|
||||
if (arg_index < rec->args.size() && rec->args[arg_index].name) {
|
||||
signature += rec->args[arg_index].name;
|
||||
} else if (arg_index == 0 && rec->is_method) {
|
||||
|
@ -272,6 +277,10 @@ protected:
|
|||
signature += " = ";
|
||||
signature += rec->args[arg_index].descr;
|
||||
}
|
||||
// Separator for positional-only arguments (placed after the
|
||||
// argument, rather than before like *
|
||||
if (rec->nargs_pos_only > 0 && (arg_index + 1) == rec->nargs_pos_only)
|
||||
signature += ", /";
|
||||
arg_index++;
|
||||
} else if (c == '%') {
|
||||
const std::type_info *t = types[type_index++];
|
||||
|
@ -297,6 +306,7 @@ protected:
|
|||
signature += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_index != args || types[type_index] != nullptr)
|
||||
pybind11_fail("Internal error while parsing type signature (2)");
|
||||
|
||||
|
@ -410,7 +420,7 @@ protected:
|
|||
}
|
||||
|
||||
/* Install docstring */
|
||||
PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;
|
||||
auto *func = (PyCFunctionObject *) m_ptr;
|
||||
if (func->m_ml->ml_doc)
|
||||
std::free(const_cast<char *>(func->m_ml->ml_doc));
|
||||
func->m_ml->ml_doc = strdup(signatures.c_str());
|
||||
|
@ -455,7 +465,7 @@ protected:
|
|||
*it = overloads;
|
||||
|
||||
/* Need to know how many arguments + keyword arguments there are to pick the right overload */
|
||||
const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in);
|
||||
const auto n_args_in = (size_t) PyTuple_GET_SIZE(args_in);
|
||||
|
||||
handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr,
|
||||
result = PYBIND11_TRY_NEXT_OVERLOAD;
|
||||
|
@ -512,7 +522,7 @@ protected:
|
|||
size_t num_args = func.nargs; // Number of positional arguments that we need
|
||||
if (func.has_args) --num_args; // (but don't count py::args
|
||||
if (func.has_kwargs) --num_args; // or py::kwargs)
|
||||
size_t pos_args = num_args - func.nargs_kwonly;
|
||||
size_t pos_args = num_args - func.nargs_kw_only;
|
||||
|
||||
if (!func.has_args && n_args_in > pos_args)
|
||||
continue; // Too many positional arguments for this overload
|
||||
|
@ -533,7 +543,7 @@ protected:
|
|||
self_value_and_holder.type->dealloc(self_value_and_holder);
|
||||
|
||||
call.init_self = PyTuple_GET_ITEM(args_in, 0);
|
||||
call.args.push_back(reinterpret_cast<PyObject *>(&self_value_and_holder));
|
||||
call.args.emplace_back(reinterpret_cast<PyObject *>(&self_value_and_holder));
|
||||
call.args_convert.push_back(false);
|
||||
++args_copied;
|
||||
}
|
||||
|
@ -561,6 +571,26 @@ protected:
|
|||
// We'll need to copy this if we steal some kwargs for defaults
|
||||
dict kwargs = reinterpret_borrow<dict>(kwargs_in);
|
||||
|
||||
// 1.5. Fill in any missing pos_only args from defaults if they exist
|
||||
if (args_copied < func.nargs_pos_only) {
|
||||
for (; args_copied < func.nargs_pos_only; ++args_copied) {
|
||||
const auto &arg = func.args[args_copied];
|
||||
handle value;
|
||||
|
||||
if (arg.value) {
|
||||
value = arg.value;
|
||||
}
|
||||
if (value) {
|
||||
call.args.push_back(value);
|
||||
call.args_convert.push_back(arg.convert);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (args_copied < func.nargs_pos_only)
|
||||
continue; // Not enough defaults to fill the positional arguments
|
||||
}
|
||||
|
||||
// 2. Check kwargs and, failing that, defaults that may help complete the list
|
||||
if (args_copied < num_args) {
|
||||
bool copied_kwargs = false;
|
||||
|
@ -596,7 +626,7 @@ protected:
|
|||
}
|
||||
|
||||
// 3. Check everything was consumed (unless we have a kwargs arg)
|
||||
if (kwargs && kwargs.size() > 0 && !func.has_kwargs)
|
||||
if (kwargs && !kwargs.empty() && !func.has_kwargs)
|
||||
continue; // Unconsumed kwargs, but no py::kwargs argument to accept them
|
||||
|
||||
// 4a. If we have a py::args argument, create a new tuple with leftovers
|
||||
|
@ -776,18 +806,27 @@ protected:
|
|||
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
|
||||
if (!some_args) some_args = true;
|
||||
else msg += ", ";
|
||||
msg += pybind11::repr(args_[ti]);
|
||||
try {
|
||||
msg += pybind11::repr(args_[ti]);
|
||||
} catch (const error_already_set&) {
|
||||
msg += "<repr raised Error>";
|
||||
}
|
||||
}
|
||||
if (kwargs_in) {
|
||||
auto kwargs = reinterpret_borrow<dict>(kwargs_in);
|
||||
if (kwargs.size() > 0) {
|
||||
if (!kwargs.empty()) {
|
||||
if (some_args) msg += "; ";
|
||||
msg += "kwargs: ";
|
||||
bool first = true;
|
||||
for (auto kwarg : kwargs) {
|
||||
if (first) first = false;
|
||||
else msg += ", ";
|
||||
msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
|
||||
msg += pybind11::str("{}=").format(kwarg.first);
|
||||
try {
|
||||
msg += pybind11::repr(kwarg.second);
|
||||
} catch (const error_already_set&) {
|
||||
msg += "<repr raised Error>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -813,15 +852,15 @@ protected:
|
|||
};
|
||||
|
||||
/// Wrapper for Python extension modules
|
||||
class module : public object {
|
||||
class module_ : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check)
|
||||
PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)
|
||||
|
||||
/// Create a new top-level Python module with the given name and docstring
|
||||
explicit module(const char *name, const char *doc = nullptr) {
|
||||
explicit module_(const char *name, const char *doc = nullptr) {
|
||||
if (!options::show_user_defined_docstrings()) doc = nullptr;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyModuleDef *def = new PyModuleDef();
|
||||
auto *def = new PyModuleDef();
|
||||
std::memset(def, 0, sizeof(PyModuleDef));
|
||||
def->m_name = name;
|
||||
def->m_doc = doc;
|
||||
|
@ -832,7 +871,7 @@ public:
|
|||
m_ptr = Py_InitModule3(name, nullptr, doc);
|
||||
#endif
|
||||
if (m_ptr == nullptr)
|
||||
pybind11_fail("Internal error in module::module()");
|
||||
pybind11_fail("Internal error in module_::module_()");
|
||||
inc_ref();
|
||||
}
|
||||
|
||||
|
@ -842,7 +881,7 @@ public:
|
|||
details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.
|
||||
\endrst */
|
||||
template <typename Func, typename... Extra>
|
||||
module &def(const char *name_, Func &&f, const Extra& ... extra) {
|
||||
module_ &def(const char *name_, Func &&f, const Extra& ... extra) {
|
||||
cpp_function func(std::forward<Func>(f), name(name_), scope(*this),
|
||||
sibling(getattr(*this, name_, none())), extra...);
|
||||
// NB: allow overwriting here because cpp_function sets up a chain with the intention of
|
||||
|
@ -861,10 +900,10 @@ public:
|
|||
py::module m2 = m.def_submodule("sub", "A submodule of 'example'");
|
||||
py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
|
||||
\endrst */
|
||||
module def_submodule(const char *name, const char *doc = nullptr) {
|
||||
module_ def_submodule(const char *name, const char *doc = nullptr) {
|
||||
std::string full_name = std::string(PyModule_GetName(m_ptr))
|
||||
+ std::string(".") + std::string(name);
|
||||
auto result = reinterpret_borrow<module>(PyImport_AddModule(full_name.c_str()));
|
||||
auto result = reinterpret_borrow<module_>(PyImport_AddModule(full_name.c_str()));
|
||||
if (doc && options::show_user_defined_docstrings())
|
||||
result.attr("__doc__") = pybind11::str(doc);
|
||||
attr(name) = result;
|
||||
|
@ -872,11 +911,11 @@ public:
|
|||
}
|
||||
|
||||
/// Import and return a module or throws `error_already_set`.
|
||||
static module import(const char *name) {
|
||||
static module_ import(const char *name) {
|
||||
PyObject *obj = PyImport_ImportModule(name);
|
||||
if (!obj)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<module>(obj);
|
||||
return reinterpret_steal<module_>(obj);
|
||||
}
|
||||
|
||||
/// Reload the module or throws `error_already_set`.
|
||||
|
@ -884,7 +923,7 @@ public:
|
|||
PyObject *obj = PyImport_ReloadModule(ptr());
|
||||
if (!obj)
|
||||
throw error_already_set();
|
||||
*this = reinterpret_steal<module>(obj);
|
||||
*this = reinterpret_steal<module_>(obj);
|
||||
}
|
||||
|
||||
// Adds an object to the module using the given name. Throws if an object with the given name
|
||||
|
@ -901,6 +940,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
using module = module_;
|
||||
|
||||
/// \ingroup python_builtins
|
||||
/// Return a dictionary representing the global variables in the current execution frame,
|
||||
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
|
||||
|
@ -981,7 +1022,7 @@ protected:
|
|||
void install_buffer_funcs(
|
||||
buffer_info *(*get_buffer)(PyObject *, void *),
|
||||
void *get_buffer_data) {
|
||||
PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr;
|
||||
auto *type = (PyHeapTypeObject*) m_ptr;
|
||||
auto tinfo = detail::get_type_info(&type->ht_type);
|
||||
|
||||
if (!type->ht_type.tp_as_buffer)
|
||||
|
@ -1047,6 +1088,13 @@ inline void call_operator_delete(void *p, size_t s, size_t a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
inline void add_class_method(object& cls, const char *name_, const cpp_function &cf) {
|
||||
cls.attr(cf.name()) = cf;
|
||||
if (strcmp(name_, "__eq__") == 0 && !cls.attr("__dict__").contains("__hash__")) {
|
||||
cls.attr("__hash__") = none();
|
||||
}
|
||||
}
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
/// Given a pointer to a member function, cast it to its `Derived` version.
|
||||
|
@ -1144,7 +1192,7 @@ public:
|
|||
class_ &def(const char *name_, Func&& f, const Extra&... extra) {
|
||||
cpp_function cf(method_adaptor<type>(std::forward<Func>(f)), name(name_), is_method(*this),
|
||||
sibling(getattr(*this, name_, none())), extra...);
|
||||
attr(cf.name()) = cf;
|
||||
add_class_method(*this, name_, cf);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1196,7 +1244,7 @@ public:
|
|||
|
||||
template <typename Func> class_& def_buffer(Func &&func) {
|
||||
struct capture { Func func; };
|
||||
capture *ptr = new capture { std::forward<Func>(func) };
|
||||
auto *ptr = new capture { std::forward<Func>(func) };
|
||||
install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* {
|
||||
detail::make_caster<type> caster;
|
||||
if (!caster.load(obj, false))
|
||||
|
@ -1381,6 +1429,13 @@ private:
|
|||
|
||||
/// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
|
||||
static void dealloc(detail::value_and_holder &v_h) {
|
||||
// We could be deallocating because we are cleaning up after a Python exception.
|
||||
// If so, the Python error indicator will be set. We need to clear that before
|
||||
// running the destructor, in case the destructor code calls more Python.
|
||||
// If we don't, the Python API will exit with an exception, and pybind11 will
|
||||
// throw error_already_set from the C++ destructor which is forbidden and triggers
|
||||
// std::terminate().
|
||||
error_scope scope;
|
||||
if (v_h.holder_constructed()) {
|
||||
v_h.holder<holder_type>().~holder_type();
|
||||
v_h.set_holder_constructed(false);
|
||||
|
@ -1436,7 +1491,7 @@ struct enum_base {
|
|||
|
||||
m_base.attr("__repr__") = cpp_function(
|
||||
[](handle arg) -> str {
|
||||
handle type = arg.get_type();
|
||||
handle type = type::handle_of(arg);
|
||||
object type_name = type.attr("__name__");
|
||||
dict entries = type.attr("__entries");
|
||||
for (const auto &kv : entries) {
|
||||
|
@ -1450,7 +1505,7 @@ struct enum_base {
|
|||
|
||||
m_base.attr("name") = property(cpp_function(
|
||||
[](handle arg) -> str {
|
||||
dict entries = arg.get_type().attr("__entries");
|
||||
dict entries = type::handle_of(arg).attr("__entries");
|
||||
for (const auto &kv : entries) {
|
||||
if (handle(kv.second[int_(0)]).equal(arg))
|
||||
return pybind11::str(kv.first);
|
||||
|
@ -1489,7 +1544,7 @@ struct enum_base {
|
|||
#define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \
|
||||
m_base.attr(op) = cpp_function( \
|
||||
[](object a, object b) { \
|
||||
if (!a.get_type().is(b.get_type())) \
|
||||
if (!type::handle_of(a).is(type::handle_of(b))) \
|
||||
strict_behavior; \
|
||||
return expr; \
|
||||
}, \
|
||||
|
@ -1736,7 +1791,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|||
typename KeyType = decltype((*std::declval<Iterator>()).first),
|
||||
typename... Extra>
|
||||
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
|
||||
typedef detail::iterator_state<Iterator, Sentinel, true, Policy> state;
|
||||
using state = detail::iterator_state<Iterator, Sentinel, true, Policy>;
|
||||
|
||||
if (!detail::get_type_info(typeid(state), false)) {
|
||||
class_<state>(handle(), "iterator", pybind11::module_local())
|
||||
|
@ -1815,10 +1870,10 @@ template <typename type>
|
|||
class exception : public object {
|
||||
public:
|
||||
exception() = default;
|
||||
exception(handle scope, const char *name, PyObject *base = PyExc_Exception) {
|
||||
exception(handle scope, const char *name, handle base = PyExc_Exception) {
|
||||
std::string full_name = scope.attr("__name__").cast<std::string>() +
|
||||
std::string(".") + name;
|
||||
m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base, NULL);
|
||||
m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), NULL);
|
||||
if (hasattr(scope, name))
|
||||
pybind11_fail("Error during initialization: multiple incompatible "
|
||||
"definitions with name \"" + std::string(name) + "\"");
|
||||
|
@ -1848,7 +1903,7 @@ PYBIND11_NAMESPACE_END(detail)
|
|||
template <typename CppException>
|
||||
exception<CppException> ®ister_exception(handle scope,
|
||||
const char *name,
|
||||
PyObject *base = PyExc_Exception) {
|
||||
handle base = PyExc_Exception) {
|
||||
auto &ex = detail::get_exception_object<CppException>();
|
||||
if (!ex) ex = exception<CppException>(scope, name, base);
|
||||
|
||||
|
@ -2057,21 +2112,22 @@ error_already_set::~error_already_set() {
|
|||
}
|
||||
}
|
||||
|
||||
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
|
||||
handle self = detail::get_object_handle(this_ptr, this_type);
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
inline function get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
|
||||
handle self = get_object_handle(this_ptr, this_type);
|
||||
if (!self)
|
||||
return function();
|
||||
handle type = self.get_type();
|
||||
handle type = type::handle_of(self);
|
||||
auto key = std::make_pair(type.ptr(), name);
|
||||
|
||||
/* Cache functions that aren't overloaded in Python to avoid
|
||||
/* Cache functions that aren't overridden in Python to avoid
|
||||
many costly Python dictionary lookups below */
|
||||
auto &cache = detail::get_internals().inactive_overload_cache;
|
||||
auto &cache = get_internals().inactive_override_cache;
|
||||
if (cache.find(key) != cache.end())
|
||||
return function();
|
||||
|
||||
function overload = getattr(self, name, function());
|
||||
if (overload.is_cpp_function()) {
|
||||
function override = getattr(self, name, function());
|
||||
if (override.is_cpp_function()) {
|
||||
cache.insert(key);
|
||||
return function();
|
||||
}
|
||||
|
@ -2111,34 +2167,36 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
|
|||
Py_DECREF(result);
|
||||
#endif
|
||||
|
||||
return overload;
|
||||
return override;
|
||||
}
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
/** \rst
|
||||
Try to retrieve a python method by the provided name from the instance pointed to by the this_ptr.
|
||||
|
||||
:this_ptr: The pointer to the object the overload should be retrieved for. This should be the first
|
||||
non-trampoline class encountered in the inheritance chain.
|
||||
:name: The name of the overloaded Python method to retrieve.
|
||||
:this_ptr: The pointer to the object the overriden method should be retrieved for. This should be
|
||||
the first non-trampoline class encountered in the inheritance chain.
|
||||
:name: The name of the overridden Python method to retrieve.
|
||||
:return: The Python method by this name from the object or an empty function wrapper.
|
||||
\endrst */
|
||||
template <class T> function get_overload(const T *this_ptr, const char *name) {
|
||||
template <class T> function get_override(const T *this_ptr, const char *name) {
|
||||
auto tinfo = detail::get_type_info(typeid(T));
|
||||
return tinfo ? get_type_overload(this_ptr, tinfo, name) : function();
|
||||
return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function();
|
||||
}
|
||||
|
||||
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \
|
||||
#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \
|
||||
do { \
|
||||
pybind11::gil_scoped_acquire gil; \
|
||||
pybind11::function overload = pybind11::get_overload(static_cast<const cname *>(this), name); \
|
||||
if (overload) { \
|
||||
auto o = overload(__VA_ARGS__); \
|
||||
pybind11::function override = pybind11::get_override(static_cast<const cname *>(this), name); \
|
||||
if (override) { \
|
||||
auto o = override(__VA_ARGS__); \
|
||||
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
|
||||
static pybind11::detail::overload_caster_t<ret_type> caster; \
|
||||
static pybind11::detail::override_caster_t<ret_type> caster; \
|
||||
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
||||
} \
|
||||
else return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
|
||||
} \
|
||||
}
|
||||
} while (false)
|
||||
|
||||
/** \rst
|
||||
Macro to populate the virtual method in the trampoline class. This macro tries to look up a method named 'fn'
|
||||
|
@ -2149,7 +2207,7 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
|||
.. code-block:: cpp
|
||||
|
||||
std::string toString() override {
|
||||
PYBIND11_OVERLOAD_NAME(
|
||||
PYBIND11_OVERRIDE_NAME(
|
||||
std::string, // Return type (ret_type)
|
||||
Animal, // Parent class (cname)
|
||||
"__str__", // Name of method in Python (name)
|
||||
|
@ -2157,17 +2215,21 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
|||
);
|
||||
}
|
||||
\endrst */
|
||||
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \
|
||||
return cname::fn(__VA_ARGS__)
|
||||
#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...) \
|
||||
do { \
|
||||
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
|
||||
return cname::fn(__VA_ARGS__); \
|
||||
} while (false)
|
||||
|
||||
/** \rst
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD_NAME`, except that it
|
||||
throws if no overload can be found.
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE_NAME`, except that it
|
||||
throws if no override can be found.
|
||||
\endrst */
|
||||
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \
|
||||
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\"");
|
||||
#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...) \
|
||||
do { \
|
||||
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
|
||||
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
|
||||
} while (false)
|
||||
|
||||
/** \rst
|
||||
Macro to populate the virtual method in the trampoline class. This macro tries to look up the method
|
||||
|
@ -2184,7 +2246,7 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
|||
|
||||
// Trampoline (need one for each virtual function)
|
||||
std::string go(int n_times) override {
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
std::string, // Return type (ret_type)
|
||||
Animal, // Parent class (cname)
|
||||
go, // Name of function in C++ (must match Python name) (fn)
|
||||
|
@ -2193,15 +2255,39 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
|||
}
|
||||
};
|
||||
\endrst */
|
||||
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERLOAD_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
#define PYBIND11_OVERRIDE(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
|
||||
/** \rst
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD`, except that it throws
|
||||
if no overload can be found.
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE`, except that it throws
|
||||
if no override can be found.
|
||||
\endrst */
|
||||
#define PYBIND11_OVERRIDE_PURE(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
|
||||
|
||||
// Deprecated versions
|
||||
|
||||
PYBIND11_DEPRECATED("get_type_overload has been deprecated")
|
||||
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
|
||||
return detail::get_type_override(this_ptr, this_type, name);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline function get_overload(const T *this_ptr, const char *name) {
|
||||
return get_override(this_ptr, name);
|
||||
}
|
||||
|
||||
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) \
|
||||
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)
|
||||
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__)
|
||||
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__);
|
||||
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERRIDE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__)
|
||||
#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERLOAD_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);
|
||||
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|||
/* A few forward declarations */
|
||||
class handle; class object;
|
||||
class str; class iterator;
|
||||
class type;
|
||||
struct arg; struct arg_v;
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
@ -34,7 +35,7 @@ namespace accessor_policies {
|
|||
struct sequence_item;
|
||||
struct list_item;
|
||||
struct tuple_item;
|
||||
}
|
||||
} // namespace accessor_policies
|
||||
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
||||
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
||||
using item_accessor = accessor<accessor_policies::generic_item>;
|
||||
|
@ -151,7 +152,8 @@ public:
|
|||
|
||||
/// Return the object's current reference count
|
||||
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
|
||||
/// Return a handle to the Python type object underlying the instance
|
||||
|
||||
PYBIND11_DEPRECATED("Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()")
|
||||
handle get_type() const;
|
||||
|
||||
private:
|
||||
|
@ -240,7 +242,7 @@ public:
|
|||
~object() { dec_ref(); }
|
||||
|
||||
/** \rst
|
||||
Resets the internal pointer to ``nullptr`` without without decreasing the
|
||||
Resets the internal pointer to ``nullptr`` without decreasing the
|
||||
object's reference count. The function returns a raw handle to the original
|
||||
Python object.
|
||||
\endrst */
|
||||
|
@ -330,13 +332,27 @@ public:
|
|||
error_already_set(const error_already_set &) = default;
|
||||
error_already_set(error_already_set &&) = default;
|
||||
|
||||
inline ~error_already_set();
|
||||
inline ~error_already_set() override;
|
||||
|
||||
/// Give the currently-held error back to Python, if any. If there is currently a Python error
|
||||
/// already set it is cleared first. After this call, the current object no longer stores the
|
||||
/// error variables (but the `.what()` string is still available).
|
||||
void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); }
|
||||
|
||||
/// If it is impossible to raise the currently-held error, such as in destructor, we can write
|
||||
/// it out using Python's unraisable hook (sys.unraisablehook). The error context should be
|
||||
/// some object whose repr() helps identify the location of the error. Python already knows the
|
||||
/// type and value of the error, so there is no need to repeat that. For example, __func__ could
|
||||
/// be helpful. After this call, the current object no longer stores the error variables,
|
||||
/// and neither does Python.
|
||||
void discard_as_unraisable(object err_context) {
|
||||
restore();
|
||||
PyErr_WriteUnraisable(err_context.ptr());
|
||||
}
|
||||
void discard_as_unraisable(const char *err_context) {
|
||||
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
|
||||
}
|
||||
|
||||
// Does nothing; provided for backwards compatibility.
|
||||
PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated")
|
||||
void clear() {}
|
||||
|
@ -370,7 +386,7 @@ bool isinstance(handle obj) { return T::check_(obj); }
|
|||
template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
|
||||
bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); }
|
||||
|
||||
template <> inline bool isinstance<handle>(handle obj) = delete;
|
||||
template <> inline bool isinstance<handle>(handle) = delete;
|
||||
template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; }
|
||||
|
||||
/// \ingroup python_builtins
|
||||
|
@ -736,9 +752,7 @@ inline bool PyIterable_Check(PyObject *obj) {
|
|||
}
|
||||
|
||||
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
|
||||
#endif
|
||||
|
||||
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
|
||||
|
||||
|
@ -784,7 +798,9 @@ PYBIND11_NAMESPACE_END(detail)
|
|||
Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \
|
||||
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
|
||||
bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \
|
||||
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); }
|
||||
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \
|
||||
template <typename Policy_> \
|
||||
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
|
||||
|
||||
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
|
||||
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
||||
|
@ -794,9 +810,7 @@ PYBIND11_NAMESPACE_END(detail)
|
|||
{ if (!m_ptr) throw error_already_set(); } \
|
||||
Name(object &&o) \
|
||||
: Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
|
||||
{ if (!m_ptr) throw error_already_set(); } \
|
||||
template <typename Policy_> \
|
||||
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
|
||||
{ if (!m_ptr) throw error_already_set(); }
|
||||
|
||||
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
|
||||
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
|
||||
|
@ -878,6 +892,32 @@ private:
|
|||
object value = {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
class type : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT(type, object, PyType_Check)
|
||||
|
||||
/// Return a type handle from a handle or an object
|
||||
static handle handle_of(handle h) { return handle((PyObject*) Py_TYPE(h.ptr())); }
|
||||
|
||||
/// Return a type object from a handle or an object
|
||||
static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); }
|
||||
|
||||
// Defined in pybind11/cast.h
|
||||
/// Convert C++ type to handle if previously registered. Does not convert
|
||||
/// standard types, like int, float. etc. yet.
|
||||
/// See https://github.com/pybind/pybind11/issues/2486
|
||||
template<typename T>
|
||||
static handle handle_of();
|
||||
|
||||
/// Convert C++ type to type if previously registered. Does not convert
|
||||
/// standard types, like int, float. etc. yet.
|
||||
/// See https://github.com/pybind/pybind11/issues/2486
|
||||
template<typename T>
|
||||
static type of() {return type(type::handle_of<T>(), borrowed_t{}); }
|
||||
};
|
||||
|
||||
class iterable : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)
|
||||
|
@ -908,7 +948,7 @@ public:
|
|||
Return a string representation of the object. This is analogous to
|
||||
the ``str()`` function in Python.
|
||||
\endrst */
|
||||
explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { }
|
||||
explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { if (!m_ptr) throw error_already_set(); }
|
||||
|
||||
operator std::string() const {
|
||||
object temp = *this;
|
||||
|
@ -933,8 +973,8 @@ private:
|
|||
/// Return string representation -- always returns a new reference, even if already a str
|
||||
static PyObject *raw_str(PyObject *op) {
|
||||
PyObject *str_value = PyObject_Str(op);
|
||||
if (!str_value) throw error_already_set();
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (!str_value) throw error_already_set();
|
||||
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
||||
Py_XDECREF(str_value); str_value = unicode;
|
||||
#endif
|
||||
|
@ -948,7 +988,7 @@ inline namespace literals {
|
|||
String literal version of `str`
|
||||
\endrst */
|
||||
inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
/// \addtogroup pytypes
|
||||
/// @{
|
||||
|
@ -1020,13 +1060,11 @@ public:
|
|||
none() : object(Py_None, borrowed_t{}) { }
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
class ellipsis : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)
|
||||
ellipsis() : object(Py_Ellipsis, borrowed_t{}) { }
|
||||
};
|
||||
#endif
|
||||
|
||||
class bool_ : public object {
|
||||
public:
|
||||
|
@ -1325,7 +1363,7 @@ public:
|
|||
buffer_info request(bool writable = false) const {
|
||||
int flags = PyBUF_STRIDES | PyBUF_FORMAT;
|
||||
if (writable) flags |= PyBUF_WRITABLE;
|
||||
Py_buffer *view = new Py_buffer();
|
||||
auto *view = new Py_buffer();
|
||||
if (PyObject_GetBuffer(m_ptr, view, flags) != 0) {
|
||||
delete view;
|
||||
throw error_already_set();
|
||||
|
@ -1542,7 +1580,8 @@ template <typename D>
|
|||
str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); }
|
||||
|
||||
template <typename D>
|
||||
handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); }
|
||||
PYBIND11_DEPRECATED("Use py::type::of(h) instead of h.get_type()")
|
||||
handle object_api<D>::get_type() const { return type::handle_of(*this); }
|
||||
|
||||
template <typename D>
|
||||
bool object_api<D>::rich_compare(object_api const &other, int value) const {
|
||||
|
|
|
@ -289,7 +289,7 @@ template<typename T> struct optional_caster {
|
|||
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
|
||||
};
|
||||
|
||||
#if PYBIND11_HAS_OPTIONAL
|
||||
#if defined(PYBIND11_HAS_OPTIONAL)
|
||||
template<typename T> struct type_caster<std::optional<T>>
|
||||
: public optional_caster<std::optional<T>> {};
|
||||
|
||||
|
@ -297,7 +297,7 @@ template<> struct type_caster<std::nullopt_t>
|
|||
: public void_caster<std::nullopt_t> {};
|
||||
#endif
|
||||
|
||||
#if PYBIND11_HAS_EXP_OPTIONAL
|
||||
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
|
||||
template<typename T> struct type_caster<std::experimental::optional<T>>
|
||||
: public optional_caster<std::experimental::optional<T>> {};
|
||||
|
||||
|
@ -369,7 +369,7 @@ struct variant_caster<V<Ts...>> {
|
|||
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]"));
|
||||
};
|
||||
|
||||
#if PYBIND11_HAS_VARIANT
|
||||
#if defined(PYBIND11_HAS_VARIANT)
|
||||
template <typename... Ts>
|
||||
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
|
||||
#endif
|
||||
|
|
|
@ -223,7 +223,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
||||
throw error_already_set();
|
||||
|
||||
Vector *seq = new Vector();
|
||||
auto *seq = new Vector();
|
||||
seq->reserve((size_t) slicelength);
|
||||
|
||||
for (size_t i=0; i<slicelength; ++i) {
|
||||
|
@ -397,14 +397,19 @@ vector_buffer(Class_& cl) {
|
|||
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() + ")");
|
||||
|
||||
auto vec = std::unique_ptr<Vector>(new Vector());
|
||||
vec->reserve((size_t) info.shape[0]);
|
||||
T *p = static_cast<T*>(info.ptr);
|
||||
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
||||
T *end = p + info.shape[0] * step;
|
||||
for (; p != end; p += step)
|
||||
vec->push_back(*p);
|
||||
return vec.release();
|
||||
if (step == 1) {
|
||||
return Vector(p, end);
|
||||
}
|
||||
else {
|
||||
Vector vec;
|
||||
vec.reserve((size_t) info.shape[0]);
|
||||
for (; p != end; p += step)
|
||||
vec.push_back(*p);
|
||||
return vec;
|
||||
}
|
||||
}));
|
||||
|
||||
return;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from ._version import version_info, __version__ # noqa: F401 imported but unused
|
||||
|
||||
from ._version import version_info, __version__
|
||||
from .commands import get_include, get_cmake_dir
|
||||
|
||||
|
||||
def get_include(user=False):
|
||||
import os
|
||||
d = os.path.dirname(__file__)
|
||||
if os.path.exists(os.path.join(d, "include")):
|
||||
# Package is installed
|
||||
return os.path.join(d, "include")
|
||||
else:
|
||||
# Package is from a source directory
|
||||
return os.path.join(os.path.dirname(d), "include")
|
||||
__all__ = (
|
||||
"version_info",
|
||||
"__version__",
|
||||
"get_include",
|
||||
"get_cmake_dir",
|
||||
)
|
||||
|
|
|
@ -5,13 +5,15 @@ import argparse
|
|||
import sys
|
||||
import sysconfig
|
||||
|
||||
from . import get_include
|
||||
from .commands import get_include, get_cmake_dir
|
||||
|
||||
|
||||
def print_includes():
|
||||
dirs = [sysconfig.get_path('include'),
|
||||
sysconfig.get_path('platinclude'),
|
||||
get_include()]
|
||||
dirs = [
|
||||
sysconfig.get_path("include"),
|
||||
sysconfig.get_path("platinclude"),
|
||||
get_include(),
|
||||
]
|
||||
|
||||
# Make unique but preserve order
|
||||
unique_dirs = []
|
||||
|
@ -19,19 +21,29 @@ def print_includes():
|
|||
if d not in unique_dirs:
|
||||
unique_dirs.append(d)
|
||||
|
||||
print(' '.join('-I' + d for d in unique_dirs))
|
||||
print(" ".join("-I" + d for d in unique_dirs))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(prog='python -m pybind11')
|
||||
parser.add_argument('--includes', action='store_true',
|
||||
help='Include flags for both pybind11 and Python headers.')
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--includes",
|
||||
action="store_true",
|
||||
help="Include flags for both pybind11 and Python headers.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cmakedir",
|
||||
action="store_true",
|
||||
help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if not sys.argv[1:]:
|
||||
parser.print_help()
|
||||
if args.includes:
|
||||
print_includes()
|
||||
if args.cmakedir:
|
||||
print(get_cmake_dir())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
version_info = (2, 5, 'dev1')
|
||||
__version__ = '.'.join(map(str, version_info))
|
||||
|
||||
|
||||
def _to_int(s):
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
return s
|
||||
|
||||
|
||||
__version__ = "2.6.0.dev1"
|
||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
|
||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def get_include(user=False):
|
||||
installed_path = os.path.join(DIR, "include")
|
||||
source_path = os.path.join(os.path.dirname(DIR), "include")
|
||||
return installed_path if os.path.exists(installed_path) else source_path
|
||||
|
||||
|
||||
def get_cmake_dir():
|
||||
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
|
||||
if os.path.exists(cmake_installed_path):
|
||||
return cmake_installed_path
|
||||
else:
|
||||
msg = "pybind11 not installed, installation required to access the CMake files"
|
||||
raise ImportError(msg)
|
|
@ -0,0 +1,270 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This module provides helpers for C++11+ projects using pybind11.
|
||||
|
||||
LICENSE:
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import warnings
|
||||
|
||||
try:
|
||||
from setuptools.command.build_ext import build_ext as _build_ext
|
||||
from setuptools import Extension as _Extension
|
||||
except ImportError:
|
||||
from distutils.command.build_ext import build_ext as _build_ext
|
||||
from distutils.extension import Extension as _Extension
|
||||
|
||||
import distutils.errors
|
||||
|
||||
|
||||
WIN = sys.platform.startswith("win32")
|
||||
PY2 = sys.version_info[0] < 3
|
||||
MACOS = sys.platform.startswith("darwin")
|
||||
STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
|
||||
|
||||
|
||||
# It is recommended to use PEP 518 builds if using this module. However, this
|
||||
# file explicitly supports being copied into a user's project directory
|
||||
# standalone, and pulling pybind11 with the deprecated setup_requires feature.
|
||||
# If you copy the file, remember to add it to your MANIFEST.in, and add the current
|
||||
# directory into your path if it sits beside your setup.py.
|
||||
|
||||
|
||||
class Pybind11Extension(_Extension):
|
||||
"""
|
||||
Build a C++11+ Extension module with pybind11. This automatically adds the
|
||||
recommended flags when you init the extension and assumes C++ sources - you
|
||||
can further modify the options yourself.
|
||||
|
||||
The customizations are:
|
||||
|
||||
* ``/EHsc`` and ``/bigobj`` on Windows
|
||||
* ``stdlib=libc++`` on macOS
|
||||
* ``visibility=hidden`` and ``-g0`` on Unix
|
||||
|
||||
Finally, you can set ``cxx_std`` via constructor or afterwords to enable
|
||||
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
|
||||
``build_ext``, which will search for the highest supported extension for
|
||||
you if the ``cxx_std`` property is not set. Do not set the ``cxx_std``
|
||||
property more than once, as flags are added when you set it. Set the
|
||||
property to None to disable the addition of C++ standard flags.
|
||||
|
||||
If you want to add pybind11 headers manually, for example for an exact
|
||||
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):
|
||||
for flag in flags:
|
||||
if flag not in self.extra_compile_args:
|
||||
self.extra_compile_args.append(flag)
|
||||
|
||||
def _add_lflags(self, *flags):
|
||||
for flag in flags:
|
||||
if flag not in self.extra_compile_args:
|
||||
self.extra_link_args.append(flag)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
self._cxx_level = 0
|
||||
cxx_std = kwargs.pop("cxx_std", 0)
|
||||
|
||||
if "language" not in kwargs:
|
||||
kwargs["language"] = "c++"
|
||||
|
||||
include_pybind11 = kwargs.pop("include_pybind11", True)
|
||||
|
||||
# Can't use super here because distutils has old-style classes in
|
||||
# Python 2!
|
||||
_Extension.__init__(self, *args, **kwargs)
|
||||
|
||||
# Include the installed package pybind11 headers
|
||||
if include_pybind11:
|
||||
# If using setup_requires, this fails the first time - that's okay
|
||||
try:
|
||||
import pybind11
|
||||
|
||||
pyinc = pybind11.get_include()
|
||||
|
||||
if pyinc not in self.include_dirs:
|
||||
self.include_dirs.append(pyinc)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Have to use the accessor manually to support Python 2 distutils
|
||||
Pybind11Extension.cxx_std.__set__(self, cxx_std)
|
||||
|
||||
if WIN:
|
||||
self._add_cflags("/EHsc", "/bigobj")
|
||||
else:
|
||||
self._add_cflags("-fvisibility=hidden", "-g0")
|
||||
if MACOS:
|
||||
self._add_cflags("-stdlib=libc++")
|
||||
self._add_lflags("-stdlib=libc++")
|
||||
|
||||
@property
|
||||
def cxx_std(self):
|
||||
"""
|
||||
The CXX standard level. If set, will add the required flags. If left
|
||||
at 0, it will trigger an automatic search when pybind11's build_ext
|
||||
is used. If None, will have no effect. Besides just the flags, this
|
||||
may add a register warning/error fix for Python 2 or macos-min 10.9
|
||||
or 10.14.
|
||||
"""
|
||||
return self._cxx_level
|
||||
|
||||
@cxx_std.setter
|
||||
def cxx_std(self, level):
|
||||
|
||||
if self._cxx_level:
|
||||
warnings.warn("You cannot safely change the cxx_level after setting it!")
|
||||
|
||||
# MSVC 2015 Update 3 and later only have 14 (and later 17) modes
|
||||
if WIN and level == 11:
|
||||
level = 14
|
||||
|
||||
self._cxx_level = level
|
||||
|
||||
if not level:
|
||||
return
|
||||
|
||||
self.extra_compile_args.append(STD_TMPL.format(level))
|
||||
|
||||
if MACOS and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
|
||||
# C++17 requires a higher min version of macOS
|
||||
macosx_min = "-mmacosx-version-min=" + ("10.9" if level < 17 else "10.14")
|
||||
self.extra_compile_args.append(macosx_min)
|
||||
self.extra_link_args.append(macosx_min)
|
||||
|
||||
if PY2:
|
||||
if level >= 17:
|
||||
self.extra_compile_args.append("/wd503" if WIN else "-Wno-register")
|
||||
elif not WIN and level >= 14:
|
||||
self.extra_compile_args.append("-Wno-deprecated-register")
|
||||
|
||||
|
||||
# Just in case someone clever tries to multithread
|
||||
tmp_chdir_lock = threading.Lock()
|
||||
cpp_cache_lock = threading.Lock()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tmp_chdir():
|
||||
"Prepare and enter a temporary directory, cleanup when done"
|
||||
|
||||
# Threadsafe
|
||||
with tmp_chdir_lock:
|
||||
olddir = os.getcwd()
|
||||
try:
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
os.chdir(tmpdir)
|
||||
yield tmpdir
|
||||
finally:
|
||||
os.chdir(olddir)
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
# cf http://bugs.python.org/issue26689
|
||||
def has_flag(compiler, flag):
|
||||
"""
|
||||
Return the flag if a flag name is supported on the
|
||||
specified compiler, otherwise None (can be used as a boolean).
|
||||
If multiple flags are passed, return the first that matches.
|
||||
"""
|
||||
|
||||
with tmp_chdir():
|
||||
fname = "flagcheck.cpp"
|
||||
with open(fname, "w") as f:
|
||||
f.write("int main (int argc, char **argv) { return 0; }")
|
||||
|
||||
try:
|
||||
compiler.compile([fname], extra_postargs=[flag])
|
||||
except distutils.errors.CompileError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Every call will cache the result
|
||||
cpp_flag_cache = None
|
||||
|
||||
|
||||
def auto_cpp_level(compiler):
|
||||
"""
|
||||
Return the max supported C++ std level (17, 14, or 11).
|
||||
"""
|
||||
|
||||
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] + ([] if WIN else [11])
|
||||
|
||||
for level in levels:
|
||||
if has_flag(compiler, STD_TMPL.format(level)):
|
||||
with cpp_cache_lock:
|
||||
cpp_flag_cache = level
|
||||
return level
|
||||
|
||||
msg = "Unsupported compiler -- at least C++11 support is needed!"
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
||||
class build_ext(_build_ext): # noqa: N801
|
||||
"""
|
||||
Customized build_ext that allows an auto-search for the highest supported
|
||||
C++ level for Pybind11Extension.
|
||||
"""
|
||||
|
||||
def build_extensions(self):
|
||||
"""
|
||||
Build extensions, injecting C++ std for Pybind11Extension if needed.
|
||||
"""
|
||||
|
||||
for ext in self.extensions:
|
||||
if hasattr(ext, "_cxx_level") and ext._cxx_level == 0:
|
||||
# Python 2 syntax - old-style distutils class
|
||||
ext.__class__.cxx_std.__set__(ext, auto_cpp_level(self.compiler))
|
||||
|
||||
# Python 2 doesn't allow super here, since distutils uses old-style
|
||||
# classes!
|
||||
_build_ext.build_extensions(self)
|
|
@ -0,0 +1,3 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "wheel", "cmake==3.18.0", "ninja"]
|
||||
build-backend = "setuptools.build_meta"
|
|
@ -1,6 +1,58 @@
|
|||
[metadata]
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
description = Seamless operability between C++11 and Python
|
||||
author = Wenzel Jakob
|
||||
author_email = "wenzel.jakob@epfl.ch"
|
||||
url = "https://github.com/pybind/pybind11"
|
||||
license = BSD
|
||||
|
||||
classifiers =
|
||||
Development Status :: 5 - Production/Stable
|
||||
Intended Audience :: Developers
|
||||
Topic :: Software Development :: Libraries :: Python Modules
|
||||
Topic :: Utilities
|
||||
Programming Language :: C++
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
License :: OSI Approved :: BSD License
|
||||
Programming Language :: Python :: Implementation :: PyPy
|
||||
Programming Language :: Python :: Implementation :: CPython
|
||||
Programming Language :: C++
|
||||
Topic :: Software Development :: Libraries :: Python Modules
|
||||
|
||||
keywords =
|
||||
C++11
|
||||
Python bindings
|
||||
|
||||
[options]
|
||||
python_requires = >=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4
|
||||
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]
|
||||
max-line-length = 99
|
||||
show_source = True
|
||||
|
@ -10,3 +62,5 @@ ignore =
|
|||
E201, E241, W504,
|
||||
# camelcase 'cPickle' imported as lowercase 'pickle'
|
||||
N813
|
||||
# Black conflict
|
||||
W503, E203
|
||||
|
|
|
@ -3,128 +3,113 @@
|
|||
|
||||
# Setup script for PyPI; use CMakeFile.txt to build extension modules
|
||||
|
||||
from setuptools import setup
|
||||
from distutils.command.install_headers import install_headers
|
||||
from distutils.command.build_py import build_py
|
||||
from pybind11 import __version__
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
package_data = [
|
||||
'include/pybind11/detail/class.h',
|
||||
'include/pybind11/detail/common.h',
|
||||
'include/pybind11/detail/descr.h',
|
||||
'include/pybind11/detail/init.h',
|
||||
'include/pybind11/detail/internals.h',
|
||||
'include/pybind11/detail/typeid.h',
|
||||
'include/pybind11/attr.h',
|
||||
'include/pybind11/buffer_info.h',
|
||||
'include/pybind11/cast.h',
|
||||
'include/pybind11/chrono.h',
|
||||
'include/pybind11/common.h',
|
||||
'include/pybind11/complex.h',
|
||||
'include/pybind11/eigen.h',
|
||||
'include/pybind11/embed.h',
|
||||
'include/pybind11/eval.h',
|
||||
'include/pybind11/functional.h',
|
||||
'include/pybind11/iostream.h',
|
||||
'include/pybind11/numpy.h',
|
||||
'include/pybind11/operators.h',
|
||||
'include/pybind11/options.h',
|
||||
'include/pybind11/pybind11.h',
|
||||
'include/pybind11/pytypes.h',
|
||||
'include/pybind11/stl.h',
|
||||
'include/pybind11/stl_bind.h',
|
||||
]
|
||||
import setuptools.command.sdist
|
||||
|
||||
# Prevent installation of pybind11 headers by setting
|
||||
# PYBIND11_USE_CMAKE.
|
||||
if os.environ.get('PYBIND11_USE_CMAKE'):
|
||||
headers = []
|
||||
else:
|
||||
headers = package_data
|
||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
VERSION_REGEX = re.compile(
|
||||
r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE
|
||||
)
|
||||
|
||||
# PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers
|
||||
# files, and the sys.prefix files (CMake and headers).
|
||||
|
||||
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"
|
||||
extra_cmd = 'cmdclass["sdist"] = SDist\n'
|
||||
|
||||
to_src = (
|
||||
("pyproject.toml", "tools/pyproject.toml"),
|
||||
("setup.py", setup_py),
|
||||
)
|
||||
|
||||
# Read the listed version
|
||||
with open("pybind11/_version.py") as f:
|
||||
code = compile(f.read(), "pybind11/_version.py", "exec")
|
||||
loc = {}
|
||||
exec(code, loc)
|
||||
version = loc["__version__"]
|
||||
|
||||
# Verify that the version matches the one in C++
|
||||
with open("include/pybind11/detail/common.h") as f:
|
||||
matches = dict(VERSION_REGEX.findall(f.read()))
|
||||
cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches)
|
||||
if version != cpp_version:
|
||||
msg = "Python version {} does not match C++ version {}!".format(
|
||||
version, cpp_version
|
||||
)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
||||
class InstallHeaders(install_headers):
|
||||
"""Use custom header installer because the default one flattens subdirectories"""
|
||||
def run(self):
|
||||
if not self.distribution.headers:
|
||||
return
|
||||
|
||||
for header in self.distribution.headers:
|
||||
subdir = os.path.dirname(os.path.relpath(header, 'include/pybind11'))
|
||||
install_dir = os.path.join(self.install_dir, subdir)
|
||||
self.mkpath(install_dir)
|
||||
|
||||
(out, _) = self.copy_file(header, install_dir)
|
||||
self.outfiles.append(out)
|
||||
def get_and_replace(filename, binary=False, **opts):
|
||||
with open(filename, "rb" if binary else "r") as f:
|
||||
contents = f.read()
|
||||
# Replacement has to be done on text in Python 3 (both work in Python 2)
|
||||
if binary:
|
||||
return string.Template(contents.decode()).substitute(opts).encode()
|
||||
else:
|
||||
return string.Template(contents).substitute(opts)
|
||||
|
||||
|
||||
# Install the headers inside the package as well
|
||||
class BuildPy(build_py):
|
||||
def build_package_data(self):
|
||||
build_py.build_package_data(self)
|
||||
for header in package_data:
|
||||
target = os.path.join(self.build_lib, 'pybind11', header)
|
||||
self.mkpath(os.path.dirname(target))
|
||||
self.copy_file(header, target, preserve_mode=False)
|
||||
# Use our input files instead when making the SDist (and anything that depends
|
||||
# on it, like a wheel)
|
||||
class SDist(setuptools.command.sdist.sdist):
|
||||
def make_release_tree(self, base_dir, files):
|
||||
setuptools.command.sdist.sdist.make_release_tree(self, base_dir, files)
|
||||
|
||||
def get_outputs(self, include_bytecode=1):
|
||||
outputs = build_py.get_outputs(self, include_bytecode=include_bytecode)
|
||||
for header in package_data:
|
||||
target = os.path.join(self.build_lib, 'pybind11', header)
|
||||
outputs.append(target)
|
||||
return outputs
|
||||
for to, src in to_src:
|
||||
txt = get_and_replace(src, binary=True, version=version, extra_cmd="")
|
||||
|
||||
dest = os.path.join(base_dir, to)
|
||||
|
||||
# This is normally linked, so unlink before writing!
|
||||
os.unlink(dest)
|
||||
with open(dest, "wb") as f:
|
||||
f.write(txt)
|
||||
|
||||
|
||||
setup(
|
||||
name='pybind11',
|
||||
version=__version__,
|
||||
description='Seamless operability between C++11 and Python',
|
||||
author='Wenzel Jakob',
|
||||
author_email='wenzel.jakob@epfl.ch',
|
||||
url='https://github.com/pybind/pybind11',
|
||||
download_url='https://github.com/pybind/pybind11/tarball/v' + __version__,
|
||||
packages=['pybind11'],
|
||||
license='BSD',
|
||||
headers=headers,
|
||||
zip_safe=False,
|
||||
cmdclass=dict(install_headers=InstallHeaders, build_py=BuildPy),
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Utilities',
|
||||
'Programming Language :: C++',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'License :: OSI Approved :: BSD License'
|
||||
],
|
||||
keywords='C++11, Python bindings',
|
||||
long_description="""pybind11 is a lightweight header-only library that
|
||||
exposes C++ types in Python and vice versa, mainly to create Python bindings of
|
||||
existing C++ code. Its goals and syntax are similar to the excellent
|
||||
Boost.Python by David Abrahams: to minimize boilerplate code in traditional
|
||||
extension modules by inferring type information using compile-time
|
||||
introspection.
|
||||
# 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)
|
||||
|
||||
The main issue with Boost.Python-and the reason for creating such a similar
|
||||
project-is Boost. Boost is an enormously large and complex suite of utility
|
||||
libraries that works with almost every C++ compiler in existence. This
|
||||
compatibility has its cost: arcane template tricks and workarounds are
|
||||
necessary to support the oldest and buggiest of compiler specimens. Now that
|
||||
C++11-compatible compilers are widely available, this heavy machinery has
|
||||
become an excessively large and unnecessary dependency.
|
||||
|
||||
Think of this library as a tiny self-contained version of Boost.Python with
|
||||
everything stripped away that isn't relevant for binding generation. Without
|
||||
comments, the core header files only require ~4K lines of code and depend on
|
||||
Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This
|
||||
compact implementation was possible thanks to some of the new C++11 language
|
||||
features (specifically: tuples, lambda functions and variadic templates). Since
|
||||
its creation, this library has grown beyond Boost.Python in many ways, leading
|
||||
to dramatically simpler binding code in many common situations.""")
|
||||
# Remove the CMake install directory when done
|
||||
@contextlib.contextmanager
|
||||
def remove_output(*sources):
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
for src in sources:
|
||||
shutil.rmtree(src)
|
||||
|
||||
|
||||
with remove_output("pybind11/include", "pybind11/share"):
|
||||
# Generate the files if they are not present.
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
cmd = ["cmake", "-S", ".", "-B", tmpdir] + [
|
||||
"-DCMAKE_INSTALL_PREFIX=pybind11",
|
||||
"-DBUILD_TESTING=OFF",
|
||||
"-DPYBIND11_NOPYTHON=ON",
|
||||
]
|
||||
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||
subprocess.check_call(cmd, **cmake_opts)
|
||||
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
||||
|
||||
txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd)
|
||||
code = compile(txt, setup_py, "exec")
|
||||
exec(code, {"SDist": SDist})
|
||||
|
|
|
@ -5,80 +5,150 @@
|
|||
# All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
option(PYBIND11_WERROR "Report all warnings as errors" OFF)
|
||||
set(PYBIND11_TEST_OVERRIDE "" CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
||||
# work as its own project and load the pybind11Config to get the tools we need
|
||||
project(pybind11_tests CXX)
|
||||
# Only needed for CMake < 3.5 support
|
||||
include(CMakeParseArguments)
|
||||
|
||||
find_package(pybind11 REQUIRED CONFIG)
|
||||
# Filter out items; print an optional message if any items filtered
|
||||
#
|
||||
# Usage:
|
||||
# pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "")
|
||||
#
|
||||
macro(PYBIND11_FILTER_TESTS LISTNAME)
|
||||
cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN})
|
||||
set(PYBIND11_FILTER_TESTS_FOUND OFF)
|
||||
foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS)
|
||||
list(FIND ${LISTNAME} ${filename} _FILE_FOUND)
|
||||
if(_FILE_FOUND GREATER -1)
|
||||
list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND})
|
||||
set(PYBIND11_FILTER_TESTS_FOUND ON)
|
||||
endif()
|
||||
endforeach()
|
||||
if(PYBIND11_FILTER_TESTS_FOUND AND ARG_MESSAGE)
|
||||
message(STATUS "${ARG_MESSAGE}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# New Python support
|
||||
if(DEFINED Python_EXECUTABLE)
|
||||
set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
|
||||
set(PYTHON_VERSION "${Python_VERSION}")
|
||||
endif()
|
||||
|
||||
# There's no harm in including a project in a project
|
||||
project(pybind11_tests CXX)
|
||||
|
||||
# Access FindCatch and more
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools")
|
||||
|
||||
option(PYBIND11_WERROR "Report all warnings as errors" OFF)
|
||||
option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF)
|
||||
option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF)
|
||||
set(PYBIND11_TEST_OVERRIDE
|
||||
""
|
||||
CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
|
||||
set(PYBIND11_TEST_FILTER
|
||||
""
|
||||
CACHE STRING "Tests from ;-separated list of *.cpp files will be removed from all tests")
|
||||
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
||||
# work as its own project and load the pybind11Config to get the tools we need
|
||||
find_package(pybind11 REQUIRED CONFIG)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting tests build type to MinSizeRel as none was specified")
|
||||
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
|
||||
"MinSizeRel" "RelWithDebInfo")
|
||||
set(CMAKE_BUILD_TYPE
|
||||
MinSizeRel
|
||||
CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel"
|
||||
"RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
if(PYBIND11_CUDA_TESTS)
|
||||
enable_language(CUDA)
|
||||
if(DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD})
|
||||
endif()
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
# Full set of test files (you can override these; see below)
|
||||
set(PYBIND11_TEST_FILES
|
||||
test_async.cpp
|
||||
test_buffers.cpp
|
||||
test_builtin_casters.cpp
|
||||
test_call_policies.cpp
|
||||
test_callbacks.cpp
|
||||
test_chrono.cpp
|
||||
test_class.cpp
|
||||
test_constants_and_functions.cpp
|
||||
test_copy_move.cpp
|
||||
test_custom_type_casters.cpp
|
||||
test_docstring_options.cpp
|
||||
test_eigen.cpp
|
||||
test_enum.cpp
|
||||
test_eval.cpp
|
||||
test_exceptions.cpp
|
||||
test_factory_constructors.cpp
|
||||
test_gil_scoped.cpp
|
||||
test_iostream.cpp
|
||||
test_kwargs_and_defaults.cpp
|
||||
test_local_bindings.cpp
|
||||
test_methods_and_attributes.cpp
|
||||
test_modules.cpp
|
||||
test_multiple_inheritance.cpp
|
||||
test_numpy_array.cpp
|
||||
test_numpy_dtypes.cpp
|
||||
test_numpy_vectorize.cpp
|
||||
test_opaque_types.cpp
|
||||
test_operator_overloading.cpp
|
||||
test_pickling.cpp
|
||||
test_pytypes.cpp
|
||||
test_sequences_and_iterators.cpp
|
||||
test_smart_ptr.cpp
|
||||
test_stl.cpp
|
||||
test_stl_binders.cpp
|
||||
test_tagbased_polymorphic.cpp
|
||||
test_union.cpp
|
||||
test_virtual_functions.cpp
|
||||
)
|
||||
test_async.cpp
|
||||
test_buffers.cpp
|
||||
test_builtin_casters.cpp
|
||||
test_call_policies.cpp
|
||||
test_callbacks.cpp
|
||||
test_chrono.cpp
|
||||
test_class.cpp
|
||||
test_constants_and_functions.cpp
|
||||
test_copy_move.cpp
|
||||
test_custom_type_casters.cpp
|
||||
test_docstring_options.cpp
|
||||
test_eigen.cpp
|
||||
test_enum.cpp
|
||||
test_eval.cpp
|
||||
test_exceptions.cpp
|
||||
test_factory_constructors.cpp
|
||||
test_gil_scoped.cpp
|
||||
test_iostream.cpp
|
||||
test_kwargs_and_defaults.cpp
|
||||
test_local_bindings.cpp
|
||||
test_methods_and_attributes.cpp
|
||||
test_modules.cpp
|
||||
test_multiple_inheritance.cpp
|
||||
test_numpy_array.cpp
|
||||
test_numpy_dtypes.cpp
|
||||
test_numpy_vectorize.cpp
|
||||
test_opaque_types.cpp
|
||||
test_operator_overloading.cpp
|
||||
test_pickling.cpp
|
||||
test_pytypes.cpp
|
||||
test_sequences_and_iterators.cpp
|
||||
test_smart_ptr.cpp
|
||||
test_stl.cpp
|
||||
test_stl_binders.cpp
|
||||
test_tagbased_polymorphic.cpp
|
||||
test_union.cpp
|
||||
test_virtual_functions.cpp)
|
||||
|
||||
# Invoking cmake with something like:
|
||||
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.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:
|
||||
# cmake -DPYBIND11_TEST_OVERRIDE= ..
|
||||
if (PYBIND11_TEST_OVERRIDE)
|
||||
if(PYBIND11_TEST_OVERRIDE)
|
||||
set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
|
||||
endif()
|
||||
|
||||
# Skip test_async for Python < 3.5
|
||||
list(FIND PYBIND11_TEST_FILES test_async.cpp PYBIND11_TEST_FILES_ASYNC_I)
|
||||
if((PYBIND11_TEST_FILES_ASYNC_I GREATER -1) AND ("${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" VERSION_LESS 3.5))
|
||||
message(STATUS "Skipping test_async because Python version ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} < 3.5")
|
||||
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I})
|
||||
# You can also filter tests:
|
||||
if(PYBIND11_TEST_FILTER)
|
||||
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
|
||||
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:
|
||||
# /pybind11/tests/test_constants_and_functions.cpp(125):
|
||||
# error: incompatible exception specifications
|
||||
if(PYBIND11_CUDA_TESTS)
|
||||
pybind11_filter_tests(
|
||||
PYBIND11_TEST_FILES test_constants_and_functions.cpp MESSAGE
|
||||
"Skipping test_constants_and_functions due to incompatible exception specifications")
|
||||
endif()
|
||||
|
||||
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
||||
|
@ -86,16 +156,10 @@ string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
|||
# 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
|
||||
# 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
|
||||
test_stl_binders.py
|
||||
)
|
||||
set(PYBIND11_CROSS_MODULE_TESTS test_exceptions.py test_local_bindings.py test_stl.py
|
||||
test_stl_binders.py)
|
||||
|
||||
set(PYBIND11_CROSS_MODULE_GIL_TESTS
|
||||
test_gil_scoped.py
|
||||
)
|
||||
set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py)
|
||||
|
||||
# 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"
|
||||
|
@ -105,21 +169,45 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
|||
# Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
|
||||
# Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
|
||||
# produces a fatal error if loaded from a pre-3.0 cmake.
|
||||
if (NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
find_package(Eigen3 3.2.7 QUIET CONFIG)
|
||||
if (EIGEN3_FOUND)
|
||||
if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1)
|
||||
set(PYBIND11_EIGEN_VIA_TARGET 1)
|
||||
endif()
|
||||
if(DOWNLOAD_EIGEN)
|
||||
if(CMAKE_VERSION VERSION_LESS 3.11)
|
||||
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
|
||||
endif()
|
||||
|
||||
set(EIGEN3_VERSION_STRING "3.3.7")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
eigen
|
||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
||||
GIT_TAG ${EIGEN3_VERSION_STRING})
|
||||
|
||||
FetchContent_GetProperties(eigen)
|
||||
if(NOT eigen_POPULATED)
|
||||
message(STATUS "Downloading Eigen")
|
||||
FetchContent_Populate(eigen)
|
||||
endif()
|
||||
|
||||
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
|
||||
set(EIGEN3_FOUND TRUE)
|
||||
|
||||
else()
|
||||
find_package(Eigen3 3.2.7 QUIET CONFIG)
|
||||
|
||||
if(NOT EIGEN3_FOUND)
|
||||
# Couldn't load via target, so fall back to allowing module mode finding, which will pick up
|
||||
# tools/FindEigen3.cmake
|
||||
find_package(Eigen3 3.2.7 QUIET)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT EIGEN3_FOUND)
|
||||
# Couldn't load via target, so fall back to allowing module mode finding, which will pick up
|
||||
# tools/FindEigen3.cmake
|
||||
find_package(Eigen3 3.2.7 QUIET)
|
||||
endif()
|
||||
|
||||
if(EIGEN3_FOUND)
|
||||
if(NOT TARGET Eigen3::Eigen)
|
||||
add_library(Eigen3::Eigen IMPORTED INTERFACE)
|
||||
set_property(TARGET Eigen3::Eigen PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${EIGEN3_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
# Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed
|
||||
# rather than looking it up in the cmake script); older versions, and the
|
||||
# tools/FindEigen3.cmake, set EIGEN3_VERSION instead.
|
||||
|
@ -129,28 +217,56 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
|
|||
message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
|
||||
else()
|
||||
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
|
||||
message(STATUS "Building tests WITHOUT Eigen")
|
||||
message(STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN on CMake 3.11+ to download")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Optional dependency for some tests (boost::variant is only supported with version >= 1.56)
|
||||
find_package(Boost 1.56)
|
||||
|
||||
if(Boost_FOUND)
|
||||
if(NOT TARGET Boost::headers)
|
||||
if(TARGET Boost::boost)
|
||||
# Classic FindBoost
|
||||
add_library(Boost::headers ALIAS Boost::boost)
|
||||
else()
|
||||
# Very old FindBoost, or newer Boost than CMake in older CMakes
|
||||
add_library(Boost::headers IMPORTED INTERFACE)
|
||||
set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
||||
${Boost_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Compile with compiler warnings turned on
|
||||
function(pybind11_enable_warnings target_name)
|
||||
if(MSVC)
|
||||
target_compile_options(${target_name} PRIVATE /W4)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
|
||||
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
|
||||
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual
|
||||
-Wdeprecated -Wundef)
|
||||
endif()
|
||||
|
||||
if(PYBIND11_WERROR)
|
||||
if(MSVC)
|
||||
target_compile_options(${target_name} PRIVATE /WX)
|
||||
elseif(PYBIND11_CUDA_TESTS)
|
||||
target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
|
||||
target_compile_options(${target_name} PRIVATE -Werror)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Needs to be readded since the ordering requires these to be after the ones above
|
||||
if(CMAKE_CXX_STANDARD
|
||||
AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
||||
AND PYTHON_VERSION VERSION_LESS 3.0)
|
||||
if(CMAKE_CXX_STANDARD LESS 17)
|
||||
target_compile_options(${target_name} PUBLIC -Wno-deprecated-register)
|
||||
else()
|
||||
target_compile_options(${target_name} PUBLIC -Wno-register)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(test_targets pybind11_tests)
|
||||
|
@ -158,7 +274,7 @@ set(test_targets pybind11_tests)
|
|||
# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it
|
||||
foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
|
||||
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
||||
if (i GREATER -1)
|
||||
if(i GREATER -1)
|
||||
list(APPEND test_targets pybind11_cross_module_tests)
|
||||
break()
|
||||
endif()
|
||||
|
@ -166,78 +282,118 @@ endforeach()
|
|||
|
||||
foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
|
||||
list(FIND PYBIND11_PYTEST_FILES ${t} i)
|
||||
if (i GREATER -1)
|
||||
if(i GREATER -1)
|
||||
list(APPEND test_targets cross_module_gil_utils)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(testdir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# Support CUDA testing by forcing the target file to compile with NVCC
|
||||
if(PYBIND11_CUDA_TESTS)
|
||||
set_property(SOURCE ${PYBIND11_TEST_FILES} PROPERTY LANGUAGE CUDA)
|
||||
endif()
|
||||
|
||||
foreach(target ${test_targets})
|
||||
set(test_files ${PYBIND11_TEST_FILES})
|
||||
if(NOT target STREQUAL "pybind11_tests")
|
||||
if(NOT "${target}" STREQUAL "pybind11_tests")
|
||||
set(test_files "")
|
||||
endif()
|
||||
|
||||
# Support CUDA testing by forcing the target file to compile with NVCC
|
||||
if(PYBIND11_CUDA_TESTS)
|
||||
set_property(SOURCE ${target}.cpp PROPERTY LANGUAGE CUDA)
|
||||
endif()
|
||||
|
||||
# Create the binding library
|
||||
pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})
|
||||
pybind11_enable_warnings(${target})
|
||||
|
||||
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
get_property(
|
||||
suffix
|
||||
TARGET ${target}
|
||||
PROPERTY SUFFIX)
|
||||
set(source_output "${CMAKE_CURRENT_SOURCE_DIR}/${target}${suffix}")
|
||||
if(suffix AND EXISTS "${source_output}")
|
||||
message(WARNING "Output file also in source directory; "
|
||||
"please remove to avoid confusion: ${source_output}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(${target} PRIVATE /utf-8)
|
||||
endif()
|
||||
|
||||
if(EIGEN3_FOUND)
|
||||
if (PYBIND11_EIGEN_VIA_TARGET)
|
||||
target_link_libraries(${target} PRIVATE Eigen3::Eigen)
|
||||
else()
|
||||
target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR})
|
||||
endif()
|
||||
target_link_libraries(${target} PRIVATE Eigen3::Eigen)
|
||||
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN)
|
||||
endif()
|
||||
|
||||
if(Boost_FOUND)
|
||||
target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(${target} PRIVATE Boost::headers)
|
||||
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
|
||||
endif()
|
||||
|
||||
# Always write the output file directly into the 'tests' directory (even on MSVC)
|
||||
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
|
||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER ${config} config)
|
||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
|
||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Make sure pytest is found or produce a fatal error
|
||||
# Make sure pytest is found or produce a warning
|
||||
if(NOT PYBIND11_PYTEST_FOUND)
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)"
|
||||
RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET)
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)"
|
||||
RESULT_VARIABLE pytest_not_found
|
||||
OUTPUT_VARIABLE pytest_version
|
||||
ERROR_QUIET)
|
||||
if(pytest_not_found)
|
||||
message(FATAL_ERROR "Running the tests requires pytest. Please install it manually"
|
||||
" (try: ${PYTHON_EXECUTABLE} -m pip install pytest)")
|
||||
elseif(pytest_version VERSION_LESS 3.0)
|
||||
message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}"
|
||||
"Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)")
|
||||
message(WARNING "Running the tests requires pytest. Please install it manually"
|
||||
" (try: ${PYTHON_EXECUTABLE} -m pip install pytest)")
|
||||
elseif(pytest_version VERSION_LESS 3.1)
|
||||
message(WARNING "Running the tests requires pytest >= 3.1. Found: ${pytest_version}"
|
||||
"Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)")
|
||||
else()
|
||||
set(PYBIND11_PYTEST_FOUND
|
||||
TRUE
|
||||
CACHE INTERNAL "")
|
||||
endif()
|
||||
set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "")
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.2)
|
||||
set(PYBIND11_USES_TERMINAL "")
|
||||
else()
|
||||
set(PYBIND11_USES_TERMINAL "USES_TERMINAL")
|
||||
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
# This is not used later in the build, so it's okay to regenerate each time.
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pytest.ini" "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini"
|
||||
COPYONLY)
|
||||
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini"
|
||||
"\ntestpaths = \"${CMAKE_CURRENT_SOURCE_DIR}\"")
|
||||
|
||||
endif()
|
||||
|
||||
# cmake 3.12 added list(transform <list> prepend
|
||||
# but we can't use it yet
|
||||
string(REPLACE "test_" "${CMAKE_CURRENT_BINARY_DIR}/test_" PYBIND11_BINARY_TEST_FILES
|
||||
"${PYBIND11_PYTEST_FILES}")
|
||||
|
||||
# A single command to compile and run the tests
|
||||
add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES}
|
||||
DEPENDS ${test_targets} WORKING_DIRECTORY ${testdir} ${PYBIND11_USES_TERMINAL})
|
||||
add_custom_target(
|
||||
pytest
|
||||
COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_BINARY_PYTEST_FILES}
|
||||
DEPENDS ${test_targets}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
USES_TERMINAL)
|
||||
|
||||
if(PYBIND11_TEST_OVERRIDE)
|
||||
add_custom_command(TARGET pytest POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
|
||||
add_custom_command(
|
||||
TARGET pytest
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
|
||||
endif()
|
||||
|
||||
# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
|
||||
|
@ -245,17 +401,23 @@ add_custom_target(check DEPENDS pytest)
|
|||
|
||||
# The remaining tests only apply when being built as part of the pybind11 project, but not if the
|
||||
# tests are being built independently.
|
||||
if (NOT PROJECT_NAME STREQUAL "pybind11")
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it:
|
||||
add_custom_command(TARGET pybind11_tests POST_BUILD
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py
|
||||
$<TARGET_FILE:pybind11_tests> ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
|
||||
add_custom_command(
|
||||
TARGET pybind11_tests
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/libsize.py
|
||||
$<TARGET_FILE:pybind11_tests>
|
||||
${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
|
||||
|
||||
# Test embedding the interpreter. Provides the `cpptest` target.
|
||||
add_subdirectory(test_embed)
|
||||
if(NOT PYBIND11_CUDA_TESTS)
|
||||
# Test embedding the interpreter. Provides the `cpptest` target.
|
||||
add_subdirectory(test_embed)
|
||||
|
||||
# Test CMake build using functions and targets from subdirectory or installed location
|
||||
add_subdirectory(test_cmake_build)
|
||||
# Test CMake build using functions and targets from subdirectory or installed location
|
||||
add_subdirectory(test_cmake_build)
|
||||
endif()
|
||||
|
|
|
@ -5,22 +5,26 @@ Extends output capture as needed by pybind11: ignore constructors, optional unor
|
|||
Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import textwrap
|
||||
import difflib
|
||||
import re
|
||||
import sys
|
||||
import contextlib
|
||||
import platform
|
||||
import difflib
|
||||
import gc
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
import env
|
||||
|
||||
# Early diagnostic for failed imports
|
||||
import pybind11_tests # noqa: F401
|
||||
|
||||
_unicode_marker = re.compile(r'u(\'[^\']*\')')
|
||||
_long_marker = re.compile(r'([0-9])L')
|
||||
_hexadecimal = re.compile(r'0x[0-9a-fA-F]+')
|
||||
|
||||
# test_async.py requires support for async and await
|
||||
# Avoid collecting Python3 only files
|
||||
collect_ignore = []
|
||||
if sys.version_info[:2] < (3, 5):
|
||||
if env.PY2:
|
||||
collect_ignore.append("test_async.py")
|
||||
|
||||
|
||||
|
@ -192,59 +196,5 @@ def gc_collect():
|
|||
|
||||
|
||||
def pytest_configure():
|
||||
"""Add import suppression and test requirements to `pytest` namespace"""
|
||||
try:
|
||||
import numpy as np
|
||||
except ImportError:
|
||||
np = None
|
||||
try:
|
||||
import scipy
|
||||
except ImportError:
|
||||
scipy = None
|
||||
try:
|
||||
from pybind11_tests.eigen import have_eigen
|
||||
except ImportError:
|
||||
have_eigen = False
|
||||
pypy = platform.python_implementation() == "PyPy"
|
||||
|
||||
skipif = pytest.mark.skipif
|
||||
pytest.suppress = suppress
|
||||
pytest.requires_numpy = skipif(not np, reason="numpy is not installed")
|
||||
pytest.requires_scipy = skipif(not np, reason="scipy is not installed")
|
||||
pytest.requires_eigen_and_numpy = skipif(not have_eigen or not np,
|
||||
reason="eigen and/or numpy are not installed")
|
||||
pytest.requires_eigen_and_scipy = skipif(
|
||||
not have_eigen or not scipy, reason="eigen and/or scipy are not installed")
|
||||
pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy")
|
||||
pytest.bug_in_pypy = pytest.mark.xfail(pypy, reason="bug in PyPy")
|
||||
pytest.unsupported_on_pypy3 = skipif(pypy and sys.version_info.major >= 3,
|
||||
reason="unsupported on PyPy3")
|
||||
pytest.unsupported_on_pypy_lt_6 = skipif(pypy and sys.pypy_version_info[0] < 6,
|
||||
reason="unsupported on PyPy<6")
|
||||
pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3,
|
||||
reason="unsupported on Python 2.x")
|
||||
pytest.gc_collect = gc_collect
|
||||
|
||||
|
||||
def _test_import_pybind11():
|
||||
"""Early diagnostic for test module initialization errors
|
||||
|
||||
When there is an error during initialization, the first import will report the
|
||||
real error while all subsequent imports will report nonsense. This import test
|
||||
is done early (in the pytest configuration file, before any tests) in order to
|
||||
avoid the noise of having all tests fail with identical error messages.
|
||||
|
||||
Any possible exception is caught here and reported manually *without* the stack
|
||||
trace. This further reduces noise since the trace would only show pytest internals
|
||||
which are not useful for debugging pybind11 module issues.
|
||||
"""
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
import pybind11_tests # noqa: F401 imported but unused
|
||||
except Exception as e:
|
||||
print("Failed to import pybind11_tests from pytest:")
|
||||
print(" {}: {}".format(type(e).__name__, e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
_test_import_pybind11()
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import platform
|
||||
import sys
|
||||
|
||||
LINUX = sys.platform.startswith("linux")
|
||||
MACOS = sys.platform.startswith("darwin")
|
||||
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
|
||||
|
||||
CPYTHON = platform.python_implementation() == "CPython"
|
||||
PYPY = platform.python_implementation() == "PyPy"
|
||||
|
||||
PY2 = sys.version_info.major == 2
|
||||
|
||||
PY = sys.version_info
|
|
@ -0,0 +1,259 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import contextlib
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import zipfile
|
||||
|
||||
# These tests must be run explicitly
|
||||
# They require CMake 3.15+ (--install)
|
||||
|
||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
||||
|
||||
|
||||
main_headers = {
|
||||
"include/pybind11/attr.h",
|
||||
"include/pybind11/buffer_info.h",
|
||||
"include/pybind11/cast.h",
|
||||
"include/pybind11/chrono.h",
|
||||
"include/pybind11/common.h",
|
||||
"include/pybind11/complex.h",
|
||||
"include/pybind11/eigen.h",
|
||||
"include/pybind11/embed.h",
|
||||
"include/pybind11/eval.h",
|
||||
"include/pybind11/functional.h",
|
||||
"include/pybind11/iostream.h",
|
||||
"include/pybind11/numpy.h",
|
||||
"include/pybind11/operators.h",
|
||||
"include/pybind11/options.h",
|
||||
"include/pybind11/pybind11.h",
|
||||
"include/pybind11/pytypes.h",
|
||||
"include/pybind11/stl.h",
|
||||
"include/pybind11/stl_bind.h",
|
||||
}
|
||||
|
||||
detail_headers = {
|
||||
"include/pybind11/detail/class.h",
|
||||
"include/pybind11/detail/common.h",
|
||||
"include/pybind11/detail/descr.h",
|
||||
"include/pybind11/detail/init.h",
|
||||
"include/pybind11/detail/internals.h",
|
||||
"include/pybind11/detail/typeid.h",
|
||||
}
|
||||
|
||||
cmake_files = {
|
||||
"share/cmake/pybind11/FindPythonLibsNew.cmake",
|
||||
"share/cmake/pybind11/pybind11Common.cmake",
|
||||
"share/cmake/pybind11/pybind11Config.cmake",
|
||||
"share/cmake/pybind11/pybind11ConfigVersion.cmake",
|
||||
"share/cmake/pybind11/pybind11NewTools.cmake",
|
||||
"share/cmake/pybind11/pybind11Targets.cmake",
|
||||
"share/cmake/pybind11/pybind11Tools.cmake",
|
||||
}
|
||||
|
||||
py_files = {
|
||||
"__init__.py",
|
||||
"__main__.py",
|
||||
"_version.py",
|
||||
"commands.py",
|
||||
"setup_helpers.py",
|
||||
}
|
||||
|
||||
headers = main_headers | detail_headers
|
||||
src_files = headers | cmake_files
|
||||
all_files = src_files | py_files
|
||||
|
||||
|
||||
sdist_files = {
|
||||
"pybind11",
|
||||
"pybind11/include",
|
||||
"pybind11/include/pybind11",
|
||||
"pybind11/include/pybind11/detail",
|
||||
"pybind11/share",
|
||||
"pybind11/share/cmake",
|
||||
"pybind11/share/cmake/pybind11",
|
||||
"pyproject.toml",
|
||||
"setup.cfg",
|
||||
"setup.py",
|
||||
"LICENSE",
|
||||
"MANIFEST.in",
|
||||
"README.md",
|
||||
"PKG-INFO",
|
||||
}
|
||||
|
||||
local_sdist_files = {
|
||||
".egg-info",
|
||||
".egg-info/PKG-INFO",
|
||||
".egg-info/SOURCES.txt",
|
||||
".egg-info/dependency_links.txt",
|
||||
".egg-info/not-zip-safe",
|
||||
".egg-info/top_level.txt",
|
||||
}
|
||||
|
||||
|
||||
def test_build_sdist(monkeypatch, tmpdir):
|
||||
|
||||
monkeypatch.chdir(MAIN_DIR)
|
||||
|
||||
out = subprocess.check_output(
|
||||
[
|
||||
sys.executable,
|
||||
"setup.py",
|
||||
"sdist",
|
||||
"--formats=tar",
|
||||
"--dist-dir",
|
||||
str(tmpdir),
|
||||
]
|
||||
)
|
||||
if hasattr(out, "decode"):
|
||||
out = out.decode()
|
||||
|
||||
(sdist,) = tmpdir.visit("*.tar")
|
||||
|
||||
with tarfile.open(str(sdist)) as tar:
|
||||
start = tar.getnames()[0] + "/"
|
||||
version = start[9:-1]
|
||||
simpler = set(n.split("/", 1)[-1] for n in tar.getnames()[1:])
|
||||
|
||||
with contextlib.closing(
|
||||
tar.extractfile(tar.getmember(start + "setup.py"))
|
||||
) as f:
|
||||
setup_py = f.read()
|
||||
|
||||
with contextlib.closing(
|
||||
tar.extractfile(tar.getmember(start + "pyproject.toml"))
|
||||
) as f:
|
||||
pyproject_toml = f.read()
|
||||
|
||||
files = set("pybind11/{}".format(n) for n in all_files)
|
||||
files |= sdist_files
|
||||
files |= set("pybind11{}".format(n) for n in local_sdist_files)
|
||||
files.add("pybind11.egg-info/entry_points.txt")
|
||||
files.add("pybind11.egg-info/requires.txt")
|
||||
assert simpler == files
|
||||
|
||||
with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f:
|
||||
contents = (
|
||||
string.Template(f.read().decode())
|
||||
.substitute(version=version, extra_cmd="")
|
||||
.encode()
|
||||
)
|
||||
assert setup_py == contents
|
||||
|
||||
with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f:
|
||||
contents = f.read()
|
||||
assert pyproject_toml == contents
|
||||
|
||||
|
||||
def test_build_global_dist(monkeypatch, tmpdir):
|
||||
|
||||
monkeypatch.chdir(MAIN_DIR)
|
||||
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
||||
|
||||
out = subprocess.check_output(
|
||||
[
|
||||
sys.executable,
|
||||
"setup.py",
|
||||
"sdist",
|
||||
"--formats=tar",
|
||||
"--dist-dir",
|
||||
str(tmpdir),
|
||||
]
|
||||
)
|
||||
if hasattr(out, "decode"):
|
||||
out = out.decode()
|
||||
|
||||
(sdist,) = tmpdir.visit("*.tar")
|
||||
|
||||
with tarfile.open(str(sdist)) as tar:
|
||||
start = tar.getnames()[0] + "/"
|
||||
version = start[16:-1]
|
||||
simpler = set(n.split("/", 1)[-1] for n in tar.getnames()[1:])
|
||||
|
||||
with contextlib.closing(
|
||||
tar.extractfile(tar.getmember(start + "setup.py"))
|
||||
) as f:
|
||||
setup_py = f.read()
|
||||
|
||||
with contextlib.closing(
|
||||
tar.extractfile(tar.getmember(start + "pyproject.toml"))
|
||||
) as f:
|
||||
pyproject_toml = f.read()
|
||||
|
||||
files = set("pybind11/{}".format(n) for n in all_files)
|
||||
files |= sdist_files
|
||||
files |= set("pybind11_global{}".format(n) for n in local_sdist_files)
|
||||
assert simpler == files
|
||||
|
||||
with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f:
|
||||
contents = (
|
||||
string.Template(f.read().decode())
|
||||
.substitute(version=version, extra_cmd="")
|
||||
.encode()
|
||||
)
|
||||
assert setup_py == contents
|
||||
|
||||
with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f:
|
||||
contents = f.read()
|
||||
assert pyproject_toml == contents
|
||||
|
||||
|
||||
def tests_build_wheel(monkeypatch, tmpdir):
|
||||
monkeypatch.chdir(MAIN_DIR)
|
||||
|
||||
subprocess.check_output(
|
||||
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
|
||||
)
|
||||
|
||||
(wheel,) = tmpdir.visit("*.whl")
|
||||
|
||||
files = set("pybind11/{}".format(n) for n in all_files)
|
||||
files |= {
|
||||
"dist-info/LICENSE",
|
||||
"dist-info/METADATA",
|
||||
"dist-info/RECORD",
|
||||
"dist-info/WHEEL",
|
||||
"dist-info/entry_points.txt",
|
||||
"dist-info/top_level.txt",
|
||||
}
|
||||
|
||||
with zipfile.ZipFile(str(wheel)) as z:
|
||||
names = z.namelist()
|
||||
|
||||
trimmed = set(n for n in names if "dist-info" not in n)
|
||||
trimmed |= set(
|
||||
"dist-info/{}".format(n.split("/", 1)[-1]) for n in names if "dist-info" in n
|
||||
)
|
||||
assert files == trimmed
|
||||
|
||||
|
||||
def tests_build_global_wheel(monkeypatch, tmpdir):
|
||||
monkeypatch.chdir(MAIN_DIR)
|
||||
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
|
||||
|
||||
subprocess.check_output(
|
||||
[sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
|
||||
)
|
||||
|
||||
(wheel,) = tmpdir.visit("*.whl")
|
||||
|
||||
files = set("data/data/{}".format(n) for n in src_files)
|
||||
files |= set("data/headers/{}".format(n[8:]) for n in headers)
|
||||
files |= {
|
||||
"dist-info/LICENSE",
|
||||
"dist-info/METADATA",
|
||||
"dist-info/WHEEL",
|
||||
"dist-info/top_level.txt",
|
||||
"dist-info/RECORD",
|
||||
}
|
||||
|
||||
with zipfile.ZipFile(str(wheel)) as z:
|
||||
names = z.namelist()
|
||||
|
||||
beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0]
|
||||
trimmed = set(n[len(beginning) + 1 :] for n in names)
|
||||
|
||||
assert files == trimmed
|
|
@ -0,0 +1,95 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("std", [11, 0])
|
||||
def test_simple_setup_py(monkeypatch, tmpdir, std):
|
||||
monkeypatch.chdir(tmpdir)
|
||||
monkeypatch.syspath_prepend(MAIN_DIR)
|
||||
|
||||
(tmpdir / "setup.py").write_text(
|
||||
dedent(
|
||||
u"""\
|
||||
import sys
|
||||
sys.path.append({MAIN_DIR!r})
|
||||
|
||||
from setuptools import setup, Extension
|
||||
from pybind11.setup_helpers import build_ext, Pybind11Extension
|
||||
|
||||
std = {std}
|
||||
|
||||
ext_modules = [
|
||||
Pybind11Extension(
|
||||
"simple_setup",
|
||||
sorted(["main.cpp"]),
|
||||
cxx_std=std,
|
||||
),
|
||||
]
|
||||
|
||||
cmdclass = dict()
|
||||
if std == 0:
|
||||
cmdclass["build_ext"] = build_ext
|
||||
|
||||
|
||||
setup(
|
||||
name="simple_setup_package",
|
||||
cmdclass=cmdclass,
|
||||
ext_modules=ext_modules,
|
||||
)
|
||||
"""
|
||||
).format(MAIN_DIR=MAIN_DIR, std=std),
|
||||
encoding="ascii",
|
||||
)
|
||||
|
||||
(tmpdir / "main.cpp").write_text(
|
||||
dedent(
|
||||
u"""\
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
int f(int x) {
|
||||
return x * 3;
|
||||
}
|
||||
PYBIND11_MODULE(simple_setup, m) {
|
||||
m.def("f", &f);
|
||||
}
|
||||
"""
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
|
||||
subprocess.check_call(
|
||||
[sys.executable, "setup.py", "build_ext", "--inplace"],
|
||||
stdout=sys.stdout,
|
||||
stderr=sys.stderr,
|
||||
)
|
||||
|
||||
# Debug helper printout, normally hidden
|
||||
for item in tmpdir.listdir():
|
||||
print(item.basename)
|
||||
|
||||
assert (
|
||||
len([f for f in tmpdir.listdir() if f.basename.startswith("simple_setup")]) == 1
|
||||
)
|
||||
assert len(list(tmpdir.listdir())) == 4 # two files + output + build_dir
|
||||
|
||||
(tmpdir / "test.py").write_text(
|
||||
dedent(
|
||||
u"""\
|
||||
import simple_setup
|
||||
assert simple_setup.f(3) == 9
|
||||
"""
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
|
||||
subprocess.check_call(
|
||||
[sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr
|
||||
)
|
|
@ -58,7 +58,7 @@ public:
|
|||
std::string name_;
|
||||
const std::string &name() { return name_; }
|
||||
};
|
||||
}
|
||||
} // namespace pets
|
||||
|
||||
struct MixGL { int i; MixGL(int i) : i{i} {} };
|
||||
struct MixGL2 { int i; MixGL2(int i) : i{i} {} };
|
||||
|
|
|
@ -32,11 +32,11 @@ std::list<std::function<void(py::module &)>> &initializers() {
|
|||
}
|
||||
|
||||
test_initializer::test_initializer(Initializer init) {
|
||||
initializers().push_back(init);
|
||||
initializers().emplace_back(init);
|
||||
}
|
||||
|
||||
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
||||
initializers().push_back([=](py::module &parent) {
|
||||
initializers().emplace_back([=](py::module &parent) {
|
||||
auto m = parent.def_submodule(submodule_name);
|
||||
init(m);
|
||||
});
|
||||
|
@ -88,6 +88,4 @@ PYBIND11_MODULE(pybind11_tests, m) {
|
|||
|
||||
for (const auto &initializer : initializers())
|
||||
initializer(m);
|
||||
|
||||
if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
[pytest]
|
||||
minversion = 3.0
|
||||
norecursedirs = test_cmake_build test_embed
|
||||
minversion = 3.1
|
||||
norecursedirs = test_* extra_*
|
||||
xfail_strict = True
|
||||
addopts =
|
||||
# show summary of skipped tests
|
||||
-rs
|
||||
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
|
||||
--capture=sys
|
||||
# enable all warnings
|
||||
-Wa
|
||||
filterwarnings =
|
||||
# make warnings into errors but ignore certain third-party extension issues
|
||||
error
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
--extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010/
|
||||
numpy==1.16.6; python_version<"3.6"
|
||||
numpy==1.18.0; platform_python_implementation=="PyPy" and sys_platform=="darwin" and python_version>="3.6"
|
||||
numpy==1.19.1; (platform_python_implementation!="PyPy" or sys_platform!="darwin") and python_version>="3.6" and python_version<"3.9"
|
||||
pytest==4.6.9; python_version<"3.5"
|
||||
pytest==5.4.3; python_version>="3.5"
|
||||
scipy==1.2.3; (platform_python_implementation!="PyPy" or sys_platform!="darwin") and python_version<"3.6"
|
||||
scipy==1.5.2; (platform_python_implementation!="PyPy" or sys_platform!="darwin") and python_version>="3.6" and python_version<"3.9"
|
|
@ -1,7 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import asyncio
|
||||
import pytest
|
||||
from pybind11_tests import async_module as m
|
||||
|
||||
asyncio = pytest.importorskip("asyncio")
|
||||
m = pytest.importorskip("pybind11_tests.async_module")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import io
|
||||
import struct
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
||||
from pybind11_tests import buffers as m
|
||||
from pybind11_tests import ConstructorStats
|
||||
|
||||
PY3 = sys.version_info[0] >= 3
|
||||
|
||||
pytestmark = pytest.requires_numpy
|
||||
|
||||
with pytest.suppress(ImportError):
|
||||
import numpy as np
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
|
||||
def test_from_python():
|
||||
|
@ -39,9 +35,7 @@ def test_from_python():
|
|||
assert cstats.move_assignments == 0
|
||||
|
||||
|
||||
# PyPy: Memory leak in the "np.array(m, copy=False)" call
|
||||
# https://bitbucket.org/pypy/pypy/issues/2444
|
||||
@pytest.unsupported_on_pypy
|
||||
# https://foss.heptapod.net/pypy/pypy/-/issues/2444
|
||||
def test_to_python():
|
||||
mat = m.Matrix(5, 4)
|
||||
assert memoryview(mat).shape == (5, 4)
|
||||
|
@ -76,7 +70,6 @@ def test_to_python():
|
|||
assert cstats.move_assignments == 0
|
||||
|
||||
|
||||
@pytest.unsupported_on_pypy
|
||||
def test_inherited_protocol():
|
||||
"""SquareMatrix is derived from Matrix and inherits the buffer protocol"""
|
||||
|
||||
|
@ -85,7 +78,6 @@ def test_inherited_protocol():
|
|||
assert np.asarray(matrix).shape == (5, 5)
|
||||
|
||||
|
||||
@pytest.unsupported_on_pypy
|
||||
def test_pointer_to_member_fn():
|
||||
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
|
||||
buf = cls()
|
||||
|
@ -94,19 +86,17 @@ def test_pointer_to_member_fn():
|
|||
assert value == 0x12345678
|
||||
|
||||
|
||||
@pytest.unsupported_on_pypy
|
||||
def test_readonly_buffer():
|
||||
buf = m.BufferReadOnly(0x64)
|
||||
view = memoryview(buf)
|
||||
assert view[0] == 0x64 if PY3 else b'd'
|
||||
assert view[0] == b'd' if env.PY2 else 0x64
|
||||
assert view.readonly
|
||||
|
||||
|
||||
@pytest.unsupported_on_pypy
|
||||
def test_selective_readonly_buffer():
|
||||
buf = m.BufferReadOnlySelect()
|
||||
|
||||
memoryview(buf)[0] = 0x64 if PY3 else b'd'
|
||||
memoryview(buf)[0] = b'd' if env.PY2 else 0x64
|
||||
assert buf.value == 0x64
|
||||
|
||||
io.BytesIO(b'A').readinto(buf)
|
||||
|
@ -114,6 +104,6 @@ def test_selective_readonly_buffer():
|
|||
|
||||
buf.readonly = True
|
||||
with pytest.raises(TypeError):
|
||||
memoryview(buf)[0] = 0 if PY3 else b'\0'
|
||||
memoryview(buf)[0] = b'\0' if env.PY2 else 0
|
||||
with pytest.raises(TypeError):
|
||||
io.BytesIO(b'1').readinto(buf)
|
||||
|
|
|
@ -117,12 +117,16 @@ TEST_SUBMODULE(builtin_casters, m) {
|
|||
return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); });
|
||||
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
|
||||
|
||||
static std::pair<int, std::string> int_string_pair{2, "items"};
|
||||
m.def("int_string_pair", []() { return &int_string_pair; });
|
||||
|
||||
// test_builtins_cast_return_none
|
||||
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
||||
m.def("return_none_char", []() -> const char * { return nullptr; });
|
||||
m.def("return_none_bool", []() -> bool * { return nullptr; });
|
||||
m.def("return_none_int", []() -> int * { return nullptr; });
|
||||
m.def("return_none_float", []() -> float * { return nullptr; });
|
||||
m.def("return_none_pair", []() -> std::pair<int,int> * { return nullptr; });
|
||||
|
||||
// test_none_deferred
|
||||
m.def("defer_none_cstring", [](char *) { return false; });
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
||||
from pybind11_tests import builtin_casters as m
|
||||
from pybind11_tests import UserType, IncType
|
||||
|
||||
|
@ -115,13 +117,16 @@ def test_bytes_to_string():
|
|||
"""Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
|
||||
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
||||
# Issue #816
|
||||
import sys
|
||||
byte = bytes if sys.version_info[0] < 3 else str
|
||||
|
||||
assert m.strlen(byte("hi")) == 2
|
||||
assert m.string_length(byte("world")) == 5
|
||||
assert m.string_length(byte("a\x00b")) == 3
|
||||
assert m.strlen(byte("a\x00b")) == 1 # C-string limitation
|
||||
def to_bytes(s):
|
||||
b = s if env.PY2 else s.encode("utf8")
|
||||
assert isinstance(b, bytes)
|
||||
return b
|
||||
|
||||
assert m.strlen(to_bytes("hi")) == 2
|
||||
assert m.string_length(to_bytes("world")) == 5
|
||||
assert m.string_length(to_bytes("a\x00b")) == 3
|
||||
assert m.strlen(to_bytes("a\x00b")) == 1 # C-string limitation
|
||||
|
||||
# passing in a utf8 encoded string should work
|
||||
assert m.string_length(u'💩'.encode("utf8")) == 4
|
||||
|
@ -187,12 +192,11 @@ def test_string_view(capture):
|
|||
|
||||
def test_integer_casting():
|
||||
"""Issue #929 - out-of-range integer values shouldn't be accepted"""
|
||||
import sys
|
||||
assert m.i32_str(-1) == "-1"
|
||||
assert m.i64_str(-1) == "-1"
|
||||
assert m.i32_str(2000000000) == "2000000000"
|
||||
assert m.u32_str(2000000000) == "2000000000"
|
||||
if sys.version_info < (3,):
|
||||
if env.PY2:
|
||||
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
||||
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
|
||||
assert m.i64_str(long(-999999999999)) == "-999999999999" # noqa: F821 undefined name
|
||||
|
@ -214,7 +218,7 @@ def test_integer_casting():
|
|||
m.i32_str(3000000000)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
||||
if sys.version_info < (3,):
|
||||
if env.PY2:
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
@ -250,6 +254,8 @@ def test_tuple(doc):
|
|||
assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
|
||||
assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
|
||||
|
||||
assert m.int_string_pair() == (2, "items")
|
||||
|
||||
|
||||
def test_builtins_cast_return_none():
|
||||
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
|
||||
|
@ -258,6 +264,7 @@ def test_builtins_cast_return_none():
|
|||
assert m.return_none_bool() is None
|
||||
assert m.return_none_int() is None
|
||||
assert m.return_none_float() is None
|
||||
assert m.return_none_pair() is None
|
||||
|
||||
|
||||
def test_none_deferred():
|
||||
|
@ -352,9 +359,9 @@ def test_bool_caster():
|
|||
assert convert(A(False)) is False
|
||||
|
||||
|
||||
@pytest.requires_numpy
|
||||
def test_numpy_bool():
|
||||
import numpy as np
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
|
||||
|
||||
def cant_convert(v):
|
||||
|
|
|
@ -46,6 +46,7 @@ TEST_SUBMODULE(call_policies, m) {
|
|||
class Parent {
|
||||
public:
|
||||
Parent() { py::print("Allocating parent."); }
|
||||
Parent(const Parent& parent) = default;
|
||||
~Parent() { py::print("Releasing parent."); }
|
||||
void addChild(Child *) { }
|
||||
Child *returnChild() { return new Child(); }
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
||||
from pybind11_tests import call_policies as m
|
||||
from pybind11_tests import ConstructorStats
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)
|
||||
def test_keep_alive_argument(capture):
|
||||
n_inst = ConstructorStats.detail_reg_inst()
|
||||
with capture:
|
||||
|
@ -70,8 +74,8 @@ def test_keep_alive_return_value(capture):
|
|||
"""
|
||||
|
||||
|
||||
# https://bitbucket.org/pypy/pypy/issues/2447
|
||||
@pytest.unsupported_on_pypy
|
||||
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
|
||||
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")
|
||||
def test_alive_gc(capture):
|
||||
n_inst = ConstructorStats.detail_reg_inst()
|
||||
p = m.ParentGC()
|
||||
|
|
|
@ -10,6 +10,25 @@
|
|||
|
||||
#include "pybind11_tests.h"
|
||||
#include <pybind11/chrono.h>
|
||||
#include <chrono>
|
||||
|
||||
struct different_resolutions {
|
||||
using time_point_h = std::chrono::time_point<
|
||||
std::chrono::system_clock, std::chrono::hours>;
|
||||
using time_point_m = std::chrono::time_point<
|
||||
std::chrono::system_clock, std::chrono::minutes>;
|
||||
using time_point_s = std::chrono::time_point<
|
||||
std::chrono::system_clock, std::chrono::seconds>;
|
||||
using time_point_ms = std::chrono::time_point<
|
||||
std::chrono::system_clock, std::chrono::milliseconds>;
|
||||
using time_point_us = std::chrono::time_point<
|
||||
std::chrono::system_clock, std::chrono::microseconds>;
|
||||
time_point_h timestamp_h;
|
||||
time_point_m timestamp_m;
|
||||
time_point_s timestamp_s;
|
||||
time_point_ms timestamp_ms;
|
||||
time_point_us timestamp_us;
|
||||
};
|
||||
|
||||
TEST_SUBMODULE(chrono, m) {
|
||||
using system_time = std::chrono::system_clock::time_point;
|
||||
|
@ -52,4 +71,14 @@ TEST_SUBMODULE(chrono, m) {
|
|||
m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp {
|
||||
return start + delta;
|
||||
});
|
||||
|
||||
// Test different resolutions
|
||||
py::class_<different_resolutions>(m, "different_resolutions")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("timestamp_h", &different_resolutions::timestamp_h)
|
||||
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
|
||||
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
|
||||
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
|
||||
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us)
|
||||
;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from pybind11_tests import chrono as m
|
||||
import datetime
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
||||
|
||||
def test_chrono_system_clock():
|
||||
|
||||
# Get the time from both c++ and datetime
|
||||
date0 = datetime.datetime.today()
|
||||
date1 = m.test_chrono1()
|
||||
date2 = datetime.datetime.today()
|
||||
|
||||
|
@ -13,16 +17,15 @@ def test_chrono_system_clock():
|
|||
assert isinstance(date1, datetime.datetime)
|
||||
|
||||
# The numbers should vary by a very small amount (time it took to execute)
|
||||
diff_python = abs(date2 - date0)
|
||||
diff = abs(date1 - date2)
|
||||
|
||||
# There should never be a days/seconds difference
|
||||
# There should never be a days difference
|
||||
assert diff.days == 0
|
||||
assert diff.seconds == 0
|
||||
|
||||
# We test that no more than about 0.5 seconds passes here
|
||||
# This makes sure that the dates created are very close to the same
|
||||
# but if the testing system is incredibly overloaded this should still pass
|
||||
assert diff.microseconds < 500000
|
||||
# Since datetime.datetime.today() calls time.time(), and on some platforms
|
||||
# that has 1 second accuracy, we compare this way
|
||||
assert diff.seconds <= diff_python.seconds
|
||||
|
||||
|
||||
def test_chrono_system_clock_roundtrip():
|
||||
|
@ -72,8 +75,30 @@ def test_chrono_system_clock_roundtrip_date():
|
|||
assert time2.microsecond == 0
|
||||
|
||||
|
||||
def test_chrono_system_clock_roundtrip_time():
|
||||
time1 = datetime.datetime.today().time()
|
||||
SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
|
||||
"env.WIN", reason="TZ environment variable only supported on POSIX"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("time1", [
|
||||
datetime.datetime.today().time(),
|
||||
datetime.time(0, 0, 0),
|
||||
datetime.time(0, 0, 0, 1),
|
||||
datetime.time(0, 28, 45, 109827),
|
||||
datetime.time(0, 59, 59, 999999),
|
||||
datetime.time(1, 0, 0),
|
||||
datetime.time(5, 59, 59, 0),
|
||||
datetime.time(5, 59, 59, 1),
|
||||
])
|
||||
@pytest.mark.parametrize("tz", [
|
||||
None,
|
||||
pytest.param("Europe/Brussels", marks=SKIP_TZ_ENV_ON_WIN),
|
||||
pytest.param("Asia/Pyongyang", marks=SKIP_TZ_ENV_ON_WIN),
|
||||
pytest.param("America/New_York", marks=SKIP_TZ_ENV_ON_WIN),
|
||||
])
|
||||
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
|
||||
if tz is not None:
|
||||
monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz))
|
||||
|
||||
# Roundtrip the time
|
||||
datetime2 = m.test_chrono2(time1)
|
||||
|
@ -175,3 +200,13 @@ def test_nano_timepoint():
|
|||
time = datetime.datetime.now()
|
||||
time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60))
|
||||
assert(time1 == time + datetime.timedelta(seconds=60))
|
||||
|
||||
|
||||
def test_chrono_different_resolutions():
|
||||
resolutions = m.different_resolutions()
|
||||
time = datetime.datetime.now()
|
||||
resolutions.timestamp_h = time
|
||||
resolutions.timestamp_m = time
|
||||
resolutions.timestamp_s = time
|
||||
resolutions.timestamp_ms = time
|
||||
resolutions.timestamp_us = time
|
||||
|
|
|
@ -103,7 +103,7 @@ TEST_SUBMODULE(class_, m) {
|
|||
BaseClass() = default;
|
||||
BaseClass(const BaseClass &) = default;
|
||||
BaseClass(BaseClass &&) = default;
|
||||
virtual ~BaseClass() {}
|
||||
virtual ~BaseClass() = default;
|
||||
};
|
||||
struct DerivedClass1 : BaseClass { };
|
||||
struct DerivedClass2 : BaseClass { };
|
||||
|
@ -134,6 +134,32 @@ TEST_SUBMODULE(class_, m) {
|
|||
);
|
||||
});
|
||||
|
||||
struct Invalid {};
|
||||
|
||||
// test_type
|
||||
m.def("check_type", [](int category) {
|
||||
// Currently not supported (via a fail at compile time)
|
||||
// See https://github.com/pybind/pybind11/issues/2486
|
||||
// if (category == 2)
|
||||
// return py::type::of<int>();
|
||||
if (category == 1)
|
||||
return py::type::of<DerivedClass1>();
|
||||
else
|
||||
return py::type::of<Invalid>();
|
||||
});
|
||||
|
||||
m.def("get_type_of", [](py::object ob) {
|
||||
return py::type::of(ob);
|
||||
});
|
||||
|
||||
m.def("as_type", [](py::object ob) {
|
||||
auto tp = py::type(ob);
|
||||
if (py::isinstance<py::type>(ob))
|
||||
return tp;
|
||||
else
|
||||
throw std::runtime_error("Invalid type");
|
||||
});
|
||||
|
||||
// test_mismatched_holder
|
||||
struct MismatchBase1 { };
|
||||
struct MismatchDerived1 : MismatchBase1 { };
|
||||
|
@ -227,6 +253,8 @@ TEST_SUBMODULE(class_, m) {
|
|||
static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; }
|
||||
static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); }
|
||||
virtual ~AliasedHasOpNewDelSize() = default;
|
||||
AliasedHasOpNewDelSize() = default;
|
||||
AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize&) = delete;
|
||||
};
|
||||
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
|
||||
PyAliasedHasOpNewDelSize() = default;
|
||||
|
@ -277,6 +305,8 @@ TEST_SUBMODULE(class_, m) {
|
|||
class ProtectedB {
|
||||
public:
|
||||
virtual ~ProtectedB() = default;
|
||||
ProtectedB() = default;
|
||||
ProtectedB(const ProtectedB &) = delete;
|
||||
|
||||
protected:
|
||||
virtual int foo() const { return value; }
|
||||
|
@ -287,7 +317,7 @@ TEST_SUBMODULE(class_, m) {
|
|||
|
||||
class TrampolineB : public ProtectedB {
|
||||
public:
|
||||
int foo() const override { PYBIND11_OVERLOAD(int, ProtectedB, foo, ); }
|
||||
int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }
|
||||
};
|
||||
|
||||
class PublicistB : public ProtectedB {
|
||||
|
@ -323,7 +353,7 @@ TEST_SUBMODULE(class_, m) {
|
|||
// test_reentrant_implicit_conversion_failure
|
||||
// #1035: issue with runaway reentrant implicit conversion
|
||||
struct BogusImplicitConversion {
|
||||
BogusImplicitConversion(const BogusImplicitConversion &) { }
|
||||
BogusImplicitConversion(const BogusImplicitConversion &) = default;
|
||||
};
|
||||
|
||||
py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
|
||||
|
@ -375,19 +405,34 @@ TEST_SUBMODULE(class_, m) {
|
|||
// test_non_final_final
|
||||
struct IsNonFinalFinal {};
|
||||
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());
|
||||
|
||||
struct PyPrintDestructor {
|
||||
PyPrintDestructor() = default;
|
||||
~PyPrintDestructor() {
|
||||
py::print("Print from destructor");
|
||||
}
|
||||
void throw_something() { throw std::runtime_error("error"); }
|
||||
};
|
||||
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
|
||||
.def(py::init<>())
|
||||
.def("throw_something", &PyPrintDestructor::throw_something);
|
||||
}
|
||||
|
||||
template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; };
|
||||
template <int N> class BreaksBase { public:
|
||||
virtual ~BreaksBase() = default;
|
||||
BreaksBase() = default;
|
||||
BreaksBase(const BreaksBase&) = delete;
|
||||
};
|
||||
template <int N> class BreaksTramp : public BreaksBase<N> {};
|
||||
// These should all compile just fine:
|
||||
typedef py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>> DoesntBreak1;
|
||||
typedef py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>> DoesntBreak2;
|
||||
typedef py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>> DoesntBreak3;
|
||||
typedef py::class_<BreaksBase<4>, BreaksTramp<4>> DoesntBreak4;
|
||||
typedef py::class_<BreaksBase<5>> DoesntBreak5;
|
||||
typedef py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>> DoesntBreak6;
|
||||
typedef py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>> DoesntBreak7;
|
||||
typedef py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>> DoesntBreak8;
|
||||
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
|
||||
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
|
||||
using DoesntBreak3 = py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>>;
|
||||
using DoesntBreak4 = py::class_<BreaksBase<4>, BreaksTramp<4>>;
|
||||
using DoesntBreak5 = py::class_<BreaksBase<5>>;
|
||||
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
|
||||
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
|
||||
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
|
||||
#define CHECK_BASE(N) static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<N>>::value, \
|
||||
"DoesntBreak" #N " has wrong type!")
|
||||
CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
|
||||
from pybind11_tests import class_ as m
|
||||
from pybind11_tests import UserType, ConstructorStats
|
||||
|
||||
|
@ -24,6 +26,40 @@ def test_instance(msg):
|
|||
assert cstats.alive() == 0
|
||||
|
||||
|
||||
def test_type():
|
||||
assert m.check_type(1) == m.DerivedClass1
|
||||
with pytest.raises(RuntimeError) as execinfo:
|
||||
m.check_type(0)
|
||||
|
||||
assert 'pybind11::detail::get_type_info: unable to find type info' in str(execinfo.value)
|
||||
assert 'Invalid' in str(execinfo.value)
|
||||
|
||||
# Currently not supported
|
||||
# See https://github.com/pybind/pybind11/issues/2486
|
||||
# assert m.check_type(2) == int
|
||||
|
||||
|
||||
def test_type_of_py():
|
||||
assert m.get_type_of(1) == int
|
||||
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
||||
assert m.get_type_of(int) == type
|
||||
|
||||
|
||||
def test_type_of_py_nodelete():
|
||||
# If the above test deleted the class, this will segfault
|
||||
assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
|
||||
|
||||
|
||||
def test_as_type_py():
|
||||
assert m.as_type(int) == int
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
assert m.as_type(1) == int
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
|
||||
|
||||
|
||||
def test_docstrings(doc):
|
||||
assert doc(UserType) == "A `py::class_` type for testing"
|
||||
assert UserType.__name__ == "UserType"
|
||||
|
@ -261,7 +297,7 @@ def test_brace_initialization():
|
|||
assert b.vec == [123, 456]
|
||||
|
||||
|
||||
@pytest.unsupported_on_pypy
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_class_refcount():
|
||||
"""Instances must correctly increase/decrease the reference count of their types (#1029)"""
|
||||
from sys import getrefcount
|
||||
|
@ -307,8 +343,8 @@ def test_aligned():
|
|||
assert p % 1024 == 0
|
||||
|
||||
|
||||
# https://bitbucket.org/pypy/pypy/issues/2742
|
||||
@pytest.unsupported_on_pypy
|
||||
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_final():
|
||||
with pytest.raises(TypeError) as exc_info:
|
||||
class PyFinalChild(m.IsFinal):
|
||||
|
@ -316,10 +352,16 @@ def test_final():
|
|||
assert str(exc_info.value).endswith("is not an acceptable base type")
|
||||
|
||||
|
||||
# https://bitbucket.org/pypy/pypy/issues/2742
|
||||
@pytest.unsupported_on_pypy
|
||||
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
|
||||
@pytest.mark.xfail("env.PYPY")
|
||||
def test_non_final_final():
|
||||
with pytest.raises(TypeError) as exc_info:
|
||||
class PyNonFinalFinalChild(m.IsNonFinalFinal):
|
||||
pass
|
||||
assert str(exc_info.value).endswith("is not an acceptable base type")
|
||||
|
||||
|
||||
# https://github.com/pybind/pybind11/issues/1878
|
||||
def test_exception_rvalue_abort():
|
||||
with pytest.raises(RuntimeError):
|
||||
m.PyPrintDestructor().throw_something()
|
||||
|
|
|
@ -1,56 +1,77 @@
|
|||
# Built-in in CMake 3.5+
|
||||
include(CMakeParseArguments)
|
||||
|
||||
add_custom_target(test_cmake_build)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.1)
|
||||
# 3.0 needed for interface library for subdirectory_target/installed_target
|
||||
# 3.1 needed for cmake -E env for testing
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(CMakeParseArguments)
|
||||
function(pybind11_add_build_test name)
|
||||
cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN})
|
||||
|
||||
set(build_options "-DCMAKE_PREFIX_PATH=${PROJECT_BINARY_DIR}/mock_install"
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}"
|
||||
"-DPYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}")
|
||||
if(NOT ARG_INSTALL)
|
||||
list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${PROJECT_SOURCE_DIR}")
|
||||
set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
|
||||
|
||||
if(PYBIND11_FINDPYTHON)
|
||||
list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}")
|
||||
|
||||
if(DEFINED Python_ROOT_DIR)
|
||||
list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}")
|
||||
endif()
|
||||
|
||||
list(APPEND build_options "-DPython_EXECUTABLE=${Python_EXECUTABLE}")
|
||||
else()
|
||||
list(APPEND build_options "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}")
|
||||
endif()
|
||||
|
||||
add_custom_target(test_${name} ${CMAKE_CTEST_COMMAND}
|
||||
--quiet --output-log ${name}.log
|
||||
--build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/${name}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${name}"
|
||||
--build-config Release
|
||||
--build-noclean
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
$<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-target check
|
||||
--build-options ${build_options}
|
||||
)
|
||||
if(ARG_INSTALL)
|
||||
add_dependencies(test_${name} mock_install)
|
||||
if(DEFINED CMAKE_CXX_STANDARD)
|
||||
list(APPEND build_options "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
|
||||
endif()
|
||||
add_dependencies(test_cmake_build test_${name})
|
||||
|
||||
if(NOT ARG_INSTALL)
|
||||
list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${pybind11_SOURCE_DIR}")
|
||||
else()
|
||||
list(APPEND build_options "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install")
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
test_build_${name}
|
||||
${CMAKE_CTEST_COMMAND}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${name}"
|
||||
--build-config
|
||||
Release
|
||||
--build-noclean
|
||||
--build-generator
|
||||
${CMAKE_GENERATOR}
|
||||
$<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform>
|
||||
${CMAKE_GENERATOR_PLATFORM}
|
||||
--build-makeprogram
|
||||
${CMAKE_MAKE_PROGRAM}
|
||||
--build-target
|
||||
check_${name}
|
||||
--build-options
|
||||
${build_options})
|
||||
if(ARG_INSTALL)
|
||||
add_dependencies(test_build_${name} mock_install)
|
||||
endif()
|
||||
add_dependencies(test_cmake_build test_build_${name})
|
||||
endfunction()
|
||||
|
||||
pybind11_add_build_test(subdirectory_function)
|
||||
pybind11_add_build_test(subdirectory_target)
|
||||
if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
|
||||
if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy")
|
||||
message(STATUS "Skipping embed test on PyPy")
|
||||
else()
|
||||
pybind11_add_build_test(subdirectory_embed)
|
||||
endif()
|
||||
|
||||
if(PYBIND11_INSTALL)
|
||||
add_custom_target(mock_install ${CMAKE_COMMAND}
|
||||
"-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/mock_install"
|
||||
-P "${PROJECT_BINARY_DIR}/cmake_install.cmake"
|
||||
)
|
||||
add_custom_target(
|
||||
mock_install ${CMAKE_COMMAND} "-DCMAKE_INSTALL_PREFIX=${pybind11_BINARY_DIR}/mock_install" -P
|
||||
"${pybind11_BINARY_DIR}/cmake_install.cmake")
|
||||
|
||||
pybind11_add_build_test(installed_function INSTALL)
|
||||
pybind11_add_build_test(installed_target INSTALL)
|
||||
if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
|
||||
if(NOT ("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy"
|
||||
))
|
||||
pybind11_add_build_test(installed_embed INSTALL)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
project(test_installed_embed CXX)
|
||||
|
||||
set(CMAKE_MODULE_PATH "")
|
||||
find_package(pybind11 CONFIG REQUIRED)
|
||||
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
|
||||
|
||||
add_executable(test_cmake_build ../embed.cpp)
|
||||
target_link_libraries(test_cmake_build PRIVATE pybind11::embed)
|
||||
add_executable(test_installed_embed ../embed.cpp)
|
||||
target_link_libraries(test_installed_embed PRIVATE pybind11::embed)
|
||||
set_target_properties(test_installed_embed PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||
|
||||
# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed).
|
||||
# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
|
||||
set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
|
||||
set_target_properties(test_installed_embed PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
|
||||
|
||||
add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py)
|
||||
add_custom_target(check_installed_embed $<TARGET_FILE:test_installed_embed>
|
||||
${PROJECT_SOURCE_DIR}/../test.py)
|
||||
|
|
|
@ -1,12 +1,38 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
project(test_installed_module CXX)
|
||||
|
||||
set(CMAKE_MODULE_PATH "")
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
project(test_installed_function CXX)
|
||||
|
||||
find_package(pybind11 CONFIG REQUIRED)
|
||||
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
|
||||
message(
|
||||
STATUS "Found pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}: ${pybind11_INCLUDE_DIRS}")
|
||||
|
||||
pybind11_add_module(test_cmake_build SHARED NO_EXTRAS ../main.cpp)
|
||||
pybind11_add_module(test_installed_function SHARED NO_EXTRAS ../main.cpp)
|
||||
set_target_properties(test_installed_function PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||
|
||||
add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
|
||||
${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
|
||||
if(DEFINED Python_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
||||
elseif(DEFINED PYTHON_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||
else()
|
||||
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
check_installed_function
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
env
|
||||
PYTHONPATH=$<TARGET_FILE_DIR:test_installed_function>
|
||||
${_Python_EXECUTABLE}
|
||||
${PROJECT_SOURCE_DIR}/../test.py
|
||||
${PROJECT_NAME})
|
||||
|
|
|
@ -1,22 +1,45 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project(test_installed_target CXX)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
set(CMAKE_MODULE_PATH "")
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
project(test_installed_target CXX)
|
||||
|
||||
find_package(pybind11 CONFIG REQUIRED)
|
||||
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
|
||||
|
||||
add_library(test_cmake_build MODULE ../main.cpp)
|
||||
add_library(test_installed_target MODULE ../main.cpp)
|
||||
|
||||
target_link_libraries(test_cmake_build PRIVATE pybind11::module)
|
||||
target_link_libraries(test_installed_target PRIVATE pybind11::module)
|
||||
set_target_properties(test_installed_target PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||
|
||||
# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
|
||||
set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
|
||||
SUFFIX "${PYTHON_MODULE_EXTENSION}")
|
||||
# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
|
||||
pybind11_extension(test_installed_target)
|
||||
|
||||
# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module).
|
||||
# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
|
||||
set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
|
||||
set_target_properties(test_installed_target PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
|
||||
|
||||
add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
|
||||
${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
|
||||
if(DEFINED Python_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
||||
elseif(DEFINED PYTHON_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||
else()
|
||||
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
check_installed_target
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
env
|
||||
PYTHONPATH=$<TARGET_FILE_DIR:test_installed_target>
|
||||
${_Python_EXECUTABLE}
|
||||
${PROJECT_SOURCE_DIR}/../test.py
|
||||
${PROJECT_NAME})
|
||||
|
|
|
@ -1,25 +1,39 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
project(test_subdirectory_embed CXX)
|
||||
|
||||
set(PYBIND11_INSTALL ON CACHE BOOL "")
|
||||
set(PYBIND11_INSTALL
|
||||
ON
|
||||
CACHE BOOL "")
|
||||
set(PYBIND11_EXPORT_NAME test_export)
|
||||
|
||||
add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
|
||||
|
||||
# Test basic target functionality
|
||||
add_executable(test_cmake_build ../embed.cpp)
|
||||
target_link_libraries(test_cmake_build PRIVATE pybind11::embed)
|
||||
add_executable(test_subdirectory_embed ../embed.cpp)
|
||||
target_link_libraries(test_subdirectory_embed PRIVATE pybind11::embed)
|
||||
set_target_properties(test_subdirectory_embed PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||
|
||||
add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py)
|
||||
add_custom_target(check_subdirectory_embed $<TARGET_FILE:test_subdirectory_embed>
|
||||
${PROJECT_SOURCE_DIR}/../test.py)
|
||||
|
||||
# Test custom export group -- PYBIND11_EXPORT_NAME
|
||||
add_library(test_embed_lib ../embed.cpp)
|
||||
target_link_libraries(test_embed_lib PRIVATE pybind11::embed)
|
||||
|
||||
install(TARGETS test_embed_lib
|
||||
EXPORT test_export
|
||||
ARCHIVE DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION lib)
|
||||
install(EXPORT test_export
|
||||
DESTINATION lib/cmake/test_export/test_export-Targets.cmake)
|
||||
install(
|
||||
TARGETS test_embed_lib
|
||||
EXPORT test_export
|
||||
ARCHIVE DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION lib)
|
||||
install(EXPORT test_export DESTINATION lib/cmake/test_export/test_export-Targets.cmake)
|
||||
|
|
|
@ -1,8 +1,34 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(test_subdirectory_module CXX)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
|
||||
pybind11_add_module(test_cmake_build THIN_LTO ../main.cpp)
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
|
||||
${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
|
||||
project(test_subdirectory_function CXX)
|
||||
|
||||
add_subdirectory("${PYBIND11_PROJECT_DIR}" pybind11)
|
||||
pybind11_add_module(test_subdirectory_function ../main.cpp)
|
||||
set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||
|
||||
if(DEFINED Python_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
||||
elseif(DEFINED PYTHON_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||
else()
|
||||
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
check_subdirectory_function
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
env
|
||||
PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_function>
|
||||
${_Python_EXECUTABLE}
|
||||
${PROJECT_SOURCE_DIR}/../test.py
|
||||
${PROJECT_NAME})
|
||||
|
|
|
@ -1,15 +1,40 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
# 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
|
||||
# the behavior using the following workaround:
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.18)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.18)
|
||||
endif()
|
||||
|
||||
project(test_subdirectory_target CXX)
|
||||
|
||||
add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
|
||||
|
||||
add_library(test_cmake_build MODULE ../main.cpp)
|
||||
add_library(test_subdirectory_target MODULE ../main.cpp)
|
||||
set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake_build)
|
||||
|
||||
target_link_libraries(test_cmake_build PRIVATE pybind11::module)
|
||||
target_link_libraries(test_subdirectory_target PRIVATE pybind11::module)
|
||||
|
||||
# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
|
||||
set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
|
||||
SUFFIX "${PYTHON_MODULE_EXTENSION}")
|
||||
# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
|
||||
pybind11_extension(test_subdirectory_target)
|
||||
|
||||
add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
|
||||
${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
|
||||
if(DEFINED Python_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${Python_EXECUTABLE}")
|
||||
elseif(DEFINED PYTHON_EXECUTABLE)
|
||||
set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
|
||||
else()
|
||||
message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)")
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
check_subdirectory_target
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
env
|
||||
PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_target>
|
||||
${_Python_EXECUTABLE}
|
||||
${PROJECT_SOURCE_DIR}/../test.py
|
||||
${PROJECT_NAME})
|
||||
|
|
|
@ -74,7 +74,7 @@ struct C {
|
|||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
};
|
||||
}
|
||||
} // namespace test_exc_sp
|
||||
|
||||
|
||||
TEST_SUBMODULE(constants_and_functions, m) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from pybind11_tests import constants_and_functions as m
|
||||
import pytest
|
||||
|
||||
m = pytest.importorskip("pybind11_tests.constants_and_functions")
|
||||
|
||||
|
||||
def test_constants():
|
||||
|
|
|
@ -19,14 +19,14 @@ struct empty {
|
|||
};
|
||||
|
||||
struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
|
||||
lacking_copy_ctor() {}
|
||||
lacking_copy_ctor() = default;
|
||||
lacking_copy_ctor(const lacking_copy_ctor& other) = delete;
|
||||
};
|
||||
|
||||
template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
|
||||
|
||||
struct lacking_move_ctor : public empty<lacking_move_ctor> {
|
||||
lacking_move_ctor() {}
|
||||
lacking_move_ctor() = default;
|
||||
lacking_move_ctor(const lacking_move_ctor& other) = delete;
|
||||
lacking_move_ctor(lacking_move_ctor&& other) = delete;
|
||||
};
|
||||
|
@ -175,14 +175,20 @@ TEST_SUBMODULE(copy_move_policies, m) {
|
|||
m.attr("has_optional") = false;
|
||||
#endif
|
||||
|
||||
// #70 compilation issue if operator new is not public
|
||||
// #70 compilation issue if operator new is not public - simple body added
|
||||
// but not needed on most compilers; MSVC and nvcc don't like a local
|
||||
// struct not having a method defined when declared, since it can not be
|
||||
// added later.
|
||||
struct PrivateOpNew {
|
||||
int value = 1;
|
||||
private:
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable: 4822) // warning C4822: local class member function does not have a body
|
||||
#endif
|
||||
void *operator new(size_t bytes);
|
||||
void *operator new(size_t bytes) {
|
||||
void *ptr = std::malloc(bytes);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
else
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
};
|
||||
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
|
||||
m.def("private_op_new_value", []() { return PrivateOpNew(); });
|
||||
|
|
|
@ -58,7 +58,8 @@ public:
|
|||
return py::none().release();
|
||||
}
|
||||
};
|
||||
}}
|
||||
} // namespace detail
|
||||
} // namespace pybind11
|
||||
|
||||
// test_custom_caster_destruction
|
||||
class DestructionTester {
|
||||
|
@ -79,7 +80,8 @@ template <> struct type_caster<DestructionTester> {
|
|||
return py::bool_(true).release();
|
||||
}
|
||||
};
|
||||
}}
|
||||
} // namespace detail
|
||||
} // namespace pybind11
|
||||
|
||||
TEST_SUBMODULE(custom_type_casters, m) {
|
||||
// test_custom_type_casters
|
||||
|
|
|
@ -87,8 +87,6 @@ TEST_SUBMODULE(eigen, m) {
|
|||
using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;
|
||||
using SparseMatrixC = Eigen::SparseMatrix<float>;
|
||||
|
||||
m.attr("have_eigen") = true;
|
||||
|
||||
// various tests
|
||||
m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });
|
||||
m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; });
|
||||
|
|
|
@ -2,17 +2,15 @@
|
|||
import pytest
|
||||
from pybind11_tests import ConstructorStats
|
||||
|
||||
pytestmark = pytest.requires_eigen_and_numpy
|
||||
np = pytest.importorskip("numpy")
|
||||
m = pytest.importorskip("pybind11_tests.eigen")
|
||||
|
||||
with pytest.suppress(ImportError):
|
||||
from pybind11_tests import eigen as m
|
||||
import numpy as np
|
||||
|
||||
ref = np.array([[ 0., 3, 0, 0, 0, 11],
|
||||
[22, 0, 0, 0, 17, 11],
|
||||
[ 7, 5, 0, 1, 0, 11],
|
||||
[ 0, 0, 0, 0, 0, 11],
|
||||
[ 0, 0, 14, 0, 8, 11]])
|
||||
ref = np.array([[ 0., 3, 0, 0, 0, 11],
|
||||
[22, 0, 0, 0, 17, 11],
|
||||
[ 7, 5, 0, 1, 0, 11],
|
||||
[ 0, 0, 0, 0, 0, 11],
|
||||
[ 0, 0, 14, 0, 8, 11]])
|
||||
|
||||
|
||||
def assert_equal_ref(mat):
|
||||
|
@ -646,8 +644,8 @@ def test_named_arguments():
|
|||
assert str(excinfo.value) == 'Nonconformable matrices!'
|
||||
|
||||
|
||||
@pytest.requires_eigen_and_scipy
|
||||
def test_sparse():
|
||||
pytest.importorskip("scipy")
|
||||
assert_sparse_equal_ref(m.sparse_r())
|
||||
assert_sparse_equal_ref(m.sparse_c())
|
||||
assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
|
||||
|
@ -656,8 +654,8 @@ def test_sparse():
|
|||
assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
|
||||
|
||||
|
||||
@pytest.requires_eigen_and_scipy
|
||||
def test_sparse_signature(doc):
|
||||
pytest.importorskip("scipy")
|
||||
assert doc(m.sparse_copy_r) == """
|
||||
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
|
||||
""" # noqa: E501 line too long
|
||||
|
|
|
@ -1,41 +1,43 @@
|
|||
if(${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
|
||||
add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported.
|
||||
if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy")
|
||||
add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported.
|
||||
set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_package(Catch 1.9.3)
|
||||
find_package(Catch 2.13.0)
|
||||
|
||||
if(CATCH_FOUND)
|
||||
message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")
|
||||
else()
|
||||
message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers"
|
||||
" manually or use `cmake -DDOWNLOAD_CATCH=1` to fetch them automatically.")
|
||||
" manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(test_embed
|
||||
catch.cpp
|
||||
test_interpreter.cpp
|
||||
)
|
||||
target_include_directories(test_embed PRIVATE ${CATCH_INCLUDE_DIR})
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_executable(test_embed catch.cpp test_interpreter.cpp)
|
||||
pybind11_enable_warnings(test_embed)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
target_link_libraries(test_embed PRIVATE pybind11::embed)
|
||||
else()
|
||||
target_include_directories(test_embed PRIVATE ${PYBIND11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS})
|
||||
target_compile_options(test_embed PRIVATE ${PYBIND11_CPP_STANDARD})
|
||||
target_link_libraries(test_embed PRIVATE ${PYTHON_LIBRARIES})
|
||||
target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads)
|
||||
|
||||
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
file(COPY test_interpreter.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(test_embed PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
add_custom_target(cpptest COMMAND $<TARGET_FILE:test_embed>
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_custom_target(
|
||||
cpptest
|
||||
COMMAND "$<TARGET_FILE:test_embed>"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
pybind11_add_module(external_module THIN_LTO external_module.cpp)
|
||||
set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER ${config} config)
|
||||
set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endforeach()
|
||||
add_dependencies(cpptest external_module)
|
||||
|
||||
add_dependencies(check cpptest)
|
||||
|
|
|
@ -30,7 +30,7 @@ private:
|
|||
class PyWidget final : public Widget {
|
||||
using Widget::Widget;
|
||||
|
||||
int the_answer() const override { PYBIND11_OVERLOAD_PURE(int, Widget, the_answer); }
|
||||
int the_answer() const override { PYBIND11_OVERRIDE_PURE(int, Widget, the_answer); }
|
||||
};
|
||||
|
||||
PYBIND11_EMBEDDED_MODULE(widget_module, m) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue