From b456ffb6e30073997ef94e98cf96b67b2fddc605 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 22 Apr 2024 15:58:05 -0700 Subject: [PATCH 01/12] Use `PYBIND11_TYPE_CASTER_RVPP` in pybind11/functional.h (all existing unit tests pass as-is) --- include/pybind11/functional.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index 0ac53f8e..4acf3dd2 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -134,11 +134,11 @@ struct type_caster> { return cpp_function(std::forward(f_), rvpp).release(); } - PYBIND11_TYPE_CASTER(type, - const_name("Callable[[") - + ::pybind11::detail::concat(make_caster::name...) - + const_name("], ") + make_caster::name - + const_name("]")); + PYBIND11_TYPE_CASTER_RVPP(type, + const_name("Callable[[") + + ::pybind11::detail::concat(make_caster::name...) + + const_name("], ") + make_caster::name + + const_name("]")); }; PYBIND11_NAMESPACE_END(detail) From e8f595bb85b95317ce4d1dbb3d04951d3f56e89a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:35:03 -0400 Subject: [PATCH 02/12] 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](https://github.com/actions/attest-build-provenance/compare/310b0a4a3b0b78ef57ecda988ee04b132db73ef8...6149ea5740be74af77f260b9db67e633f6b0a9a1) --- 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] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pip.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index 3edfa612..af397166 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -102,7 +102,7 @@ jobs: - 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@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 with: subject-path: "*/pybind11*" From 3fb16ad17587a7ad7fbe18c043e790d68ee7fab4 Mon Sep 17 00:00:00 2001 From: ObeliskGate <96614155+ObeliskGate@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:36:03 +0800 Subject: [PATCH 03/12] 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 --- include/pybind11/typing.h | 4 +--- tests/test_pytypes.py | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index b0feb946..84aaf9f7 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -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 struct StringLiteral { diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 1c6335f7..6f015eec 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -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 ( From 5ed381daac5035cad9745824f96d04e7a35924e7 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 27 Aug 2024 00:23:51 +0700 Subject: [PATCH 04/12] Replace all SMART_HOLDER_WIP comments with reminders, notes, or pointers. (#5336) The SMART_HOLDER_WIP comments are mostly from 2021. In the meantime, the smart_holder code was extremely thoroughly tested in the Google codebase (production code). Additionally, testing via PyCLIF-pybind11 provided thousands of diverse use cases that needed to satisfy many million unit tests (the success rate was about 99.999%). --- include/pybind11/detail/struct_smart_holder.h | 15 +++++++++------ include/pybind11/detail/type_caster_base.h | 9 ++++----- include/pybind11/trampoline_self_life_support.h | 5 ++--- ...test_class_sh_trampoline_shared_ptr_cpp_arg.py | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index b1e24d7b..980fc369 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -215,7 +215,7 @@ struct smart_holder { // race conditions, but in the context of Python it is a bug (elsewhere) // if the Global Interpreter Lock (GIL) is not being held when this code // is reached. - // SMART_HOLDER_WIP: IMPROVABLE: assert(GIL is held). + // PYBIND11:REMINDER: This may need to be protected by a mutex in free-threaded Python. if (vptr.use_count() != 1) { throw std::invalid_argument(std::string("Cannot disown use_count != 1 (") + context + ")."); @@ -277,29 +277,32 @@ struct smart_holder { return hld; } - // Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details). + // Caller is responsible for ensuring the complex preconditions + // (see `smart_holder_type_caster_support::load_helper`). void disown() { reset_vptr_deleter_armed_flag(false); is_disowned = true; } - // Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details). + // Caller is responsible for ensuring the complex preconditions + // (see `smart_holder_type_caster_support::load_helper`). void reclaim_disowned() { reset_vptr_deleter_armed_flag(true); is_disowned = false; } - // Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details). + // Caller is responsible for ensuring the complex preconditions + // (see `smart_holder_type_caster_support::load_helper`). void release_disowned() { vptr.reset(); } - // SMART_HOLDER_WIP: review this function. void ensure_can_release_ownership(const char *context = "ensure_can_release_ownership") const { ensure_is_not_disowned(context); ensure_vptr_is_using_builtin_delete(context); ensure_use_count_1(context); } - // Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details). + // Caller is responsible for ensuring the complex preconditions + // (see `smart_holder_type_caster_support::load_helper`). void release_ownership() { reset_vptr_deleter_armed_flag(false); release_disowned(); diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index f1a5d0d8..7cdeabdc 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -475,7 +475,7 @@ inline PyObject *make_new_instance(PyTypeObject *type); #ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT -// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. +// PYBIND11:REMINDER: Needs refactoring of existing pybind11 code. inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support) @@ -568,8 +568,7 @@ handle smart_holder_from_unique_ptr(std::unique_ptr &&src, if (static_cast(src.get()) == src_raw_void_ptr) { // This is a multiple-inheritance situation that is incompatible with the current - // shared_from_this handling (see PR #3023). - // SMART_HOLDER_WIP: IMPROVABLE: Is there a better solution? + // shared_from_this handling (see PR #3023). Is there a better solution? src_raw_void_ptr = nullptr; } auto smhldr = smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr); @@ -623,8 +622,8 @@ handle smart_holder_from_shared_ptr(const std::shared_ptr &src, void *src_raw_void_ptr = static_cast(src_raw_ptr); const detail::type_info *tinfo = st.second; if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { - // SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder. - // SMART_HOLDER_WIP: MISSING: keep_alive. + // PYBIND11:REMINDER: MISSING: Enforcement of consistency with existing smart_holder. + // PYBIND11:REMINDER: MISSING: keep_alive. return existing_inst; } diff --git a/include/pybind11/trampoline_self_life_support.h b/include/pybind11/trampoline_self_life_support.h index cef69632..a30ffda3 100644 --- a/include/pybind11/trampoline_self_life_support.h +++ b/include/pybind11/trampoline_self_life_support.h @@ -15,14 +15,13 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) -// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. +// PYBIND11:REMINDER: Needs refactoring of existing pybind11 code. inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); PYBIND11_NAMESPACE_END(detail) // The original core idea for this struct goes back to PyCLIF: // https://github.com/google/clif/blob/07f95d7e69dca2fcf7022978a55ef3acff506c19/clif/python/runtime.cc#L37 -// URL provided here mainly to give proper credit. To fully explain the `HoldPyObj` feature, more -// context is needed (SMART_HOLDER_WIP). +// URL provided here mainly to give proper credit. struct trampoline_self_life_support { detail::value_and_holder v_h; diff --git a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py index 13daeee2..85977542 100644 --- a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py +++ b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py @@ -62,7 +62,7 @@ def test_shared_ptr_arg_identity(): del obj pytest.gc_collect() - # SMART_HOLDER_WIP: the behavior below is DIFFERENT from PR #2839 + # NOTE: the behavior below is DIFFERENT from PR #2839 # python reference is gone because it is not an Alias instance assert objref() is None assert tester.has_python_instance() is False From f99ffd7e03001810a3e722bf48ad1a9e08415d7d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 27 Aug 2024 01:56:00 +0700 Subject: [PATCH 05/12] Remove test_classh_mock.cpp,py (#5338) --- tests/CMakeLists.txt | 1 - tests/test_classh_mock.cpp | 73 -------------------------------------- tests/test_classh_mock.py | 13 ------- 3 files changed, 87 deletions(-) delete mode 100644 tests/test_classh_mock.cpp delete mode 100644 tests/test_classh_mock.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 99843ee4..53de1cd9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -132,7 +132,6 @@ set(PYBIND11_TEST_FILES test_class_sh_unique_ptr_custom_deleter test_class_sh_unique_ptr_member test_class_sh_virtual_py_cpp_mix - test_classh_mock test_const_name test_constants_and_functions test_copy_move diff --git a/tests/test_classh_mock.cpp b/tests/test_classh_mock.cpp deleted file mode 100644 index 51be4ae0..00000000 --- a/tests/test_classh_mock.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "pybind11_tests.h" - -// The main purpose of this test was to ensure that the suggested -// BOILERPLATE code block (NOW DEPRECATED!) block below is correct. - -// Copy this block of code into your project. -// Replace FOOEXT with the name of your project. -// BOILERPLATE BEGIN DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED -#ifdef FOOEXT_USING_PYBIND11_SMART_HOLDER -# include -#else -# include -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -# ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT -template -using classh = class_; -# endif -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) -# ifndef PYBIND11_SH_AVL -# define PYBIND11_SH_AVL(...) std::shared_ptr<__VA_ARGS__> // "Smart_Holder if AVaiLable" -# endif -# ifndef PYBIND11_SH_DEF -# define PYBIND11_SH_DEF(...) std::shared_ptr<__VA_ARGS__> // "Smart_Holder if DEFault" -# endif -# ifndef PYBIND11_SMART_HOLDER_TYPE_CASTERS -# define PYBIND11_SMART_HOLDER_TYPE_CASTERS(...) -# endif -# ifndef PYBIND11_TYPE_CASTER_BASE_HOLDER -# define PYBIND11_TYPE_CASTER_BASE_HOLDER(...) -# endif -#endif -// BOILERPLATE END DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - -namespace { -struct FooUc {}; -struct FooUp {}; -struct FooSa {}; -struct FooSc {}; -struct FooSp {}; -} // namespace - -PYBIND11_SMART_HOLDER_TYPE_CASTERS(FooUp) // DEPRECATED -PYBIND11_SMART_HOLDER_TYPE_CASTERS(FooSp) // DEPRECATED - -PYBIND11_TYPE_CASTER_BASE_HOLDER(FooSa, std::shared_ptr) - -TEST_SUBMODULE(classh_mock, m) { - // Please see README_smart_holder.rst, in particular section - // Classic / Conservative / Progressive cross-module compatibility - - // Uses std::unique_ptr as holder in Classic or Conservative mode, py::smart_holder in - // Progressive mode. - py::class_(m, "FooUc").def(py::init<>()); - - // Uses std::unique_ptr as holder in Classic mode, py::smart_holder in Conservative or - // Progressive mode. - py::classh(m, "FooUp").def(py::init<>()); - - // Always uses std::shared_ptr as holder. - py::class_>(m, "FooSa").def(py::init<>()); - - // Uses std::shared_ptr as holder in Classic or Conservative mode, py::smart_holder in - // Progressive mode. - py::class_(m, "FooSc").def(py::init<>()); - // -------------- std::shared_ptr -- same length by design, to not disturb the - // indentation of existing code. - - // Uses std::shared_ptr as holder in Classic mode, py::smart_holder in Conservative or - // Progressive mode. - py::class_(m, "FooSp").def(py::init<>()); - // -------------- std::shared_ptr -- same length by design, to not disturb the - // indentation of existing code. -} diff --git a/tests/test_classh_mock.py b/tests/test_classh_mock.py deleted file mode 100644 index b05cd0c5..00000000 --- a/tests/test_classh_mock.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from pybind11_tests import classh_mock as m - - -def test_foobar(): - # Not really testing anything in particular. The main purpose of this test is to ensure the - # suggested BOILERPLATE code block in test_classh_mock.cpp is correct. - assert m.FooUc() - assert m.FooUp() - assert m.FooSa() - assert m.FooSc() - assert m.FooSp() From 86e9f25dfcf95b44a78a48139e2650103b34253a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Aug 2024 14:09:54 -0700 Subject: [PATCH 06/12] Systematically replace all google/pybind11k with google/pybind11clif, except in README.md --- docs/classes.rst | 2 +- include/pybind11/detail/class.h | 2 +- include/pybind11/detail/function_record_pyobject.h | 2 +- include/pybind11/pybind11.h | 2 +- tests/test_pickling.cpp | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/classes.rst b/docs/classes.rst index a38ca6ea..f5ba2b94 100644 --- a/docs/classes.rst +++ b/docs/classes.rst @@ -557,4 +557,4 @@ The ``name`` property returns the name of the enum value as a unicode string. .. note:: ``py::native_enum`` was added as an alternative to ``py::enum_`` - with http://github.com/google/pybind11k/pull/30005 + with http://github.com/google/pybind11clif/pull/30005 diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 26498df6..1426bde6 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -198,7 +198,7 @@ inline bool ensure_base_init_functions_were_called(PyObject *self) { return true; } -// See google/pybind11k#30095 for background. +// See google/pybind11clif#30095 for background. #if !defined(PYBIND11_INIT_SAFETY_CHECKS_VIA_INTERCEPTING_TP_INIT) \ && !defined(PYBIND11_INIT_SAFETY_CHECKS_VIA_DEFAULT_PYBIND11_METACLASS) # if !defined(PYPY_VERSION) diff --git a/include/pybind11/detail/function_record_pyobject.h b/include/pybind11/detail/function_record_pyobject.h index be434112..9acaba6a 100644 --- a/include/pybind11/detail/function_record_pyobject.h +++ b/include/pybind11/detail/function_record_pyobject.h @@ -2,7 +2,7 @@ // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// For background see the description of PR google/pybind11k#30099. +// For background see the description of PR google/pybind11clif#30099. #pragma once diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index accba3fe..7ccedcaf 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -414,7 +414,7 @@ class cpp_function : public function { if (rec->name == nullptr) { rec->name = guarded_strdup(""); } else if (std::strcmp(rec->name, "__setstate__[non-constructor]") == 0) { - // See google/pybind11k#30094 for background. + // See google/pybind11clif#30094 for background. rec->name = guarded_strdup("__setstate__"); } else { rec->name = guarded_strdup(rec->name); diff --git a/tests/test_pickling.cpp b/tests/test_pickling.cpp index 831dd924..85d5cb69 100644 --- a/tests/test_pickling.cpp +++ b/tests/test_pickling.cpp @@ -65,7 +65,7 @@ void wrap(py::module m) { namespace exercise_getinitargs_getstate_setstate { -// Exercise `__setstate__[non-constructor]` (see google/pybind11k#30094), which +// Exercise `__setstate__[non-constructor]` (see google/pybind11clif#30094), which // was added to support a pickle protocol as established with Boost.Python // (in 2002): // https://www.boost.org/doc/libs/1_31_0/libs/python/doc/v2/pickle.html @@ -103,7 +103,7 @@ void wrap(py::module m) { }, py::arg("protocol") = -1) .def( - "__setstate__[non-constructor]", // See google/pybind11k#30094 for background. + "__setstate__[non-constructor]", // See google/pybind11clif#30094 for background. [](StoreTwoWithState *self, const std::string &state) { self->SetState(state); }, py::arg("state")); } From 6c67dace764592b6f1547ed3e6423c6559b02f41 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 26 Aug 2024 15:24:12 -0700 Subject: [PATCH 07/12] Reduce README.rst to a minimum. --- README.rst | 197 +++-------------------------------------------------- 1 file changed, 11 insertions(+), 186 deletions(-) diff --git a/README.rst b/README.rst index f554ae9d..85f85750 100644 --- a/README.rst +++ b/README.rst @@ -1,193 +1,18 @@ -=========================================================================== -pybind11k — A fork of pybind11 set up for sustained innovation & continuity -=========================================================================== +============================================================================ +pybind11clif — A fork of pybind11 to support the PyCLIF-pybind11 unification +============================================================================ -Warning — New features are still in flux -======================================== +WARNING — The PyCLIF-pybind11 unification was SUSPENDED. +======================================================== -pybind11k is used Google-internally to build thousands of extensions that are deployed to production and is also regularly tested with all CLANG sanitizers. However, feature stability guarantees are currently limited in this way: +Possibly, **THIS FORK WILL NO LONGER BE UPDATED**. -0. pybind11k is meant to maximize backward-compatiblity with `pybind11 (master) `_. +Please use the upstream project: https://github.com/pybind/pybind11 -1. The main driving force for adding new features is the PyCLIF-pybind11 integration work (for Googlers: `go/pyclif_pybind11_fusion `_). Until this work is completed, it is impractical for us to take external use cases into account when evolving new features. This is because we can globally test changes fairly easily internally, but not externally. +For completeness, this repo was renamed twice: -2. After the PyCLIF-pybind11 work is completed we will commit to greater feature stability and update the documentation. +* Originally the name was google/pywrapcc (Feb 2023), -Outstanding new features: ``py::native_enum`` (google/pybind11k#30005), ``py::return_value_policy_pack`` (google/pybind11k#30011), enhanced pybind11/functional.h API (google/pybind11k#30022) +* then google/pybind11k (Apr 2024), -Background / Overview -===================== - -This pybind11k fork originated from the `pybind11 smart_holder `_ branch. It was created with two important goals in mind: - -1. Sustained innovation and proactive bug fixes. -2. Sustained continuity. - -With original pybind11, these two goals are in a conflict. In the early days of pybind11 this was not so much of a problem, but this has been changing with growing adoption. - -Regarding goal 1: pybind11 has two serious long-standing bugs (pybind/pybind11#1138, pybind/pybind11#1333) that have never been fixed on the master branch, but were fixed on the smart_holder branch in early-mid 2021. - -Regarding goal 2: The original and still current ``pybind11::smart_holder`` implementation is a compromise solution that avoids an `"ABI break" `_, concretely, changes to the ``pybind11::details::internals`` ``struct``. Each time the ``internals`` are changed, the ``PYBIND11_INTERNALS_VERSION`` needs to be incremented, cutting off interoperability with existing PyPI wheels based on pybind11, without giving any hint about this problem at runtime. In the meantime, two other PRs were merged on the pybind11 master branch that require changes to the ``internals``, PRs pybind/pybind11#3275 and pybind/pybind11#4254. To avoid ABI breaks, these PRs were effectively held back behind ``#ifdef`` s. This problem came to a breaking point with PR pybind/pybind11#4329, for which hiding the new feature behind ``#ifdef`` s is not a practical option. - -Obviously, neither repeatedly breaking interoperability with existing PyPI wheels, nor holding back bug fixes and new features, is desirable. Therefore PR pybind/pybind11#4329 was extended to include a generalization of the ``internals`` approach, under the name ``cross_extension_shared_state``. The fundamental difference is that established shared state is left untouched, and new shared states are added as needed, largely resolving the conflict between innovation & continuity. The price to pay is added complexity managing the evolving shared states, but that is assumed to be a relatively small extra effort for a few developers, resulting in a big usability gain for a much larger number of users. Ultimately, this is just the familiar innovate-deprecate-cleanup life cycle typical for many (all?) long-term successful major projects (e.g. C++, Python). Even pybind11k developers are likely to see this as a win worth paying a price for, because they are more free to innovate. - -A direct consequence of goal 2. is that the C++ pybind11 namespace cannot abruptly be changed, because renaming would break both API and ABI compatibility. The intent is to change the API gradually, driven primarily by code health and innovation-related refactoring needs. - -Notes regarding the choice of name for this fork -================================================ - -The main motivations for this choice of name are: - -* We want it to be immediately obvious that pybind11k is rooted in pybind11. Users should not be surprised to find that the main include is still ``pybind11/pybind11.h``, the C++ namespace name is still ``pybind11``, the C++ macros are still prefixed with ``PYBIND11_``, and that ``pip install pybind11k`` (not yet available) produces an installation similar to that of ``pip install pybind11``. - -* ``11k`` is short for ``11000``, not to be taken too seriously, but it is meant to signal that we will inevitably need to move beyond the C++11 standard, and that any software needs to evolve to survive long-term. - -* And yes, the ``k`` is also playing on `"Py3k" `_. - -ORIGINAL pybind11 README below (to be updated) -============================================== - -**pybind11** is a lightweight header-only library that exposes C++ types -in Python and vice versa, mainly to create Python bindings of existing -C++ code. Its goals and syntax are similar to the excellent -`Boost.Python `_ -library by David Abrahams: to minimize boilerplate code in traditional -extension modules by inferring type information using compile-time -introspection. - -The main issue with Boost.Python—and the reason for creating such a -similar project—is Boost. Boost is an enormously large and complex suite -of utility libraries that works with almost every C++ compiler in -existence. This compatibility has its cost: arcane template tricks and -workarounds are necessary to support the oldest and buggiest of compiler -specimens. Now that C++11-compatible compilers are widely available, -this heavy machinery has become an excessively large and unnecessary -dependency. - -Think of this library as a tiny self-contained version of Boost.Python -with everything stripped away that isn't relevant for binding -generation. Without comments, the core header files only require ~4K -lines of code and depend on Python (3.8+, or PyPy) and the C++ -standard library. This compact implementation was possible thanks to -some C++11 language features (specifically: tuples, lambda functions and -variadic templates). Since its creation, this library has grown beyond -Boost.Python in many ways, leading to dramatically simpler binding code in many -common situations. - -Tutorial and reference documentation is provided at -`pybind11.readthedocs.io `_. -A PDF version of the manual is available -`here `_. -And the source code is always available at -`github.com/pybind/pybind11 `_. - - -Core features -------------- - - -pybind11 can map the following core C++ features to Python: - -- Functions accepting and returning custom data structures per value, - reference, or pointer -- Instance methods and static methods -- Overloaded functions -- Instance attributes and static attributes -- Arbitrary exception types -- Enumerations -- Callbacks -- Iterators and ranges -- Custom operators -- Single and multiple inheritance -- STL data structures -- Smart pointers with reference counting like ``std::shared_ptr`` -- Internal references with correct reference counting -- C++ classes with virtual (and pure virtual) methods can be extended - in Python -- Integrated NumPy support (NumPy 2 requires pybind11 2.12+) - -Goodies -------- - -In addition to the core functionality, pybind11 provides some extra -goodies: - -- Python 3.8+, and PyPy3 7.3 are supported with an implementation-agnostic - interface (pybind11 2.9 was the last version to support Python 2 and 3.5). - -- It is possible to bind C++11 lambda functions with captured - variables. The lambda capture data is stored inside the resulting - Python function object. - -- pybind11 uses C++11 move constructors and move assignment operators - whenever possible to efficiently transfer custom data types. - -- It's easy to expose the internal storage of custom data types through - Pythons' buffer protocols. This is handy e.g. for fast conversion - between C++ matrix classes like Eigen and NumPy without expensive - copy operations. - -- pybind11 can automatically vectorize functions so that they are - transparently applied to all entries of one or more NumPy array - arguments. - -- Python's slice-based access and assignment operations can be - supported with just a few lines of code. - -- Everything is contained in just a few header files; there is no need - to link against any additional libraries. - -- Binaries are generally smaller by a factor of at least 2 compared to - equivalent bindings generated by Boost.Python. A recent pybind11 - conversion of PyRosetta, an enormous Boost.Python binding project, - `reported `_ - a binary size reduction of **5.4x** and compile time reduction by - **5.8x**. - -- Function signatures are precomputed at compile time (using - ``constexpr``), leading to smaller binaries. - -- With little extra effort, C++ types can be pickled and unpickled - similar to regular Python objects. - -Supported compilers -------------------- - -1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or - newer) -2. GCC 4.8 or newer -3. Microsoft Visual Studio 2017 or newer -4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI) -5. Cygwin/GCC (previously tested on 2.5.1) -6. NVCC (CUDA 11.0 tested in CI) -7. NVIDIA PGI (20.9 tested in CI) - -About ------ - -This project was created by `Wenzel -Jakob `_. Significant features and/or -improvements to the code were contributed by Jonas Adler, Lori A. Burns, -Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel -Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov, Johan Mabille, Tomasz Miąsko, -Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim -Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart. - -We thank Google for a generous financial contribution to the continuous -integration infrastructure used by this project. - - -Contributing -~~~~~~~~~~~~ - -See the `contributing -guide `_ -for information on building and contributing to pybind11. - -License -~~~~~~~ - -pybind11 is provided under a BSD-style license that can be found in the -`LICENSE `_ -file. By using, distributing, or contributing to this project, you agree -to the terms and conditions of this license. +* then google/pybind11clif (Aug 2024). From 65f4266cefc48401fadd4623f5af430359a6866d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 28 Aug 2024 11:04:48 +0700 Subject: [PATCH 08/12] Add `while True` & `top` method to FAQ. (#5340) --- docs/faq.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/faq.rst b/docs/faq.rst index 92777b5b..31e33f8b 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -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 ============================================= From 66c3774a6402224b1724329c81c880e76633a92b Mon Sep 17 00:00:00 2001 From: Jan Iwaszkiewicz Date: Thu, 29 Aug 2024 05:55:50 +0200 Subject: [PATCH 09/12] 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 --- CMakeLists.txt | 3 +- include/pybind11/warnings.h | 75 ++++++++++++++++++++++++ tests/CMakeLists.txt | 3 +- tests/extra_python_package/test_files.py | 1 + tests/test_warnings.cpp | 46 +++++++++++++++ tests/test_warnings.py | 68 +++++++++++++++++++++ 6 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 include/pybind11/warnings.h create mode 100644 tests/test_warnings.cpp create mode 100644 tests/test_warnings.py diff --git a/CMakeLists.txt b/CMakeLists.txt index ed297194..a641925e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,7 +160,8 @@ 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) diff --git a/include/pybind11/warnings.h b/include/pybind11/warnings.h new file mode 100644 index 00000000..263b2990 --- /dev/null +++ b/include/pybind11/warnings.h @@ -0,0 +1,75 @@ +/* + pybind11/warnings.h: Python warnings wrappers. + + Copyright (c) 2024 Jan Iwaszkiewicz + + 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(".") + 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(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) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cd94ef3e..d2156f46 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -154,7 +154,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" .. diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 0a5db901..7ad9b806 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -47,6 +47,7 @@ "include/pybind11/stl_bind.h", "include/pybind11/type_caster_pyobject_ptr.h", "include/pybind11/typing.h", + "include/pybind11/warnings.h", } detail_headers = { diff --git a/tests/test_warnings.cpp b/tests/test_warnings.cpp new file mode 100644 index 00000000..e76f2124 --- /dev/null +++ b/tests/test_warnings.cpp @@ -0,0 +1,46 @@ +/* + tests/test_warnings.cpp -- usage of warnings::warn() and warnings categories. + + Copyright (c) 2024 Jan Iwaszkiewicz + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include + +#include "pybind11_tests.h" + +#include + +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 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); }); +} diff --git a/tests/test_warnings.py b/tests/test_warnings.py new file mode 100644 index 00000000..4313432c --- /dev/null +++ b/tests/test_warnings.py @@ -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 From 6fdebcc2aa6916a837f15cf603094248855621c1 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 28 Aug 2024 23:49:29 -0700 Subject: [PATCH 10/12] Transfer pybind11/cast.h diff from cl/627122374 (originally 2024-04-22). --- include/pybind11/cast.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 7d485f63..c0f38fd7 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1943,6 +1943,18 @@ struct arg : detail::arg_base { template arg_v operator=(T &&value) const; + /// Same as `arg_base::noconvert()`, but returns *this as arg&, not arg_base& + arg &noconvert(bool flag = true) { + arg_base::noconvert(flag); + return *this; + } + + /// Same as `arg_base::noconvert()`, but returns *this as arg&, not arg_base& + arg &none(bool flag = true) { + arg_base::none(flag); + return *this; + } + arg &policies(const from_python_policies &policies) { m_policies = policies; return *this; @@ -2013,6 +2025,12 @@ struct arg_v : arg { return *this; } + /// Same as `arg::policies()`, but returns *this as arg_v&, not arg& + arg_v &policies(const from_python_policies &policies) { + arg::policies(policies); + return *this; + } + /// The default value object value; bool value_is_nullptr = false; From d1a6d597b9dc8321a95056da3856f5b9523643f5 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 29 Aug 2024 01:28:08 -0700 Subject: [PATCH 11/12] Add tests. --- tests/test_return_value_policy_pack.cpp | 46 +++++++++++++++++++++++++ tests/test_return_value_policy_pack.py | 30 ++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/tests/test_return_value_policy_pack.cpp b/tests/test_return_value_policy_pack.cpp index 2e021b6d..dd2f5c12 100644 --- a/tests/test_return_value_policy_pack.cpp +++ b/tests/test_return_value_policy_pack.cpp @@ -436,4 +436,50 @@ TEST_SUBMODULE(return_value_policy_pack, m) { py::class_(m, "IntOwner").def_readonly("val", &IntOwner::val); m.def("call_callback_pass_int_owner_const_ptr", call_callback_pass_int_owner_const_ptr); + + // Ensure chaining py::arg() member functions works. + m.def( + "arg_chaining_noconvert_policies", + [](const std::function &cb) { + return cb("\x80" + "ArgNoconvertPolicies"); + }, + py::arg("cb").noconvert().policies(py::return_value_policy_pack({rvpb})), + rvpb); + m.def( + "arg_chaining_none_policies", + [](const std::function &cb) { + return cb("\x80" + "ArgNonePolicies"); + }, + py::arg("cb").none().policies(py::return_value_policy_pack({rvpb})), + rvpb); + m.def( + "arg_chaining_policies_noconvert", + [](const std::function &cb) { + return cb("\x80" + "ArgPoliciesNoconvert"); + }, + py::arg("cb").policies(py::return_value_policy_pack({rvpb})).noconvert(), + rvpb); + + // Ensure chaining py::arg_v() member functions works. + // This does not look very useful, but .policies() chaining was added because + // chaining for .noconvert() and .none() existed already. + m.def( + "arg_v_chaining_noconvert", + [](int num) { return num + 10; }, + (py::arg("num") = 2).noconvert()); + m.def("arg_v_chaining_none", [](int num) { return num + 20; }, (py::arg("num") = 3).none()); + m.def( + "arg_v_chaining_none_policies", + [](const std::function &cb) { + if (cb) { + return cb("\x80" + "ArgvNonePolicies"); + } + return std::string(""); + }, + (py::arg("cb") = py::none()).policies(py::return_value_policy_pack({rvpb})), + rvpb); } diff --git a/tests/test_return_value_policy_pack.py b/tests/test_return_value_policy_pack.py index 022ae644..8b45dc9b 100644 --- a/tests/test_return_value_policy_pack.py +++ b/tests/test_return_value_policy_pack.py @@ -337,3 +337,33 @@ def cb(int_owner): return int_owner.val + 40 assert m.call_callback_pass_int_owner_const_ptr(cb) == 543 + + +@pytest.mark.parametrize( + ("fn", "expected"), + [ + (m.arg_chaining_noconvert_policies, b"\x80ArgNoconvertPolicies"), + (m.arg_chaining_none_policies, b"\x80ArgNonePolicies"), + (m.arg_chaining_policies_noconvert, b"\x80ArgPoliciesNoconvert"), + ], +) +def test_arg_chaining(fn, expected): + assert fn(lambda arg: arg + b"Extra") == expected + b"Extra" + + +def test_arg_v_chaining_noconvert(): + assert m.arg_v_chaining_noconvert() == 12 + assert m.arg_v_chaining_noconvert(4) == 14 + + +def test_arg_v_chaining_none(): + assert m.arg_v_chaining_none() == 23 + assert m.arg_v_chaining_none(5) == 25 + + +def test_arg_v_chaining_none_policies(): + assert m.arg_v_chaining_none_policies() == b"" + assert ( + m.arg_v_chaining_none_policies(lambda arg: arg + b"Extra") + == b"\x80ArgvNonePoliciesExtra" + ) From 8535cd3f38f5f611b0181be7d5f0a34b36aee2bb Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 29 Aug 2024 01:46:56 -0700 Subject: [PATCH 12/12] Remove stray `{}`: ``` /__w/pybind11clif/pybind11clif/tests/test_return_value_policy_pack.cpp:447:73: error: braces around scalar initializer [-Werror,-Wbraced-scalar-init] 447 | py::arg("cb").noconvert().policies(py::return_value_policy_pack({rvpb})), | ^~~~~~ ``` --- tests/test_return_value_policy_pack.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_return_value_policy_pack.cpp b/tests/test_return_value_policy_pack.cpp index dd2f5c12..84da0dce 100644 --- a/tests/test_return_value_policy_pack.cpp +++ b/tests/test_return_value_policy_pack.cpp @@ -444,7 +444,7 @@ TEST_SUBMODULE(return_value_policy_pack, m) { return cb("\x80" "ArgNoconvertPolicies"); }, - py::arg("cb").noconvert().policies(py::return_value_policy_pack({rvpb})), + py::arg("cb").noconvert().policies(py::return_value_policy_pack(rvpb)), rvpb); m.def( "arg_chaining_none_policies", @@ -452,7 +452,7 @@ TEST_SUBMODULE(return_value_policy_pack, m) { return cb("\x80" "ArgNonePolicies"); }, - py::arg("cb").none().policies(py::return_value_policy_pack({rvpb})), + py::arg("cb").none().policies(py::return_value_policy_pack(rvpb)), rvpb); m.def( "arg_chaining_policies_noconvert", @@ -460,7 +460,7 @@ TEST_SUBMODULE(return_value_policy_pack, m) { return cb("\x80" "ArgPoliciesNoconvert"); }, - py::arg("cb").policies(py::return_value_policy_pack({rvpb})).noconvert(), + py::arg("cb").policies(py::return_value_policy_pack(rvpb)).noconvert(), rvpb); // Ensure chaining py::arg_v() member functions works. @@ -480,6 +480,6 @@ TEST_SUBMODULE(return_value_policy_pack, m) { } return std::string(""); }, - (py::arg("cb") = py::none()).policies(py::return_value_policy_pack({rvpb})), + (py::arg("cb") = py::none()).policies(py::return_value_policy_pack(rvpb)), rvpb); }