From 6d98d4d8d4682d3f4ea405d1f800bf5427f5cd75 Mon Sep 17 00:00:00 2001 From: gentlegiantJGC Date: Mon, 11 Nov 2024 22:51:01 +0000 Subject: [PATCH] Add type hints for args and kwargs (#5357) * Allow subclasses of args and kwargs The current implementation disallows subclasses of args and kwargs * Added object type hint to args and kwargs * Added type hinted args and kwargs classes * Changed default type hint to typing.Any * Removed args and kwargs type hint * Updated tests Modified the tests from #5381 to use the real Args and KWArgs classes * Added comment --- include/pybind11/cast.h | 8 ++++++++ include/pybind11/pytypes.h | 12 ++++++++++++ tests/test_kwargs_and_defaults.cpp | 22 +--------------------- tests/test_kwargs_and_defaults.py | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index f6a7e83be..2ae25c2eb 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1012,10 +1012,18 @@ template <> struct handle_type_name { static constexpr auto name = const_name("*args"); }; +template +struct handle_type_name> { + static constexpr auto name = const_name("*args: ") + make_caster::name; +}; template <> struct handle_type_name { static constexpr auto name = const_name("**kwargs"); }; +template +struct handle_type_name> { + static constexpr auto name = const_name("**kwargs: ") + make_caster::name; +}; template <> struct handle_type_name { static constexpr auto name = const_name(); diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 027e36098..60d51fdcf 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -2226,6 +2226,18 @@ class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) }; +// Subclasses of args and kwargs to support type hinting +// as defined in PEP 484. See #5357 for more info. +template +class Args : public args { + using args::args; +}; + +template +class KWArgs : public kwargs { + using kwargs::kwargs; +}; + class anyset : public object { public: PYBIND11_OBJECT(anyset, object, PyAnySet_Check) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 09036ccd5..831947f16 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -14,26 +14,6 @@ #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); }; @@ -345,7 +325,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { // Test support for args and kwargs subclasses m.def("args_kwargs_subclass_function", - [](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { + [](const py::Args &args, const py::KWArgs &kwargs) { return py::make_tuple(args, kwargs); }); } diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index e3e9a0a0d..e558d8ad2 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -20,7 +20,7 @@ def test_function_signatures(doc): ) assert ( doc(m.args_kwargs_subclass_function) - == "args_kwargs_subclass_function(*Args, **KWArgs) -> tuple" + == "args_kwargs_subclass_function(*args: str, **kwargs: str) -> tuple" ) assert ( doc(m.KWClass.foo0)