diff --git a/changelog.d/1446.change.md b/changelog.d/1446.change.md index 2a069ea36..6c0754987 100644 --- a/changelog.d/1446.change.md +++ b/changelog.d/1446.change.md @@ -1,2 +1 @@ -On 3.14, the cycles in slotted classes are now manually broken. -An explicit call to `gc.collect()` is still necessary, unfortunately. +Added support for Python 3.14. diff --git a/changelog.d/1451.change.md b/changelog.d/1451.change.md new file mode 100644 index 000000000..6c0754987 --- /dev/null +++ b/changelog.d/1451.change.md @@ -0,0 +1 @@ +Added support for Python 3.14. diff --git a/pyproject.toml b/pyproject.toml index 2d665ffce..bdb832e3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -196,6 +196,7 @@ line-length = 79 [tool.ruff.per-file-target-version] "tests/test_pattern_matching.py" = "py310" +"tests/test_forward_references.py" = "py314" [tool.ruff.lint] select = ["ALL"] diff --git a/src/attr/_compat.py b/src/attr/_compat.py index 130de4303..bc68ed9ea 100644 --- a/src/attr/_compat.py +++ b/src/attr/_compat.py @@ -17,10 +17,16 @@ PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) -if PY_3_14_PLUS: # pragma: no cover +if PY_3_14_PLUS: import annotationlib - _get_annotations = annotationlib.get_annotations + # We request forward-ref annotations to not break in the presence of + # forward references. + + def _get_annotations(cls): + return annotationlib.get_annotations( + cls, format=annotationlib.Format.FORWARDREF + ) else: diff --git a/conftest.py b/tests/conftest.py similarity index 79% rename from conftest.py rename to tests/conftest.py index e22f79d53..3e48c3fdf 100644 --- a/conftest.py +++ b/tests/conftest.py @@ -6,7 +6,7 @@ from hypothesis import HealthCheck, settings -from attr._compat import PY_3_10_PLUS +from attr._compat import PY_3_10_PLUS, PY_3_14_PLUS @pytest.fixture(name="slots", params=(True, False)) @@ -33,4 +33,6 @@ def pytest_configure(config): collect_ignore = [] if not PY_3_10_PLUS: - collect_ignore.extend(["tests/test_pattern_matching.py"]) + collect_ignore.extend(["test_pattern_matching.py"]) +if not PY_3_14_PLUS: + collect_ignore.extend(["test_forward_references.py"]) diff --git a/tests/test_forward_references.py b/tests/test_forward_references.py new file mode 100644 index 000000000..90dfc2b0c --- /dev/null +++ b/tests/test_forward_references.py @@ -0,0 +1,22 @@ +""" +Tests for behavior specific to forward references via PEP 749. +""" + +from attrs import define, fields, resolve_types + + +def test_forward_class_reference(): + """ + Class A can reference B even though it is defined later. + """ + + @define + class A: + b: B + + class B: + pass + + resolve_types(A) + + assert fields(A).b.type is B