From 14d2dda5eba15591123832cefb359a851095dbbe Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sun, 15 Dec 2024 15:46:10 -0500 Subject: [PATCH] update test case --- include/pybind11/typing.h | 17 ++++++++++++++--- tests/test_pytypes.cpp | 10 ++++------ tests/test_pytypes.py | 20 +++++++++++++++----- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index ee8748c2b..005279058 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -88,6 +88,12 @@ class Final : public object { using object::object; }; +template +class ClassVar : public object { + PYBIND11_OBJECT_DEFAULT(ClassVar, object, PyObject_Type) + using object::object; +}; + template class TypeGuard : public bool_ { using bool_::bool_; @@ -257,14 +263,19 @@ struct handle_type_name> { = const_name("Optional[") + as_return_type>::name + const_name("]"); }; -// TypeGuard and TypeIs use as_return_type to use the return type if available, which is usually -// the narrower type. - template struct handle_type_name> { static constexpr auto name = const_name("Final[") + make_caster::name + const_name("]"); }; +template +struct handle_type_name> { + static constexpr auto name = const_name("ClassVar[") + make_caster::name + const_name("]"); +}; + +// TypeGuard and TypeIs use as_return_type to use the return type if available, which is usually +// the narrower type. + template struct handle_type_name> { static constexpr auto name diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index b9051f82b..819ed1801 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -1045,13 +1045,11 @@ TEST_SUBMODULE(pytypes, m) { struct Empty {}; py::class_(m, "EmptyAnnotationClass"); - struct Point { - float x; - py::dict dict_str_int; - }; + struct Point {}; auto point = py::class_(m, "Point"); - point.attr_with_type_hint("x"); - point.attr_with_type_hint>("dict_str_int") = py::dict(); + point.def(py::init()); + point.attr_with_type_hint>("x"); + point.attr_with_type_hint>>("dict_str_int") = py::dict(); m.attr_with_type_hint>("CONST_INT") = 3; m.attr("defined_PYBIND11_CPP17") = true; diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 84f1b66fc..748aaa9fd 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -1106,8 +1106,8 @@ def test_dict_ranges(tested_dict, expected): # https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older def get_annotations_helper(o): if isinstance(o, type): - return o.__dict__.get("__annotations__", {}) - return getattr(o, "__annotations__", {}) + return o.__dict__.get("__annotations__", None) + return getattr(o, "__annotations__", None) @pytest.mark.skipif( @@ -1129,9 +1129,19 @@ def test_class_attribute_types() -> None: empty_annotations = get_annotations_helper(m.EmptyAnnotationClass) annotations = get_annotations_helper(m.Point) - assert empty_annotations == {} - assert annotations["x"] == "float" - assert annotations["dict_str_int"] == "dict[str, int]" + assert empty_annotations is None + assert annotations["x"] == "ClassVar[float]" + assert annotations["dict_str_int"] == "ClassVar[dict[str, int]]" + + m.Point.x = 1.0 + assert m.Point.x == 1.0 + + point = m.Point() + assert point.x == 1.0 + + point.dict_str_int["hi"] = 3 + assert m.Point().dict_str_int == {"hi": 3} + @pytest.mark.skipif(