From 14cde218ef05d7568e2eac9672d1566093c1edf6 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 20 Sep 2024 11:28:13 +0100 Subject: [PATCH 01/11] 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. --- include/pybind11/cast.h | 4 ++-- 1 file changed, 2 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(); From 82906b97c1a05e84e0c64a1df30c729afda5a32b Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 20 Sep 2024 18:57:50 +0100 Subject: [PATCH 02/11] Added test case --- tests/test_kwargs_and_defaults.cpp | 12 ++++++++++++ tests/test_kwargs_and_defaults.py | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index bc76ec7c2d..f82db75437 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -322,4 +322,16 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::pos_only{}, py::arg("i"), py::arg("j")); + + // Test support for args and kwargs subclasses + class ArgsSubclass: public py::args{ + using py::args::args; + } + class KWArgsSubclass: public py::kwargs{ + using py::kwargs::kwargs; + } + 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..8c9d46b041 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -426,3 +426,8 @@ def test_args_refcount(): assert m.mixed_args_refcount(myval, myval, myval) == (exp3_3, exp3_3, exp3_3) assert m.class_default_argument() == "" + + assert m.args_kwargs_subclass_function(7, 8, myval, a=1, b=myval) == ( + (7, 8, myval), + {"a": 1, "b": myval}, + ) From 82c99336cad32660b217f45de01e78859dc58d99 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:58:16 +0000 Subject: [PATCH 03/11] style: pre-commit fixes --- tests/test_kwargs_and_defaults.cpp | 16 +++++++--------- tests/test_kwargs_and_defaults.py | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index f82db75437..5d9298749d 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -322,16 +322,14 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::pos_only{}, py::arg("i"), py::arg("j")); - + // Test support for args and kwargs subclasses - class ArgsSubclass: public py::args{ + class ArgsSubclass : public py::args { using py::args::args; - } - class KWArgsSubclass: public py::kwargs{ + } class KWArgsSubclass : public py::kwargs { using py::kwargs::kwargs; - } - m.def("args_kwargs_subclass_function", [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { - return py::make_tuple(args, kwargs); - }); - + } 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 8c9d46b041..ac1f71a903 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -426,7 +426,7 @@ def test_args_refcount(): assert m.mixed_args_refcount(myval, myval, myval) == (exp3_3, exp3_3, exp3_3) assert m.class_default_argument() == "" - + assert m.args_kwargs_subclass_function(7, 8, myval, a=1, b=myval) == ( (7, 8, myval), {"a": 1, "b": myval}, From 4aaf8bb35fc405345cc8fc73967e70bc97ff3db4 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 20 Sep 2024 19:24:38 +0100 Subject: [PATCH 04/11] Added missing semi-colons --- tests/test_kwargs_and_defaults.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 5d9298749d..738e9e6575 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -324,12 +324,13 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::arg("j")); // Test support for args and kwargs subclasses - class ArgsSubclass : public py::args { + class ArgsSubclass: public py::args{ using py::args::args; - } class KWArgsSubclass : public py::kwargs { + }; + class KWArgsSubclass: public py::kwargs{ using py::kwargs::kwargs; - } m.def("args_kwargs_subclass_function", - [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { - return py::make_tuple(args, kwargs); - }); + }; + m.def("args_kwargs_subclass_function", [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { + return py::make_tuple(args, kwargs); + }); } From ce5e7be7f841f628a307f7d6097946c5517d495e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 18:25:09 +0000 Subject: [PATCH 05/11] style: pre-commit fixes --- tests/test_kwargs_and_defaults.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 738e9e6575..31386f181e 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -324,13 +324,14 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::arg("j")); // Test support for args and kwargs subclasses - class ArgsSubclass: public py::args{ + class ArgsSubclass : public py::args { using py::args::args; }; - class KWArgsSubclass: public py::kwargs{ + class KWArgsSubclass : public py::kwargs { using py::kwargs::kwargs; }; - m.def("args_kwargs_subclass_function", [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { - return py::make_tuple(args, kwargs); - }); + m.def("args_kwargs_subclass_function", + [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { + return py::make_tuple(args, kwargs); + }); } From 4f54b374fbc51338175d619e893074e9572af494 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 20 Sep 2024 20:10:49 +0100 Subject: [PATCH 06/11] Added handle_type_name --- tests/test_kwargs_and_defaults.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 31386f181e..4586d98abc 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -330,6 +330,14 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { class KWArgsSubclass : public py::kwargs { using py::kwargs::kwargs; }; + template <> + struct handle_type_name { + static constexpr auto name = const_name("*args"); + }; + template <> + struct handle_type_name { + static constexpr auto name = const_name("**kwargs"); + }; m.def("args_kwargs_subclass_function", [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { return py::make_tuple(args, kwargs); From 97c6798f72259f4b91989e506ea4d0be3f2a68a1 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 20 Sep 2024 20:17:28 +0100 Subject: [PATCH 07/11] Moved classes outside of function --- tests/test_kwargs_and_defaults.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 4586d98abc..30ecd9bd9f 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -14,6 +14,22 @@ #include +// Classes needed for subclass test. +class ArgsSubclass : public py::args { + using py::args::args; +}; +class KWArgsSubclass : public py::kwargs { + using py::kwargs::kwargs; +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("*args"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("**kwargs"); +}; + TEST_SUBMODULE(kwargs_and_defaults, m) { auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; @@ -324,20 +340,6 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::arg("j")); // Test support for args and kwargs subclasses - class ArgsSubclass : public py::args { - using py::args::args; - }; - class KWArgsSubclass : public py::kwargs { - using py::kwargs::kwargs; - }; - template <> - struct handle_type_name { - static constexpr auto name = const_name("*args"); - }; - template <> - struct handle_type_name { - static constexpr auto name = const_name("**kwargs"); - }; m.def("args_kwargs_subclass_function", [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { return py::make_tuple(args, kwargs); From 19503bfd31acc9a611a03deaec1912f7d2b6139e Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Fri, 20 Sep 2024 20:21:46 +0100 Subject: [PATCH 08/11] Added namespaces --- tests/test_kwargs_and_defaults.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 30ecd9bd9f..03c1212734 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -21,14 +21,19 @@ class ArgsSubclass : public py::args { class KWArgsSubclass : public py::kwargs { using py::kwargs::kwargs; }; -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 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"); + }; + } +} + TEST_SUBMODULE(kwargs_and_defaults, m) { auto kw_func From b74f295c9d9f7447192f105535f1aaec170cee99 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 19:22:07 +0000 Subject: [PATCH 09/11] style: pre-commit fixes --- tests/test_kwargs_and_defaults.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 03c1212734..afa9956c31 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -22,18 +22,17 @@ 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 { +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 From 00ad6a583ecb382f48fc88b730c4254b6dd4f5c1 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Tue, 24 Sep 2024 09:17:12 +0100 Subject: [PATCH 10/11] Refactored tests Added more tests and moved tests to more appropriate locations. --- tests/test_kwargs_and_defaults.cpp | 4 ++-- tests/test_kwargs_and_defaults.py | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index afa9956c31..09036ccd51 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -25,11 +25,11 @@ namespace pybind11 { namespace detail { template <> struct handle_type_name { - static constexpr auto name = const_name("*args"); + static constexpr auto name = const_name("*Args"); }; template <> struct handle_type_name { - static constexpr auto name = const_name("**kwargs"); + static constexpr auto name = const_name("**KWArgs"); }; } // namespace detail } // namespace pybind11 diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index ac1f71a903..e3d3a32719 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -17,6 +17,9 @@ 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 +101,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): @@ -412,6 +416,12 @@ def test_args_refcount(): {"a": 1, "b": myval}, ) 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) @@ -426,8 +436,3 @@ def test_args_refcount(): assert m.mixed_args_refcount(myval, myval, myval) == (exp3_3, exp3_3, exp3_3) assert m.class_default_argument() == "" - - assert m.args_kwargs_subclass_function(7, 8, myval, a=1, b=myval) == ( - (7, 8, myval), - {"a": 1, "b": myval}, - ) From 2bcdea6a09dcc0317aa97377d907e87e9d4c5f57 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 08:17:39 +0000 Subject: [PATCH 11/11] style: pre-commit fixes --- tests/test_kwargs_and_defaults.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index e3d3a32719..e3f758165c 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -18,7 +18,8 @@ def test_function_signatures(doc): 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" + doc(m.args_kwargs_subclass_function) + == "args_kwargs_subclass_function(*Args, **KWArgs) -> tuple" ) assert ( doc(m.KWClass.foo0) @@ -416,7 +417,7 @@ def test_args_refcount(): {"a": 1, "b": myval}, ) assert refcount(myval) == expected - + assert m.args_kwargs_subclass_function(7, 8, myval, a=1, b=myval) == ( (7, 8, myval), {"a": 1, "b": myval},