From 7780fbca6c37ccc9c3c8f358f485543cfdb132af Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 19 Oct 2023 15:42:43 -0700 Subject: [PATCH 01/39] Try `Annotated[Any, "cpp_namespace::UserType"]` unconditionally. --- include/pybind11/pybind11.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index a94f6f0f13..0b4f46f6d8 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -493,7 +493,7 @@ class cpp_function : public function { } else { std::string tname(t->name()); detail::clean_type_id(tname); - signature += tname; + signature += "Annotated[Any, \"" + tname + "\"]"; } } else { signature += c; From 76b4a34aff6e7fd1ae2728588c5fd5914f7320d0 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 19 Oct 2023 15:43:55 -0700 Subject: [PATCH 02/39] Add `struct handle_type_name<...>` specializations for `object`, `list`, etc. This resolves all test failures except: ``` E - create_rec_nested(arg0: int) -> numpy.ndarray[Annotated[Any, "NestedStruct"]] ... FAILED test_numpy_dtypes.py::test_signature - assert --- actual / +++ expected ``` --- include/pybind11/cast.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 3c9b7c9273..77eb619958 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -874,6 +874,38 @@ struct handle_type_name { static constexpr auto name = const_name(); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("object"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("list"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("dict"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("set"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("frozenset"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("anyset"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("str"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("tuple"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("bool"); }; From 794d97e54e22bebb4657f47a52affa5ed76da469 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 19 Oct 2023 15:45:57 -0700 Subject: [PATCH 03/39] Revert "Add `struct handle_type_name<...>` specializations for `object`, `list`, etc." This reverts commit 76b4a34aff6e7fd1ae2728588c5fd5914f7320d0. --- include/pybind11/cast.h | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 77eb619958..3c9b7c9273 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -874,38 +874,6 @@ struct handle_type_name { static constexpr auto name = const_name(); }; template <> -struct handle_type_name { - static constexpr auto name = const_name("object"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("list"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("dict"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("set"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("frozenset"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("anyset"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("str"); -}; -template <> -struct handle_type_name { - static constexpr auto name = const_name("tuple"); -}; -template <> struct handle_type_name { static constexpr auto name = const_name("bool"); }; From 2cafdab279d080838b2219f5d66daaeb1a2fe1ba Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 19 Oct 2023 16:18:24 -0700 Subject: [PATCH 04/39] Add `cpp_name_needs_typing_annotated()` --- include/pybind11/pybind11.h | 6 +++++- include/pybind11/typing.h | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 0b4f46f6d8..35f5c13ba3 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -493,7 +493,11 @@ class cpp_function : public function { } else { std::string tname(t->name()); detail::clean_type_id(tname); - signature += "Annotated[Any, \"" + tname + "\"]"; + if (detail::cpp_name_needs_typing_annotated(tname.c_str())) { + signature += "Annotated[Any, \"" + tname + "\"]"; + } else { + signature += tname; + } } } else { signature += c; diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index b7b1a4e54a..6c2bea28ad 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -113,5 +113,15 @@ struct handle_type_name> { + const_name("]"); }; +inline bool cpp_name_needs_typing_annotated(const char *cpp_name) { + while (*cpp_name) { + char c = *cpp_name++; + if (c == ':' || c == '<') { // Assuming valid names, there is no need to check for '>'. + return true; + } + } + return false; +} + PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) From f6ae40bd0780bd9bb5f0fdcfc4c35396a9c27647 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 19 Oct 2023 21:54:15 -0700 Subject: [PATCH 05/39] clang-tidy compatibility --- include/pybind11/typing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index 6c2bea28ad..c489c6d3a6 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -114,7 +114,7 @@ struct handle_type_name> { }; inline bool cpp_name_needs_typing_annotated(const char *cpp_name) { - while (*cpp_name) { + while (*cpp_name != '\0') { char c = *cpp_name++; if (c == ':' || c == '<') { // Assuming valid names, there is no need to check for '>'. return true; From 272152e68b062749e892dbb362ced079064fd666 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 20 Oct 2023 22:10:54 -0700 Subject: [PATCH 06/39] `Annotated[Any, CppTypePybind11("cpp_namespace::UserType")]` based on a suggestion by @sizmailov https://github.com/pybind/pybind11/pull/4888#issuecomment-1773618327 --- include/pybind11/pybind11.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 35f5c13ba3..d51a0c6fb2 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -494,7 +494,7 @@ class cpp_function : public function { std::string tname(t->name()); detail::clean_type_id(tname); if (detail::cpp_name_needs_typing_annotated(tname.c_str())) { - signature += "Annotated[Any, \"" + tname + "\"]"; + signature += "Annotated[Any, CppTypePybind11(\"" + tname + "\")]"; } else { signature += tname; } From bb8709a0d6cc0b77ee54a6a6296ca63d65bc3c28 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 11:09:09 -0700 Subject: [PATCH 07/39] Remove `cpp_name_needs_typing_annotated()`. Preparation for bringing back commit 76b4a34aff6e7fd1ae2728588c5fd5914f7320d0. --- include/pybind11/pybind11.h | 6 +----- include/pybind11/typing.h | 10 ---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d51a0c6fb2..f3bccd8241 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -493,11 +493,7 @@ class cpp_function : public function { } else { std::string tname(t->name()); detail::clean_type_id(tname); - if (detail::cpp_name_needs_typing_annotated(tname.c_str())) { - signature += "Annotated[Any, CppTypePybind11(\"" + tname + "\")]"; - } else { - signature += tname; - } + signature += "Annotated[Any, CppTypePybind11(\"" + tname + "\")]"; } } else { signature += c; diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index c489c6d3a6..b7b1a4e54a 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -113,15 +113,5 @@ struct handle_type_name> { + const_name("]"); }; -inline bool cpp_name_needs_typing_annotated(const char *cpp_name) { - while (*cpp_name != '\0') { - char c = *cpp_name++; - if (c == ':' || c == '<') { // Assuming valid names, there is no need to check for '>'. - return true; - } - } - return false; -} - PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) From 199532e98977a456cc86579e905b22c23e16d4c3 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 11:09:39 -0700 Subject: [PATCH 08/39] Reapply "Add `struct handle_type_name<...>` specializations for `object`, `list`, etc." This reverts commit 794d97e54e22bebb4657f47a52affa5ed76da469. --- include/pybind11/cast.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 8b5beb0ef6..9da63772ed 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -876,6 +876,38 @@ struct handle_type_name { static constexpr auto name = const_name(); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("object"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("list"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("dict"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("set"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("frozenset"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("anyset"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("str"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("tuple"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("bool"); }; From 7280380378c05be4aed539cc2722b87b90f4a35b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 11:20:45 -0700 Subject: [PATCH 09/39] Fix `handle_type_name` as suggested by @sizmailov: https://github.com/pybind/pybind11/pull/4888#discussion_r1367775289 NOTE: This is actually a bug fix, in its own right. --- include/pybind11/cast.h | 8 ++++---- tests/test_pytypes.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 9da63772ed..af6705b62d 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -888,6 +888,10 @@ struct handle_type_name { static constexpr auto name = const_name("dict"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("set"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("set"); }; @@ -896,10 +900,6 @@ struct handle_type_name { static constexpr auto name = const_name("frozenset"); }; template <> -struct handle_type_name { - static constexpr auto name = const_name("anyset"); -}; -template <> struct handle_type_name { static constexpr auto name = const_name("str"); }; diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 2b2027316c..2824d29f94 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -121,7 +121,7 @@ def test_set(capture, doc): assert m.anyset_contains({"foo"}, "foo") assert doc(m.get_set) == "get_set() -> set" - assert doc(m.print_anyset) == "print_anyset(arg0: anyset) -> None" + assert doc(m.print_anyset) == "print_anyset(arg0: set) -> None" def test_frozenset(capture, doc): From 70a510c305ea3259153e3201c66f009ca80c416f Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 11:15:19 -0700 Subject: [PATCH 10/39] Adjust test_numpy_dtypes test_signature to new behavior. --- tests/test_numpy_dtypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index d10457eeb2..9f9582e1f6 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -342,8 +342,8 @@ def test_complex_array(): def test_signature(doc): assert ( - doc(m.create_rec_nested) - == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" + doc(m.create_rec_nested) == "create_rec_nested(arg0: int) " + '-> numpy.ndarray[Annotated[Any, CppTypePybind11("NestedStruct")]]' ) From ace70b077fed43e0bf9bcc90bf84587cade3ad5a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 12:43:01 -0700 Subject: [PATCH 11/39] Render `anyset` as `set | frozenset` as suggested by @sizmailov: https://github.com/pybind/pybind11/pull/4888#discussion_r1367785281 --- include/pybind11/cast.h | 2 +- tests/test_pytypes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index af6705b62d..69c07bef1d 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -889,7 +889,7 @@ struct handle_type_name { }; template <> struct handle_type_name { - static constexpr auto name = const_name("set"); + static constexpr auto name = const_name("set | frozenset"); }; template <> struct handle_type_name { diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 2824d29f94..cd082cdea2 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -121,7 +121,7 @@ def test_set(capture, doc): assert m.anyset_contains({"foo"}, "foo") assert doc(m.get_set) == "get_set() -> set" - assert doc(m.print_anyset) == "print_anyset(arg0: set) -> None" + assert doc(m.print_anyset) == "print_anyset(arg0: set | frozenset) -> None" def test_frozenset(capture, doc): From 7c8991a0a0d14ec325714d994689e723a8affdba Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 13:03:25 -0700 Subject: [PATCH 12/39] Use `Union[set, frozenset]` for internal consistency. --- include/pybind11/cast.h | 2 +- tests/test_pytypes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 69c07bef1d..b04083e2fa 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -889,7 +889,7 @@ struct handle_type_name { }; template <> struct handle_type_name { - static constexpr auto name = const_name("set | frozenset"); + static constexpr auto name = const_name("Union[set, frozenset]"); }; template <> struct handle_type_name { diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index cd082cdea2..87d5d55182 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -121,7 +121,7 @@ def test_set(capture, doc): assert m.anyset_contains({"foo"}, "foo") assert doc(m.get_set) == "get_set() -> set" - assert doc(m.print_anyset) == "print_anyset(arg0: set | frozenset) -> None" + assert doc(m.print_anyset) == "print_anyset(arg0: Union[set, frozenset]) -> None" def test_frozenset(capture, doc): From 63a48815fc7225022ff7314dc3861404a76d5fce Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 21 Oct 2023 23:55:33 -0700 Subject: [PATCH 13/39] Add missing `handle_type_name` specialization (discovered only through global testing). --- include/pybind11/cast.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index b04083e2fa..e5bc4f2668 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -952,6 +952,10 @@ struct handle_type_name { static constexpr auto name = const_name("Sequence"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("slice"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("*args"); }; From 3c209443552e0be509592f2bab6f6221353e2e5d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 22 Oct 2023 07:57:11 -0700 Subject: [PATCH 14/39] Add missing `handle_type_name<>` specializations for `bytearray`, `memoryview`, `type`. Discovered via manual inspection by @sizmailov: https://github.com/pybind/pybind11/pull/4888#issuecomment-1774023960 --- include/pybind11/cast.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e5bc4f2668..cdeb4aa8ba 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -952,10 +952,22 @@ struct handle_type_name { static constexpr auto name = const_name("Sequence"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("bytearray"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("memoryview"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("slice"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("type"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("*args"); }; From 74817b7f9f384cd5fd15d5765d3c6594adac2e0a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 22 Oct 2023 07:32:12 -0700 Subject: [PATCH 15/39] Add missing `handle_type_name`. Discovered via manual inspection by @sizmailov: https://github.com/pybind/pybind11/pull/4888#issuecomment-1774023960 NOTE: This is actually a bug fix, in its own right. --- include/pybind11/pybind11.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index f3bccd8241..8ae27a8a17 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1318,6 +1318,15 @@ class module_ : public object { } }; +PYBIND11_NAMESPACE_BEGIN(detail) + +template <> +struct handle_type_name { + static constexpr auto name = const_name("module"); +}; + +PYBIND11_NAMESPACE_END(detail) + // When inside a namespace (or anywhere as long as it's not the first item on a line), // C++20 allows "module" to be used. This is provided for backward compatibility, and for // simplicity, if someone wants to use py::module for example, that is perfectly safe. From 6a3a954a6b85d2f5dd770f7ab08d12bf1052a1b5 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 22 Oct 2023 07:53:00 -0700 Subject: [PATCH 16/39] Add missing `handle_type_name`. Discovered via manual inspection by @sizmailov: https://github.com/pybind/pybind11/pull/4888#issuecomment-1774023960 NOTE: This is actually a bug fix, in its own right. --- include/pybind11/numpy.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 8551aa2648..225d02571a 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -41,10 +41,16 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_WARNING_DISABLE_MSVC(4127) +class dtype; // Forward declaration class array; // Forward declaration PYBIND11_NAMESPACE_BEGIN(detail) +template <> +struct handle_type_name { + static constexpr auto name = const_name("numpy.dtype"); +}; + template <> struct handle_type_name { static constexpr auto name = const_name("numpy.ndarray"); From 169b0e57ebda14c47f159823ea57c1971f713121 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 22 Oct 2023 09:14:33 -0700 Subject: [PATCH 17/39] Add test returning `py::exception` (fails at runtime). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passing `py::exception` does not compile: ``` pytypes.h:459:36: error: could not convert ‘{h, pybind11::object::borrowed_t()}’ from ‘’ to ‘pybind11::exception’ 459 | return {h, object::borrowed_t{}}; ``` --- tests/test_exceptions.cpp | 3 +++ tests/test_exceptions.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index d3af7ab728..c1d05bb241 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -382,4 +382,7 @@ TEST_SUBMODULE(exceptions, m) { // function returns None instead of int, should give a useful error message fn().cast(); }); + + // m.def("pass_exception_void", [](const py::exception&) {}); // Does not compile. + m.def("return_exception_void", []() { return py::exception(); }); } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 5d8e6292aa..da35a74f04 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -419,3 +419,9 @@ def test_fn_cast_int_exception(): assert str(excinfo.value).startswith( "Unable to cast Python instance of type to C++ type" ) + + +def test_return_exception_void(): + with pytest.raises(TypeError) as excinfo: + m.return_exception_void() + assert 'Annotated[Any, CppTypePybind11("exception")]' in str(excinfo.value) From 0b984334d99103d1ac82467558f6f7f491e38d49 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 12:59:19 -0800 Subject: [PATCH 18/39] Remove `CppTypePybind11()` wrapping for now. --- include/pybind11/pybind11.h | 2 +- tests/test_exceptions.py | 2 +- tests/test_numpy_dtypes.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b8f3224ae4..33ad041fd7 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -494,7 +494,7 @@ class cpp_function : public function { } else { std::string tname(t->name()); detail::clean_type_id(tname); - signature += "Annotated[Any, CppTypePybind11(\"" + tname + "\")]"; + signature += "Annotated[Any, \"" + tname + "\"]"; } } else { signature += c; diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index da35a74f04..336754ca12 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -424,4 +424,4 @@ def test_fn_cast_int_exception(): def test_return_exception_void(): with pytest.raises(TypeError) as excinfo: m.return_exception_void() - assert 'Annotated[Any, CppTypePybind11("exception")]' in str(excinfo.value) + assert 'Annotated[Any, "exception"]' in str(excinfo.value) diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 9f9582e1f6..7653c770b0 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -343,7 +343,7 @@ def test_complex_array(): def test_signature(doc): assert ( doc(m.create_rec_nested) == "create_rec_nested(arg0: int) " - '-> numpy.ndarray[Annotated[Any, CppTypePybind11("NestedStruct")]]' + '-> numpy.ndarray[Annotated[Any, "NestedStruct"]]' ) From 781304e43127d7f66003d77a0bc2ff3a8405edef Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 13:01:42 -0800 Subject: [PATCH 19/39] Add test_cases_for_stubgen Material to inform https://github.com/python/mypy/issues/16306 --- tests/CMakeLists.txt | 1 + tests/test_cases_for_stubgen.cpp | 72 ++++++++++++++++++++++++++++++++ tests/test_cases_for_stubgen.py | 68 ++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 tests/test_cases_for_stubgen.cpp create mode 100644 tests/test_cases_for_stubgen.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d68067df6d..3632194ee4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -117,6 +117,7 @@ set(PYBIND11_TEST_FILES test_builtin_casters test_call_policies test_callbacks + test_cases_for_stubgen test_chrono test_class test_const_name diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp new file mode 100644 index 0000000000..9bbbcbd07d --- /dev/null +++ b/tests/test_cases_for_stubgen.cpp @@ -0,0 +1,72 @@ +#include "pybind11/stl_bind.h" +#include "pybind11_tests.h" + +#include + +namespace test_cases_for_stubgen { + +struct user_type { + bool operator<(const user_type &) const { return false; } +}; + +struct minimal_caster { + static constexpr auto name = py::detail::const_name(); + + static py::handle + cast(user_type const & /*src*/, py::return_value_policy /*policy*/, py::handle /*parent*/) { + return py::none().release(); + } + + // Maximizing simplicity. This will go terribly wrong for other arg types. + template + using cast_op_type = const user_type &; + + // NOLINTNEXTLINE(google-explicit-constructor) + operator user_type const &() { + static user_type obj; + return obj; + } + + bool load(py::handle /*src*/, bool /*convert*/) { return false; } +}; + +} // namespace test_cases_for_stubgen + +namespace pybind11 { +namespace detail { + +template <> +struct type_caster : test_cases_for_stubgen::minimal_caster {}; + +} // namespace detail +} // namespace pybind11 + +TEST_SUBMODULE(cases_for_stubgen, m) { + using namespace test_cases_for_stubgen; + + m.def("pass_user_type", [](const user_type &) {}); + m.def("return_user_type", []() { return user_type(); }); + + py::bind_map>(m, "MapIntUserType"); + py::bind_map>(m, "MapUserTypeInt"); + +#define MAP_TYPE(MapTypePythonName, ...) \ + py::class_<__VA_ARGS__>(m, MapTypePythonName) \ + .def( \ + "keys", \ + [](const __VA_ARGS__ &v) { return py::make_key_iterator(v); }, \ + py::keep_alive<0, 1>()) \ + .def( \ + "values", \ + [](const __VA_ARGS__ &v) { return py::make_value_iterator(v); }, \ + py::keep_alive<0, 1>()) \ + .def( \ + "__iter__", \ + [](const __VA_ARGS__ &v) { return py::make_iterator(v.begin(), v.end()); }, \ + py::keep_alive<0, 1>()) + + MAP_TYPE("MapFloatUserType", std::map); + MAP_TYPE("MapUserTypeFloat", std::map); + +#undef MAP_TYPE +} diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py new file mode 100644 index 0000000000..b1e0c552e7 --- /dev/null +++ b/tests/test_cases_for_stubgen.py @@ -0,0 +1,68 @@ +import pytest + +from pybind11_tests import cases_for_stubgen as m + + +@pytest.mark.parametrize( + ("docstring", "expected"), + [ + ( + m.pass_user_type.__doc__, + 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::user_type"]) -> None\n', + ), + ( + m.return_user_type.__doc__, + 'return_user_type() -> Annotated[Any, "test_cases_for_stubgen::user_type"]\n', + ), + ( + m.MapIntUserType.keys.__doc__, + "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView[int]\n", + ), + ( + m.MapIntUserType.values.__doc__, + "values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[test_cases_for_stubgen::user_type]\n", + ), + ( + m.MapIntUserType.items.__doc__, + "items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, test_cases_for_stubgen::user_type]\n", + ), + ( + m.MapUserTypeInt.keys.__doc__, + "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[test_cases_for_stubgen::user_type]\n", + ), + ( + m.MapUserTypeInt.values.__doc__, + "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView[int]\n", + ), + ( + m.MapUserTypeInt.items.__doc__, + "items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[test_cases_for_stubgen::user_type, int]\n", + ), + ( + m.MapFloatUserType.keys.__doc__, + "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n", + ), + ( + m.MapFloatUserType.values.__doc__, + 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + ), + ( + m.MapFloatUserType.__iter__.__doc__, + '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, "test_cases_for_stubgen::user_type"]]]\n', + ), + ( + m.MapUserTypeFloat.keys.__doc__, + 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + ), + ( + m.MapUserTypeFloat.values.__doc__, + "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[float]\n", + ), + ( + m.MapUserTypeFloat.__iter__.__doc__, + '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::user_type"], float]]\n', + ), + ], +) +def test_docstring(docstring, expected): + assert docstring == expected From 61ee34ee07400d1e7b2d749cd61f0ac7e1914024 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 13:23:11 -0800 Subject: [PATCH 20/39] Pull in `Annotated[list[int], FixedSize(2)]` from test_stl --- tests/test_cases_for_stubgen.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index b1e0c552e7..8ca2aceadd 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -1,6 +1,7 @@ import pytest from pybind11_tests import cases_for_stubgen as m +from pybind11_tests import stl as test_stl @pytest.mark.parametrize( @@ -62,6 +63,14 @@ m.MapUserTypeFloat.__iter__.__doc__, '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::user_type"], float]]\n', ), + ( + test_stl.cast_array.__doc__, + "cast_array() -> Annotated[list[int], FixedSize(2)]\n", + ), + ( + test_stl.load_array.__doc__, + "load_array(arg0: Annotated[list[int], FixedSize(2)]) -> bool\n", + ), ], ) def test_docstring(docstring, expected): From 11040768ca17bbbd8a7ad31310f455b5ea2aaf66 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 13:50:20 -0800 Subject: [PATCH 21/39] Add `Annotated[Any, "..."]` wrapping in `type_info_description()` --- include/pybind11/detail/type_caster_base.h | 2 +- tests/test_cases_for_stubgen.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 476646ee8f..77f3d4790b 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -1207,7 +1207,7 @@ PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { return th.attr("__module__").cast() + '.' + th.attr("__qualname__").cast(); } - return clean_type_id(ti.name()); + return "Annotated[Any, \"" + clean_type_id(ti.name()) + "\"]"; } PYBIND11_NAMESPACE_END(detail) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 8ca2aceadd..e57e038ced 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -21,15 +21,15 @@ ), ( m.MapIntUserType.values.__doc__, - "values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[test_cases_for_stubgen::user_type]\n", + 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', ), ( m.MapIntUserType.items.__doc__, - "items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, test_cases_for_stubgen::user_type]\n", + 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', ), ( m.MapUserTypeInt.keys.__doc__, - "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[test_cases_for_stubgen::user_type]\n", + 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', ), ( m.MapUserTypeInt.values.__doc__, @@ -37,7 +37,7 @@ ), ( m.MapUserTypeInt.items.__doc__, - "items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[test_cases_for_stubgen::user_type, int]\n", + 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, "test_cases_for_stubgen::user_type"], int]\n', ), ( m.MapFloatUserType.keys.__doc__, From e5f210e61b3d90209603d8c23b532829a0c1e50d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 14:08:59 -0800 Subject: [PATCH 22/39] Rename `user_type` to `UserType` --- tests/test_cases_for_stubgen.cpp | 30 +++++++++++++++--------------- tests/test_cases_for_stubgen.py | 20 ++++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index 9bbbcbd07d..43a87e0bee 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -5,25 +5,25 @@ namespace test_cases_for_stubgen { -struct user_type { - bool operator<(const user_type &) const { return false; } +struct UserType { + bool operator<(const UserType &) const { return false; } }; struct minimal_caster { - static constexpr auto name = py::detail::const_name(); + static constexpr auto name = py::detail::const_name(); static py::handle - cast(user_type const & /*src*/, py::return_value_policy /*policy*/, py::handle /*parent*/) { + cast(UserType const & /*src*/, py::return_value_policy /*policy*/, py::handle /*parent*/) { return py::none().release(); } // Maximizing simplicity. This will go terribly wrong for other arg types. template - using cast_op_type = const user_type &; + using cast_op_type = const UserType &; // NOLINTNEXTLINE(google-explicit-constructor) - operator user_type const &() { - static user_type obj; + operator UserType const &() { + static UserType obj; return obj; } @@ -36,19 +36,19 @@ namespace pybind11 { namespace detail { template <> -struct type_caster : test_cases_for_stubgen::minimal_caster {}; +struct type_caster : test_cases_for_stubgen::minimal_caster {}; } // namespace detail } // namespace pybind11 TEST_SUBMODULE(cases_for_stubgen, m) { - using namespace test_cases_for_stubgen; + using UserType = test_cases_for_stubgen::UserType; - m.def("pass_user_type", [](const user_type &) {}); - m.def("return_user_type", []() { return user_type(); }); + m.def("pass_user_type", [](const UserType &) {}); + m.def("return_user_type", []() { return UserType(); }); - py::bind_map>(m, "MapIntUserType"); - py::bind_map>(m, "MapUserTypeInt"); + py::bind_map>(m, "MapIntUserType"); + py::bind_map>(m, "MapUserTypeInt"); #define MAP_TYPE(MapTypePythonName, ...) \ py::class_<__VA_ARGS__>(m, MapTypePythonName) \ @@ -65,8 +65,8 @@ TEST_SUBMODULE(cases_for_stubgen, m) { [](const __VA_ARGS__ &v) { return py::make_iterator(v.begin(), v.end()); }, \ py::keep_alive<0, 1>()) - MAP_TYPE("MapFloatUserType", std::map); - MAP_TYPE("MapUserTypeFloat", std::map); + MAP_TYPE("MapFloatUserType", std::map); + MAP_TYPE("MapUserTypeFloat", std::map); #undef MAP_TYPE } diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index e57e038ced..24508ac21b 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -9,11 +9,11 @@ [ ( m.pass_user_type.__doc__, - 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::user_type"]) -> None\n', + 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::UserType"]) -> None\n', ), ( m.return_user_type.__doc__, - 'return_user_type() -> Annotated[Any, "test_cases_for_stubgen::user_type"]\n', + 'return_user_type() -> Annotated[Any, "test_cases_for_stubgen::UserType"]\n', ), ( m.MapIntUserType.keys.__doc__, @@ -21,15 +21,15 @@ ), ( m.MapIntUserType.values.__doc__, - 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', ), ( m.MapIntUserType.items.__doc__, - 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', ), ( m.MapUserTypeInt.keys.__doc__, - 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', ), ( m.MapUserTypeInt.values.__doc__, @@ -37,7 +37,7 @@ ), ( m.MapUserTypeInt.items.__doc__, - 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, "test_cases_for_stubgen::user_type"], int]\n', + 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, "test_cases_for_stubgen::UserType"], int]\n', ), ( m.MapFloatUserType.keys.__doc__, @@ -45,15 +45,15 @@ ), ( m.MapFloatUserType.values.__doc__, - 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', ), ( m.MapFloatUserType.__iter__.__doc__, - '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, "test_cases_for_stubgen::user_type"]]]\n', + '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, "test_cases_for_stubgen::UserType"]]]\n', ), ( m.MapUserTypeFloat.keys.__doc__, - 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, "test_cases_for_stubgen::user_type"]]\n', + 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', ), ( m.MapUserTypeFloat.values.__doc__, @@ -61,7 +61,7 @@ ), ( m.MapUserTypeFloat.__iter__.__doc__, - '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::user_type"], float]]\n', + '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::UserType"], float]]\n', ), ( test_stl.cast_array.__doc__, From d1694d9ac5368512c8ebd2ca88deb51995f31f6b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 22:28:38 -0800 Subject: [PATCH 23/39] Use locally defined bindings to avoid dependency on test_stl. --- tests/test_cases_for_stubgen.cpp | 16 +++++++++++++--- tests/test_cases_for_stubgen.py | 9 ++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index 43a87e0bee..e24f2ee53a 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -1,6 +1,8 @@ +#include "pybind11/stl.h" #include "pybind11/stl_bind.h" #include "pybind11_tests.h" +#include #include namespace test_cases_for_stubgen { @@ -41,6 +43,11 @@ struct type_caster : test_cases_for_stubgen::m } // namespace detail } // namespace pybind11 +PYBIND11_MAKE_OPAQUE(std::map); +PYBIND11_MAKE_OPAQUE(std::map); +PYBIND11_MAKE_OPAQUE(std::map); +PYBIND11_MAKE_OPAQUE(std::map); + TEST_SUBMODULE(cases_for_stubgen, m) { using UserType = test_cases_for_stubgen::UserType; @@ -50,7 +57,7 @@ TEST_SUBMODULE(cases_for_stubgen, m) { py::bind_map>(m, "MapIntUserType"); py::bind_map>(m, "MapUserTypeInt"); -#define MAP_TYPE(MapTypePythonName, ...) \ +#define LOCAL_HELPER(MapTypePythonName, ...) \ py::class_<__VA_ARGS__>(m, MapTypePythonName) \ .def( \ "keys", \ @@ -65,8 +72,11 @@ TEST_SUBMODULE(cases_for_stubgen, m) { [](const __VA_ARGS__ &v) { return py::make_iterator(v.begin(), v.end()); }, \ py::keep_alive<0, 1>()) - MAP_TYPE("MapFloatUserType", std::map); - MAP_TYPE("MapUserTypeFloat", std::map); + LOCAL_HELPER("MapFloatUserType", std::map); + LOCAL_HELPER("MapUserTypeFloat", std::map); #undef MAP_TYPE + + m.def("pass_std_array_int_2", [](const std::array &) {}); + m.def("return_std_array_int_3", []() { return std::array{{1, 2, 3}}; }); } diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 24508ac21b..7505cfa799 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -1,7 +1,6 @@ import pytest from pybind11_tests import cases_for_stubgen as m -from pybind11_tests import stl as test_stl @pytest.mark.parametrize( @@ -64,12 +63,12 @@ '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::UserType"], float]]\n', ), ( - test_stl.cast_array.__doc__, - "cast_array() -> Annotated[list[int], FixedSize(2)]\n", + m.pass_std_array_int_2.__doc__, + "pass_std_array_int_2(arg0: Annotated[list[int], FixedSize(2)]) -> None\n", ), ( - test_stl.load_array.__doc__, - "load_array(arg0: Annotated[list[int], FixedSize(2)]) -> bool\n", + m.return_std_array_int_3.__doc__, + "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n", ), ], ) From 1b4fa7172b49d123eacaa44c08584cb15f33dea3 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 22:50:34 -0800 Subject: [PATCH 24/39] Unmodified copy of https://github.com/python/mypy/blob/c6cb3c6282003dd3dadcf028735f9ba6190a0c84/test-data/pybind11_mypy_demo/src/main.cpp --- tests/test_cases_for_stubgen.cpp | 124 +++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index e24f2ee53a..9611913f03 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -7,6 +7,127 @@ namespace test_cases_for_stubgen { +// The `basics` code was copied from here (to have all test cases for stubgen in one place): +// https://github.com/python/mypy/blob/c6cb3c6282003dd3dadcf028735f9ba6190a0c84/test-data/pybind11_mypy_demo/src/main.cpp +// Copyright (c) 2016 The Pybind Development Team, All rights reserved. + +namespace basics { + +int answer() { + return 42; +} + +int sum(int a, int b) { + return a + b; +} + +double midpoint(double left, double right){ + return left + (right - left)/2; +} + +double weighted_midpoint(double left, double right, double alpha=0.5) { + return left + (right - left) * alpha; +} + +struct Point { + + enum class LengthUnit { + mm=0, + pixel, + inch + }; + + enum class AngleUnit { + radian=0, + degree + }; + + Point() : Point(0, 0) {} + Point(double x, double y) : x(x), y(y) {} + + static const Point origin; + static const Point x_axis; + static const Point y_axis; + + static LengthUnit length_unit; + static AngleUnit angle_unit; + + double length() const { + return std::sqrt(x * x + y * y); + } + + double distance_to(double other_x, double other_y) const { + double dx = x - other_x; + double dy = y - other_y; + return std::sqrt(dx*dx + dy*dy); + } + + double distance_to(const Point& other) const { + return distance_to(other.x, other.y); + } + + double x, y; +}; + +const Point Point::origin = Point(0, 0); +const Point Point::x_axis = Point(1, 0); +const Point Point::y_axis = Point(0, 1); + +Point::LengthUnit Point::length_unit = Point::LengthUnit::mm; +Point::AngleUnit Point::angle_unit = Point::AngleUnit::radian; + +} // namespace: basics + +void bind_basics(py::module& basics) { + + using namespace basics; + + // Functions + basics.def("answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings + basics.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''"); + basics.def("midpoint", &midpoint, py::arg("left"), py::arg("right")); + basics.def("weighted_midpoint", weighted_midpoint, py::arg("left"), py::arg("right"), py::arg("alpha")=0.5); + + // Classes + py::class_ pyPoint(basics, "Point"); + py::enum_ pyLengthUnit(pyPoint, "LengthUnit"); + py::enum_ pyAngleUnit(pyPoint, "AngleUnit"); + + pyPoint + .def(py::init<>()) + .def(py::init(), py::arg("x"), py::arg("y")) + .def("distance_to", py::overload_cast(&Point::distance_to, py::const_), py::arg("x"), py::arg("y")) + .def("distance_to", py::overload_cast(&Point::distance_to, py::const_), py::arg("other")) + .def_readwrite("x", &Point::x) + .def_property("y", + [](Point& self){ return self.y; }, + [](Point& self, double value){ self.y = value; } + ) + .def_property_readonly("length", &Point::length) + .def_property_readonly_static("x_axis", [](py::object cls){return Point::x_axis;}) + .def_property_readonly_static("y_axis", [](py::object cls){return Point::y_axis;}) + .def_readwrite_static("length_unit", &Point::length_unit) + .def_property_static("angle_unit", + [](py::object& /*cls*/){ return Point::angle_unit; }, + [](py::object& /*cls*/, Point::AngleUnit value){ Point::angle_unit = value; } + ); + + pyPoint.attr("origin") = Point::origin; + + pyLengthUnit + .value("mm", Point::LengthUnit::mm) + .value("pixel", Point::LengthUnit::pixel) + .value("inch", Point::LengthUnit::inch); + + pyAngleUnit + .value("radian", Point::AngleUnit::radian) + .value("degree", Point::AngleUnit::degree); + + // Module-level attributes + basics.attr("PI") = std::acos(-1); + basics.attr("__version__") = "0.0.1"; +} + struct UserType { bool operator<(const UserType &) const { return false; } }; @@ -49,6 +170,9 @@ PYBIND11_MAKE_OPAQUE(std::map); PYBIND11_MAKE_OPAQUE(std::map); TEST_SUBMODULE(cases_for_stubgen, m) { + auto basics = m.def_submodule("basics"); + bind_basics(basics); + using UserType = test_cases_for_stubgen::UserType; m.def("pass_user_type", [](const UserType &) {}); From 644d15054eda304ea453c1549d8952df37760c09 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 22:52:49 -0800 Subject: [PATCH 25/39] Minimal changes to make the basics code build. --- tests/test_cases_for_stubgen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index 9611913f03..75c172ba7a 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -104,8 +104,8 @@ void bind_basics(py::module& basics) { [](Point& self, double value){ self.y = value; } ) .def_property_readonly("length", &Point::length) - .def_property_readonly_static("x_axis", [](py::object cls){return Point::x_axis;}) - .def_property_readonly_static("y_axis", [](py::object cls){return Point::y_axis;}) + .def_property_readonly_static("x_axis", [](py::object /*cls*/){return Point::x_axis;}) + .def_property_readonly_static("y_axis", [](py::object /*cls*/){return Point::y_axis;}) .def_readwrite_static("length_unit", &Point::length_unit) .def_property_static("angle_unit", [](py::object& /*cls*/){ return Point::angle_unit; }, @@ -171,7 +171,7 @@ PYBIND11_MAKE_OPAQUE(std::map); TEST_SUBMODULE(cases_for_stubgen, m) { auto basics = m.def_submodule("basics"); - bind_basics(basics); + test_cases_for_stubgen::bind_basics(basics); using UserType = test_cases_for_stubgen::UserType; From 1fa0065967db6360a7a3a88cb26c7a97779e01dd Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 22:55:01 -0800 Subject: [PATCH 26/39] pre-commit clang-format, NO manual changes. --- tests/test_cases_for_stubgen.cpp | 168 +++++++++++++++---------------- 1 file changed, 79 insertions(+), 89 deletions(-) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index 75c172ba7a..7b55ce6994 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -13,60 +13,43 @@ namespace test_cases_for_stubgen { namespace basics { -int answer() { - return 42; -} +int answer() { return 42; } -int sum(int a, int b) { - return a + b; -} +int sum(int a, int b) { return a + b; } -double midpoint(double left, double right){ - return left + (right - left)/2; -} +double midpoint(double left, double right) { return left + (right - left) / 2; } -double weighted_midpoint(double left, double right, double alpha=0.5) { - return left + (right - left) * alpha; +double weighted_midpoint(double left, double right, double alpha = 0.5) { + return left + (right - left) * alpha; } struct Point { - enum class LengthUnit { - mm=0, - pixel, - inch - }; + enum class LengthUnit { mm = 0, pixel, inch }; - enum class AngleUnit { - radian=0, - degree - }; + enum class AngleUnit { radian = 0, degree }; - Point() : Point(0, 0) {} - Point(double x, double y) : x(x), y(y) {} + Point() : Point(0, 0) {} + Point(double x, double y) : x(x), y(y) {} - static const Point origin; - static const Point x_axis; - static const Point y_axis; + static const Point origin; + static const Point x_axis; + static const Point y_axis; - static LengthUnit length_unit; - static AngleUnit angle_unit; + static LengthUnit length_unit; + static AngleUnit angle_unit; - double length() const { - return std::sqrt(x * x + y * y); - } + double length() const { return std::sqrt(x * x + y * y); } - double distance_to(double other_x, double other_y) const { - double dx = x - other_x; - double dy = y - other_y; - return std::sqrt(dx*dx + dy*dy); - } + double distance_to(double other_x, double other_y) const { + double dx = x - other_x; + double dy = y - other_y; + return std::sqrt(dx * dx + dy * dy); + } - double distance_to(const Point& other) const { - return distance_to(other.x, other.y); - } + double distance_to(const Point &other) const { return distance_to(other.x, other.y); } - double x, y; + double x, y; }; const Point Point::origin = Point(0, 0); @@ -76,56 +59,63 @@ const Point Point::y_axis = Point(0, 1); Point::LengthUnit Point::length_unit = Point::LengthUnit::mm; Point::AngleUnit Point::angle_unit = Point::AngleUnit::radian; -} // namespace: basics - -void bind_basics(py::module& basics) { - - using namespace basics; - - // Functions - basics.def("answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings - basics.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''"); - basics.def("midpoint", &midpoint, py::arg("left"), py::arg("right")); - basics.def("weighted_midpoint", weighted_midpoint, py::arg("left"), py::arg("right"), py::arg("alpha")=0.5); - - // Classes - py::class_ pyPoint(basics, "Point"); - py::enum_ pyLengthUnit(pyPoint, "LengthUnit"); - py::enum_ pyAngleUnit(pyPoint, "AngleUnit"); - - pyPoint - .def(py::init<>()) - .def(py::init(), py::arg("x"), py::arg("y")) - .def("distance_to", py::overload_cast(&Point::distance_to, py::const_), py::arg("x"), py::arg("y")) - .def("distance_to", py::overload_cast(&Point::distance_to, py::const_), py::arg("other")) - .def_readwrite("x", &Point::x) - .def_property("y", - [](Point& self){ return self.y; }, - [](Point& self, double value){ self.y = value; } - ) - .def_property_readonly("length", &Point::length) - .def_property_readonly_static("x_axis", [](py::object /*cls*/){return Point::x_axis;}) - .def_property_readonly_static("y_axis", [](py::object /*cls*/){return Point::y_axis;}) - .def_readwrite_static("length_unit", &Point::length_unit) - .def_property_static("angle_unit", - [](py::object& /*cls*/){ return Point::angle_unit; }, - [](py::object& /*cls*/, Point::AngleUnit value){ Point::angle_unit = value; } - ); - - pyPoint.attr("origin") = Point::origin; - - pyLengthUnit - .value("mm", Point::LengthUnit::mm) - .value("pixel", Point::LengthUnit::pixel) - .value("inch", Point::LengthUnit::inch); - - pyAngleUnit - .value("radian", Point::AngleUnit::radian) - .value("degree", Point::AngleUnit::degree); - - // Module-level attributes - basics.attr("PI") = std::acos(-1); - basics.attr("__version__") = "0.0.1"; +} // namespace basics + +void bind_basics(py::module &basics) { + + using namespace basics; + + // Functions + basics.def( + "answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings + basics.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''"); + basics.def("midpoint", &midpoint, py::arg("left"), py::arg("right")); + basics.def("weighted_midpoint", + weighted_midpoint, + py::arg("left"), + py::arg("right"), + py::arg("alpha") = 0.5); + + // Classes + py::class_ pyPoint(basics, "Point"); + py::enum_ pyLengthUnit(pyPoint, "LengthUnit"); + py::enum_ pyAngleUnit(pyPoint, "AngleUnit"); + + pyPoint.def(py::init<>()) + .def(py::init(), py::arg("x"), py::arg("y")) + .def("distance_to", + py::overload_cast(&Point::distance_to, py::const_), + py::arg("x"), + py::arg("y")) + .def("distance_to", + py::overload_cast(&Point::distance_to, py::const_), + py::arg("other")) + .def_readwrite("x", &Point::x) + .def_property( + "y", + [](Point &self) { return self.y; }, + [](Point &self, double value) { self.y = value; }) + .def_property_readonly("length", &Point::length) + .def_property_readonly_static("x_axis", [](py::object /*cls*/) { return Point::x_axis; }) + .def_property_readonly_static("y_axis", [](py::object /*cls*/) { return Point::y_axis; }) + .def_readwrite_static("length_unit", &Point::length_unit) + .def_property_static( + "angle_unit", + [](py::object & /*cls*/) { return Point::angle_unit; }, + [](py::object & /*cls*/, Point::AngleUnit value) { Point::angle_unit = value; }); + + pyPoint.attr("origin") = Point::origin; + + pyLengthUnit.value("mm", Point::LengthUnit::mm) + .value("pixel", Point::LengthUnit::pixel) + .value("inch", Point::LengthUnit::inch); + + pyAngleUnit.value("radian", Point::AngleUnit::radian) + .value("degree", Point::AngleUnit::degree); + + // Module-level attributes + basics.attr("PI") = std::acos(-1); + basics.attr("__version__") = "0.0.1"; } struct UserType { From 69dac469fe5128a13b5d5470bacbf2677363b5dd Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 23:19:48 -0800 Subject: [PATCH 27/39] Add `m.basics` tests in ntest_cases_for_stubgen.py --- tests/test_cases_for_stubgen.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 7505cfa799..f314039e3c 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -6,6 +6,29 @@ @pytest.mark.parametrize( ("docstring", "expected"), [ + ( + m.basics.answer.__doc__, + 'answer() -> int\n\nanswer docstring, with end quote"\n', + ), + ( + m.basics.sum.__doc__, + "sum(arg0: int, arg1: int) -> int\n\nmultiline docstring test, edge case quotes \"\"\"'''\n", + ), + (m.basics.midpoint.__doc__, "midpoint(left: float, right: float) -> float\n"), + ( + m.basics.weighted_midpoint.__doc__, + "weighted_midpoint(left: float, right: float, alpha: float = 0.5) -> float\n", + ), + ( + m.basics.Point.__init__.__doc__, + "__init__(*args, **kwargs)\nOverloaded function.\n\n1. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point) -> None\n\n2. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> None\n", + ), + ( + m.basics.Point.distance_to.__doc__, + "distance_to(*args, **kwargs)\nOverloaded function.\n\n1. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> float\n\n2. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, other: pybind11_tests.cases_for_stubgen.basics.Point) -> float\n", + ), + (m.basics.Point.length_unit.__doc__, "Members:\n\n mm\n\n pixel\n\n inch"), + (m.basics.Point.angle_unit.__doc__, "Members:\n\n radian\n\n degree"), ( m.pass_user_type.__doc__, 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::UserType"]) -> None\n', From 1a2e8a662456b978e596fd19b6df271d36eafa38 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 23:35:28 -0800 Subject: [PATCH 28/39] C++11 compatibility. --- tests/test_cases_for_stubgen.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index 7b55ce6994..6e81286485 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -83,6 +83,7 @@ void bind_basics(py::module &basics) { pyPoint.def(py::init<>()) .def(py::init(), py::arg("x"), py::arg("y")) +#ifdef PYBIND11_CPP14 .def("distance_to", py::overload_cast(&Point::distance_to, py::const_), py::arg("x"), @@ -90,6 +91,15 @@ void bind_basics(py::module &basics) { .def("distance_to", py::overload_cast(&Point::distance_to, py::const_), py::arg("other")) +#else + .def("distance_to", + static_cast(&Point::distance_to), + py::arg("x"), + py::arg("y")) + .def("distance_to", + static_cast(&Point::distance_to), + py::arg("other")) +#endif .def_readwrite("x", &Point::x) .def_property( "y", From 79f6bdca36c83e729d33e61897f1538895bc568b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 23:40:33 -0800 Subject: [PATCH 29/39] Replace `.stl_binders.` with `.cases_for_stubgen.` --- tests/test_cases_for_stubgen.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index f314039e3c..f5c069304b 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -96,4 +96,6 @@ ], ) def test_docstring(docstring, expected): + # On some platforms the stl_binders module name prevails for KeysView, ValuesView, ItemsView. + docstring = docstring.replace(".stl_binders.", ".cases_for_stubgen.") assert docstring == expected From 2376f6e953ea2d2fb3a4604f28e6d112e08e57af Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 14 Nov 2023 23:46:42 -0800 Subject: [PATCH 30/39] Use py::handle instead of py::object to avoid clang-tidy errors. --- tests/test_cases_for_stubgen.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index 6e81286485..e084ea2720 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -106,13 +106,13 @@ void bind_basics(py::module &basics) { [](Point &self) { return self.y; }, [](Point &self, double value) { self.y = value; }) .def_property_readonly("length", &Point::length) - .def_property_readonly_static("x_axis", [](py::object /*cls*/) { return Point::x_axis; }) - .def_property_readonly_static("y_axis", [](py::object /*cls*/) { return Point::y_axis; }) + .def_property_readonly_static("x_axis", [](py::handle /*cls*/) { return Point::x_axis; }) + .def_property_readonly_static("y_axis", [](py::handle /*cls*/) { return Point::y_axis; }) .def_readwrite_static("length_unit", &Point::length_unit) .def_property_static( "angle_unit", - [](py::object & /*cls*/) { return Point::angle_unit; }, - [](py::object & /*cls*/, Point::AngleUnit value) { Point::angle_unit = value; }); + [](py::handle /*cls*/) { return Point::angle_unit; }, + [](py::handle /*cls*/, Point::AngleUnit value) { Point::angle_unit = value; }); pyPoint.attr("origin") = Point::origin; From bdbb10d9a3244b9e28382a126af07e04c3a80bba Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 16 Nov 2023 00:08:23 -0800 Subject: [PATCH 31/39] Add some deeply nested test cases. --- tests/test_cases_for_stubgen.cpp | 20 ++++++++++++++++++-- tests/test_cases_for_stubgen.py | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/test_cases_for_stubgen.cpp b/tests/test_cases_for_stubgen.cpp index e084ea2720..cd947f97b1 100644 --- a/tests/test_cases_for_stubgen.cpp +++ b/tests/test_cases_for_stubgen.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace test_cases_for_stubgen { @@ -198,9 +199,24 @@ TEST_SUBMODULE(cases_for_stubgen, m) { LOCAL_HELPER("MapFloatUserType", std::map); LOCAL_HELPER("MapUserTypeFloat", std::map); - -#undef MAP_TYPE +#undef LOCAL_HELPER m.def("pass_std_array_int_2", [](const std::array &) {}); m.def("return_std_array_int_3", []() { return std::array{{1, 2, 3}}; }); + + // Rather arbitrary, meant to be a torture test for recursive processing. + using nested_case_01a = std::vector>; + using nested_case_02a = std::vector; + using nested_case_03a = std::map, UserType>; + using nested_case_04a = std::map; + using nested_case_05a = std::vector; + using nested_case_06a = std::map; +#define LOCAL_HELPER(name) m.def(#name, [](const name &) {}) + LOCAL_HELPER(nested_case_01a); + LOCAL_HELPER(nested_case_02a); + LOCAL_HELPER(nested_case_03a); + LOCAL_HELPER(nested_case_04a); + LOCAL_HELPER(nested_case_05a); + LOCAL_HELPER(nested_case_06a); +#undef LOCAL_HELPER } diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index f5c069304b..f383b4964a 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -93,6 +93,30 @@ m.return_std_array_int_3.__doc__, "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n", ), + ( + m.nested_case_01a.__doc__, + "nested_case_01a(arg0: list[Annotated[list[int], FixedSize(2)]]) -> None\n", + ), + ( + m.nested_case_02a.__doc__, + 'nested_case_02a(arg0: list[Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', + ), + ( + m.nested_case_03a.__doc__, + 'nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', + ), + ( + m.nested_case_04a.__doc__, + 'nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]) -> None\n', + ), + ( + m.nested_case_05a.__doc__, + 'nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]) -> None\n', + ), + ( + m.nested_case_06a.__doc__, + 'nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]]) -> None\n', + ), ], ) def test_docstring(docstring, expected): From 429a1f820dccd2d2f2323eb000dba84ed53783ef Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 16 Nov 2023 00:33:38 -0800 Subject: [PATCH 32/39] Make test_cases_for_stubgen.py much more compact, and the `pytest -v` output much easier to read. --- tests/test_cases_for_stubgen.py | 156 ++++++++------------------------ 1 file changed, 38 insertions(+), 118 deletions(-) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index f383b4964a..6bebacb2b1 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -2,124 +2,44 @@ from pybind11_tests import cases_for_stubgen as m +TEST_CASES = { + "m.basics.answer.__doc__": 'answer() -> int\n\nanswer docstring, with end quote"\n', + "m.basics.sum.__doc__": "sum(arg0: int, arg1: int) -> int\n\nmultiline docstring test, edge case quotes \"\"\"'''\n", + "m.basics.midpoint.__doc__": "midpoint(left: float, right: float) -> float\n", + "m.basics.weighted_midpoint.__doc__": "weighted_midpoint(left: float, right: float, alpha: float = 0.5) -> float\n", + "m.basics.Point.__init__.__doc__": "__init__(*args, **kwargs)\nOverloaded function.\n\n1. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point) -> None\n\n2. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> None\n", + "m.basics.Point.distance_to.__doc__": "distance_to(*args, **kwargs)\nOverloaded function.\n\n1. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> float\n\n2. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, other: pybind11_tests.cases_for_stubgen.basics.Point) -> float\n", + "m.basics.Point.length_unit.__doc__": "Members:\n\n mm\n\n pixel\n\n inch", + "m.basics.Point.angle_unit.__doc__": "Members:\n\n radian\n\n degree", + "m.pass_user_type.__doc__": 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::UserType"]) -> None\n', + "m.return_user_type.__doc__": 'return_user_type() -> Annotated[Any, "test_cases_for_stubgen::UserType"]\n', + "m.MapIntUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView[int]\n", + "m.MapIntUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapIntUserType.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapUserTypeInt.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapUserTypeInt.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView[int]\n", + "m.MapUserTypeInt.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, "test_cases_for_stubgen::UserType"], int]\n', + "m.MapFloatUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n", + "m.MapFloatUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapFloatUserType.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, "test_cases_for_stubgen::UserType"]]]\n', + "m.MapUserTypeFloat.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapUserTypeFloat.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[float]\n", + "m.MapUserTypeFloat.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::UserType"], float]]\n', + "m.pass_std_array_int_2.__doc__": "pass_std_array_int_2(arg0: Annotated[list[int], FixedSize(2)]) -> None\n", + "m.return_std_array_int_3.__doc__": "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n", + "m.nested_case_01a.__doc__": "nested_case_01a(arg0: list[Annotated[list[int], FixedSize(2)]]) -> None\n", + "m.nested_case_02a.__doc__": 'nested_case_02a(arg0: list[Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', + "m.nested_case_03a.__doc__": 'nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', + "m.nested_case_04a.__doc__": 'nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]) -> None\n', + "m.nested_case_05a.__doc__": 'nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]) -> None\n', + "m.nested_case_06a.__doc__": 'nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]]) -> None\n', +} -@pytest.mark.parametrize( - ("docstring", "expected"), - [ - ( - m.basics.answer.__doc__, - 'answer() -> int\n\nanswer docstring, with end quote"\n', - ), - ( - m.basics.sum.__doc__, - "sum(arg0: int, arg1: int) -> int\n\nmultiline docstring test, edge case quotes \"\"\"'''\n", - ), - (m.basics.midpoint.__doc__, "midpoint(left: float, right: float) -> float\n"), - ( - m.basics.weighted_midpoint.__doc__, - "weighted_midpoint(left: float, right: float, alpha: float = 0.5) -> float\n", - ), - ( - m.basics.Point.__init__.__doc__, - "__init__(*args, **kwargs)\nOverloaded function.\n\n1. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point) -> None\n\n2. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> None\n", - ), - ( - m.basics.Point.distance_to.__doc__, - "distance_to(*args, **kwargs)\nOverloaded function.\n\n1. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> float\n\n2. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, other: pybind11_tests.cases_for_stubgen.basics.Point) -> float\n", - ), - (m.basics.Point.length_unit.__doc__, "Members:\n\n mm\n\n pixel\n\n inch"), - (m.basics.Point.angle_unit.__doc__, "Members:\n\n radian\n\n degree"), - ( - m.pass_user_type.__doc__, - 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::UserType"]) -> None\n', - ), - ( - m.return_user_type.__doc__, - 'return_user_type() -> Annotated[Any, "test_cases_for_stubgen::UserType"]\n', - ), - ( - m.MapIntUserType.keys.__doc__, - "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView[int]\n", - ), - ( - m.MapIntUserType.values.__doc__, - 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - ), - ( - m.MapIntUserType.items.__doc__, - 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - ), - ( - m.MapUserTypeInt.keys.__doc__, - 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - ), - ( - m.MapUserTypeInt.values.__doc__, - "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView[int]\n", - ), - ( - m.MapUserTypeInt.items.__doc__, - 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, "test_cases_for_stubgen::UserType"], int]\n', - ), - ( - m.MapFloatUserType.keys.__doc__, - "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n", - ), - ( - m.MapFloatUserType.values.__doc__, - 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - ), - ( - m.MapFloatUserType.__iter__.__doc__, - '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, "test_cases_for_stubgen::UserType"]]]\n', - ), - ( - m.MapUserTypeFloat.keys.__doc__, - 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - ), - ( - m.MapUserTypeFloat.values.__doc__, - "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[float]\n", - ), - ( - m.MapUserTypeFloat.__iter__.__doc__, - '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::UserType"], float]]\n', - ), - ( - m.pass_std_array_int_2.__doc__, - "pass_std_array_int_2(arg0: Annotated[list[int], FixedSize(2)]) -> None\n", - ), - ( - m.return_std_array_int_3.__doc__, - "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n", - ), - ( - m.nested_case_01a.__doc__, - "nested_case_01a(arg0: list[Annotated[list[int], FixedSize(2)]]) -> None\n", - ), - ( - m.nested_case_02a.__doc__, - 'nested_case_02a(arg0: list[Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', - ), - ( - m.nested_case_03a.__doc__, - 'nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', - ), - ( - m.nested_case_04a.__doc__, - 'nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]) -> None\n', - ), - ( - m.nested_case_05a.__doc__, - 'nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]) -> None\n', - ), - ( - m.nested_case_06a.__doc__, - 'nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]]) -> None\n', - ), - ], -) -def test_docstring(docstring, expected): + +@pytest.mark.parametrize("test_case", TEST_CASES.keys()) +def test_docstring(test_case): + assert dir(m) # Only direct use of m, to stop tooling from removing the import. # On some platforms the stl_binders module name prevails for KeysView, ValuesView, ItemsView. - docstring = docstring.replace(".stl_binders.", ".cases_for_stubgen.") + docstring = eval(test_case).replace(".stl_binders.", ".cases_for_stubgen.") # noqa: PGH001 + expected = TEST_CASES[test_case] assert docstring == expected From 2b2ffebeb81ba44f38a457a3038993f1f7d6a16a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 16 Nov 2023 12:31:13 -0800 Subject: [PATCH 33/39] Introduce `detail::annotated_any()` helper. --- include/pybind11/detail/type_caster_base.h | 6 +++++- include/pybind11/pybind11.h | 4 +--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 77f3d4790b..1b37621677 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -1201,13 +1201,17 @@ class type_caster_base : public type_caster_generic { static Constructor make_move_constructor(...) { return nullptr; } }; +inline std::string annotated_any(const std::string &cpp_type) { + return "Annotated[Any, \"" + cpp_type + "\"]"; +} + PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { if (auto *type_data = get_type_info(ti)) { handle th((PyObject *) type_data->type); return th.attr("__module__").cast() + '.' + th.attr("__qualname__").cast(); } - return "Annotated[Any, \"" + clean_type_id(ti.name()) + "\"]"; + return annotated_any(clean_type_id(ti.name())); } PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 33ad041fd7..84b415a688 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -492,9 +492,7 @@ class cpp_function : public function { signature += rec->scope.attr("__module__").cast() + "." + rec->scope.attr("__qualname__").cast(); } else { - std::string tname(t->name()); - detail::clean_type_id(tname); - signature += "Annotated[Any, \"" + tname + "\"]"; + signature += detail::annotated_any(detail::clean_type_id(t->name())); } } else { signature += c; From 65661fee3988faaa553ac7d742404454f5333b0c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 16 Nov 2023 12:51:42 -0800 Subject: [PATCH 34/39] Change `detail::annotated_any()` to produce `pybind11.CppType(...)` Background: * https://github.com/python/mypy/issues/16306#issuecomment-1815191849 * https://github.com/python/mypy/issues/16306#issuecomment-1815246274 --- include/pybind11/detail/type_caster_base.h | 2 +- tests/test_cases_for_stubgen.py | 30 +++++++++++----------- tests/test_exceptions.py | 2 +- tests/test_numpy_dtypes.py | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 1b37621677..697c94bdd5 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -1202,7 +1202,7 @@ class type_caster_base : public type_caster_generic { }; inline std::string annotated_any(const std::string &cpp_type) { - return "Annotated[Any, \"" + cpp_type + "\"]"; + return "Annotated[Any, pybind11.CppType(\"" + cpp_type + "\")]"; } PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 6bebacb2b1..59d801aa05 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -11,28 +11,28 @@ "m.basics.Point.distance_to.__doc__": "distance_to(*args, **kwargs)\nOverloaded function.\n\n1. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> float\n\n2. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, other: pybind11_tests.cases_for_stubgen.basics.Point) -> float\n", "m.basics.Point.length_unit.__doc__": "Members:\n\n mm\n\n pixel\n\n inch", "m.basics.Point.angle_unit.__doc__": "Members:\n\n radian\n\n degree", - "m.pass_user_type.__doc__": 'pass_user_type(arg0: Annotated[Any, "test_cases_for_stubgen::UserType"]) -> None\n', - "m.return_user_type.__doc__": 'return_user_type() -> Annotated[Any, "test_cases_for_stubgen::UserType"]\n', + "m.pass_user_type.__doc__": 'pass_user_type(arg0: Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]) -> None\n', + "m.return_user_type.__doc__": 'return_user_type() -> Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]\n', "m.MapIntUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView[int]\n", - "m.MapIntUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - "m.MapIntUserType.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - "m.MapUserTypeInt.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapIntUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', + "m.MapIntUserType.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', + "m.MapUserTypeInt.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', "m.MapUserTypeInt.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView[int]\n", - "m.MapUserTypeInt.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, "test_cases_for_stubgen::UserType"], int]\n', + "m.MapUserTypeInt.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")], int]\n', "m.MapFloatUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n", - "m.MapFloatUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', - "m.MapFloatUserType.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, "test_cases_for_stubgen::UserType"]]]\n', - "m.MapUserTypeFloat.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, "test_cases_for_stubgen::UserType"]]\n', + "m.MapFloatUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', + "m.MapFloatUserType.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]\n', + "m.MapUserTypeFloat.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', "m.MapUserTypeFloat.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[float]\n", - "m.MapUserTypeFloat.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, "test_cases_for_stubgen::UserType"], float]]\n', + "m.MapUserTypeFloat.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")], float]]\n', "m.pass_std_array_int_2.__doc__": "pass_std_array_int_2(arg0: Annotated[list[int], FixedSize(2)]) -> None\n", "m.return_std_array_int_3.__doc__": "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n", "m.nested_case_01a.__doc__": "nested_case_01a(arg0: list[Annotated[list[int], FixedSize(2)]]) -> None\n", - "m.nested_case_02a.__doc__": 'nested_case_02a(arg0: list[Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', - "m.nested_case_03a.__doc__": 'nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], Annotated[Any, "test_cases_for_stubgen::UserType"]]) -> None\n', - "m.nested_case_04a.__doc__": 'nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]) -> None\n', - "m.nested_case_05a.__doc__": 'nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]) -> None\n', - "m.nested_case_06a.__doc__": 'nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, "test_cases_for_stubgen::UserType"]]]]]) -> None\n', + "m.nested_case_02a.__doc__": 'nested_case_02a(arg0: list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]) -> None\n', + "m.nested_case_03a.__doc__": 'nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]) -> None\n', + "m.nested_case_04a.__doc__": 'nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]) -> None\n', + "m.nested_case_05a.__doc__": 'nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]]) -> None\n', + "m.nested_case_06a.__doc__": 'nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]]]) -> None\n', } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 336754ca12..22b9d4d46e 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -424,4 +424,4 @@ def test_fn_cast_int_exception(): def test_return_exception_void(): with pytest.raises(TypeError) as excinfo: m.return_exception_void() - assert 'Annotated[Any, "exception"]' in str(excinfo.value) + assert 'Annotated[Any, pybind11.CppType("exception")]' in str(excinfo.value) diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 7653c770b0..01b4cc01e6 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -343,7 +343,7 @@ def test_complex_array(): def test_signature(doc): assert ( doc(m.create_rec_nested) == "create_rec_nested(arg0: int) " - '-> numpy.ndarray[Annotated[Any, "NestedStruct"]]' + '-> numpy.ndarray[Annotated[Any, pybind11.CppType("NestedStruct")]]' ) From 813660cbd4f1638147ea420d1960206cdda01f9b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 16 Dec 2023 16:45:59 -0800 Subject: [PATCH 35/39] Change `annotated_any()` to `quote_cpp_type_name()` --- include/pybind11/detail/type_caster_base.h | 6 +++--- include/pybind11/pybind11.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 697c94bdd5..68c7d9c5ac 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -1201,8 +1201,8 @@ class type_caster_base : public type_caster_generic { static Constructor make_move_constructor(...) { return nullptr; } }; -inline std::string annotated_any(const std::string &cpp_type) { - return "Annotated[Any, pybind11.CppType(\"" + cpp_type + "\")]"; +inline std::string quote_cpp_type_name(const std::string &cpp_type_name) { + return "`" + cpp_type_name + "`"; // See PR #4888 } PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { @@ -1211,7 +1211,7 @@ PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { return th.attr("__module__").cast() + '.' + th.attr("__qualname__").cast(); } - return annotated_any(clean_type_id(ti.name())); + return quote_cpp_type_name(clean_type_id(ti.name())); } PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 84b415a688..bc2f5924a7 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -492,7 +492,7 @@ class cpp_function : public function { signature += rec->scope.attr("__module__").cast() + "." + rec->scope.attr("__qualname__").cast(); } else { - signature += detail::annotated_any(detail::clean_type_id(t->name())); + signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name())); } } else { signature += c; From 66ee131d84b2714aec394b37b3064ee22cb4c0fe Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 16 Dec 2023 16:52:07 -0800 Subject: [PATCH 36/39] Test changes to adjust to previous commit (Change `annotated_any()` to `quote_cpp_type_name()`) --- tests/test_cases_for_stubgen.py | 30 +++++++++++++++--------------- tests/test_exceptions.py | 2 +- tests/test_numpy_dtypes.py | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 59d801aa05..6e1c267359 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -11,28 +11,28 @@ "m.basics.Point.distance_to.__doc__": "distance_to(*args, **kwargs)\nOverloaded function.\n\n1. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> float\n\n2. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, other: pybind11_tests.cases_for_stubgen.basics.Point) -> float\n", "m.basics.Point.length_unit.__doc__": "Members:\n\n mm\n\n pixel\n\n inch", "m.basics.Point.angle_unit.__doc__": "Members:\n\n radian\n\n degree", - "m.pass_user_type.__doc__": 'pass_user_type(arg0: Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]) -> None\n', - "m.return_user_type.__doc__": 'return_user_type() -> Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]\n', + "m.pass_user_type.__doc__": "pass_user_type(arg0: `test_cases_for_stubgen::UserType`) -> None\n", + "m.return_user_type.__doc__": "return_user_type() -> `test_cases_for_stubgen::UserType`\n", "m.MapIntUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView[int]\n", - "m.MapIntUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', - "m.MapIntUserType.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', - "m.MapUserTypeInt.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', + "m.MapIntUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[`test_cases_for_stubgen::UserType`]\n", + "m.MapIntUserType.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, `test_cases_for_stubgen::UserType`]\n", + "m.MapUserTypeInt.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[`test_cases_for_stubgen::UserType`]\n", "m.MapUserTypeInt.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView[int]\n", - "m.MapUserTypeInt.items.__doc__": 'items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")], int]\n', + "m.MapUserTypeInt.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[`test_cases_for_stubgen::UserType`, int]\n", "m.MapFloatUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n", - "m.MapFloatUserType.values.__doc__": 'values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', - "m.MapFloatUserType.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]\n', - "m.MapUserTypeFloat.keys.__doc__": 'keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]\n', + "m.MapFloatUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[`test_cases_for_stubgen::UserType`]\n", + "m.MapFloatUserType.__iter__.__doc__": "__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, `test_cases_for_stubgen::UserType`]]\n", + "m.MapUserTypeFloat.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[`test_cases_for_stubgen::UserType`]\n", "m.MapUserTypeFloat.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[float]\n", - "m.MapUserTypeFloat.__iter__.__doc__": '__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")], float]]\n', + "m.MapUserTypeFloat.__iter__.__doc__": "__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[`test_cases_for_stubgen::UserType`, float]]\n", "m.pass_std_array_int_2.__doc__": "pass_std_array_int_2(arg0: Annotated[list[int], FixedSize(2)]) -> None\n", "m.return_std_array_int_3.__doc__": "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n", "m.nested_case_01a.__doc__": "nested_case_01a(arg0: list[Annotated[list[int], FixedSize(2)]]) -> None\n", - "m.nested_case_02a.__doc__": 'nested_case_02a(arg0: list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]) -> None\n', - "m.nested_case_03a.__doc__": 'nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]) -> None\n', - "m.nested_case_04a.__doc__": 'nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]) -> None\n', - "m.nested_case_05a.__doc__": 'nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]]) -> None\n', - "m.nested_case_06a.__doc__": 'nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[Annotated[Any, pybind11.CppType("test_cases_for_stubgen::UserType")]]]]]) -> None\n', + "m.nested_case_02a.__doc__": "nested_case_02a(arg0: list[`test_cases_for_stubgen::UserType`]) -> None\n", + "m.nested_case_03a.__doc__": "nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], `test_cases_for_stubgen::UserType`]) -> None\n", + "m.nested_case_04a.__doc__": "nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]]) -> None\n", + "m.nested_case_05a.__doc__": "nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]]]) -> None\n", + "m.nested_case_06a.__doc__": "nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]]]]) -> None\n", } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 22b9d4d46e..a0c51c5641 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -424,4 +424,4 @@ def test_fn_cast_int_exception(): def test_return_exception_void(): with pytest.raises(TypeError) as excinfo: m.return_exception_void() - assert 'Annotated[Any, pybind11.CppType("exception")]' in str(excinfo.value) + assert "`exception`" in str(excinfo.value) diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 01b4cc01e6..eff2350057 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -343,7 +343,7 @@ def test_complex_array(): def test_signature(doc): assert ( doc(m.create_rec_nested) == "create_rec_nested(arg0: int) " - '-> numpy.ndarray[Annotated[Any, pybind11.CppType("NestedStruct")]]' + "-> numpy.ndarray[`NestedStruct`]" ) From d14d91e02afba4046c9a899ad47a20220ac1f1a5 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 16 Dec 2023 19:06:16 -0800 Subject: [PATCH 37/39] Remove `handle_type_name` default implementation, add explicit specializations, adjust tests. The primary change is: ```diff template -struct handle_type_name { - static constexpr auto name = const_name(); -}; +struct handle_type_name; + ``` All other changes are adjustments to restore successful build & test. --- include/pybind11/cast.h | 41 ++++++++++++++++++++++++++++++++++--- include/pybind11/pybind11.h | 14 +++++++++++++ include/pybind11/pytypes.h | 1 + tests/test_exceptions.py | 2 +- tests/test_pytypes.cpp | 9 ++++++++ 5 files changed, 63 insertions(+), 4 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index cdeb4aa8ba..fbccf8bf5d 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -872,9 +872,8 @@ template struct is_holder_type> : std::true_type {}; template -struct handle_type_name { - static constexpr auto name = const_name(); -}; +struct handle_type_name; + template <> struct handle_type_name { static constexpr auto name = const_name("object"); @@ -968,6 +967,18 @@ struct handle_type_name { static constexpr auto name = const_name("type"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("capsule"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("ellipsis"); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name("weakref"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("*args"); }; @@ -975,6 +986,30 @@ template <> struct handle_type_name { static constexpr auto name = const_name("**kwargs"); }; +template <> +struct handle_type_name { + static constexpr auto name = const_name(); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name(); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name(); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name(); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name(); +}; +template <> +struct handle_type_name { + static constexpr auto name = const_name(); +}; template struct pyobject_caster { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index bc2f5924a7..429d2138d1 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1190,6 +1190,15 @@ class cpp_function : public function { } }; +PYBIND11_NAMESPACE_BEGIN(detail) + +template <> +struct handle_type_name { + static constexpr auto name = const_name("Callable"); +}; + +PYBIND11_NAMESPACE_END(detail) + /// Wrapper for Python extension modules class module_ : public object { public: @@ -2618,6 +2627,11 @@ class exception : public object { PYBIND11_NAMESPACE_BEGIN(detail) +template <> +struct handle_type_name> { + static constexpr auto name = const_name("Exception"); +}; + // Helper function for register_exception and register_local_exception template exception & diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index e7c7c8124d..d5f6af8e02 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -59,6 +59,7 @@ struct sequence_item; struct list_item; struct tuple_item; } // namespace accessor_policies +// PLEASE KEEP handle_type_name SPECIALIZATIONS IN SYNC. using obj_attr_accessor = accessor; using str_attr_accessor = accessor; using item_accessor = accessor; diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index a0c51c5641..378ec63488 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -424,4 +424,4 @@ def test_fn_cast_int_exception(): def test_return_exception_void(): with pytest.raises(TypeError) as excinfo: m.return_exception_void() - assert "`exception`" in str(excinfo.value) + assert "Exception" in str(excinfo.value) diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index 0cd480ebba..03d46ae98d 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -41,6 +41,15 @@ class float_ : public py::object { }; } // namespace external +namespace pybind11 { +namespace detail { +template <> +struct handle_type_name { + static constexpr auto name = const_name("float"); +}; +} // namespace detail +} // namespace pybind11 + namespace implicit_conversion_from_0_to_handle { // Uncomment to trigger compiler error. Note: Before PR #4008 this used to compile successfully. // void expected_to_trigger_compiler_error() { py::handle(0); } From bf6077affc84e7469877c54bad02e0f2c41e196e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 06:21:36 +0000 Subject: [PATCH 38/39] style: pre-commit fixes --- tests/test_cases_for_stubgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 6e1c267359..9ef99b06ea 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -40,6 +40,6 @@ def test_docstring(test_case): assert dir(m) # Only direct use of m, to stop tooling from removing the import. # On some platforms the stl_binders module name prevails for KeysView, ValuesView, ItemsView. - docstring = eval(test_case).replace(".stl_binders.", ".cases_for_stubgen.") # noqa: PGH001 + docstring = eval(test_case).replace(".stl_binders.", ".cases_for_stubgen.") expected = TEST_CASES[test_case] assert docstring == expected From d57ed515a82899050e2c9c364bb8b3f339a46c2b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 2 Apr 2024 20:35:57 -0700 Subject: [PATCH 39/39] Adjustments related to pybind/pybind11#4985 --- tests/test_cases_for_stubgen.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_cases_for_stubgen.py b/tests/test_cases_for_stubgen.py index 9ef99b06ea..ed59aaedf9 100644 --- a/tests/test_cases_for_stubgen.py +++ b/tests/test_cases_for_stubgen.py @@ -13,12 +13,12 @@ "m.basics.Point.angle_unit.__doc__": "Members:\n\n radian\n\n degree", "m.pass_user_type.__doc__": "pass_user_type(arg0: `test_cases_for_stubgen::UserType`) -> None\n", "m.return_user_type.__doc__": "return_user_type() -> `test_cases_for_stubgen::UserType`\n", - "m.MapIntUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView[int]\n", - "m.MapIntUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView[`test_cases_for_stubgen::UserType`]\n", - "m.MapIntUserType.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView[int, `test_cases_for_stubgen::UserType`]\n", - "m.MapUserTypeInt.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView[`test_cases_for_stubgen::UserType`]\n", - "m.MapUserTypeInt.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView[int]\n", - "m.MapUserTypeInt.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView[`test_cases_for_stubgen::UserType`, int]\n", + "m.MapIntUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView\n", + "m.MapIntUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView\n", + "m.MapIntUserType.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView\n", + "m.MapUserTypeInt.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView\n", + "m.MapUserTypeInt.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView\n", + "m.MapUserTypeInt.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView\n", "m.MapFloatUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n", "m.MapFloatUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[`test_cases_for_stubgen::UserType`]\n", "m.MapFloatUserType.__iter__.__doc__": "__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, `test_cases_for_stubgen::UserType`]]\n",