diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 4708101d80..3c6f72abdf 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1465,21 +1465,24 @@ template <> struct handle_type_name { static constexpr auto name = const_name("weakref.ReferenceType"); }; +// args/Args/kwargs/KWArgs have name as well as typehint included template <> struct handle_type_name { - static constexpr auto name = const_name("*args"); + static constexpr auto name = io_name("*args", "tuple"); }; template struct handle_type_name> { - static constexpr auto name = const_name("*args: ") + make_caster::name; + static constexpr auto name + = io_name("*args: ", "tuple[") + make_caster::name + io_name("", ", ...]"); }; template <> struct handle_type_name { - static constexpr auto name = const_name("**kwargs"); + static constexpr auto name = io_name("**kwargs", "dict[str, typing.Any]"); }; template struct handle_type_name> { - static constexpr auto name = const_name("**kwargs: ") + make_caster::name; + static constexpr auto name + = io_name("**kwargs: ", "dict[str, ") + make_caster::name + io_name("", "]"); }; template <> struct handle_type_name { @@ -1905,13 +1908,20 @@ inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name, } #endif +namespace typing { +template +class Tuple : public tuple { + using tuple::tuple; +}; +} // namespace typing + template -tuple make_tuple() { +typing::Tuple<> make_tuple() { return tuple(0); } template -tuple make_tuple(Args &&...args_) { +typing::Tuple make_tuple(Args &&...args_) { constexpr size_t size = sizeof...(Args); std::array args{{reinterpret_steal( detail::make_caster::cast(std::forward(args_), policy, nullptr))...}}; @@ -1930,7 +1940,12 @@ tuple make_tuple(Args &&...args_) { for (auto &arg_value : args) { PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr()); } + PYBIND11_WARNING_PUSH +#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING + PYBIND11_WARNING_DISABLE_CLANG("-Wreturn-std-move") +#endif return result; + PYBIND11_WARNING_POP } /// \ingroup annotations diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index 9589d74d2a..d7c84cb841 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -501,9 +501,15 @@ template struct pickle_factory { - static_assert(std::is_same, intrinsic_t>::value, - "The type returned by `__getstate__` must be the same " - "as the argument accepted by `__setstate__`"); + using Ret = intrinsic_t; + using Arg = intrinsic_t; + + // Subclasses are now allowed for support between type hint and generic versions of types + // (e.g.) typing::List <--> list + static_assert(std::is_same::value || std::is_base_of::value + || std::is_base_of::value, + "The type returned by `__getstate__` must be the same or subclass of the " + "argument accepted by `__setstate__`"); remove_reference_t get; remove_reference_t set; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 8ab4681c76..5cc9e9e1c8 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -120,7 +120,8 @@ inline std::string generate_function_signature(const char *type_caster_name_fiel const auto c = *pc; if (c == '{') { // Write arg name for everything except *args and **kwargs. - is_starred = *(pc + 1) == '*'; + // Detect {@*args...} or {@**kwargs...} + is_starred = *(pc + 1) == '@' && *(pc + 2) == '*'; if (is_starred) { continue; } diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index 1715026efa..43e2187b9e 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -34,10 +34,7 @@ PYBIND11_NAMESPACE_BEGIN(typing) There is no additional enforcement of types at runtime. */ -template -class Tuple : public tuple { - using tuple::tuple; -}; +// Tuple type hint defined in cast.h for use in py::make_tuple to avoid circular includes template class Dict : public dict { diff --git a/tests/test_factory_constructors.cpp b/tests/test_factory_constructors.cpp index a387cd2e76..e50494b33a 100644 --- a/tests/test_factory_constructors.cpp +++ b/tests/test_factory_constructors.cpp @@ -376,10 +376,14 @@ TEST_SUBMODULE(factory_constructors, m) { py::print("noisy placement new"); return p; } - static void operator delete(void *p, size_t) { + static void operator delete(void *p) noexcept { py::print("noisy delete"); ::operator delete(p); } + static void operator delete(void *p, size_t) { + py::print("noisy delete size"); + ::operator delete(p); + } static void operator delete(void *, void *) { py::print("noisy placement delete"); } }; diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index b62e4b7412..4a8c6bd6bb 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -34,11 +34,12 @@ def test_function_signatures(doc): ) assert doc(m.args_function) == "args_function(*args) -> tuple" assert ( - doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" + doc(m.args_kwargs_function) + == "args_kwargs_function(*args, **kwargs) -> tuple[tuple, dict[str, typing.Any]]" ) assert ( doc(m.args_kwargs_subclass_function) - == "args_kwargs_subclass_function(*args: str, **kwargs: str) -> tuple" + == "args_kwargs_subclass_function(*args: str, **kwargs: str) -> tuple[tuple[str, ...], dict[str, str]]" ) assert ( doc(m.KWClass.foo0) @@ -138,7 +139,7 @@ def test_mixed_args_and_kwargs(msg): msg(excinfo.value) == """ mixed_plus_args(): incompatible function arguments. The following argument types are supported: - 1. (arg0: typing.SupportsInt, arg1: typing.SupportsFloat, *args) -> tuple + 1. (arg0: typing.SupportsInt, arg1: typing.SupportsFloat, *args) -> tuple[int, float, tuple] Invoked with: 1 """ @@ -149,7 +150,7 @@ def test_mixed_args_and_kwargs(msg): msg(excinfo.value) == """ mixed_plus_args(): incompatible function arguments. The following argument types are supported: - 1. (arg0: typing.SupportsInt, arg1: typing.SupportsFloat, *args) -> tuple + 1. (arg0: typing.SupportsInt, arg1: typing.SupportsFloat, *args) -> tuple[int, float, tuple] Invoked with: """ @@ -183,7 +184,7 @@ def test_mixed_args_and_kwargs(msg): msg(excinfo.value) == """ mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported: - 1. (i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, **kwargs) -> tuple + 1. (i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, **kwargs) -> tuple[int, float, tuple, dict[str, typing.Any]] Invoked with: 1; kwargs: i=1 """ @@ -194,7 +195,7 @@ def test_mixed_args_and_kwargs(msg): msg(excinfo.value) == """ mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported: - 1. (i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, **kwargs) -> tuple + 1. (i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, **kwargs) -> tuple[int, float, tuple, dict[str, typing.Any]] Invoked with: 1, 2; kwargs: j=1 """ @@ -211,7 +212,7 @@ def test_mixed_args_and_kwargs(msg): msg(excinfo.value) == """ args_kwonly(): incompatible function arguments. The following argument types are supported: - 1. (i: typing.SupportsInt, j: typing.SupportsFloat, *args, z: typing.SupportsInt) -> tuple + 1. (i: typing.SupportsInt, j: typing.SupportsFloat, *args, z: typing.SupportsInt) -> tuple[int, float, tuple, int] Invoked with: 2, 2.5, 22 """ @@ -233,12 +234,12 @@ def test_mixed_args_and_kwargs(msg): ) assert ( m.args_kwonly_kwargs.__doc__ - == "args_kwonly_kwargs(i: typing.SupportsInt, j: typing.SupportsFloat, *args, z: typing.SupportsInt, **kwargs) -> tuple\n" + == "args_kwonly_kwargs(i: typing.SupportsInt, j: typing.SupportsFloat, *args, z: typing.SupportsInt, **kwargs) -> tuple[int, float, tuple, int, dict[str, typing.Any]]\n" ) assert ( m.args_kwonly_kwargs_defaults.__doc__ - == "args_kwonly_kwargs_defaults(i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, z: typing.SupportsInt = 42, **kwargs) -> tuple\n" + == "args_kwonly_kwargs_defaults(i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, z: typing.SupportsInt = 42, **kwargs) -> tuple[int, float, tuple, int, dict[str, typing.Any]]\n" ) assert m.args_kwonly_kwargs_defaults() == (1, 3.14159, (), 42, {}) assert m.args_kwonly_kwargs_defaults(2) == (2, 3.14159, (), 42, {}) @@ -344,7 +345,7 @@ def test_positional_only_args(): # Mix it with args and kwargs: assert ( m.args_kwonly_full_monty.__doc__ - == "args_kwonly_full_monty(arg0: typing.SupportsInt = 1, arg1: typing.SupportsInt = 2, /, j: typing.SupportsFloat = 3.14159, *args, z: typing.SupportsInt = 42, **kwargs) -> tuple\n" + == "args_kwonly_full_monty(arg0: typing.SupportsInt = 1, arg1: typing.SupportsInt = 2, /, j: typing.SupportsFloat = 3.14159, *args, z: typing.SupportsInt = 42, **kwargs) -> tuple[int, int, float, tuple, int, dict[str, typing.Any]]\n" ) assert m.args_kwonly_full_monty() == (1, 2, 3.14159, (), 42, {}) assert m.args_kwonly_full_monty(8) == (8, 2, 3.14159, (), 42, {}) @@ -394,23 +395,23 @@ def test_positional_only_args(): def test_signatures(): assert ( m.kw_only_all.__doc__ - == "kw_only_all(*, i: typing.SupportsInt, j: typing.SupportsInt) -> tuple\n" + == "kw_only_all(*, i: typing.SupportsInt, j: typing.SupportsInt) -> tuple[int, int]\n" ) assert ( m.kw_only_mixed.__doc__ - == "kw_only_mixed(i: typing.SupportsInt, *, j: typing.SupportsInt) -> tuple\n" + == "kw_only_mixed(i: typing.SupportsInt, *, j: typing.SupportsInt) -> tuple[int, int]\n" ) assert ( m.pos_only_all.__doc__ - == "pos_only_all(i: typing.SupportsInt, j: typing.SupportsInt, /) -> tuple\n" + == "pos_only_all(i: typing.SupportsInt, j: typing.SupportsInt, /) -> tuple[int, int]\n" ) assert ( m.pos_only_mix.__doc__ - == "pos_only_mix(i: typing.SupportsInt, /, j: typing.SupportsInt) -> tuple\n" + == "pos_only_mix(i: typing.SupportsInt, /, j: typing.SupportsInt) -> tuple[int, int]\n" ) assert ( m.pos_kw_only_mix.__doc__ - == "pos_kw_only_mix(i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt) -> tuple\n" + == "pos_kw_only_mix(i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt) -> tuple[int, int, int]\n" )