Skip to content

Commit 61e8179

Browse files
Tinchehynek
andauthored
Allow forward-references on 3.14 (#1451)
* Request stringified annotations * Add test * ruff: mark test_forward_references as 3.14 * Use FORWARDREF instead See https://github.com/python/cpython/blob/9d3b53c47fab9ebf1f40d6f21b7d1ad391c14cd7/Lib/dataclasses.py#L989-L990 * Fix comment * Apply docstring standard * Add news fragment Unite with the other one to avoid confusion. * Temporal form * Flesh out test --------- Co-authored-by: Hynek Schlawack <[email protected]>
1 parent 199cd54 commit 61e8179

File tree

6 files changed

+37
-6
lines changed

6 files changed

+37
-6
lines changed

changelog.d/1446.change.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
On 3.14, the cycles in slotted classes are now manually broken.
2-
An explicit call to `gc.collect()` is still necessary, unfortunately.
1+
Added support for Python 3.14.

changelog.d/1451.change.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for Python 3.14.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ line-length = 79
196196

197197
[tool.ruff.per-file-target-version]
198198
"tests/test_pattern_matching.py" = "py310"
199+
"tests/test_forward_references.py" = "py314"
199200

200201
[tool.ruff.lint]
201202
select = ["ALL"]

src/attr/_compat.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@
1717
PY_3_14_PLUS = sys.version_info[:2] >= (3, 14)
1818

1919

20-
if PY_3_14_PLUS: # pragma: no cover
20+
if PY_3_14_PLUS:
2121
import annotationlib
2222

23-
_get_annotations = annotationlib.get_annotations
23+
# We request forward-ref annotations to not break in the presence of
24+
# forward references.
25+
26+
def _get_annotations(cls):
27+
return annotationlib.get_annotations(
28+
cls, format=annotationlib.Format.FORWARDREF
29+
)
2430

2531
else:
2632

conftest.py renamed to tests/conftest.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from hypothesis import HealthCheck, settings
88

9-
from attr._compat import PY_3_10_PLUS
9+
from attr._compat import PY_3_10_PLUS, PY_3_14_PLUS
1010

1111

1212
@pytest.fixture(name="slots", params=(True, False))
@@ -33,4 +33,6 @@ def pytest_configure(config):
3333

3434
collect_ignore = []
3535
if not PY_3_10_PLUS:
36-
collect_ignore.extend(["tests/test_pattern_matching.py"])
36+
collect_ignore.extend(["test_pattern_matching.py"])
37+
if not PY_3_14_PLUS:
38+
collect_ignore.extend(["test_forward_references.py"])

tests/test_forward_references.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
Tests for behavior specific to forward references via PEP 749.
3+
"""
4+
5+
from attrs import define, fields, resolve_types
6+
7+
8+
def test_forward_class_reference():
9+
"""
10+
Class A can reference B even though it is defined later.
11+
"""
12+
13+
@define
14+
class A:
15+
b: B
16+
17+
class B:
18+
pass
19+
20+
resolve_types(A)
21+
22+
assert fields(A).b.type is B

0 commit comments

Comments
 (0)