From 5b7c0b04b9f9993912808da444de3b2ebdc65e80 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 13 Sep 2024 16:59:50 -0400 Subject: [PATCH 1/7] docs: update changelog for 2.13.6 (#5372) * docs: update changelog for 2.13.6 Signed-off-by: Henry Schreiner * docs: mention supported versions --------- Signed-off-by: Henry Schreiner --- docs/changelog.rst | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0145317743..a91082113f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -31,6 +31,37 @@ New Features: * The ``array_caster`` in pybind11/stl.h was enhanced to support value types that are not default-constructible. `#5305 `_ +* Added ``py::warnings`` namespace with ``py::warnings::warn`` and ``py::warnings::new_warning_type`` that provides the interface for Python warnings. + `#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 `_ + + +Bug fixes: + +* Using ``__cpp_nontype_template_args`` instead of ``__cpp_nontype_template_parameter_class``. + `#5330 `_ + +* Properly translate C++ exception to Python exception when creating Python buffer from wrapped object. + `#5324 `_ + + +Documentation: + +* Adds an answer (FAQ) for "What is a highly conclusive and simple way to find memory leaks?". + `#5340 `_ + + Version 2.13.5 (August 22, 2024) -------------------------------- @@ -238,6 +269,18 @@ Other: * Update docs and noxfile. `#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 `_ + Version 2.12.0 (March 27, 2024) ------------------------------- @@ -413,6 +456,18 @@ Other: * An ``assert()`` was added to help Coverty avoid generating a false positive. `#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 `_ + Version 2.11.1 (July 17, 2023) ------------------------------ From 0cf3a0f7b514b3a3fb541ad3197964fa5c4da554 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 13 Sep 2024 20:21:43 -0400 Subject: [PATCH 2/7] ci: PyPI attestations (#5374) --- .github/workflows/pip.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index a2c4dba6bc..3713537379 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -91,11 +91,12 @@ 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 @@ -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 From a7910be6307e442297e55c84901a96dd0d046e93 Mon Sep 17 00:00:00 2001 From: "Bobby R. Bruce" Date: Sat, 14 Sep 2024 23:51:50 -0700 Subject: [PATCH 3/7] 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. --- include/pybind11/pybind11.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 5219c0ff85..c52df969e6 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1382,7 +1382,17 @@ class generic_type : public object { } 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) { From 1d9483ff735cc0f7fad391f03e9db2716cf5bbfb Mon Sep 17 00:00:00 2001 From: vfdev Date: Tue, 17 Sep 2024 18:47:20 +0200 Subject: [PATCH 4/7] 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> --- .../pybind11/detail/exception_translation.h | 22 +++++------ include/pybind11/detail/internals.h | 20 +++++++++- include/pybind11/pybind11.h | 21 +++++----- tests/custom_exceptions.py | 10 +++++ tests/test_exceptions.cpp | 39 +++++++++++++++++++ tests/test_exceptions.py | 5 +++ 6 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 tests/custom_exceptions.py diff --git a/include/pybind11/detail/exception_translation.h b/include/pybind11/detail/exception_translation.h index 2764180bb0..22ae8a1c94 100644 --- a/include/pybind11/detail/exception_translation.h +++ b/include/pybind11/detail/exception_translation.h @@ -50,17 +50,17 @@ inline void try_translate_exceptions() { - 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; - }); + bool handled = with_exception_translators( + [&](std::forward_list &exception_translators, + std::forward_list &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!"); diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 7cc6f53adf..fa224e0326 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -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 registered_types_cpp; @@ -643,6 +648,19 @@ inline auto with_internals(const F &cb) -> decltype(cb(get_internals())) { return cb(internals); } +template +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 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. diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c52df969e6..bcdf641f43 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2586,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(translator)); - }); + detail::with_exception_translators( + [&](std::forward_list &exception_translators, + std::forward_list &local_exception_translators) { + (void) local_exception_translators; + exception_translators.push_front(std::forward(translator)); + }); } /** @@ -2599,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(translator)); - }); + detail::with_exception_translators( + [&](std::forward_list &exception_translators, + std::forward_list &local_exception_translators) { + (void) exception_translators; + local_exception_translators.push_front(std::forward(translator)); + }); } /** diff --git a/tests/custom_exceptions.py b/tests/custom_exceptions.py new file mode 100644 index 0000000000..b1a092d761 --- /dev/null +++ b/tests/custom_exceptions.py @@ -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 diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index c1d05bb241..0a970065b4 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -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&) {}); // Does not compile. m.def("return_exception_void", []() { return py::exception(); }); + + m.def("throws7", []() { + auto data = CustomData("abc"); + throw MyException7(data); + }); + + py::class_(m, "CustomData", py::module_local()) + .def(py::init()) + .def_readwrite("a", &CustomData::a); + + PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store + 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()); + } + }); } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index ba5063a749..a8fd105ea0 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -3,6 +3,7 @@ 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""" From ad9fd39e143c8296a49a1b5b258cb6aa24e23889 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 10:19:17 -0700 Subject: [PATCH 5/7] 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/emscripten.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/emscripten.yaml b/.github/workflows/emscripten.yaml index 14b2b9dc7d..79c783e7fe 100644 --- a/.github/workflows/emscripten.yaml +++ b/.github/workflows/emscripten.yaml @@ -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: From 1f8b4a7f1a1c5cc9bd6e0d63fe15540e6c458b24 Mon Sep 17 00:00:00 2001 From: Hintay Date: Fri, 20 Sep 2024 00:24:35 +0900 Subject: [PATCH 6/7] fix(cmake): `NO_EXTRAS` in `pybind11_add_module` function partially working (#5378) --- tools/pybind11NewTools.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake index d3e938fab0..8bac211e14 100644 --- a/tools/pybind11NewTools.cmake +++ b/tools/pybind11NewTools.cmake @@ -274,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` From 7e418f49243bb7d13fa92cf2634af1eeac386465 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Tue, 24 Sep 2024 18:28:22 +0100 Subject: [PATCH 7/7] Allow subclasses of py::args and py::kwargs (#5381) * Allow subclasses of py::args and py::kwargs The current implementation does not allow subclasses of args or kwargs. This change allows subclasses to be used. * Added test case * style: pre-commit fixes * Added missing semi-colons * style: pre-commit fixes * Added handle_type_name * Moved classes outside of function * Added namespaces * style: pre-commit fixes * Refactored tests Added more tests and moved tests to more appropriate locations. * style: pre-commit fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/cast.h | 4 ++-- tests/test_kwargs_and_defaults.cpp | 26 ++++++++++++++++++++++++++ tests/test_kwargs_and_defaults.py | 11 +++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 0c862e4bec..e3c8b9f659 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1570,9 +1570,9 @@ class argument_loader { using indices = make_index_sequence; template - using argument_is_args = std::is_same, args>; + using argument_is_args = std::is_base_of>; template - using argument_is_kwargs = std::is_same, kwargs>; + using argument_is_kwargs = std::is_base_of>; // Get kwargs argument position, or -1 if not present: static constexpr auto kwargs_pos = constexpr_last(); diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index bc76ec7c2d..09036ccd51 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -14,6 +14,26 @@ #include +// Classes needed for subclass test. +class ArgsSubclass : public py::args { + using py::args::args; +}; +class KWArgsSubclass : public py::kwargs { + using py::kwargs::kwargs; +}; +namespace pybind11 { +namespace detail { +template <> +struct handle_type_name { + static constexpr auto name = const_name("*Args"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("**KWArgs"); +}; +} // namespace detail +} // namespace pybind11 + TEST_SUBMODULE(kwargs_and_defaults, m) { auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; @@ -322,4 +342,10 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::pos_only{}, py::arg("i"), py::arg("j")); + + // Test support for args and kwargs subclasses + m.def("args_kwargs_subclass_function", + [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { + return py::make_tuple(args, kwargs); + }); } diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index b9b1a7ea87..e3f758165c 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -17,6 +17,10 @@ def test_function_signatures(doc): assert ( doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" ) + assert ( + doc(m.args_kwargs_subclass_function) + == "args_kwargs_subclass_function(*Args, **KWArgs) -> tuple" + ) assert ( doc(m.KWClass.foo0) == "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None" @@ -98,6 +102,7 @@ def test_arg_and_kwargs(): args = "a1", "a2" kwargs = {"arg3": "a3", "arg4": 4} assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs) + assert m.args_kwargs_subclass_function(*args, **kwargs) == (args, kwargs) def test_mixed_args_and_kwargs(msg): @@ -413,6 +418,12 @@ def test_args_refcount(): ) assert refcount(myval) == expected + assert m.args_kwargs_subclass_function(7, 8, myval, a=1, b=myval) == ( + (7, 8, myval), + {"a": 1, "b": myval}, + ) + assert refcount(myval) == expected + exp3 = refcount(myval, myval, myval) assert m.args_refcount(myval, myval, myval) == (exp3, exp3, exp3) assert refcount(myval) == expected