Fix ClassVar forward reference detection (#1593)
fix: detect ClassVar forward refs
Co-authored-by: Hynek Schlawack <hs@ox.cx>
diff --git a/changelog.d/1593.change.md b/changelog.d/1593.change.md
new file mode 100644
index 0000000..d3fd8eb
--- /dev/null
+++ b/changelog.d/1593.change.md
@@ -0,0 +1 @@
+Unimported `typing.ClassVar` annotations created as forward references are now detected as class variables.
diff --git a/src/attr/_make.py b/src/attr/_make.py
index 04104d9..c71e872 100644
--- a/src/attr/_make.py
+++ b/src/attr/_make.py
@@ -297,6 +297,7 @@
annotations which would put attrs-based classes at a performance
disadvantage compared to plain old classes.
"""
+ annot = getattr(annot, "__forward_arg__", annot)
annot = str(annot)
# Annotation can be quoted.
diff --git a/tests/test_annotations.py b/tests/test_annotations.py
index e193d4b..de3d105 100644
--- a/tests/test_annotations.py
+++ b/tests/test_annotations.py
@@ -434,6 +434,23 @@
assert_init_annotations(C)
+ @pytest.mark.skipif(
+ sys.version_info[:2] < (3, 14),
+ reason="Python 3.14 changed annotation evaluation behavior.",
+ )
+ def test_missing_classvar_import(self, slots):
+ """
+ Unimported ClassVars are recognized as ForwardRefs.
+ """
+
+ @attr.s(auto_attribs=True, slots=slots)
+ class C:
+ cls_var: ClassVar[str] # noqa: F821
+ value: int = 1
+
+ assert "cls_var" not in attr.fields_dict(C)
+ assert 1 == C().value
+
def test_keyword_only_auto_attribs(self):
"""
`kw_only` propagates to attributes defined via `auto_attribs`.
@@ -691,6 +708,7 @@
"typing.ClassVar",
"'typing.ClassVar[dict]'",
"t.ClassVar[int]",
+ typing.ForwardRef("ClassVar[str]"),
],
)
def test_is_class_var(annot):