Restore basic functionality on 3.14[sic] (#1329)
* Restore basic functionality on 3.14[sic] Essentially switch to PEP 649 / 749 for annotations. Some tests need to be skipped for now, but the rest is working. Fixes #1326 * Add news fragment * We have not 3.14 CI yet * Use imprerative xfails instead of skips
This commit is contained in:
parent
f520d9a89f
commit
7373d88f9b
|
@ -0,0 +1 @@
|
||||||
|
Restored support for PEP [649](https://peps.python.org/pep-0649/) / [749](https://peps.python.org/pep-0749/)-implementing Pythons -- currently 3.14-dev.
|
|
@ -15,6 +15,7 @@ PY_3_9_PLUS = sys.version_info[:2] >= (3, 9)
|
||||||
PY_3_10_PLUS = sys.version_info[:2] >= (3, 10)
|
PY_3_10_PLUS = sys.version_info[:2] >= (3, 10)
|
||||||
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
|
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
|
||||||
PY_3_13_PLUS = sys.version_info[:2] >= (3, 13)
|
PY_3_13_PLUS = sys.version_info[:2] >= (3, 13)
|
||||||
|
PY_3_14_PLUS = sys.version_info[:2] >= (3, 14)
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info < (3, 8):
|
if sys.version_info < (3, 8):
|
||||||
|
@ -25,6 +26,19 @@ if sys.version_info < (3, 8):
|
||||||
else:
|
else:
|
||||||
from typing import Protocol # noqa: F401
|
from typing import Protocol # noqa: F401
|
||||||
|
|
||||||
|
if PY_3_14_PLUS: # pragma: no cover
|
||||||
|
import annotationlib
|
||||||
|
|
||||||
|
_get_annotations = annotationlib.get_annotations
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _get_annotations(cls):
|
||||||
|
"""
|
||||||
|
Get annotations for *cls*.
|
||||||
|
"""
|
||||||
|
return cls.__dict__.get("__annotations__", {})
|
||||||
|
|
||||||
|
|
||||||
class _AnnotationExtractor:
|
class _AnnotationExtractor:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -23,6 +23,7 @@ from ._compat import (
|
||||||
PY_3_8_PLUS,
|
PY_3_8_PLUS,
|
||||||
PY_3_10_PLUS,
|
PY_3_10_PLUS,
|
||||||
_AnnotationExtractor,
|
_AnnotationExtractor,
|
||||||
|
_get_annotations,
|
||||||
get_generic_base,
|
get_generic_base,
|
||||||
)
|
)
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
|
@ -308,13 +309,6 @@ def _has_own_attribute(cls, attrib_name):
|
||||||
return attrib_name in cls.__dict__
|
return attrib_name in cls.__dict__
|
||||||
|
|
||||||
|
|
||||||
def _get_annotations(cls):
|
|
||||||
"""
|
|
||||||
Get annotations for *cls*.
|
|
||||||
"""
|
|
||||||
return cls.__dict__.get("__annotations__", {})
|
|
||||||
|
|
||||||
|
|
||||||
def _collect_base_attrs(cls, taken_attr_names):
|
def _collect_base_attrs(cls, taken_attr_names):
|
||||||
"""
|
"""
|
||||||
Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.
|
Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.
|
||||||
|
|
|
@ -8,12 +8,17 @@ import pytest
|
||||||
|
|
||||||
from hypothesis import given
|
from hypothesis import given
|
||||||
|
|
||||||
|
from attr._compat import PY_3_14_PLUS
|
||||||
|
|
||||||
from .strategies import simple_classes
|
from .strategies import simple_classes
|
||||||
|
|
||||||
|
|
||||||
cloudpickle = pytest.importorskip("cloudpickle")
|
cloudpickle = pytest.importorskip("cloudpickle")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(
|
||||||
|
PY_3_14_PLUS, reason="cloudpickle is currently broken on 3.14."
|
||||||
|
)
|
||||||
class TestCloudpickleCompat:
|
class TestCloudpickleCompat:
|
||||||
"""
|
"""
|
||||||
Tests for compatibility with ``cloudpickle``.
|
Tests for compatibility with ``cloudpickle``.
|
||||||
|
|
|
@ -12,6 +12,7 @@ import pytest
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
|
|
||||||
|
from attr._compat import PY_3_14_PLUS
|
||||||
from attr._make import _is_class_var
|
from attr._make import _is_class_var
|
||||||
from attr.exceptions import UnannotatedAttributeError
|
from attr.exceptions import UnannotatedAttributeError
|
||||||
|
|
||||||
|
@ -588,6 +589,8 @@ class TestAnnotations:
|
||||||
"""
|
"""
|
||||||
References to self class using quotes can be resolved.
|
References to self class using quotes can be resolved.
|
||||||
"""
|
"""
|
||||||
|
if PY_3_14_PLUS and not slots:
|
||||||
|
pytest.xfail("References are changing a lot in 3.14.")
|
||||||
|
|
||||||
@attr.s(slots=slots, auto_attribs=True)
|
@attr.s(slots=slots, auto_attribs=True)
|
||||||
class A:
|
class A:
|
||||||
|
@ -603,6 +606,8 @@ class TestAnnotations:
|
||||||
"""
|
"""
|
||||||
Forward references can be resolved.
|
Forward references can be resolved.
|
||||||
"""
|
"""
|
||||||
|
if PY_3_14_PLUS and not slots:
|
||||||
|
pytest.xfail("Forward references are changing a lot in 3.14.")
|
||||||
|
|
||||||
@attr.s(slots=slots, auto_attribs=True)
|
@attr.s(slots=slots, auto_attribs=True)
|
||||||
class A:
|
class A:
|
||||||
|
|
|
@ -21,7 +21,7 @@ from hypothesis.strategies import booleans, integers, lists, sampled_from, text
|
||||||
import attr
|
import attr
|
||||||
|
|
||||||
from attr import _config
|
from attr import _config
|
||||||
from attr._compat import PY_3_8_PLUS, PY_3_10_PLUS
|
from attr._compat import PY_3_8_PLUS, PY_3_10_PLUS, PY_3_14_PLUS
|
||||||
from attr._make import (
|
from attr._make import (
|
||||||
Attribute,
|
Attribute,
|
||||||
Factory,
|
Factory,
|
||||||
|
@ -1838,9 +1838,11 @@ class TestClassBuilder:
|
||||||
assert [C2] == C.__subclasses__()
|
assert [C2] == C.__subclasses__()
|
||||||
|
|
||||||
@pytest.mark.skipif(not PY_3_8_PLUS, reason="cached_property is 3.8+")
|
@pytest.mark.skipif(not PY_3_8_PLUS, reason="cached_property is 3.8+")
|
||||||
|
@pytest.mark.xfail(PY_3_14_PLUS, reason="Currently broken on nightly.")
|
||||||
def test_no_references_to_original_when_using_cached_property(self):
|
def test_no_references_to_original_when_using_cached_property(self):
|
||||||
"""
|
"""
|
||||||
When subclassing a slotted class and using cached property, there are no stray references to the original class.
|
When subclassing a slotted class and using cached property, there are
|
||||||
|
no stray references to the original class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@attr.s(slots=True)
|
@attr.s(slots=True)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"""
|
"""
|
||||||
Unit tests for slots-related functionality.
|
Unit tests for slots-related functionality.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import pickle
|
import pickle
|
||||||
import weakref
|
import weakref
|
||||||
|
@ -14,7 +15,7 @@ import pytest
|
||||||
import attr
|
import attr
|
||||||
import attrs
|
import attrs
|
||||||
|
|
||||||
from attr._compat import PY_3_8_PLUS, PYPY
|
from attr._compat import PY_3_8_PLUS, PY_3_14_PLUS, PYPY
|
||||||
|
|
||||||
|
|
||||||
# Pympler doesn't work on PyPy.
|
# Pympler doesn't work on PyPy.
|
||||||
|
@ -774,6 +775,9 @@ def test_slots_cached_property_works_on_frozen_isntances():
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not PY_3_8_PLUS, reason="cached_property is 3.8+")
|
@pytest.mark.skipif(not PY_3_8_PLUS, reason="cached_property is 3.8+")
|
||||||
|
@pytest.mark.xfail(
|
||||||
|
PY_3_14_PLUS, reason="3.14 returns weird annotation for cached_properies"
|
||||||
|
)
|
||||||
def test_slots_cached_property_infers_type():
|
def test_slots_cached_property_infers_type():
|
||||||
"""
|
"""
|
||||||
Infers type of cached property.
|
Infers type of cached property.
|
||||||
|
|
Loading…
Reference in New Issue