Compare commits

...

26 Commits

Author SHA1 Message Date
Aaron Gokaslan 1cc33d1edc
Merge 7a3a51435e into 1f8b4a7f1a 2024-09-20 23:44:24 -07:00
Hintay 1f8b4a7f1a
fix(cmake): `NO_EXTRAS` in `pybind11_add_module` function partially working (#5378) 2024-09-19 11:24:35 -04:00
dependabot[bot] ad9fd39e14
chore(deps): bump pypa/cibuildwheel in the actions group (#5376)
Bumps the actions group with 1 update: [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel).


Updates `pypa/cibuildwheel` from 2.20 to 2.21
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v2.20...v2.21)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-17 10:19:17 -07:00
vfdev 1d9483ff73
Added exception translator specific mutex used with try_translate_exceptions (#5362)
* Added exception translator specific mutex used with try_translate_exceptions
Fixes #5346

* - Replaced with_internals_for_exception_translator by with_exception_translators
- Incremented PYBIND11_INTERNALS_VERSION
- Added a test

* style: pre-commit fixes

* Fixed formatting and added explicit to ctors

* Addressed PR review comments

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-09-17 09:47:20 -07:00
Bobby R. Bruce a7910be630
Add warn disable for GGC 12 bound checking error (#5355)
Issue: #5224

The `internals.registered_types_py...` line in pybind11.h triggers a
false-positive bounds checking warning in GCC 12.

This is discussed in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115824.

The workaround implemented is taken from suggestions then refactored to
use the `PYBIND11_WARNING_PUSH` and `PYBIND11_WARNING_POP` MACROS.
2024-09-14 23:51:50 -07:00
Henry Schreiner 0cf3a0f7b5
ci: PyPI attestations (#5374) 2024-09-13 20:21:43 -04:00
Henry Schreiner 5b7c0b04b9
docs: update changelog for 2.13.6 (#5372)
* docs: update changelog for 2.13.6

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* docs: mention supported versions

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-09-13 16:59:50 -04:00
Ralf W. Grosse-Kunstleve ef5a9560bb
Enable type-safe interoperability between different independent Python/C++ bindings systems. (#5296)
* `self.__cpp_transporter__()` proof of concept: Enable passing C++ pointers across extensions even if the `PYBIND11_INTERNALS_VERSION`s do not match.

* Include cleanup (mainly to resolve PyPy build failures).

* Fix clang-tidy errors.

* Resolve `error: extra

* factor out platform_abi_id.h from internals.h (no functional changes)

* factor out internals_version.h from internals.h (no functional changes)

* Update CMakeLists.txt, tests/extra_python_package/test_files.py

* Revert "factor out internals_version.h from internals.h (no functional changes)"

This reverts commit 3ccea8cd43.

* Remove internals_version.h from CMakeLists.txt, tests/extra_python_package/test_files.py

* `.__cpp_transporter__()` implementation: compare `pybind11_platform_abi_id`, `cpp_typeid_name`

* Add PremiumTraveler

* Rename test_cpp_transporter_traveler_type.h -> test_cpp_transporter_traveler_types.h

* Expand tests: `PremiumTraveler`, `get_points()`

* Shuffle order of tests (no real changes).

* Move `__cpp_transporter__` lambda to `py::cpp_transporter()` regular function.

* Use `type_caster_generic::load(self)` instead of `cast<T *>(self)`

* Pass `const std::type_info *` via `py::capsule` (instead of `cpp_typeid_name`).

* Make platform_abi_id.h completely stand-alone.

* rename exo_planet.cpp -> exo_planet_pybind11.cpp

* Add exo_planet_c_api.cpp (incomplete).

* Fix silly oversight (wrong filename in `#include`).

* Resolve clang-tidy errors:

```
/__w/pybind11/pybind11/tests/exo_planet_c_api.cpp:10:18: error: 'wrapGetLuggage' is a static definition in anonymous namespace; static is redundant here [readability-static-definition-in-anonymous-namespace,-warnings-as-errors]
   10 | static PyObject *wrapGetLuggage(PyObject *, PyObject *) { return PyUnicode_FromString("TODO"); }
      | ~~~~~~           ^
/__w/pybind11/pybind11/tests/exo_planet_c_api.cpp:14:20: error: 'ThisMethodDef' is a static definition in anonymous namespace; static is redundant here [readability-static-definition-in-anonymous-namespace,-warnings-as-errors]
   14 | static PyMethodDef ThisMethodDef[]
      | ~~~~~~             ^
/__w/pybind11/pybind11/tests/exo_planet_c_api.cpp:17:27: error: 'ThisModuleDef' is a static definition in anonymous namespace; static is redundant here [readability-static-definition-in-anonymous-namespace,-warnings-as-errors]
   17 | static struct PyModuleDef ThisModuleDef = {
      | ~~~~~~                    ^
```

* Implement exo_planet_c_api GetLuggage(), GetPoints()

* Move new code from test_cpp_transporter_traveler_bindings.h to pybind11/detail/type_caster_base.h, under the name `class_dunder_cpp_transporter()`

* Fix oversight.

* Unconditionally add `__cpp_transporter__` method to all `py::class_` objects, but do not include that magic method in docstring signatures.

* Back out pybind11/detail/platform_abi_id.h for now. Maximizing reusability can be handled separately, later.

* Small cleanup.

* Restore and add to `test_call_cpp_transporter_*()`

* Ensure https://github.com/pybind/pybind11/issues/3788 does not bite again.

* `class_dunder_cpp_transporter()`: replace `obj.cast<std::string>()` with `std::string(obj)`

* Add (simple) copyright notices in all newly added files.

* Globally replace cpp_transporter with cpp_conduit

* style: pre-commit fixes

* IWYU fixes

* Rename `class_dunder_cpp_conduit()` -> `cpp_conduit_method()`

* Change `pybind11_platform_abi_id`, `pointer_kind` argument types from `str` to `bytes`.

This avoids the unicode decode/encode roundtrips:

* More robust (no decode/encode errors).

* Minor runtime optimization.

* Systematically rename `cap_cpp_type_info` -> `cpp_type_info_capsule` (no functional changes).

* Systematically replace `cpp_type_info_capsule` `name`: `"const std::type_info *"` -> `typeid(std::type_info).name()` (this IS a functional change).

This provides an extra layer of protection against C++ ABI mismatches:

* The first and most important layer is that the `PYBIND11_PLATFORM_ABI_ID`s must match between extensions.

* The second layer is that the `typeid(std::type_info).name()`s must match between extensions.

* Fix sort order accident in tests/CMakeLists.txt

* Apply suggestions from code review

Co-authored-by: Aaron Gokaslan <aaronGokaslan@gmail.com>

* style: pre-commit fixes

* refactor: rename to _pybind_conduit_v1_

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Add test_home_planet_wrap_very_lonely_traveler(), test_exo_planet_pybind11_wrap_very_lonely_traveler()

* Resolve clang-tidy errors:

```
/__w/pybind11/pybind11/tests/test_cpp_conduit_traveler_bindings.h:39:32: error: parameter 'm' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param,-warnings-as-errors]
   10 |     py::class_<LonelyTraveler>(m, "LonelyTraveler");
      |                                ^
      |                                std::move( )
/__w/pybind11/pybind11/tests/test_cpp_conduit_traveler_bindings.h:43:52: error: parameter 'm' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param,-warnings-as-errors]
   43 |     py::class_<VeryLonelyTraveler, LonelyTraveler>(m, "VeryLonelyTraveler");
      |                                                    ^
      |                                                    std::move( )
```

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rwgk@google.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
Co-authored-by: Aaron Gokaslan <aaronGokaslan@gmail.com>
2024-09-13 00:18:29 -04:00
dependabot[bot] 5efc7439d4
chore(deps): bump the actions group with 2 updates (#5361)
Bumps the actions group with 2 updates: [deadsnakes/action](https://github.com/deadsnakes/action) and [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


Updates `deadsnakes/action` from 3.1.0 to 3.2.0
- [Release notes](https://github.com/deadsnakes/action/releases)
- [Commits](https://github.com/deadsnakes/action/compare/v3.1.0...v3.2.0)

Updates `actions/attest-build-provenance` from 1.4.2 to 1.4.3
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](6149ea5740...1c608d11d6)

---
updated-dependencies:
- dependency-name: deadsnakes/action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 14:31:38 -04:00
pre-commit-ci[bot] 8a801bdc32
chore(deps): update pre-commit hooks (#5350)
* chore(deps): update pre-commit hooks

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.5.6 → v0.6.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.6...v0.6.3)
- [github.com/pre-commit/mirrors-mypy: v1.11.1 → v1.11.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.1...v1.11.2)
- [github.com/sirosen/texthooks: 0.6.6 → 0.6.7](https://github.com/sirosen/texthooks/compare/0.6.6...0.6.7)
- [github.com/PyCQA/pylint: v3.2.6 → v3.2.7](https://github.com/PyCQA/pylint/compare/v3.2.6...v3.2.7)
- [github.com/python-jsonschema/check-jsonschema: 0.29.1 → 0.29.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.29.1...0.29.2)

* style: pre-commit fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-09-03 10:51:21 -04:00
Vasily Litvinov aeda49ed0b
Properly translate C++ exception to Python exception when creating Python buffer from wrapped object (#5324)
* Add test for throwing def_buffer case

* Translate C++ -> Python exceptions in buffer creation

This required a little refactoring to extract exception translation to a separate method

* Fix code formatting

* Fix "unused parameter" warning

* Refactor per review

* style: pre-commit fixes

* Address review comments

* Address review comments

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-09-02 09:01:59 -07:00
Jan Iwaszkiewicz 66c3774a64
Warnings wrappers to use from C++ (#5291)
* Add warning wrappers that allow to call warnings from pybind level

* Add missing include for warnings.h

* Change messages on failed checks, extend testing

* clang-tidy fix

* Refactor tests for warnings

* Move handle before check

* Remove unnecessary parametrized
2024-08-28 20:55:50 -07:00
Ralf W. Grosse-Kunstleve 65f4266cef
Add `while True` & `top` method to FAQ. (#5340) 2024-08-27 21:04:48 -07:00
ObeliskGate 3fb16ad175
fix: using `__cpp_nontype_template_args` instead of `__cpp_nontype_template_parameter_class` (#5330)
* fix: use `__cpp_nontype_template_args` instead of gnu extensions

* fix: add feature test value

* fix: change `PYBIND11_TYPING_H_HAS_STRING_LITERAL` skip reason
2024-08-25 23:36:03 -04:00
dependabot[bot] e8f595bb85
chore(deps): bump actions/attest-build-provenance in the actions group (#5335)
Bumps the actions group with 1 update: [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


Updates `actions/attest-build-provenance` from 1.4.1 to 1.4.2
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](310b0a4a3b...6149ea5740)

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-25 23:35:03 -04:00
Henry Schreiner c2291e597f
docs: prepare for 2.13.5 (#5327)
* docs: prepare for 2.13.5

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Update docs/changelog.rst

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-08-22 14:12:17 -04:00
DWesl efa2b20d69
docs: clarify requirements for including pybind11 (#5326)
* DOC: Clarify requirements for including pybind11

Inherited from requirements for including Python.h

Closes #4999

* style: pre-commit fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-08-22 00:29:21 -04:00
Henry Schreiner 9966ad409d
fix: allow -Wpedantic in C++20 mode (#5322)
* fix: allow -Wpedantic again

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: ignore pedantic warning for PYBIND11_DECLARE_HOLDER_TYPE

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: try just turning off pedantic for one file

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: only run pedantic in C++20 mode

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Update tests/local_bindings.h

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-08-22 00:27:50 -04:00
ObeliskGate 2baf9d6833
fix: `<ranges>` support for `py::tuple` and `py::list` (#5314)
* feat: add `<ranges>` support for `py::tuple` and `py::list`

* fix: format the code

* fix: disable `ranges` in clang < 16

* refactor: move `<ranges>` test macro to `test_pytypes.h`

* refactor: seperate `ranges` test into 3 funcs

* style: compress the if statement

* style: pre-commit fixes

* style: better formatting

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-08-21 15:33:06 -04:00
Henry Schreiner 7d85baa6a1
fix: never use `..` in a header include (#5321)
* fix: never use `..` in a header include

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: one more parent include

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-08-21 13:16:49 -04:00
Ralf W. Grosse-Kunstleve a1d00916b2
Backport of https://github.com/google/pywrapcc/pull/30034 (#5305) 2024-08-14 22:30:29 -07:00
Henry Schreiner bd5951b691
docs: prepare for 2.13.4 (#5312)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-08-14 23:57:37 -04:00
Henry Schreiner 28dbce4157
feat: require CMake 3.15+ (#5304)
* feat: require CMake 3.15+

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Apply suggestions from code review

* Update CMakeLists.txt

* fix: adapt for CMake 3.30+ (using 3.18+)

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2024-08-14 18:21:04 -04:00
Markus Bauer d893f9723a
fix: escape paths with spaces in pybind11-config (#4874)
* fix: Escape paths with spaces in include list from --includes

* fix: --includes should not use shlex on Windows platforms

* Apply suggestions from code review

* fix: use custom impl

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Support trailing backslashes

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Markus Bauer <markus.bauer@cispa.saarland>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2024-08-14 17:25:37 -04:00
Henry Schreiner fc97cc41d5
Revert "fix: quote paths from pybind11-config (#5302)" (#5309)
This reverts commit 8d9f4d50cc.
2024-08-14 12:36:45 -04:00
Aaron Gokaslan 7a3a51435e Add testcase for issue 2059 2021-09-07 11:02:29 -04:00
74 changed files with 1491 additions and 454 deletions

View File

@ -81,7 +81,7 @@ nox -s build
### Full setup
To setup an ideal development environment, run the following commands on a
system with CMake 3.14+:
system with CMake 3.15+:
```bash
python3 -m venv venv
@ -96,8 +96,8 @@ Tips:
* You can use `virtualenv` (faster, from PyPI) instead of `venv`.
* 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+
* If you don't have CMake 3.15+, just add "cmake" to the pip install command.
* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython.
* 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`.
@ -149,8 +149,8 @@ To run the tests, you can "build" the check target:
cmake --build build --target check
```
`--target` can be spelled `-t` in CMake 3.15+. You can also run individual
tests with these targets:
`--target` can be spelled `-t`. You can also run individual tests with these
targets:
* `pytest`: Python tests only, using the
[pytest](https://docs.pytest.org/en/stable/) framework

View File

@ -243,7 +243,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
uses: deadsnakes/action@v3.1.0
uses: deadsnakes/action@v3.2.0
with:
python-version: ${{ matrix.python-version }}
debug: ${{ matrix.python-debug }}

View File

@ -31,7 +31,7 @@ jobs:
include:
- runs-on: ubuntu-20.04
arch: x64
cmake: "3.5"
cmake: "3.15"
- runs-on: ubuntu-20.04
arch: x64
@ -39,7 +39,7 @@ jobs:
- runs-on: macos-13
arch: x64
cmake: "3.8"
cmake: "3.15"
- runs-on: windows-2019
arch: x64 # x86 compilers seem to be missing on 2019 image

View File

@ -22,7 +22,7 @@ jobs:
submodules: true
fetch-depth: 0
- uses: pypa/cibuildwheel@v2.20
- uses: pypa/cibuildwheel@v2.21
env:
PYODIDE_BUILD_EXPORTS: whole_archive
with:

View File

@ -91,18 +91,19 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
needs: [packaging]
environment: pypi
environment:
name: pypi
url: https://pypi.org/p/pybind11
permissions:
id-token: write
attestations: write
contents: read
steps:
# Downloads all to directories matching the artifact names
- uses: actions/download-artifact@v4
- name: Generate artifact attestation for sdist and wheel
uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
with:
subject-path: "*/pybind11*"
@ -110,8 +111,10 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: standard/
attestations: true
- name: Publish global package
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: global/
attestations: true

View File

@ -32,7 +32,7 @@ repos:
# Ruff, the Python auto-correcting linter/formatter written in Rust
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.6
rev: v0.6.3
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
@ -40,7 +40,7 @@ repos:
# Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.11.1"
rev: "v1.11.2"
hooks:
- id: mypy
args: []
@ -93,7 +93,7 @@ repos:
# Avoid directional quotes
- repo: https://github.com/sirosen/texthooks
rev: "0.6.6"
rev: "0.6.7"
hooks:
- id: fix-ligatures
- id: fix-smartquotes
@ -142,14 +142,14 @@ repos:
# PyLint has native support - not always usable, but works for us
- repo: https://github.com/PyCQA/pylint
rev: "v3.2.6"
rev: "v3.2.7"
hooks:
- id: pylint
files: ^pybind11
# Check schemas on some of our YAML files
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.29.1
rev: 0.29.2
hooks:
- id: check-readthedocs
- id: check-github-workflows

View File

@ -10,16 +10,7 @@ if(NOT CMAKE_VERSION VERSION_LESS "3.27")
cmake_policy(GET CMP0148 _pybind11_cmp0148)
endif()
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
if(_pybind11_cmp0148)
cmake_policy(SET CMP0148 ${_pybind11_cmp0148})
@ -27,9 +18,7 @@ if(_pybind11_cmp0148)
endif()
# Avoid infinite recursion if tests include this as a subdirectory
if(DEFINED PYBIND11_MASTER_PROJECT)
return()
endif()
include_guard(GLOBAL)
# Extract project version from source
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h"
@ -74,14 +63,6 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
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)
@ -133,8 +114,7 @@ cmake_dependent_option(
"Install pybind11 headers in Python include directory instead of default installation prefix"
OFF "PYBIND11_INSTALL" OFF)
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default}
"NOT CMAKE_VERSION VERSION_LESS 3.12" OFF)
option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default})
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
# (makes transition easier while we support both modes).
@ -149,12 +129,14 @@ endif()
set(PYBIND11_HEADERS
include/pybind11/detail/class.h
include/pybind11/detail/common.h
include/pybind11/detail/cpp_conduit.h
include/pybind11/detail/descr.h
include/pybind11/detail/init.h
include/pybind11/detail/internals.h
include/pybind11/detail/type_caster_base.h
include/pybind11/detail/typeid.h
include/pybind11/detail/value_and_holder.h
include/pybind11/detail/exception_translation.h
include/pybind11/attr.h
include/pybind11/buffer_info.h
include/pybind11/cast.h
@ -180,10 +162,11 @@ set(PYBIND11_HEADERS
include/pybind11/stl_bind.h
include/pybind11/stl/filesystem.h
include/pybind11/type_caster_pyobject_ptr.h
include/pybind11/typing.h)
include/pybind11/typing.h
include/pybind11/warnings.h)
# Compare with grep and warn if mismatched
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
if(PYBIND11_MASTER_PROJECT)
file(
GLOB_RECURSE _pybind11_header_check
LIST_DIRECTORIES false
@ -201,10 +184,7 @@ if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
endif()
endif()
# 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}")
list(TRANSFORM PYBIND11_HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
# Cache variable so this can be used in parent projects
set(pybind11_INCLUDE_DIR
@ -274,25 +254,11 @@ if(PYBIND11_INSTALL)
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
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()
# CMake 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)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake

View File

@ -162,7 +162,7 @@ the declaration
.. code-block:: cpp
PYBIND11_MAKE_OPAQUE(std::vector<int>);
PYBIND11_MAKE_OPAQUE(std::vector<int>)
before any binding code (e.g. invocations to ``class_::def()``, etc.). This
macro must be specified at the top level (and outside of any namespaces), since
@ -207,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`:
// Don't forget this
#include <pybind11/stl_bind.h>
PYBIND11_MAKE_OPAQUE(std::vector<int>);
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>);
PYBIND11_MAKE_OPAQUE(std::vector<int>)
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>)
// ...

View File

@ -18,7 +18,7 @@ information, see :doc:`/compiling`.
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.29)
cmake_minimum_required(VERSION 3.15...3.30)
project(example)
find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)`

View File

@ -124,7 +124,7 @@ top namespace level before any binding code:
.. code-block:: cpp
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
placeholder name that is used as a template parameter of the second argument.
@ -136,7 +136,7 @@ by default. Specify
.. code-block:: cpp
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true);
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true)
if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the
risk of inconsistencies (such as multiple independent ``SmartPtr`` instances
@ -154,7 +154,7 @@ specialized:
.. code-block:: cpp
// Always needed for custom holder types
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
// Only needed if the type's `.get()` goes by another name
namespace PYBIND11_NAMESPACE { namespace detail {

View File

@ -78,6 +78,13 @@ For brevity, all code examples assume that the following two lines are present:
namespace py = pybind11;
.. note::
``pybind11/pybind11.h`` includes ``Python.h``, as such it must be the first file
included in any source file or header for `the same reasons as Python.h`_.
.. _`the same reasons as Python.h`: https://docs.python.org/3/extending/extending.html#a-simple-example
Some features may require additional headers, but those will be specified as needed.
.. _simple_example:

View File

@ -20,7 +20,76 @@ New Features:
* Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27).
`#5191 <https://github.com/pybind/pybind11/pull/5191>`_
Support for CMake older than 3.15 and some older compilers will also be removed.
* stl.h ``list|set|map_caster`` were made more user friendly: it is no longer
necessary to explicitly convert Python iterables to ``tuple()``, ``set()``,
or ``map()`` in many common situations.
`#4686 <https://github.com/pybind/pybind11/pull/4686>`_
* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported.
`#5304 <https://github.com/pybind/pybind11/pull/5304>`_
* The ``array_caster`` in pybind11/stl.h was enhanced to support value types that are not default-constructible.
`#5305 <https://github.com/pybind/pybind11/pull/5305>`_
* Added ``py::warnings`` namespace with ``py::warnings::warn`` and ``py::warnings::new_warning_type`` that provides the interface for Python warnings.
`#5291 <https://github.com/pybind/pybind11/pull/5291>`_
Version 2.13.6 (September 13, 2024)
-----------------------------------
New Features:
* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all
``py::class_``-wrapped types, to enable type-safe interoperability between
different independent Python/C++ bindings systems, including pybind11
versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on
pybind11 2.11.2, 2.12.1, and 2.13.6+.
`#5296 <https://github.com/pybind/pybind11/pull/5296>`_
Bug fixes:
* Using ``__cpp_nontype_template_args`` instead of ``__cpp_nontype_template_parameter_class``.
`#5330 <https://github.com/pybind/pybind11/pull/5330>`_
* Properly translate C++ exception to Python exception when creating Python buffer from wrapped object.
`#5324 <https://github.com/pybind/pybind11/pull/5324>`_
Documentation:
* Adds an answer (FAQ) for "What is a highly conclusive and simple way to find memory leaks?".
`#5340 <https://github.com/pybind/pybind11/pull/5340>`_
Version 2.13.5 (August 22, 2024)
--------------------------------
Bug fixes:
* Fix includes when using Windows long paths (``\\?\`` prefix).
`#5321 <https://github.com/pybind/pybind11/pull/5321>`_
* Support ``-Wpedantic`` in C++20 mode.
`#5322 <https://github.com/pybind/pybind11/pull/5322>`_
* Fix and test ``<ranges>`` support for ``py::tuple`` and ``py::list``.
`#5314 <https://github.com/pybind/pybind11/pull/5314>`_
Version 2.13.4 (August 14, 2024)
--------------------------------
Bug fixes:
* Fix paths with spaces, including on Windows.
(Replaces regression from `#5302 <https://github.com/pybind/pybind11/pull/5302>`_)
`#4874 <https://github.com/pybind/pybind11/pull/4874>`_
Documentation:
* Remove repetitive words.
`#5308 <https://github.com/pybind/pybind11/pull/5308>`_
Version 2.13.3 (August 13, 2024)
--------------------------------
@ -200,6 +269,18 @@ Other:
* Update docs and noxfile.
`#5071 <https://github.com/pybind/pybind11/pull/5071>`_
Version 2.12.1 (September 13, 2024)
-----------------------------------
New Features:
* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all
``py::class_``-wrapped types, to enable type-safe interoperability between
different independent Python/C++ bindings systems, including pybind11
versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on
pybind11 2.11.2, 2.12.1, and 2.13.6+.
`#5296 <https://github.com/pybind/pybind11/pull/5296>`_
Version 2.12.0 (March 27, 2024)
-------------------------------
@ -375,6 +456,18 @@ Other:
* An ``assert()`` was added to help Coverty avoid generating a false positive.
`#4817 <https://github.com/pybind/pybind11/pull/4817>`_
Version 2.11.2 (September 13, 2024)
-----------------------------------
New Features:
* A new ``self._pybind11_conduit_v1_()`` method is automatically added to all
``py::class_``-wrapped types, to enable type-safe interoperability between
different independent Python/C++ bindings systems, including pybind11
versions with different ``PYBIND11_INTERNALS_VERSION``'s. Supported on
pybind11 2.11.2, 2.12.1, and 2.13.6+.
`#5296 <https://github.com/pybind/pybind11/pull/5296>`_
Version 2.11.1 (July 17, 2023)
------------------------------

View File

@ -18,7 +18,7 @@ A Python extension module can be created with just a few lines of code:
.. code-block:: cmake
cmake_minimum_required(VERSION 3.15...3.29)
cmake_minimum_required(VERSION 3.15...3.30)
project(example LANGUAGES CXX)
set(PYBIND11_FINDPYTHON ON)
@ -319,11 +319,11 @@ Building with CMake
For C++ codebases that have an existing CMake-based build system, a Python
extension module can be created with just a few lines of code, as seen above in
the module section. Pybind11 currently supports a lower minimum if you don't
use the modern FindPython, though be aware that CMake 3.27 removed the old
mechanism, so pybind11 will automatically switch if the old mechanism is not
available. Please opt into the new mechanism if at all possible. Our default
may change in future versions. This is the minimum required:
the module section. Pybind11 currently defaults to the old mechanism, though be
aware that CMake 3.27 removed the old mechanism, so pybind11 will automatically
switch if the old mechanism is not available. Please opt into the new mechanism
if at all possible. Our default may change in future versions. This is the
minimum required:
@ -333,6 +333,9 @@ may change in future versions. This is the minimum required:
.. versionchanged:: 2.11
CMake 3.5+ is required.
.. versionchanged:: 2.14
CMake 3.15+ is required.
Further information can be found at :doc:`cmake/index`.
@ -444,7 +447,7 @@ See the `Config file`_ docstring for details of relevant CMake variables.
.. code-block:: cmake
cmake_minimum_required(VERSION 3.4...3.18)
cmake_minimum_required(VERSION 3.15...3.30)
project(example LANGUAGES CXX)
find_package(pybind11 REQUIRED)
@ -483,14 +486,13 @@ can refer to the same [cmake_example]_ repository for a full sample project
FindPython mode
---------------
CMake 3.12+ (3.15+ recommended, 3.18.2+ ideal) 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:
Modern CMake (3.18.2+ ideal) 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.15...3.22)
cmake_minimum_required(VERSION 3.15...3.30)
project(example LANGUAGES CXX)
find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED)
@ -541,7 +543,7 @@ available in all modes. The targets provided are:
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``
Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython) or ``pybind11::python_link_helper``
``pybind11::embed``
Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs
@ -568,7 +570,7 @@ You can use these targets to build complex applications. For example, the
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.29)
cmake_minimum_required(VERSION 3.15...3.30)
project(example LANGUAGES CXX)
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)
@ -626,7 +628,7 @@ information about usage in C++, see :doc:`/advanced/embedding`.
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5...3.29)
cmake_minimum_required(VERSION 3.15...3.30)
project(example LANGUAGES CXX)
find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11)

View File

@ -247,6 +247,50 @@ been received, you must either explicitly interrupt execution by throwing
});
}
What is a highly conclusive and simple way to find memory leaks (e.g. in pybind11 bindings)?
============================================================================================
Use ``while True`` & ``top`` (Linux, macOS).
For example, locally change tests/test_type_caster_pyobject_ptr.py like this:
.. code-block:: diff
def test_return_list_pyobject_ptr_reference():
+ while True:
vec_obj = m.return_list_pyobject_ptr_reference(ValueHolder)
assert [e.value for e in vec_obj] == [93, 186]
# Commenting out the next `assert` will leak the Python references.
# An easy way to see evidence of the leaks:
# Insert `while True:` as the first line of this function and monitor the
# process RES (Resident Memory Size) with the Unix top command.
- assert m.dec_ref_each_pyobject_ptr(vec_obj) == 2
+ # assert m.dec_ref_each_pyobject_ptr(vec_obj) == 2
Then run the test as you would normally do, which will go into the infinite loop.
**In another shell, but on the same machine** run:
.. code-block:: bash
top
This will show:
.. code-block::
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1266095 rwgk 20 0 5207496 611372 45696 R 100.0 0.3 0:08.01 test_type_caste
Look for the number under ``RES`` there. You'll see it going up very quickly.
**Don't forget to Ctrl-C the test command** before your machine becomes
unresponsive due to swapping.
This method only takes a couple minutes of effort and is very conclusive.
What you want to see is that the ``RES`` number is stable after a couple
seconds.
CMake doesn't detect the right Python version
=============================================
@ -258,9 +302,9 @@ CMake configure line. (Replace ``$(which python)`` with a path to python if
your prefer.)
You can alternatively try ``-DPYBIND11_FINDPYTHON=ON``, which will activate the
new CMake FindPython support instead of pybind11's custom search. Requires
CMake 3.12+, and 3.15+ or 3.18.2+ are even better. You can set this in your
``CMakeLists.txt`` before adding or finding pybind11, as well.
new CMake FindPython support instead of pybind11's custom search. Newer CMake,
like, 3.18.2+, is recommended. You can set this in your ``CMakeLists.txt``
before adding or finding pybind11, as well.
Inconsistent detection of Python version in CMake and pybind11
==============================================================
@ -281,11 +325,11 @@ There are three possible solutions:
from CMake and rely on pybind11 in detecting Python version. If this is not
possible, the CMake machinery should be called *before* including pybind11.
2. Set ``PYBIND11_FINDPYTHON`` to ``True`` or use ``find_package(Python
COMPONENTS Interpreter Development)`` on modern CMake (3.12+, 3.15+ better,
3.18.2+ best). Pybind11 in these cases uses the new CMake FindPython instead
of the old, deprecated search tools, and these modules are much better at
finding the correct Python. If FindPythonLibs/Interp are not available
(CMake 3.27+), then this will be ignored and FindPython will be used.
COMPONENTS Interpreter Development)`` on modern CMake ( 3.18.2+ best).
Pybind11 in these cases uses the new CMake FindPython instead of the old,
deprecated search tools, and these modules are much better at finding the
correct Python. If FindPythonLibs/Interp are not available (CMake 3.27+),
then this will be ignored and FindPython will be used.
3. Set ``PYBIND11_NOPYTHON`` to ``TRUE``. Pybind11 will not search for Python.
However, you will have to use the target-based system, and do more setup
yourself, because it does not know about or include things that depend on

View File

@ -9,8 +9,10 @@
#pragma once
#include "../attr.h"
#include "../options.h"
#include <pybind11/attr.h>
#include <pybind11/options.h>
#include "exception_translation.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
@ -581,7 +583,18 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
return -1;
}
std::memset(view, 0, sizeof(Py_buffer));
buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
buffer_info *info = nullptr;
try {
info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
} catch (...) {
try_translate_exceptions();
raise_from(PyExc_BufferError, "Error getting buffer");
return -1;
}
if (info == nullptr) {
pybind11_fail("FATAL UNEXPECTED SITUATION: tinfo->get_buffer() returned nullptr.");
}
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
delete info;
// view->obj = nullptr; // Was just memset to 0, so not necessary

View File

@ -479,6 +479,8 @@ PYBIND11_WARNING_POP
}
\endrst */
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
#define PYBIND11_MODULE(name, variable, ...) \
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
PYBIND11_MAYBE_UNUSED; \
@ -499,6 +501,7 @@ PYBIND11_WARNING_POP
PYBIND11_CATCH_INIT_EXCEPTIONS \
} \
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
PYBIND11_WARNING_POP
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)

View File

@ -0,0 +1,77 @@
// Copyright (c) 2024 The pybind Community.
#pragma once
#include <pybind11/pytypes.h>
#include "common.h"
#include "internals.h"
#include <typeinfo>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// Forward declaration needed here: Refactoring opportunity.
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);
inline bool type_is_managed_by_our_internals(PyTypeObject *type_obj) {
#if defined(PYPY_VERSION)
auto &internals = get_internals();
return bool(internals.registered_types_py.find(type_obj)
!= internals.registered_types_py.end());
#else
return bool(type_obj->tp_new == pybind11_object_new);
#endif
}
inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) {
PyObject *descr = _PyType_Lookup(type_obj, attr_name);
return bool((descr != nullptr) && PyInstanceMethod_Check(descr));
}
inline object try_get_cpp_conduit_method(PyObject *obj) {
if (PyType_Check(obj)) {
return object();
}
PyTypeObject *type_obj = Py_TYPE(obj);
str attr_name("_pybind11_conduit_v1_");
bool assumed_to_be_callable = false;
if (type_is_managed_by_our_internals(type_obj)) {
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) {
return object();
}
assumed_to_be_callable = true;
}
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr());
if (method == nullptr) {
PyErr_Clear();
return object();
}
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) {
Py_DECREF(method);
return object();
}
return reinterpret_steal<object>(method);
}
inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src,
const std::type_info *cpp_type_info) {
object method = try_get_cpp_conduit_method(src.ptr());
if (method) {
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name());
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID),
cpp_type_info_capsule,
bytes("raw_pointer_ephemeral"));
if (isinstance<capsule>(cpp_conduit)) {
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer();
}
}
return nullptr;
}
#define PYBIND11_HAS_CPP_CONDUIT 1
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -0,0 +1,71 @@
/*
pybind11/detail/exception_translation.h: means to translate C++ exceptions to Python exceptions
Copyright (c) 2024 The Pybind Development Team.
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "common.h"
#include "internals.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// Apply all the extensions translators from a list
// Return true if one of the translators completed without raising an exception
// itself. Return of false indicates that if there are other translators
// available, they should be tried.
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
auto last_exception = std::current_exception();
for (auto &translator : translators) {
try {
translator(last_exception);
return true;
} catch (...) {
last_exception = std::current_exception();
}
}
return false;
}
inline void try_translate_exceptions() {
/* When an exception is caught, give each registered exception
translator a chance to translate it to a Python exception. First
all module-local translators will be tried in reverse order of
registration. If none of the module-locale translators handle
the exception (or there are no module-locale translators) then
the global translators will be tried, also in reverse order of
registration.
A translator may choose to do one of the following:
- catch the exception and call py::set_error()
to set a standard (or custom) Python exception, or
- do nothing and let the exception fall through to the next translator, or
- delegate translation to the next translator by throwing a new type of exception.
*/
bool handled = with_exception_translators(
[&](std::forward_list<ExceptionTranslator> &exception_translators,
std::forward_list<ExceptionTranslator> &local_exception_translators) {
if (detail::apply_exception_translators(local_exception_translators)) {
return true;
}
if (detail::apply_exception_translators(exception_translators)) {
return true;
}
return false;
});
if (!handled) {
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
}
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -12,10 +12,10 @@
#include "common.h"
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "../gil.h"
# include <pybind11/gil.h>
#endif
#include "../pytypes.h"
#include <pybind11/pytypes.h>
#include <exception>
#include <mutex>
@ -39,7 +39,11 @@
# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
// Version bump for Python 3.12+, before first 3.12 beta release.
// Version bump for MSVC piggy-backed on PR #4779. See comments there.
# define PYBIND11_INTERNALS_VERSION 5
# ifdef Py_GIL_DISABLED
# define PYBIND11_INTERNALS_VERSION 6
# else
# define PYBIND11_INTERNALS_VERSION 5
# endif
# else
# define PYBIND11_INTERNALS_VERSION 4
# endif
@ -177,6 +181,7 @@ static_assert(sizeof(instance_map_shard) % 64 == 0,
struct internals {
#ifdef Py_GIL_DISABLED
pymutex mutex;
pymutex exception_translator_mutex;
#endif
// std::type_index -> pybind11's type information
type_map<type_info *> registered_types_cpp;
@ -321,15 +326,17 @@ struct type_info {
# define PYBIND11_INTERNALS_KIND ""
#endif
#define PYBIND11_PLATFORM_ABI_ID \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE
#define PYBIND11_INTERNALS_ID \
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
PYBIND11_PLATFORM_ABI_ID "__"
#define PYBIND11_MODULE_LOCAL_ID \
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \
PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
PYBIND11_PLATFORM_ABI_ID "__"
/// Each module locally stores a pointer to the `internals` data. The data
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
@ -641,6 +648,19 @@ inline auto with_internals(const F &cb) -> decltype(cb(get_internals())) {
return cb(internals);
}
template <typename F>
inline auto with_exception_translators(const F &cb)
-> decltype(cb(get_internals().registered_exception_translators,
get_local_internals().registered_exception_translators)) {
auto &internals = get_internals();
#ifdef Py_GIL_DISABLED
std::unique_lock<pymutex> lock((internals).exception_translator_mutex);
#endif
auto &local_internals = get_local_internals();
return cb(internals.registered_exception_translators,
local_internals.registered_exception_translators);
}
inline std::uint64_t mix64(std::uint64_t z) {
// David Stafford's variant 13 of the MurmurHash3 finalizer popularized
// by the SplitMix PRNG.

View File

@ -9,16 +9,20 @@
#pragma once
#include "../pytypes.h"
#include <pybind11/pytypes.h>
#include "common.h"
#include "cpp_conduit.h"
#include "descr.h"
#include "internals.h"
#include "typeid.h"
#include "value_and_holder.h"
#include <cstdint>
#include <cstring>
#include <iterator>
#include <new>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeindex>
@ -610,6 +614,13 @@ public:
}
return false;
}
bool try_cpp_conduit(handle src) {
value = try_raw_pointer_ephemeral_from_cpp_conduit(src, cpptype);
if (value != nullptr) {
return true;
}
return false;
}
void check_holder_compat() {}
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
@ -741,6 +752,10 @@ public:
return true;
}
if (convert && cpptype && this_.try_cpp_conduit(src)) {
return true;
}
return false;
}
@ -768,6 +783,32 @@ public:
void *value = nullptr;
};
inline object cpp_conduit_method(handle self,
const bytes &pybind11_platform_abi_id,
const capsule &cpp_type_info_capsule,
const bytes &pointer_kind) {
#ifdef PYBIND11_HAS_STRING_VIEW
using cpp_str = std::string_view;
#else
using cpp_str = std::string;
#endif
if (cpp_str(pybind11_platform_abi_id) != PYBIND11_PLATFORM_ABI_ID) {
return none();
}
if (std::strcmp(cpp_type_info_capsule.name(), typeid(std::type_info).name()) != 0) {
return none();
}
if (cpp_str(pointer_kind) != "raw_pointer_ephemeral") {
throw std::runtime_error("Invalid pointer_kind: \"" + std::string(pointer_kind) + "\"");
}
const auto *cpp_type_info = cpp_type_info_capsule.get_pointer<const std::type_info>();
type_caster_generic caster(*cpp_type_info);
if (!caster.load(self, false)) {
return none();
}
return capsule(caster.value, cpp_type_info->name());
}
/**
* Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster
* needs to provide `operator T*()` and `operator T&()` operators.

View File

@ -9,7 +9,8 @@
#pragma once
#include "../numpy.h"
#include <pybind11/numpy.h>
#include "common.h"
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.

View File

@ -7,7 +7,8 @@
#pragma once
#include "../numpy.h"
#include <pybind11/numpy.h>
#include "common.h"
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)

View File

@ -9,8 +9,8 @@
*/
#pragma once
#include "detail/class.h"
#include "detail/exception_translation.h"
#include "detail/init.h"
#include "attr.h"
#include "gil.h"
@ -95,24 +95,6 @@ inline std::string replace_newlines_and_squash(const char *text) {
return result.substr(str_begin, str_range);
}
// Apply all the extensions translators from a list
// Return true if one of the translators completed without raising an exception
// itself. Return of false indicates that if there are other translators
// available, they should be tried.
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
auto last_exception = std::current_exception();
for (auto &translator : translators) {
try {
translator(last_exception);
return true;
} catch (...) {
last_exception = std::current_exception();
}
}
return false;
}
#if defined(_MSC_VER)
# define PYBIND11_COMPAT_STRDUP _strdup
#else
@ -610,7 +592,8 @@ protected:
int index = 0;
/* Create a nice pydoc rec including all signatures and
docstrings of the functions in the overload chain */
if (chain && options::show_function_signatures()) {
if (chain && options::show_function_signatures()
&& std::strcmp(rec->name, "_pybind11_conduit_v1_") != 0) {
// First a generic signature
signatures += rec->name;
signatures += "(*args, **kwargs)\n";
@ -619,7 +602,8 @@ protected:
// Then specific overload signatures
bool first_user_def = true;
for (auto *it = chain_start; it != nullptr; it = it->next) {
if (options::show_function_signatures()) {
if (options::show_function_signatures()
&& std::strcmp(rec->name, "_pybind11_conduit_v1_") != 0) {
if (index > 0) {
signatures += '\n';
}
@ -1038,40 +1022,7 @@ protected:
throw;
#endif
} catch (...) {
/* When an exception is caught, give each registered exception
translator a chance to translate it to a Python exception. First
all module-local translators will be tried in reverse order of
registration. If none of the module-locale translators handle
the exception (or there are no module-locale translators) then
the global translators will be tried, also in reverse order of
registration.
A translator may choose to do one of the following:
- catch the exception and call py::set_error()
to set a standard (or custom) Python exception, or
- do nothing and let the exception fall through to the next translator, or
- delegate translation to the next translator by throwing a new type of exception.
*/
bool handled = with_internals([&](internals &internals) {
auto &local_exception_translators
= get_local_internals().registered_exception_translators;
if (detail::apply_exception_translators(local_exception_translators)) {
return true;
}
auto &exception_translators = internals.registered_exception_translators;
if (detail::apply_exception_translators(exception_translators)) {
return true;
}
return false;
});
if (handled) {
return nullptr;
}
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
try_translate_exceptions();
return nullptr;
}
@ -1431,7 +1382,17 @@ protected:
} else {
internals.registered_types_cpp[tindex] = tinfo;
}
PYBIND11_WARNING_PUSH
#if defined(__GNUC__) && __GNUC__ == 12
// When using GCC 12 these warnings are disabled as they trigger
// false positive warnings. Discussed here:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115824.
PYBIND11_WARNING_DISABLE_GCC("-Warray-bounds")
PYBIND11_WARNING_DISABLE_GCC("-Wstringop-overread")
#endif
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
PYBIND11_WARNING_POP
});
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
@ -1652,6 +1613,7 @@ public:
= instances[std::type_index(typeid(type))];
});
}
def("_pybind11_conduit_v1_", cpp_conduit_method);
}
template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>
@ -2624,10 +2586,12 @@ void implicitly_convertible() {
}
inline void register_exception_translator(ExceptionTranslator &&translator) {
detail::with_internals([&](detail::internals &internals) {
internals.registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
});
detail::with_exception_translators(
[&](std::forward_list<ExceptionTranslator> &exception_translators,
std::forward_list<ExceptionTranslator> &local_exception_translators) {
(void) local_exception_translators;
exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
});
}
/**
@ -2637,11 +2601,12 @@ inline void register_exception_translator(ExceptionTranslator &&translator) {
* the exception.
*/
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
detail::with_internals([&](detail::internals &internals) {
(void) internals;
detail::get_local_internals().registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
});
detail::with_exception_translators(
[&](std::forward_list<ExceptionTranslator> &exception_translators,
std::forward_list<ExceptionTranslator> &local_exception_translators) {
(void) exception_translators;
local_exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
});
}
/**

View File

@ -1259,6 +1259,7 @@ protected:
using pointer = arrow_proxy<const handle>;
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
sequence_fast_readonly() = default;
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference dereference() const { return *ptr; }
@ -1281,6 +1282,7 @@ protected:
using pointer = arrow_proxy<const sequence_accessor>;
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}
sequence_slow_readwrite() = default;
reference dereference() const { return {obj, static_cast<size_t>(index)}; }
void increment() { ++index; }

View File

@ -11,11 +11,14 @@
#include "pybind11.h"
#include "detail/common.h"
#include "detail/descr.h"
#include "detail/type_caster_base.h"
#include <deque>
#include <initializer_list>
#include <list>
#include <map>
#include <memory>
#include <ostream>
#include <set>
#include <unordered_map>
@ -349,39 +352,68 @@ struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc
template <typename Type, typename Alloc>
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
template <typename ArrayType, typename V, size_t... I>
ArrayType vector_to_array_impl(V &&v, index_sequence<I...>) {
return {{std::move(v[I])...}};
}
// Based on https://en.cppreference.com/w/cpp/container/array/to_array
template <typename ArrayType, size_t N, typename V>
ArrayType vector_to_array(V &&v) {
return vector_to_array_impl<ArrayType, V>(std::forward<V>(v), make_index_sequence<N>{});
}
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
struct array_caster {
using value_conv = make_caster<Value>;
private:
template <bool R = Resizable>
bool require_size(enable_if_t<R, size_t> size) {
if (value.size() != size) {
value.resize(size);
}
return true;
}
template <bool R = Resizable>
bool require_size(enable_if_t<!R, size_t> size) {
return size == Size;
}
std::unique_ptr<ArrayType> value;
template <bool R = Resizable, enable_if_t<R, int> = 0>
bool convert_elements(handle seq, bool convert) {
auto l = reinterpret_borrow<sequence>(seq);
if (!require_size(l.size())) {
return false;
}
value.reset(new ArrayType{});
// Using `resize` to preserve the behavior exactly as it was before PR #5305
// For the `resize` to work, `Value` must be default constructible.
// For `std::valarray`, this is a requirement:
// https://en.cppreference.com/w/cpp/named_req/NumericType
value->resize(l.size());
size_t ctr = 0;
for (const auto &it : l) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
}
value[ctr++] = cast_op<Value &&>(std::move(conv));
(*value)[ctr++] = cast_op<Value &&>(std::move(conv));
}
return true;
}
template <bool R = Resizable, enable_if_t<!R, int> = 0>
bool convert_elements(handle seq, bool convert) {
auto l = reinterpret_borrow<sequence>(seq);
if (l.size() != Size) {
return false;
}
// The `temp` storage is needed to support `Value` types that are not
// default-constructible.
// Deliberate choice: no template specializations, for simplicity, and
// because the compile time overhead for the specializations is deemed
// more significant than the runtime overhead for the `temp` storage.
std::vector<Value> temp;
temp.reserve(l.size());
for (auto it : l) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
}
temp.emplace_back(cast_op<Value &&>(std::move(conv)));
}
value.reset(new ArrayType(vector_to_array<ArrayType, Size>(std::move(temp))));
return true;
}
public:
bool load(handle src, bool convert) {
if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
@ -416,12 +448,36 @@ public:
return l.release();
}
PYBIND11_TYPE_CASTER(ArrayType,
const_name<Resizable>(const_name(""), const_name("Annotated["))
+ const_name("list[") + value_conv::name + const_name("]")
+ const_name<Resizable>(const_name(""),
const_name(", FixedSize(")
+ const_name<Size>() + const_name(")]")));
// Code copied from PYBIND11_TYPE_CASTER macro.
// Intentionally preserving the behavior exactly as it was before PR #5305
template <typename T_, enable_if_t<std::is_same<ArrayType, remove_cv_t<T_>>::value, int> = 0>
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; // WARNING: Assumes `src` was allocated with `new`.
return h;
}
return cast(*src, policy, parent);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator ArrayType *() { return &(*value); }
// NOLINTNEXTLINE(google-explicit-constructor)
operator ArrayType &() { return *value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator ArrayType &&() && { return std::move(*value); }
template <typename T_>
using cast_op_type = movable_cast_op_type<T_>;
static constexpr auto name
= const_name<Resizable>(const_name(""), const_name("Annotated[")) + const_name("list[")
+ value_conv::name + const_name("]")
+ const_name<Resizable>(
const_name(""), const_name(", FixedSize(") + const_name<Size>() + const_name(")]"));
};
template <typename Type, size_t Size>

View File

@ -4,11 +4,11 @@
#pragma once
#include "../pybind11.h"
#include "../detail/common.h"
#include "../detail/descr.h"
#include "../cast.h"
#include "../pytypes.h"
#include <pybind11/cast.h>
#include <pybind11/detail/common.h>
#include <pybind11/detail/descr.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <string>

View File

@ -100,9 +100,7 @@ class Never : public none {
using none::none;
};
#if defined(__cpp_nontype_template_parameter_class) \
&& (/* See #5201 */ !defined(__GNUC__) \
|| (__GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 3)))
#if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911L
# define PYBIND11_TYPING_H_HAS_STRING_LITERAL
template <size_t N>
struct StringLiteral {

View File

@ -0,0 +1,75 @@
/*
pybind11/warnings.h: Python warnings wrappers.
Copyright (c) 2024 Jan Iwaszkiewicz <jiwaszkiewicz6@gmail.com>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include "detail/common.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline bool PyWarning_Check(PyObject *obj) {
int result = PyObject_IsSubclass(obj, PyExc_Warning);
if (result == 1) {
return true;
}
if (result == -1) {
raise_from(PyExc_SystemError,
"pybind11::detail::PyWarning_Check(): PyObject_IsSubclass() call failed.");
throw error_already_set();
}
return false;
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_BEGIN(warnings)
inline object
new_warning_type(handle scope, const char *name, handle base = PyExc_RuntimeWarning) {
if (!detail::PyWarning_Check(base.ptr())) {
pybind11_fail("pybind11::warnings::new_warning_type(): cannot create custom warning, base "
"must be a subclass of "
"PyExc_Warning!");
}
if (hasattr(scope, name)) {
pybind11_fail("pybind11::warnings::new_warning_type(): an attribute with name \""
+ std::string(name) + "\" exists already.");
}
std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name;
handle h(PyErr_NewException(full_name.c_str(), base.ptr(), nullptr));
if (!h) {
raise_from(PyExc_SystemError,
"pybind11::warnings::new_warning_type(): PyErr_NewException() call failed.");
throw error_already_set();
}
auto obj = reinterpret_steal<object>(h);
scope.attr(name) = obj;
return obj;
}
// Similar to Python `warnings.warn()`
inline void
warn(const char *message, handle category = PyExc_RuntimeWarning, int stack_level = 2) {
if (!detail::PyWarning_Check(category.ptr())) {
pybind11_fail(
"pybind11::warnings::warn(): cannot raise warning, category must be a subclass of "
"PyExc_Warning!");
}
if (PyErr_WarnEx(category.ptr(), message, stack_level) == -1) {
throw error_already_set();
}
}
PYBIND11_NAMESPACE_END(warnings)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -2,13 +2,35 @@
from __future__ import annotations
import argparse
import shlex
import re
import sys
import sysconfig
from ._version import __version__
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
# This is the conditional used for os.path being posixpath
if "posix" in sys.builtin_module_names:
from shlex import quote
elif "nt" in sys.builtin_module_names:
# See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121
# and the original documents:
# https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
UNSAFE = re.compile("[ \t\n\r]")
def quote(s: str) -> str:
if s and not UNSAFE.search(s):
return s
# Paths cannot contain a '"' on Windows, so we don't need to worry
# about nuanced counting here.
return f'"{s}\\"' if s.endswith("\\") else f'"{s}"'
else:
def quote(s: str) -> str:
return s
def print_includes() -> None:
dirs = [
@ -23,7 +45,7 @@ def print_includes() -> None:
if d and d not in unique_dirs:
unique_dirs.append(d)
print(" ".join(shlex.quote(f"-I{d}") for d in unique_dirs))
print(" ".join(quote(f"-I{d}") for d in unique_dirs))
def main() -> None:
@ -55,9 +77,9 @@ def main() -> None:
if args.includes:
print_includes()
if args.cmakedir:
print(shlex.quote(get_cmake_dir()))
print(quote(get_cmake_dir()))
if args.pkgconfigdir:
print(shlex.quote(get_pkgconfig_dir()))
print(quote(get_pkgconfig_dir()))
if __name__ == "__main__":

View File

@ -5,16 +5,7 @@
# 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 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
# Filter out items; print an optional message if any items filtered. This ignores extensions.
#
@ -76,8 +67,8 @@ project(pybind11_tests CXX)
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)
option(DOWNLOAD_EIGEN "Download EIGEN" OFF)
option(PYBIND11_CUDA_TESTS "Enable building CUDA tests" OFF)
set(PYBIND11_TEST_OVERRIDE
""
CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
@ -127,6 +118,7 @@ set(PYBIND11_TEST_FILES
test_const_name
test_constants_and_functions
test_copy_move
test_cpp_conduit
test_custom_type_casters
test_custom_type_setup
test_docstring_options
@ -163,7 +155,8 @@ set(PYBIND11_TEST_FILES
test_unnamed_namespace_a
test_unnamed_namespace_b
test_vector_unique_ptr_member
test_virtual_functions)
test_virtual_functions
test_warnings)
# Invoking cmake with something like:
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp" ..
@ -226,6 +219,8 @@ tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_
# And add additional targets for other tests.
tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set")
tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
tests_extra_targets("test_cpp_conduit.py"
"exo_planet_pybind11;exo_planet_c_api;home_planet_very_lonely_traveler")
set(PYBIND11_EIGEN_REPO
"https://gitlab.com/libeigen/eigen.git"
@ -249,25 +244,21 @@ endif()
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(DOWNLOAD_EIGEN)
if(CMAKE_VERSION VERSION_LESS 3.11)
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
if(CMAKE_VERSION VERSION_LESS 3.18)
set(_opts)
else()
set(_opts SOURCE_SUBDIR no-cmake-build)
endif()
include(FetchContent)
FetchContent_Declare(
eigen
GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}"
GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}")
FetchContent_GetProperties(eigen)
if(NOT eigen_POPULATED)
message(
STATUS
"Downloading Eigen ${PYBIND11_EIGEN_VERSION_STRING} (${PYBIND11_EIGEN_VERSION_HASH}) from ${PYBIND11_EIGEN_REPO}"
)
FetchContent_Populate(eigen)
GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}"
${_opts})
FetchContent_MakeAvailable(eigen)
if(NOT CMAKE_VERSION VERSION_LESS 3.18)
set(EIGEN3_INCLUDE_DIR "${eigen_SOURCE_DIR}")
endif()
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
@ -315,8 +306,7 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
endif()
message(
STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download")
message(STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON to download")
endif()
endif()
@ -396,6 +386,9 @@ function(pybind11_enable_warnings target_name)
-Wdeprecated
-Wundef
-Wnon-virtual-dtor)
if(DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD VERSION_LESS 20)
target_compile_options(${target_name} PRIVATE -Wpedantic)
endif()
endif()
if(PYBIND11_WERROR)
@ -501,12 +494,10 @@ foreach(target ${test_targets})
endforeach()
# Provide nice organisation in IDEs
if(NOT CMAKE_VERSION VERSION_LESS 3.8)
source_group(
TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include"
PREFIX "Header Files"
FILES ${PYBIND11_HEADERS})
endif()
source_group(
TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include"
PREFIX "Header Files"
FILES ${PYBIND11_HEADERS})
# Make sure pytest is found or produce a warning
pybind11_find_import(pytest VERSION 3.1)

View File

@ -136,7 +136,7 @@ class Capture:
return Output(self.err)
@pytest.fixture()
@pytest.fixture
def capture(capsys):
"""Extended `capsys` with context manager and custom equality operators"""
return Capture(capsys)
@ -172,7 +172,7 @@ def _sanitize_docstring(thing):
return _sanitize_general(s)
@pytest.fixture()
@pytest.fixture
def doc():
"""Sanitize docstrings and add custom failure explanation"""
return SanitizedString(_sanitize_docstring)
@ -184,7 +184,7 @@ def _sanitize_message(thing):
return _hexadecimal.sub("0", s)
@pytest.fixture()
@pytest.fixture
def msg():
"""Sanitize messages and add custom failure explanation"""
return SanitizedString(_sanitize_message)

View File

@ -0,0 +1,10 @@
from __future__ import annotations
class PythonMyException7(Exception):
def __init__(self, message):
self.message = message
super().__init__(message)
def __str__(self):
return "[PythonMyException7]: " + self.message.a

103
tests/exo_planet_c_api.cpp Normal file
View File

@ -0,0 +1,103 @@
// Copyright (c) 2024 The pybind Community.
// THIS MUST STAY AT THE TOP!
#include <pybind11/pybind11.h> // EXCLUSIVELY for PYBIND11_PLATFORM_ABI_ID
// Potential future direction to maximize reusability:
// (e.g. for use from SWIG, Cython, PyCLIF, nanobind):
// #include <pybind11/compat/platform_abi_id.h>
// This would only depend on:
// 1. A C++ compiler, WITHOUT requiring -fexceptions.
// 2. Python.h
#include "test_cpp_conduit_traveler_types.h"
#include <Python.h>
#include <typeinfo>
namespace {
void *get_cpp_conduit_void_ptr(PyObject *py_obj, const std::type_info *cpp_type_info) {
PyObject *cpp_type_info_capsule
= PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name(),
nullptr);
if (cpp_type_info_capsule == nullptr) {
return nullptr;
}
PyObject *cpp_conduit = PyObject_CallMethod(py_obj,
"_pybind11_conduit_v1_",
"yOy",
PYBIND11_PLATFORM_ABI_ID,
cpp_type_info_capsule,
"raw_pointer_ephemeral");
Py_DECREF(cpp_type_info_capsule);
if (cpp_conduit == nullptr) {
return nullptr;
}
void *void_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name());
Py_DECREF(cpp_conduit);
if (PyErr_Occurred()) {
return nullptr;
}
return void_ptr;
}
template <typename T>
T *get_cpp_conduit_type_ptr(PyObject *py_obj) {
void *void_ptr = get_cpp_conduit_void_ptr(py_obj, &typeid(T));
if (void_ptr == nullptr) {
return nullptr;
}
return static_cast<T *>(void_ptr);
}
extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) {
const auto *cpp_traveler
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::Traveler>(traveler);
if (cpp_traveler == nullptr) {
return nullptr;
}
return PyUnicode_FromString(cpp_traveler->luggage.c_str());
}
extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) {
const auto *cpp_premium_traveler
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::PremiumTraveler>(
premium_traveler);
if (cpp_premium_traveler == nullptr) {
return nullptr;
}
return PyLong_FromLong(static_cast<long>(cpp_premium_traveler->points));
}
PyMethodDef ThisMethodDef[] = {{"GetLuggage", wrapGetLuggage, METH_O, nullptr},
{"GetPoints", wrapGetPoints, METH_O, nullptr},
{nullptr, nullptr, 0, nullptr}};
struct PyModuleDef ThisModuleDef = {
PyModuleDef_HEAD_INIT, // m_base
"exo_planet_c_api", // m_name
nullptr, // m_doc
-1, // m_size
ThisMethodDef, // m_methods
nullptr, // m_slots
nullptr, // m_traverse
nullptr, // m_clear
nullptr // m_free
};
} // namespace
#if defined(WIN32) || defined(_WIN32)
# define EXO_PLANET_C_API_EXPORT __declspec(dllexport)
#else
# define EXO_PLANET_C_API_EXPORT __attribute__((visibility("default")))
#endif
extern "C" EXO_PLANET_C_API_EXPORT PyObject *PyInit_exo_planet_c_api() {
PyObject *m = PyModule_Create(&ThisModuleDef);
if (m == nullptr) {
return nullptr;
}
return m;
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2024 The pybind Community.
#if defined(PYBIND11_INTERNALS_VERSION)
# undef PYBIND11_INTERNALS_VERSION
#endif
#define PYBIND11_INTERNALS_VERSION 900000001
#include "test_cpp_conduit_traveler_bindings.h"
namespace pybind11_tests {
namespace test_cpp_conduit {
PYBIND11_MODULE(exo_planet_pybind11, m) {
wrap_traveler(m);
m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); });
}
} // namespace test_cpp_conduit
} // namespace pybind11_tests

View File

@ -9,7 +9,6 @@ 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))
@ -48,17 +47,20 @@ main_headers = {
"include/pybind11/stl_bind.h",
"include/pybind11/type_caster_pyobject_ptr.h",
"include/pybind11/typing.h",
"include/pybind11/warnings.h",
}
detail_headers = {
"include/pybind11/detail/class.h",
"include/pybind11/detail/common.h",
"include/pybind11/detail/cpp_conduit.h",
"include/pybind11/detail/descr.h",
"include/pybind11/detail/init.h",
"include/pybind11/detail/internals.h",
"include/pybind11/detail/type_caster_base.h",
"include/pybind11/detail/typeid.h",
"include/pybind11/detail/value_and_holder.h",
"include/pybind11/detail/exception_translation.h",
}
eigen_headers = {

View File

@ -0,0 +1,13 @@
// Copyright (c) 2024 The pybind Community.
#include "test_cpp_conduit_traveler_bindings.h"
namespace pybind11_tests {
namespace test_cpp_conduit {
PYBIND11_MODULE(home_planet_very_lonely_traveler, m) {
m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); });
}
} // namespace test_cpp_conduit
} // namespace pybind11_tests

View File

@ -56,13 +56,13 @@ private:
std::string message = "";
};
PYBIND11_MAKE_OPAQUE(LocalVec);
PYBIND11_MAKE_OPAQUE(LocalVec2);
PYBIND11_MAKE_OPAQUE(LocalMap);
PYBIND11_MAKE_OPAQUE(NonLocalVec);
// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
PYBIND11_MAKE_OPAQUE(NonLocalMap);
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
PYBIND11_MAKE_OPAQUE(LocalVec)
PYBIND11_MAKE_OPAQUE(LocalVec2)
PYBIND11_MAKE_OPAQUE(LocalMap)
PYBIND11_MAKE_OPAQUE(NonLocalVec)
// PYBIND11_MAKE_OPAQUE(NonLocalVec2) // same type as LocalVec2
PYBIND11_MAKE_OPAQUE(NonLocalMap)
PYBIND11_MAKE_OPAQUE(NonLocalMap2)
// Simple bindings (used with the above):
template <typename T, int Adjust = 0, typename... Args>
@ -70,7 +70,7 @@ py::class_<T> bind_local(Args &&...args) {
return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
return i.i + Adjust;
});
};
}
// Simulate a foreign library base class (to match the example in the docs):
namespace pets {

View File

@ -10,10 +10,6 @@ name = "pybind11_tests"
version = "0.0.1"
dependencies = ["pytest", "pytest-timeout", "numpy", "scipy"]
[tool.scikit-build]
# Hide a warning while we also support CMake < 3.15
cmake.version = ">=3.15"
[tool.scikit-build.cmake.define]
PYBIND11_FINDPYTHON = true

View File

@ -11,7 +11,7 @@ if sys.platform.startswith("emscripten"):
pytest.skip("Can't run a new event_loop in pyodide", allow_module_level=True)
@pytest.fixture()
@pytest.fixture
def event_loop():
loop = asyncio.new_event_loop()
yield loop

View File

@ -167,6 +167,18 @@ TEST_SUBMODULE(buffers, m) {
sizeof(float)});
});
class BrokenMatrix : public Matrix {
public:
BrokenMatrix(py::ssize_t rows, py::ssize_t cols) : Matrix(rows, cols) {}
void throw_runtime_error() { throw std::runtime_error("See PR #5324 for context."); }
};
py::class_<BrokenMatrix>(m, "BrokenMatrix", py::buffer_protocol())
.def(py::init<py::ssize_t, py::ssize_t>())
.def_buffer([](BrokenMatrix &m) {
m.throw_runtime_error();
return py::buffer_info();
});
// test_inherited_protocol
class SquareMatrix : public Matrix {
public:

View File

@ -228,3 +228,10 @@ def test_buffer_docstring():
m.get_buffer_info.__doc__.strip()
== "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info"
)
def test_buffer_exception():
with pytest.raises(BufferError, match="Error getting buffer") as excinfo:
memoryview(m.BrokenMatrix(1, 1))
assert isinstance(excinfo.value.__cause__, RuntimeError)
assert "for context" in str(excinfo.value.__cause__)

View File

@ -148,7 +148,7 @@ TEST_SUBMODULE(callbacks, m) {
m.def("dummy_function2", [](int i, int j) { return i + j; });
m.def(
"roundtrip",
[](std::function<int(int)> f, bool expect_none = false) {
[](std::function<int(int)> f, bool expect_none) {
if (expect_none && f) {
throw std::runtime_error("Expected None to be converted to empty std::function");
}

View File

@ -149,6 +149,10 @@ def test_qualname(doc):
assert m.NestBase.__module__ == "pybind11_tests.class_"
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
assert m.Pet.__module__ == "pybind11_tests.class_"
assert m.Pet.__qualname__ == "Pet"
assert m.Pet.name.__qualname__ == "Pet.name"
def test_inheritance(msg):
roger = m.Rabbit("Rabbit")

View File

@ -1,13 +1,4 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
project(test_installed_embed CXX)

View File

@ -1,14 +1,4 @@
cmake_minimum_required(VERSION 3.5)
project(test_installed_module CXX)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
project(test_installed_function CXX)

View File

@ -1,13 +1,4 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
project(test_installed_target CXX)

View File

@ -1,13 +1,4 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
project(test_subdirectory_embed CXX)

View File

@ -1,13 +1,4 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
project(test_subdirectory_function CXX)

View File

@ -1,13 +1,4 @@
cmake_minimum_required(VERSION 3.5)
# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
if(${CMAKE_VERSION} VERSION_LESS 3.29)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.29)
endif()
cmake_minimum_required(VERSION 3.15...3.30)
project(test_subdirectory_target CXX)

View File

@ -0,0 +1,22 @@
// Copyright (c) 2024 The pybind Community.
#include "pybind11_tests.h"
#include "test_cpp_conduit_traveler_bindings.h"
#include <typeinfo>
namespace pybind11_tests {
namespace test_cpp_conduit {
TEST_SUBMODULE(cpp_conduit, m) {
m.attr("PYBIND11_PLATFORM_ABI_ID") = py::bytes(PYBIND11_PLATFORM_ABI_ID);
m.attr("cpp_type_info_capsule_Traveler")
= py::capsule(&typeid(Traveler), typeid(std::type_info).name());
m.attr("cpp_type_info_capsule_int") = py::capsule(&typeid(int), typeid(std::type_info).name());
wrap_traveler(m);
wrap_lonely_traveler(m);
}
} // namespace test_cpp_conduit
} // namespace pybind11_tests

162
tests/test_cpp_conduit.py Normal file
View File

@ -0,0 +1,162 @@
# Copyright (c) 2024 The pybind Community.
from __future__ import annotations
import exo_planet_c_api
import exo_planet_pybind11
import home_planet_very_lonely_traveler
import pytest
from pybind11_tests import cpp_conduit as home_planet
def test_traveler_getattr_actually_exists():
t_h = home_planet.Traveler("home")
assert t_h.any_name == "Traveler GetAttr: any_name luggage: home"
def test_premium_traveler_getattr_actually_exists():
t_h = home_planet.PremiumTraveler("home", 7)
assert t_h.secret_name == "PremiumTraveler GetAttr: secret_name points: 7"
def test_call_cpp_conduit_success():
t_h = home_planet.Traveler("home")
cap = t_h._pybind11_conduit_v1_(
home_planet.PYBIND11_PLATFORM_ABI_ID,
home_planet.cpp_type_info_capsule_Traveler,
b"raw_pointer_ephemeral",
)
assert cap.__class__.__name__ == "PyCapsule"
def test_call_cpp_conduit_platform_abi_id_mismatch():
t_h = home_planet.Traveler("home")
cap = t_h._pybind11_conduit_v1_(
home_planet.PYBIND11_PLATFORM_ABI_ID + b"MISMATCH",
home_planet.cpp_type_info_capsule_Traveler,
b"raw_pointer_ephemeral",
)
assert cap is None
def test_call_cpp_conduit_cpp_type_info_capsule_mismatch():
t_h = home_planet.Traveler("home")
cap = t_h._pybind11_conduit_v1_(
home_planet.PYBIND11_PLATFORM_ABI_ID,
home_planet.cpp_type_info_capsule_int,
b"raw_pointer_ephemeral",
)
assert cap is None
def test_call_cpp_conduit_pointer_kind_invalid():
t_h = home_planet.Traveler("home")
with pytest.raises(
RuntimeError, match='^Invalid pointer_kind: "raw_pointer_ephemreal"$'
):
t_h._pybind11_conduit_v1_(
home_planet.PYBIND11_PLATFORM_ABI_ID,
home_planet.cpp_type_info_capsule_Traveler,
b"raw_pointer_ephemreal",
)
def test_home_only_basic():
t_h = home_planet.Traveler("home")
assert t_h.luggage == "home"
assert home_planet.get_luggage(t_h) == "home"
def test_home_only_premium():
p_h = home_planet.PremiumTraveler("home", 2)
assert p_h.luggage == "home"
assert home_planet.get_luggage(p_h) == "home"
assert home_planet.get_points(p_h) == 2
def test_exo_only_basic():
t_e = exo_planet_pybind11.Traveler("exo")
assert t_e.luggage == "exo"
assert exo_planet_pybind11.get_luggage(t_e) == "exo"
def test_exo_only_premium():
p_e = exo_planet_pybind11.PremiumTraveler("exo", 3)
assert p_e.luggage == "exo"
assert exo_planet_pybind11.get_luggage(p_e) == "exo"
assert exo_planet_pybind11.get_points(p_e) == 3
def test_home_passed_to_exo_basic():
t_h = home_planet.Traveler("home")
assert exo_planet_pybind11.get_luggage(t_h) == "home"
def test_exo_passed_to_home_basic():
t_e = exo_planet_pybind11.Traveler("exo")
assert home_planet.get_luggage(t_e) == "exo"
def test_home_passed_to_exo_premium():
p_h = home_planet.PremiumTraveler("home", 2)
assert exo_planet_pybind11.get_luggage(p_h) == "home"
assert exo_planet_pybind11.get_points(p_h) == 2
def test_exo_passed_to_home_premium():
p_e = exo_planet_pybind11.PremiumTraveler("exo", 3)
assert home_planet.get_luggage(p_e) == "exo"
assert home_planet.get_points(p_e) == 3
@pytest.mark.parametrize(
"traveler_type", [home_planet.Traveler, exo_planet_pybind11.Traveler]
)
def test_exo_planet_c_api_traveler(traveler_type):
t = traveler_type("socks")
assert exo_planet_c_api.GetLuggage(t) == "socks"
@pytest.mark.parametrize(
"premium_traveler_type",
[home_planet.PremiumTraveler, exo_planet_pybind11.PremiumTraveler],
)
def test_exo_planet_c_api_premium_traveler(premium_traveler_type):
pt = premium_traveler_type("gucci", 5)
assert exo_planet_c_api.GetLuggage(pt) == "gucci"
assert exo_planet_c_api.GetPoints(pt) == 5
def test_home_planet_wrap_very_lonely_traveler():
# This does not exercise the cpp_conduit feature, but is here to
# demonstrate that the cpp_conduit feature does not solve all
# cross-extension interoperability issues.
# Here is the proof that the following works for extensions with
# matching `PYBIND11_INTERNALS_ID`s:
# test_cpp_conduit.cpp:
# py::class_<LonelyTraveler>
# home_planet_very_lonely_traveler.cpp:
# py::class_<VeryLonelyTraveler, LonelyTraveler>
# See test_exo_planet_pybind11_wrap_very_lonely_traveler() for the negative
# test.
assert home_planet.LonelyTraveler is not None # Verify that the base class exists.
home_planet_very_lonely_traveler.wrap_very_lonely_traveler()
# Ensure that the derived class exists.
assert home_planet_very_lonely_traveler.VeryLonelyTraveler is not None
def test_exo_planet_pybind11_wrap_very_lonely_traveler():
# See comment under test_home_planet_wrap_very_lonely_traveler() first.
# Here the `PYBIND11_INTERNALS_ID`s don't match between:
# test_cpp_conduit.cpp:
# py::class_<LonelyTraveler>
# exo_planet_pybind11.cpp:
# py::class_<VeryLonelyTraveler, LonelyTraveler>
assert home_planet.LonelyTraveler is not None # Verify that the base class exists.
with pytest.raises(
RuntimeError,
match='^generic_type: type "VeryLonelyTraveler" referenced unknown base type '
'"pybind11_tests::test_cpp_conduit::LonelyTraveler"$',
):
exo_planet_pybind11.wrap_very_lonely_traveler()

View File

@ -0,0 +1,47 @@
// Copyright (c) 2024 The pybind Community.
#pragma once
#include <pybind11/pybind11.h>
#include "test_cpp_conduit_traveler_types.h"
#include <string>
namespace pybind11_tests {
namespace test_cpp_conduit {
namespace py = pybind11;
inline void wrap_traveler(py::module_ m) {
py::class_<Traveler>(m, "Traveler")
.def(py::init<std::string>())
.def_readwrite("luggage", &Traveler::luggage)
// See issue #3788:
.def("__getattr__", [](const Traveler &self, const std::string &key) {
return "Traveler GetAttr: " + key + " luggage: " + self.luggage;
});
m.def("get_luggage", [](const Traveler &person) { return person.luggage; });
py::class_<PremiumTraveler, Traveler>(m, "PremiumTraveler")
.def(py::init<std::string, int>())
.def_readwrite("points", &PremiumTraveler::points)
// See issue #3788:
.def("__getattr__", [](const PremiumTraveler &self, const std::string &key) {
return "PremiumTraveler GetAttr: " + key + " points: " + std::to_string(self.points);
});
m.def("get_points", [](const PremiumTraveler &person) { return person.points; });
}
inline void wrap_lonely_traveler(py::module_ m) {
py::class_<LonelyTraveler>(std::move(m), "LonelyTraveler");
}
inline void wrap_very_lonely_traveler(py::module_ m) {
py::class_<VeryLonelyTraveler, LonelyTraveler>(std::move(m), "VeryLonelyTraveler");
}
} // namespace test_cpp_conduit
} // namespace pybind11_tests

View File

@ -0,0 +1,25 @@
// Copyright (c) 2024 The pybind Community.
#pragma once
#include <string>
namespace pybind11_tests {
namespace test_cpp_conduit {
struct Traveler {
explicit Traveler(const std::string &luggage) : luggage(luggage) {}
std::string luggage;
};
struct PremiumTraveler : Traveler {
explicit PremiumTraveler(const std::string &luggage, int points)
: Traveler(luggage), points(points) {}
int points;
};
struct LonelyTraveler {};
struct VeryLonelyTraveler : LonelyTraveler {};
} // namespace test_cpp_conduit
} // namespace pybind11_tests

View File

@ -9,7 +9,7 @@ import env # noqa: F401
from pybind11_tests import custom_type_setup as m
@pytest.fixture()
@pytest.fixture
def gc_tester():
"""Tests that an object is garbage collected.

View File

@ -55,7 +55,7 @@ void reset_refs() {
}
// Returns element 2,1 from a matrix (used to test copy/nocopy)
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); }
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
// reference is referencing rows/columns correctly).
@ -76,7 +76,7 @@ struct CustomOperatorNew {
Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
TEST_SUBMODULE(eigen_matrix, m) {

View File

@ -111,6 +111,16 @@ struct PythonAlreadySetInDestructor {
py::str s;
};
struct CustomData {
explicit CustomData(const std::string &a) : a(a) {}
std::string a;
};
struct MyException7 {
explicit MyException7(const CustomData &message) : message(message) {}
CustomData message;
};
TEST_SUBMODULE(exceptions, m) {
m.def("throw_std_exception",
[]() { throw std::runtime_error("This exception was intentionally thrown."); });
@ -385,4 +395,33 @@ TEST_SUBMODULE(exceptions, m) {
// m.def("pass_exception_void", [](const py::exception<void>&) {}); // Does not compile.
m.def("return_exception_void", []() { return py::exception<void>(); });
m.def("throws7", []() {
auto data = CustomData("abc");
throw MyException7(data);
});
py::class_<CustomData>(m, "CustomData", py::module_local())
.def(py::init<const std::string &>())
.def_readwrite("a", &CustomData::a);
PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object>
PythonMyException7_storage;
PythonMyException7_storage.call_once_and_store_result([&]() {
auto mod = py::module_::import("custom_exceptions");
py::object obj = mod.attr("PythonMyException7");
return obj;
});
py::register_local_exception_translator([](std::exception_ptr p) {
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const MyException7 &e) {
auto exc_type = PythonMyException7_storage.get_stored();
py::object exc_inst = exc_type(e.message);
PyErr_SetObject(PyExc_Exception, exc_inst.ptr());
}
});
}

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import sys
import pytest
from custom_exceptions import PythonMyException7
import env
import pybind11_cross_module_tests as cm
@ -195,6 +196,10 @@ def test_custom(msg):
raise RuntimeError("Exception error: caught child from parent") from err
assert msg(excinfo.value) == "this is a helper-defined translated exception"
with pytest.raises(PythonMyException7) as excinfo:
m.throws7()
assert msg(excinfo.value) == "[PythonMyException7]: abc"
def test_nested_throws(capture):
"""Tests nested (e.g. C++ -> Python -> C++) exception handling"""

View File

@ -24,7 +24,7 @@ def test_dtypes():
)
@pytest.fixture()
@pytest.fixture
def arr():
return np.array([[1, 2, 3], [4, 5, 6]], "=u2")

View File

@ -18,7 +18,7 @@
// This also deliberately doesn't use the below StringList type alias to test
// that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator`
// bit is just the default `std::vector` allocator).
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)
using StringList = std::vector<std::string, std::allocator<std::string>>;

View File

@ -13,6 +13,14 @@
#include <utility>
//__has_include has been part of C++17, no need to check it
#if defined(PYBIND11_CPP20) && __has_include(<ranges>)
# if !defined(PYBIND11_COMPILER_CLANG) || __clang_major__ >= 16 // llvm/llvm-project#52696
# define PYBIND11_TEST_PYTYPES_HAS_RANGES
# include <ranges>
# endif
#endif
namespace external {
namespace detail {
bool check(PyObject *o) { return PyFloat_Check(o) != 0; }
@ -923,4 +931,59 @@ TEST_SUBMODULE(pytypes, m) {
#else
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
#endif
#if defined(PYBIND11_TEST_PYTYPES_HAS_RANGES)
// test_tuple_ranges
m.def("tuple_iterator_default_initialization", []() {
using TupleIterator = decltype(std::declval<py::tuple>().begin());
static_assert(std::random_access_iterator<TupleIterator>);
return TupleIterator{} == TupleIterator{};
});
m.def("transform_tuple_plus_one", [](py::tuple &tpl) {
py::list ret{};
for (auto it : tpl | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
ret.append(py::int_(it));
}
return ret;
});
// test_list_ranges
m.def("list_iterator_default_initialization", []() {
using ListIterator = decltype(std::declval<py::list>().begin());
static_assert(std::random_access_iterator<ListIterator>);
return ListIterator{} == ListIterator{};
});
m.def("transform_list_plus_one", [](py::list &lst) {
py::list ret{};
for (auto it : lst | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
ret.append(py::int_(it));
}
return ret;
});
// test_dict_ranges
m.def("dict_iterator_default_initialization", []() {
using DictIterator = decltype(std::declval<py::dict>().begin());
static_assert(std::forward_iterator<DictIterator>);
return DictIterator{} == DictIterator{};
});
m.def("transform_dict_plus_one", [](py::dict &dct) {
py::list ret{};
for (auto it : dct | std::views::transform([](auto &o) {
return std::pair{py::cast<int>(o.first) + 1,
py::cast<int>(o.second) + 1};
})) {
ret.append(py::make_tuple(py::int_(it.first), py::int_(it.second)));
}
return ret;
});
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = true;
#else
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false;
#endif
}

View File

@ -1026,7 +1026,7 @@ def test_optional_object_annotations(doc):
@pytest.mark.skipif(
not m.defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL,
reason="C++20 feature not available.",
reason="C++20 non-type template args feature not available.",
)
def test_literal(doc):
assert (
@ -1037,7 +1037,7 @@ def test_literal(doc):
@pytest.mark.skipif(
not m.defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL,
reason="C++20 feature not available.",
reason="C++20 non-type template args feature not available.",
)
def test_typevar(doc):
assert (
@ -1048,3 +1048,45 @@ def test_typevar(doc):
assert doc(m.annotate_listT_to_T) == "annotate_listT_to_T(arg0: list[T]) -> T"
assert doc(m.annotate_object_to_T) == "annotate_object_to_T(arg0: object) -> T"
@pytest.mark.skipif(
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
reason="<ranges> not available.",
)
@pytest.mark.parametrize(
("tested_tuple", "expected"),
[((1,), [2]), ((3, 4), [4, 5]), ((7, 8, 9), [8, 9, 10])],
)
def test_tuple_ranges(tested_tuple, expected):
assert m.tuple_iterator_default_initialization()
assert m.transform_tuple_plus_one(tested_tuple) == expected
@pytest.mark.skipif(
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
reason="<ranges> not available.",
)
@pytest.mark.parametrize(
("tested_list", "expected"), [([1], [2]), ([3, 4], [4, 5]), ([7, 8, 9], [8, 9, 10])]
)
def test_list_ranges(tested_list, expected):
assert m.list_iterator_default_initialization()
assert m.transform_list_plus_one(tested_list) == expected
@pytest.mark.skipif(
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
reason="<ranges> not available.",
)
@pytest.mark.parametrize(
("tested_dict", "expected"),
[
({1: 2}, [(2, 3)]),
({3: 4, 5: 6}, [(4, 5), (6, 7)]),
({7: 8, 9: 10, 11: 12}, [(8, 9), (10, 11), (12, 13)]),
],
)
def test_dict_ranges(tested_dict, expected):
assert m.dict_iterator_default_initialization()
assert m.transform_dict_plus_one(tested_dict) == expected

View File

@ -86,8 +86,8 @@ private:
};
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>)
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>)
template <typename PythonType>
py::list test_random_access_iterator(PythonType x) {

View File

@ -11,6 +11,9 @@
#include "object.h"
#include "pybind11_tests.h"
// This breaks on PYBIND11_DECLARE_HOLDER_TYPE
PYBIND11_WARNING_DISABLE_GCC("-Wpedantic")
namespace {
// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
@ -279,13 +282,13 @@ struct holder_helper<ref<T>> {
} // namespace PYBIND11_NAMESPACE
// Make pybind aware of the ref-counted wrapper type (s):
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true)
// The following is not required anymore for std::shared_ptr, but it should compile without error:
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>)
TEST_SUBMODULE(smart_ptr, m) {
// Please do not interleave `struct` and `class` definitions with bindings code,

View File

@ -59,7 +59,7 @@ struct visit_helper<boost::variant> {
} // namespace PYBIND11_NAMESPACE
#endif
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)
/// Issue #528: templated constructor
struct TplCtorClass {
@ -201,6 +201,23 @@ TEST_SUBMODULE(stl, m) {
m.def("cast_array", []() { return std::array<int, 2>{{1, 2}}; });
m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
struct NoDefaultCtor {
explicit constexpr NoDefaultCtor(int val) : val{val} {}
int val;
};
struct NoDefaultCtorArray {
explicit constexpr NoDefaultCtorArray(int i)
: arr{{NoDefaultCtor(10 + i), NoDefaultCtor(20 + i)}} {}
std::array<NoDefaultCtor, 2> arr;
};
// test_array_no_default_ctor
py::class_<NoDefaultCtor>(m, "NoDefaultCtor").def_readonly("val", &NoDefaultCtor::val);
py::class_<NoDefaultCtorArray>(m, "NoDefaultCtorArray")
.def(py::init<int>())
.def_readwrite("arr", &NoDefaultCtorArray::arr);
// test_valarray
m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
m.def("load_valarray", [](const std::valarray<int> &v) {

View File

@ -48,6 +48,13 @@ def test_array(doc):
)
def test_array_no_default_ctor():
lst = m.NoDefaultCtorArray(3)
assert [e.val for e in lst.arr] == [13, 23]
lst.arr = m.NoDefaultCtorArray(4).arr
assert [e.val for e in lst.arr] == [14, 24]
def test_valarray(doc):
"""std::valarray <-> list"""
lst = m.cast_valarray()

View File

@ -145,4 +145,4 @@ TEST_SUBMODULE(tagbased_polymorphic, m) {
.def(py::init<std::string>())
.def("purr", &Panther::purr);
m.def("create_zoo", &create_zoo);
};
}

View File

@ -589,4 +589,4 @@ void initialize_inherited_virtuals(py::module_ &m) {
// Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
m.def("test_gil", &test_gil);
m.def("test_gil_from_thread", &test_gil_from_thread);
};
}

46
tests/test_warnings.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
tests/test_warnings.cpp -- usage of warnings::warn() and warnings categories.
Copyright (c) 2024 Jan Iwaszkiewicz <jiwaszkiewicz6@gmail.com>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include <pybind11/warnings.h>
#include "pybind11_tests.h"
#include <utility>
TEST_SUBMODULE(warnings_, m) {
// Test warning mechanism base
m.def("warn_and_return_value", []() {
std::string message = "This is simple warning";
py::warnings::warn(message.c_str(), PyExc_Warning);
return 21;
});
m.def("warn_with_default_category", []() { py::warnings::warn("This is RuntimeWarning"); });
m.def("warn_with_different_category",
[]() { py::warnings::warn("This is FutureWarning", PyExc_FutureWarning); });
m.def("warn_with_invalid_category",
[]() { py::warnings::warn("Invalid category", PyExc_Exception); });
// Test custom warnings
PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> ex_storage;
ex_storage.call_once_and_store_result([&]() {
return py::warnings::new_warning_type(m, "CustomWarning", PyExc_DeprecationWarning);
});
m.def("warn_with_custom_type", []() {
py::warnings::warn("This is CustomWarning", ex_storage.get_stored());
return 37;
});
m.def("register_duplicate_warning",
[m]() { py::warnings::new_warning_type(m, "CustomWarning", PyExc_RuntimeWarning); });
}

68
tests/test_warnings.py Normal file
View File

@ -0,0 +1,68 @@
from __future__ import annotations
import warnings
import pytest
import pybind11_tests # noqa: F401
from pybind11_tests import warnings_ as m
@pytest.mark.parametrize(
("expected_category", "expected_message", "expected_value", "module_function"),
[
(Warning, "This is simple warning", 21, m.warn_and_return_value),
(RuntimeWarning, "This is RuntimeWarning", None, m.warn_with_default_category),
(FutureWarning, "This is FutureWarning", None, m.warn_with_different_category),
],
)
def test_warning_simple(
expected_category, expected_message, expected_value, module_function
):
with pytest.warns(Warning) as excinfo:
value = module_function()
assert issubclass(excinfo[0].category, expected_category)
assert str(excinfo[0].message) == expected_message
assert value == expected_value
def test_warning_wrong_subclass_fail():
with pytest.raises(Exception) as excinfo:
m.warn_with_invalid_category()
assert issubclass(excinfo.type, RuntimeError)
assert (
str(excinfo.value)
== "pybind11::warnings::warn(): cannot raise warning, category must be a subclass of PyExc_Warning!"
)
def test_warning_double_register_fail():
with pytest.raises(Exception) as excinfo:
m.register_duplicate_warning()
assert issubclass(excinfo.type, RuntimeError)
assert (
str(excinfo.value)
== 'pybind11::warnings::new_warning_type(): an attribute with name "CustomWarning" exists already.'
)
def test_warning_register():
assert m.CustomWarning is not None
with pytest.warns(m.CustomWarning) as excinfo:
warnings.warn("This is warning from Python!", m.CustomWarning, stacklevel=1)
assert issubclass(excinfo[0].category, DeprecationWarning)
assert str(excinfo[0].message) == "This is warning from Python!"
def test_warning_custom():
with pytest.warns(m.CustomWarning) as excinfo:
value = m.warn_with_custom_type()
assert issubclass(excinfo[0].category, DeprecationWarning)
assert str(excinfo[0].message) == "This is CustomWarning"
assert value == 37

View File

@ -18,11 +18,7 @@ Adds the following functions::
#]======================================================]
# CMake 3.10 has an include_guard command, but we can't use that yet
# include_guard(global) (pre-CMake 3.10)
if(TARGET pybind11::pybind11)
return()
endif()
include_guard(GLOBAL)
# If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we
# are in CONFIG mode, they should be "normal" targets instead.
@ -80,47 +76,31 @@ set_property(
# Please open an issue if you need to use it; it will be removed if no one
# needs it.
if(CMAKE_SYSTEM_NAME MATCHES Emscripten AND NOT _pybind11_no_exceptions)
if(CMAKE_VERSION VERSION_LESS 3.13)
message(WARNING "CMake 3.13+ is required to build for Emscripten. Some flags will be missing")
if(is_config)
set(_tmp_config_target pybind11::pybind11_headers)
else()
if(is_config)
set(_tmp_config_target pybind11::pybind11_headers)
else()
set(_tmp_config_target pybind11_headers)
endif()
set_property(
TARGET ${_tmp_config_target}
APPEND
PROPERTY INTERFACE_LINK_OPTIONS -fexceptions)
set_property(
TARGET ${_tmp_config_target}
APPEND
PROPERTY INTERFACE_COMPILE_OPTIONS -fexceptions)
unset(_tmp_config_target)
set(_tmp_config_target pybind11_headers)
endif()
set_property(
TARGET ${_tmp_config_target}
APPEND
PROPERTY INTERFACE_LINK_OPTIONS -fexceptions)
set_property(
TARGET ${_tmp_config_target}
APPEND
PROPERTY INTERFACE_COMPILE_OPTIONS -fexceptions)
unset(_tmp_config_target)
endif()
# --------------------------- link helper ---------------------------
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
if(CMAKE_VERSION VERSION_LESS 3.13)
# In CMake 3.11+, you can set INTERFACE properties via the normal methods, and
# this would be simpler.
set_property(
TARGET pybind11::python_link_helper
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES "$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>")
else()
# link_options was added in 3.13+
# This is safer, because you are ensured the deduplication pass in CMake will not consider
# these separate and remove one but not the other.
set_property(
TARGET pybind11::python_link_helper
APPEND
PROPERTY INTERFACE_LINK_OPTIONS "$<$<PLATFORM_ID:Darwin>:LINKER:-undefined,dynamic_lookup>")
endif()
set_property(
TARGET pybind11::python_link_helper
APPEND
PROPERTY INTERFACE_LINK_OPTIONS "$<$<PLATFORM_ID:Darwin>:LINKER:-undefined,dynamic_lookup>")
# ------------------------ Windows extras -------------------------
@ -136,22 +116,14 @@ if(MSVC) # That's also clang-cl
# /MP enables multithreaded builds (relevant when there are many files) for MSVC
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # no Clang no Intel
if(CMAKE_VERSION VERSION_LESS 3.11)
set_property(
TARGET pybind11::windows_extras
APPEND
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<NOT:$<CONFIG:Debug>>:/MP>)
else()
# Only set these options for C++ files. This is important so that, for
# instance, projects that include other types of source files like CUDA
# .cu files don't get these options propagated to nvcc since that would
# cause the build to fail.
set_property(
TARGET pybind11::windows_extras
APPEND
PROPERTY INTERFACE_COMPILE_OPTIONS
$<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>)
endif()
# Only set these options for C++ files. This is important so that, for
# instance, projects that include other types of source files like CUDA
# .cu files don't get these options propagated to nvcc since that would
# cause the build to fail.
set_property(
TARGET pybind11::windows_extras
APPEND
PROPERTY INTERFACE_COMPILE_OPTIONS $<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>)
endif()
endif()
@ -397,11 +369,7 @@ function(_pybind11_generate_lto target prefer_thin_lto)
set(is_debug "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>")
set(not_debug "$<NOT:${is_debug}>")
set(cxx_lang "$<COMPILE_LANGUAGE:CXX>")
if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11)
set(genex "${not_debug}")
else()
set(genex "$<AND:${not_debug},${cxx_lang}>")
endif()
set(genex "$<AND:${not_debug},${cxx_lang}>")
set_property(
TARGET ${target}
APPEND
@ -416,17 +384,10 @@ function(_pybind11_generate_lto target prefer_thin_lto)
endif()
if(PYBIND11_LTO_LINKER_FLAGS)
if(CMAKE_VERSION VERSION_LESS 3.11)
set_property(
TARGET ${target}
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
else()
set_property(
TARGET ${target}
APPEND
PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
endif()
set_property(
TARGET ${target}
APPEND
PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
endif()
endfunction()

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.15...3.30)
function(pybind11_guess_python_module_extension python)

View File

@ -5,10 +5,6 @@
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
if(CMAKE_VERSION VERSION_LESS 3.12)
message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12")
endif()
include_guard(DIRECTORY)
get_property(
@ -236,7 +232,6 @@ if(TARGET ${_Python}::Python)
PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Python)
endif()
# CMake 3.15+ has this
if(TARGET ${_Python}::Module)
set_property(
TARGET pybind11::module
@ -279,10 +274,6 @@ function(pybind11_add_module target_name)
target_link_libraries(${target_name} PRIVATE pybind11::embed)
endif()
if(MSVC)
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
endif()
# -fvisibility=hidden is required to allow multiple modules compiled against
# different pybind versions to work properly, and for some features (e.g.
# py::module_local). We force it on everything inside the `pybind11`

View File

@ -5,13 +5,7 @@
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# include_guard(global) (pre-CMake 3.10)
if(TARGET pybind11::python_headers)
return()
endif()
# Built-in in CMake 3.5+
include(CMakeParseArguments)
include_guard(GLOBAL)
if(pybind11_FIND_QUIETLY)
set(_pybind11_quiet QUIET)
@ -116,36 +110,19 @@ if(PYTHON_IS_DEBUG)
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
endif()
# The <3.11 code here does not support release/debug builds at the same time, like on vcpkg
if(CMAKE_VERSION VERSION_LESS 3.11)
set_property(
TARGET pybind11::module
APPEND
PROPERTY
INTERFACE_LINK_LIBRARIES
pybind11::python_link_helper
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>"
)
# The IMPORTED INTERFACE library here is to ensure that "debug" and "release" get processed outside
# of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are
# target_link_library keywords rather than real libraries.
add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE)
target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES})
target_link_libraries(
pybind11::module
INTERFACE
pybind11::python_link_helper
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:pybind11::_ClassicPythonLibraries>")
set_property(
TARGET pybind11::embed
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
else()
# The IMPORTED INTERFACE library here is to ensure that "debug" and "release" get processed outside
# of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are
# target_link_library keywords rather than real libraries.
add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE)
target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES})
target_link_libraries(
pybind11::module
INTERFACE
pybind11::python_link_helper
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:pybind11::_ClassicPythonLibraries>")
target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11
pybind11::_ClassicPythonLibraries)
endif()
target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11
pybind11::_ClassicPythonLibraries)
function(pybind11_extension name)
# The prefix and extension are provided by FindPythonLibsNew.cmake

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.15...3.30)
# Tests for pybind11_guess_python_module_extension
# Run using `cmake -P tools/test-pybind11GuessPythonExtSuffix.cmake`