Skip to content

Commit 2be85c6

Browse files
InvincibleRMChenryiiipre-commit-ci[bot]
authored
feat(types): adds support for TypeGuard and TypeIs (#5194)
* Adds support for TypeGuard and TypeIs * style: pre-commit fixes --------- Co-authored-by: Henry Schreiner <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent b5ec7c7 commit 2be85c6

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

include/pybind11/typing.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,24 @@ class Optional : public object {
8080
using object::object;
8181
};
8282

83+
template <typename T>
84+
class TypeGuard : public bool_ {
85+
using bool_::bool_;
86+
};
87+
88+
template <typename T>
89+
class TypeIs : public bool_ {
90+
using bool_::bool_;
91+
};
92+
8393
class NoReturn : public none {
8494
using none::none;
8595
};
8696

8797
class Never : public none {
8898
using none::none;
8999
};
100+
90101
#if defined(__cpp_nontype_template_parameter_class)
91102
template <size_t N>
92103
struct StringLiteral {
@@ -183,6 +194,16 @@ struct handle_type_name<typing::Optional<T>> {
183194
static constexpr auto name = const_name("Optional[") + make_caster<T>::name + const_name("]");
184195
};
185196

197+
template <typename T>
198+
struct handle_type_name<typing::TypeGuard<T>> {
199+
static constexpr auto name = const_name("TypeGuard[") + make_caster<T>::name + const_name("]");
200+
};
201+
202+
template <typename T>
203+
struct handle_type_name<typing::TypeIs<T>> {
204+
static constexpr auto name = const_name("TypeIs[") + make_caster<T>::name + const_name("]");
205+
};
206+
186207
template <>
187208
struct handle_type_name<typing::NoReturn> {
188209
static constexpr auto name = const_name("NoReturn");
@@ -192,6 +213,7 @@ template <>
192213
struct handle_type_name<typing::Never> {
193214
static constexpr auto name = const_name("Never");
194215
};
216+
195217
#if defined(__cpp_nontype_template_parameter_class)
196218
template <typing::StringLiteral... Literals>
197219
struct handle_type_name<typing::Literal<Literals...>> {

tests/test_pytypes.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,15 @@ TEST_SUBMODULE(pytypes, m) {
892892
return list;
893893
});
894894

895+
m.def("annotate_type_guard", [](py::object &o) -> py::typing::TypeGuard<py::str> {
896+
return py::isinstance<py::str>(o);
897+
});
898+
m.def("annotate_type_is",
899+
[](py::object &o) -> py::typing::TypeIs<py::str> { return py::isinstance<py::str>(o); });
900+
895901
m.def("annotate_no_return", []() -> py::typing::NoReturn { throw 0; });
896902
m.def("annotate_never", []() -> py::typing::Never { throw 0; });
903+
897904
m.def("annotate_optional_to_object",
898905
[](py::typing::Optional<int> &o) -> py::object { return o; });
899906

tests/test_pytypes.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,17 @@ def test_optional_annotations(doc):
991991
)
992992

993993

994+
def test_type_guard_annotations(doc):
995+
assert (
996+
doc(m.annotate_type_guard)
997+
== "annotate_type_guard(arg0: object) -> TypeGuard[str]"
998+
)
999+
1000+
1001+
def test_type_is_annotations(doc):
1002+
assert doc(m.annotate_type_is) == "annotate_type_is(arg0: object) -> TypeIs[str]"
1003+
1004+
9941005
def test_no_return_annotation(doc):
9951006
assert doc(m.annotate_no_return) == "annotate_no_return() -> NoReturn"
9961007

0 commit comments

Comments
 (0)