From 68405a1141fba1314c378133f12808a4d97bd3d8 Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sat, 15 Jun 2024 00:16:26 -0400 Subject: [PATCH 1/2] Add `Union` and `Optional` to typing.h (#5165) * add type unions and optionals * add type inheritance * style: pre-commit fixes * switch to inheriting from object * style: pre-commit fixes * fix text case * style: pre-commit fixes * fix bind call * fix function name * add std::move for older code * remove std::move * move away from object creation * style: pre-commit fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/typing.h | 22 ++++++++++++++++++++++ tests/test_pytypes.cpp | 22 ++++++++++++++++++++++ tests/test_pytypes.py | 21 +++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index bc275fc50..2c9eaffbc 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -63,6 +63,16 @@ class Callable : public function { using function::function; }; +template +class Union : public object { + using object::object; +}; + +template +class Optional : public object { + using object::object; +}; + PYBIND11_NAMESPACE_END(typing) PYBIND11_NAMESPACE_BEGIN(detail) @@ -121,5 +131,17 @@ struct handle_type_name> { + const_name("], ") + make_caster::name + const_name("]"); }; +template +struct handle_type_name> { + static constexpr auto name = const_name("Union[") + + ::pybind11::detail::concat(make_caster::name...) + + const_name("]"); +}; + +template +struct handle_type_name> { + static constexpr auto name = const_name("Optional[") + make_caster::name + const_name("]"); +}; + PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index f3709d40c..e97dceee3 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -844,4 +844,26 @@ TEST_SUBMODULE(pytypes, m) { m.def("annotate_iterator_int", [](const py::typing::Iterator &) {}); m.def("annotate_fn", [](const py::typing::Callable, py::str)> &) {}); + + m.def("annotate_union", + [](py::typing::List> l, + py::str a, + py::int_ b, + py::object c) -> py::typing::List> { + l.append(a); + l.append(b); + l.append(c); + return l; + }); + + m.def("union_typing_only", + [](py::typing::List> &l) + -> py::typing::List> { return l; }); + + m.def("annotate_optional", + [](py::list &list) -> py::typing::List> { + list.append(py::str("hi")); + list.append(py::none()); + return list; + }); } diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 38edfd999..ca2c51c40 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -955,3 +955,24 @@ def test_fn_annotations(doc): doc(m.annotate_fn) == "annotate_fn(arg0: Callable[[list[str], str], int]) -> None" ) + + +def test_union_annotations(doc): + assert ( + doc(m.annotate_union) + == "annotate_union(arg0: list[Union[str, int, object]], arg1: str, arg2: int, arg3: object) -> list[Union[str, int, object]]" + ) + + +def test_union_typing_only(doc): + assert ( + doc(m.union_typing_only) + == "union_typing_only(arg0: list[Union[str]]) -> list[Union[int]]" + ) + + +def test_optional_annotations(doc): + assert ( + doc(m.annotate_optional) + == "annotate_optional(arg0: list) -> list[Optional[str]]" + ) From 7c4ac91d75c60e252050e6c52a289b9b656c0a59 Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sat, 15 Jun 2024 09:25:43 -0400 Subject: [PATCH 2/2] Add type[T] support to typing.h (#5166) * add type[T] * style: pre-commit fixes * fix merge --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/typing.h | 10 ++++++++++ tests/test_pytypes.cpp | 1 + tests/test_pytypes.py | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index 2c9eaffbc..e0d0e45c4 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -63,6 +63,11 @@ class Callable : public function { using function::function; }; +template +class Type : public type { + using type::type; +}; + template class Union : public object { using object::object; @@ -131,6 +136,11 @@ struct handle_type_name> { + const_name("], ") + make_caster::name + const_name("]"); }; +template +struct handle_type_name> { + static constexpr auto name = const_name("type[") + make_caster::name + const_name("]"); +}; + template struct handle_type_name> { static constexpr auto name = const_name("Union[") diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index e97dceee3..e5a318ad8 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -844,6 +844,7 @@ TEST_SUBMODULE(pytypes, m) { m.def("annotate_iterator_int", [](const py::typing::Iterator &) {}); m.def("annotate_fn", [](const py::typing::Callable, py::str)> &) {}); + m.def("annotate_type", [](const py::typing::Type &) {}); m.def("annotate_union", [](py::typing::List> l, diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index ca2c51c40..72dac13b8 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -957,6 +957,10 @@ def test_fn_annotations(doc): ) +def test_type_annotation(doc): + assert doc(m.annotate_type) == "annotate_type(arg0: type[int]) -> None" + + def test_union_annotations(doc): assert ( doc(m.annotate_union)