Skip to content

Commit 68405a1

Browse files
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>
1 parent ab955f1 commit 68405a1

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

include/pybind11/typing.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ class Callable<Return(Args...)> : public function {
6363
using function::function;
6464
};
6565

66+
template <typename... Types>
67+
class Union : public object {
68+
using object::object;
69+
};
70+
71+
template <typename T>
72+
class Optional : public object {
73+
using object::object;
74+
};
75+
6676
PYBIND11_NAMESPACE_END(typing)
6777

6878
PYBIND11_NAMESPACE_BEGIN(detail)
@@ -121,5 +131,17 @@ struct handle_type_name<typing::Callable<Return(Args...)>> {
121131
+ const_name("], ") + make_caster<retval_type>::name + const_name("]");
122132
};
123133

134+
template <typename... Types>
135+
struct handle_type_name<typing::Union<Types...>> {
136+
static constexpr auto name = const_name("Union[")
137+
+ ::pybind11::detail::concat(make_caster<Types>::name...)
138+
+ const_name("]");
139+
};
140+
141+
template <typename T>
142+
struct handle_type_name<typing::Optional<T>> {
143+
static constexpr auto name = const_name("Optional[") + make_caster<T>::name + const_name("]");
144+
};
145+
124146
PYBIND11_NAMESPACE_END(detail)
125147
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

tests/test_pytypes.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,4 +844,26 @@ TEST_SUBMODULE(pytypes, m) {
844844
m.def("annotate_iterator_int", [](const py::typing::Iterator<int> &) {});
845845
m.def("annotate_fn",
846846
[](const py::typing::Callable<int(py::typing::List<py::str>, py::str)> &) {});
847+
848+
m.def("annotate_union",
849+
[](py::typing::List<py::typing::Union<py::str, py::int_, py::object>> l,
850+
py::str a,
851+
py::int_ b,
852+
py::object c) -> py::typing::List<py::typing::Union<py::str, py::int_, py::object>> {
853+
l.append(a);
854+
l.append(b);
855+
l.append(c);
856+
return l;
857+
});
858+
859+
m.def("union_typing_only",
860+
[](py::typing::List<py::typing::Union<py::str>> &l)
861+
-> py::typing::List<py::typing::Union<py::int_>> { return l; });
862+
863+
m.def("annotate_optional",
864+
[](py::list &list) -> py::typing::List<py::typing::Optional<py::str>> {
865+
list.append(py::str("hi"));
866+
list.append(py::none());
867+
return list;
868+
});
847869
}

tests/test_pytypes.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,3 +955,24 @@ def test_fn_annotations(doc):
955955
doc(m.annotate_fn)
956956
== "annotate_fn(arg0: Callable[[list[str], str], int]) -> None"
957957
)
958+
959+
960+
def test_union_annotations(doc):
961+
assert (
962+
doc(m.annotate_union)
963+
== "annotate_union(arg0: list[Union[str, int, object]], arg1: str, arg2: int, arg3: object) -> list[Union[str, int, object]]"
964+
)
965+
966+
967+
def test_union_typing_only(doc):
968+
assert (
969+
doc(m.union_typing_only)
970+
== "union_typing_only(arg0: list[Union[str]]) -> list[Union[int]]"
971+
)
972+
973+
974+
def test_optional_annotations(doc):
975+
assert (
976+
doc(m.annotate_optional)
977+
== "annotate_optional(arg0: list) -> list[Optional[str]]"
978+
)

0 commit comments

Comments
 (0)