diff --git a/CHANGELOG.md b/CHANGELOG.md index e964462d..237a36ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,7 +66,7 @@ See https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md#chan [#1068](https://github.com/python-attrs/attrs/issues/1068) - `attrs.has()` and `attrs.fields()` now handle generic classes correctly. [#1079](https://github.com/python-attrs/attrs/issues/1079) -- Fix frozen exception classes when raised within e.g. `contextlib.contextmanager`, which mutates their `__traceback__` attributes. +- Fix frozen exception classes when raised within, for example, `contextlib.contextmanager`, which mutates their `__traceback__` attributes. [#1081](https://github.com/python-attrs/attrs/issues/1081) - `@frozen` now works with type checkers that implement [PEP-681](https://peps.python.org/pep-0681/) (ex. [pyright](https://github.com/microsoft/pyright/)). [#1084](https://github.com/python-attrs/attrs/issues/1084) @@ -113,7 +113,7 @@ See https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md#chan Get `__init__` signatures matching any taste, peculiar or plain! The [PEP 681 compatible](https://peps.python.org/pep-0681/#field-specifier-parameters) *alias* option can be use to override private attribute name mangling, or add other arbitrary field argument name overrides. [#950](https://github.com/python-attrs/attrs/issues/950) -- `attrs.NOTHING` is now an enum value, making it possible to use with e.g. [`typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal). +- `attrs.NOTHING` is now an enum value, making it possible to use with, for example, [`typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal). [#983](https://github.com/python-attrs/attrs/issues/983) - Added missing re-import of `attr.AttrsInstance` to the `attrs` namespace. [#987](https://github.com/python-attrs/attrs/issues/987) @@ -195,7 +195,7 @@ See https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md#chan ### Backward-incompatible Changes - When using `@define`, converters are now run by default when setting an attribute on an instance -- additionally to validators. - I.e. the new default is `on_setattr=[attrs.setters.convert, attrs.setters.validate]`. + Meaning: the new default is `on_setattr=[attrs.setters.convert, attrs.setters.validate]`. This is unfortunately a breaking change, but it was an oversight, impossible to raise a `DeprecationWarning` about, and it's better to fix it now while the APIs are very fresh with few users. [#835](https://github.com/python-attrs/attrs/issues/835), @@ -494,7 +494,7 @@ See https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md#chan - `attrs` can now automatically detect your own implementations and infer `init=False`, `repr=False`, `eq=False`, `order=False`, and `hash=False` if you set `@attr.s(auto_detect=True)`. `attrs` will ignore inherited methods. - If the argument implies more than one method (e.g. `eq=True` creates both `__eq__` and `__ne__`), it's enough for *one* of them to exist and `attrs` will create *neither*. + If the argument implies more than one method (for example, `eq=True` creates both `__eq__` and `__ne__`), it's enough for *one* of them to exist and `attrs` will create *neither*. This feature requires Python 3. [#607](https://github.com/python-attrs/attrs/issues/607) @@ -727,7 +727,7 @@ See https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md#chan [#290](https://github.com/python-attrs/attrs/issues/290), [#349](https://github.com/python-attrs/attrs/issues/349) -- The order of attributes that are passed into `attr.make_class()` or the *these* argument of `@attr.s()` is now retained if the dictionary is ordered (i.e. `dict` on Python 3.6 and later, `collections.OrderedDict` otherwise). +- The order of attributes that are passed into `attr.make_class()` or the *these* argument of `@attr.s()` is now retained if the dictionary is ordered (in other words: `dict` on Python 3.6 and later, `collections.OrderedDict` otherwise). Before, the order was always determined by the order in which the attributes have been defined which may not be desirable when creating classes programmatically. @@ -1105,7 +1105,7 @@ To encourage more participation, the project has also been moved into a [dedicat ### Changes: - Added a `convert` argument to `attr.ib`, which allows specifying a function to run on arguments. - This allows for simple type conversions, e.g. with `attr.ib(convert=int)`. + This allows for simple type conversions, for example, with `attr.ib(convert=int)`. [#26](https://github.com/python-attrs/attrs/issues/26) - Speed up object creation when attribute validators are used. [#28](https://github.com/python-attrs/attrs/issues/28) diff --git a/conftest.py b/conftest.py index 4ca53847..e22f79d5 100644 --- a/conftest.py +++ b/conftest.py @@ -6,7 +6,7 @@ import pytest from hypothesis import HealthCheck, settings -from attr._compat import PY310 +from attr._compat import PY_3_10_PLUS @pytest.fixture(name="slots", params=(True, False)) @@ -32,5 +32,5 @@ def pytest_configure(config): collect_ignore = [] -if not PY310: +if not PY_3_10_PLUS: collect_ignore.extend(["tests/test_pattern_matching.py"]) diff --git a/docs/api.rst b/docs/api.rst index 2129a8ba..116dd2fb 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -11,7 +11,7 @@ If you're confused by the many names, please check out `names` for clarification - The classic ``attr`` that powers the venerable `attr.s` and `attr.ib`. - The newer ``attrs`` that only contains most modern APIs and relies on `attrs.define` and `attrs.field` to define your classes. - Additionally it offers some ``attr`` APIs with nicer defaults (e.g. `attrs.asdict`). + Additionally it offers some ``attr`` APIs with nicer defaults (for example, `attrs.asdict`). The ``attrs`` namespace is built *on top of* ``attr`` -- which will *never* go away -- and is just as stable, since it doesn't constitute a rewrite. To keep repetition low and this document at a reasonable size, the ``attr`` namespace is `documented on a separate page `, though. diff --git a/docs/examples.md b/docs/examples.md index 15f8beee..e4376420 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -569,7 +569,7 @@ AutoC(l=[], x=1, foo='every attrib needs a type if auto_attribs=True', bar=None) The generated `__init__` method will have an attribute called `__annotations__` that contains this type information. -If your annotations contain strings (e.g. forward references), +If your annotations contain strings (for example, forward references), you can resolve these after all references have been defined by using {func}`attrs.resolve_types`. This will replace the *type* attribute in the respective fields. diff --git a/docs/extending.md b/docs/extending.md index 09a7bd63..65d46883 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -214,7 +214,7 @@ For example, let's assume that you really don't like floats: Data(a=42, c='spam') ``` -A more realistic example would be to automatically convert data that you, e.g., load from JSON: +A more realistic example would be to automatically convert data that you, for example, load from JSON: ```{doctest} >>> from datetime import datetime diff --git a/docs/how-does-it-work.md b/docs/how-does-it-work.md index 11216615..70ecd455 100644 --- a/docs/how-does-it-work.md +++ b/docs/how-does-it-work.md @@ -64,7 +64,7 @@ Once constructed, frozen instances don't differ in any way from regular ones exc ### Dict Classes -Dict classes -- i.e. regular classes -- simply assign the value directly into the class' eponymous `__dict__` (and there's nothing we can do to stop the user to do the same). +Dict classes -- that is: regular classes -- simply assign the value directly into the class' eponymous `__dict__` (and there's nothing we can do to stop the user to do the same). The performance impact is negligible. @@ -95,9 +95,9 @@ Pick what's more important to you. ### Summary -You should avoid instantiating lots of frozen slotted classes (i.e. `@frozen`) in performance-critical code. +You should avoid instantiating lots of frozen slotted classes (meaning: `@frozen`) in performance-critical code. -Frozen dict classes have barely a performance impact, unfrozen slotted classes are even *faster* than unfrozen dict classes (i.e. regular classes). +Frozen dict classes have barely a performance impact, unfrozen slotted classes are even *faster* than unfrozen dict classes (meaning: regular classes). (how-slotted-cached_property)= diff --git a/docs/init.md b/docs/init.md index 50ffea42..90e194ef 100644 --- a/docs/init.md +++ b/docs/init.md @@ -370,7 +370,7 @@ For that purpose, *attrs* offers the following options: - `__attrs_post_init__` is automatically detected and run *after* *attrs* is done initializing your instance. This is useful if you want to derive some attribute from others or perform some kind of validation over the whole instance. -- `__attrs_init__` is written and attached to your class *instead* of `__init__`, if *attrs* is told to not write one (i.e. `init=False` or a combination of `auto_detect=True` and a custom `__init__`). +- `__attrs_init__` is written and attached to your class *instead* of `__init__`, if *attrs* is told to not write one (when `init=False` or a by a combination of `auto_detect=True` and a custom `__init__`). This is useful if you want full control over the initialization process, but don't want to set the attributes by hand. diff --git a/src/attr/_cmp.py b/src/attr/_cmp.py index a4a35e08..109ad89d 100644 --- a/src/attr/_cmp.py +++ b/src/attr/_cmp.py @@ -26,21 +26,21 @@ def cmp_using( The resulting class will have a full set of ordering methods if at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided. - :param Optional[callable] eq: `callable` used to evaluate equality of two + :param typing.Callable | None eq: `Callable` used to evaluate equality of two objects. - :param Optional[callable] lt: `callable` used to evaluate whether one + :param typing.Callable | None lt: `Callable` used to evaluate whether one object is less than another object. - :param Optional[callable] le: `callable` used to evaluate whether one + :param typing.Callable | None le: `Callable` used to evaluate whether one object is less than or equal to another object. - :param Optional[callable] gt: `callable` used to evaluate whether one + :param typing.Callable | None gt: `Callable` used to evaluate whether one object is greater than another object. - :param Optional[callable] ge: `callable` used to evaluate whether one + :param typing.Callable | None ge: `Callable` used to evaluate whether one object is greater than or equal to another object. :param bool require_same_type: When `True`, equality and ordering methods will return `NotImplemented` if objects are not of the same type. - :param Optional[str] class_name: Name of class. Defaults to 'Comparable'. + :param str | None class_name: Name of class. Defaults to "Comparable". See `comparison` for more details. diff --git a/src/attr/_compat.py b/src/attr/_compat.py index 9010047d..b7d7a4b8 100644 --- a/src/attr/_compat.py +++ b/src/attr/_compat.py @@ -12,7 +12,7 @@ from typing import _GenericAlias PYPY = platform.python_implementation() == "PyPy" PY_3_8_PLUS = sys.version_info[:2] >= (3, 8) PY_3_9_PLUS = sys.version_info[:2] >= (3, 9) -PY310 = 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_13_PLUS = sys.version_info[:2] >= (3, 13) diff --git a/src/attr/_funcs.py b/src/attr/_funcs.py index 4a3a36d5..5be1adb1 100644 --- a/src/attr/_funcs.py +++ b/src/attr/_funcs.py @@ -432,25 +432,25 @@ def resolve_types( Resolve any strings and forward annotations in type annotations. This is only required if you need concrete types in `Attribute`'s *type* - field. In other words, you don't need to resolve your types if you only - use them for static type checking. + field. In other words, you don't need to resolve your types if you only use + them for static type checking. With no arguments, names will be looked up in the module in which the class - was created. If this is not what you want, e.g. if the name only exists - inside a method, you may pass *globalns* or *localns* to specify other - dictionaries in which to look up these names. See the docs of + was created. If this is not what you want, for example, if the name only + exists inside a method, you may pass *globalns* or *localns* to specify + other dictionaries in which to look up these names. See the docs of `typing.get_type_hints` for more details. :param type cls: Class to resolve. - :param Optional[dict] globalns: Dictionary containing global variables. - :param Optional[dict] localns: Dictionary containing local variables. - :param Optional[list] attribs: List of attribs for the given class. - This is necessary when calling from inside a ``field_transformer`` - since *cls* is not an *attrs* class yet. - :param bool include_extras: Resolve more accurately, if possible. - Pass ``include_extras`` to ``typing.get_hints``, if supported by the - typing module. On supported Python versions (3.9+), this resolves the - types more accurately. + :param dict | None globalns: Dictionary containing global variables. + :param dict | None localns: Dictionary containing local variables. + :param list | None attribs: List of attribs for the given class. This is + necessary when calling from inside a ``field_transformer`` since *cls* + is not an *attrs* class yet. + :param bool include_extras: Resolve more accurately, if possible. Pass + ``include_extras`` to ``typing.get_hints``, if supported by the typing + module. On supported Python versions (3.9+), this resolves the types + more accurately. :raise TypeError: If *cls* is not a class. :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* @@ -464,7 +464,6 @@ def resolve_types( .. versionadded:: 20.1.0 .. versionadded:: 21.1.0 *attribs* .. versionadded:: 23.1.0 *include_extras* - """ # Since calling get_type_hints is expensive we cache whether we've # done it already. diff --git a/src/attr/_make.py b/src/attr/_make.py index 2eb3a9d9..8fadc64e 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -17,8 +17,8 @@ from operator import itemgetter # having the thread-local in the globals here. from . import _compat, _config, setters from ._compat import ( - PY310, PY_3_8_PLUS, + PY_3_10_PLUS, _AnnotationExtractor, get_generic_base, ) @@ -166,8 +166,9 @@ def attrib( If ``True``, include the attribute; if ``False``, omit it. By default, the built-in ``repr()`` function is used. To override how the attribute value is formatted, pass a ``callable`` that takes a single value and - returns a string. Note that the resulting string is used as-is, i.e. it - will be used directly *instead* of calling ``repr()`` (the default). + returns a string. Note that the resulting string is used as-is, which + means it will be used directly *instead* of calling ``repr()`` (the + default). :type repr: a `bool` or a `callable` to use a custom function. :param eq: If ``True`` (default), include this attribute in the generated @@ -312,7 +313,8 @@ def attrib( def _compile_and_eval(script, globs, locs=None, filename=""): """ - "Exec" the script with the given global (globs) and local (locs) variables. + Evaluate the script with the given global (globs) and local (locs) + variables. """ bytecode = compile(script, filename, "exec") eval(bytecode, globs, locs) @@ -499,8 +501,8 @@ def _transform_attrs( If *these* is passed, use that and don't look for them on the class. - *collect_by_mro* is True, collect them in the correct MRO order, otherwise - use the old -- incorrect -- order. See #428. + If *collect_by_mro* is True, collect them in the correct MRO order, + otherwise use the old -- incorrect -- order. See #428. Return an `_Attributes`. """ @@ -600,11 +602,7 @@ def _transform_attrs( return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map)) -def _make_cached_property_getattr( - cached_properties, - original_getattr, - cls, -): +def _make_cached_property_getattr(cached_properties, original_getattr, cls): lines = [ # Wrapped to get `__class__` into closure cell for super() # (It will be replaced with the newly constructed class after construction). @@ -801,7 +799,7 @@ class _ClassBuilder: def __repr__(self): return f"<_ClassBuilder(cls={self._cls.__name__})>" - if PY310: + if PY_3_10_PLUS: import abc def build_class(self): @@ -1339,13 +1337,13 @@ def attrs( A class decorator that adds :term:`dunder methods` according to the specified attributes using `attr.ib` or the *these* argument. - Please consider using `attrs.define` / `attrs.frozen` in new code - (``attr.s`` will *never* go away, though). + Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will + *never* go away, though). :param these: A dictionary of name to `attr.ib` mappings. This is useful to avoid the definition of your attributes within the class body - because you can't (e.g. if you want to add ``__repr__`` methods to - Django models) or don't want to. + because you can't (for example, if you want to add ``__repr__`` methods + to Django models) or don't want to. If *these* is not ``None``, *attrs* will *not* search the class body for attributes and will *not* remove any attributes from it. @@ -1354,16 +1352,16 @@ def attrs( :type these: `dict` of `str` to `attr.ib` - :param str repr_ns: When using nested classes, there's no way in Python 2 - to automatically detect that. Therefore it's possible to set the - namespace explicitly for a more meaningful ``repr`` output. + :param str repr_ns: When using nested classes, there was no way in Python 2 + to automatically detect that. This argument allows to set a custom + name for a more meaningful ``repr`` output. :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, *order*, and *hash* arguments explicitly, assume they are set to ``True`` **unless any** of the involved methods for one of the - arguments is implemented in the *current* class (i.e. it is *not* + arguments is implemented in the *current* class (meaning, it is *not* inherited from some base class). - So for example by implementing ``__eq__`` on a class yourself, *attrs* + So, for example by implementing ``__eq__`` on a class yourself, *attrs* will deduce ``eq=False`` and will create *neither* ``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible ``__ne__`` by default, so it *should* be enough to only implement ``__eq__`` in most @@ -1372,10 +1370,9 @@ def attrs( .. warning:: If you prevent *attrs* from creating the ordering methods for you - (``order=False``, e.g. by implementing ``__le__``), it becomes - *your* responsibility to make sure its ordering is sound. The best - way is to use the `functools.total_ordering` decorator. - + (``order=False``, for example, by implementing ``__le__``), it + becomes *your* responsibility to make sure its ordering is sound. + The best way is to use the `functools.total_ordering` decorator. Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, *cmp*, or *hash* overrides whatever *auto_detect* would determine. @@ -1412,26 +1409,26 @@ def attrs( ``object``, this means it will fall back to id-based hashing.). Although not recommended, you can decide for yourself and force *attrs* - to create one (e.g. if the class is immutable even though you didn't - freeze it programmatically) by passing ``True`` or not. Both of these - cases are rather special and should be used carefully. + to create one (for example, if the class is immutable even though you + didn't freeze it programmatically) by passing ``True`` or not. Both of + these cases are rather special and should be used carefully. .. seealso:: - Our documentation on `hashing`, - Python's documentation on `object.__hash__`, - - and the `GitHub issue that led to the default \ - behavior `_ for - more details. + - and the `GitHub issue that led to the default \ behavior + `_ for more + details. :param bool | None hash: Alias for *unsafe_hash*. *unsafe_hash* takes precedence. :param bool init: Create a ``__init__`` method that initializes the *attrs* - attributes. Leading underscores are stripped for the argument name. If - a ``__attrs_pre_init__`` method exists on the class, it will be called - before the class is initialized. If a ``__attrs_post_init__`` method - exists on the class, it will be called after the class is fully - initialized. + attributes. Leading underscores are stripped for the argument name + (unless an alias is set on the attribute). If a ``__attrs_pre_init__`` + method exists on the class, it will be called before the class is + initialized. If a ``__attrs_post_init__`` method exists on the class, + it will be called after the class is fully initialized. If ``init`` is ``False``, an ``__attrs_init__`` method will be injected instead. This allows you to define a custom ``__init__`` method that @@ -1472,29 +1469,28 @@ def attrs( In this case, you **must** annotate every field. If *attrs* encounters a field that is set to an `attr.ib` but lacks a type annotation, an - `attr.exceptions.UnannotatedAttributeError` is raised. Use + `attrs.exceptions.UnannotatedAttributeError` is raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't want to set a type. - If you assign a value to those attributes (e.g. ``x: int = 42``), that - value becomes the default value like if it were passed using - ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also - works as expected in most cases (see warning below). + If you assign a value to those attributes (for example, ``x: int = + 42``), that value becomes the default value like if it were passed + using ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` + also works as expected in most cases (see warning below). Attributes annotated as `typing.ClassVar`, and attributes that are neither annotated nor set to an `attr.ib` are **ignored**. .. warning:: - For features that use the attribute name to create decorators (e.g. - :ref:`validators `), you still *must* assign `attr.ib` - to them. Otherwise Python will either not find the name or try to - use the default value to call e.g. ``validator`` on it. - These errors can be quite confusing and probably the most common bug - report on our bug tracker. + For features that use the attribute name to create decorators (for + example, :ref:`validators `), you still *must* assign + `attr.ib` to them. Otherwise Python will either not find the name or + try to use the default value to call, for example, ``validator`` on + it. :param bool kw_only: Make all attributes keyword-only in the generated - ``__init__`` (if ``init`` is ``False``, this parameter is ignored). + ``__init__`` (if *init* is ``False``, this parameter is ignored). :param bool cache_hash: Ensure that the object's hash code is computed only once and stored on the object. If this is set to ``True``, hashing must be either explicitly or implicitly enabled for this class. If the @@ -1517,7 +1513,7 @@ def attrs( :param bool collect_by_mro: Setting this to `True` fixes the way *attrs* collects attributes from base classes. The default behavior is incorrect in certain cases of multiple inheritance. It should be on by - default but is kept off for backward-compatibility. + default, but is kept off for backwards-compatibility. .. seealso:: Issue `#428 `_ @@ -1530,12 +1526,12 @@ def attrs( If `True`, ``__getstate__`` and ``__setstate__`` are generated and attached to the class. This is necessary for slotted classes to be pickleable. If left `None`, it's `True` by default for slotted classes - and ``False`` for dict classes. + and `False` for dict classes. If *auto_detect* is `True`, and *getstate_setstate* is left `None`, and **either** ``__getstate__`` or ``__setstate__`` is detected directly on - the class (i.e. not inherited), it is set to `False` (this is usually - what you want). + the class (meaning: not inherited), it is set to `False` (this is + usually what you want). :param on_setattr: A callable that is run whenever the user attempts to set an attribute (either by assignment like ``i.x = 42`` or by using @@ -1553,15 +1549,15 @@ def attrs( :param callable | None field_transformer: A function that is called with the original class object and all fields - right before *attrs* finalizes the class. You can use this, e.g., to - automatically add converters or validators to fields based on their - types. + right before *attrs* finalizes the class. You can use this, for + example, to automatically add converters or validators to fields based + on their types. .. seealso:: `transform-fields` :param bool match_args: If `True` (default), set ``__match_args__`` on the class to support - :pep:`634` (Structural Pattern Matching). It is a tuple of all + :pep:`634` (*Structural Pattern Matching*). It is a tuple of all non-keyword-only ``__init__`` parameter names on Python 3.10 and later. Ignored on older Python versions. @@ -1705,7 +1701,7 @@ def attrs( raise TypeError(msg) if ( - PY310 + PY_3_10_PLUS and match_args and not _has_own_attribute(cls, "__match_args__") ): diff --git a/src/attr/converters.py b/src/attr/converters.py index 2bf4c902..76e2c49d 100644 --- a/src/attr/converters.py +++ b/src/attr/converters.py @@ -104,7 +104,8 @@ def default_if_none(default=NOTHING, factory=None): def to_bool(val): """ - Convert "boolean" strings (e.g., from env. vars.) to real booleans. + Convert "boolean" strings (for example, from environment variables) to real + booleans. Values mapping to :code:`True`: diff --git a/tests/strategies.py b/tests/strategies.py index 783058f8..cbbf5b33 100644 --- a/tests/strategies.py +++ b/tests/strategies.py @@ -145,7 +145,7 @@ def simple_classes( be generated, and if `slots=False` is passed in, no slotted classes will be generated. The same applies to `frozen` and `weakref_slot`. - By default, some attributes will be private (i.e. prefixed with an + By default, some attributes will be private (those prefixed with an underscore). If `private_attrs=True` is passed in, all attributes will be private, and if `private_attrs=False`, no attributes will be private. """ diff --git a/tests/test_abc.py b/tests/test_abc.py index a70b317a..5751b284 100644 --- a/tests/test_abc.py +++ b/tests/test_abc.py @@ -7,10 +7,12 @@ import pytest import attrs -from attr._compat import PY310, PY_3_12_PLUS +from attr._compat import PY_3_10_PLUS, PY_3_12_PLUS -@pytest.mark.skipif(not PY310, reason="abc.update_abstractmethods is 3.10+") +@pytest.mark.skipif( + not PY_3_10_PLUS, reason="abc.update_abstractmethods is 3.10+" +) class TestUpdateAbstractMethods: def test_abc_implementation(self, slots): """ diff --git a/tests/test_make.py b/tests/test_make.py index b67453d5..1760964b 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -21,7 +21,7 @@ from hypothesis.strategies import booleans, integers, lists, sampled_from, text import attr from attr import _config -from attr._compat import PY310, PY_3_8_PLUS +from attr._compat import PY_3_8_PLUS, PY_3_10_PLUS from attr._make import ( Attribute, Factory, @@ -2492,7 +2492,7 @@ class TestAutoDetect: C, "__getstate__", None ) - @pytest.mark.skipif(PY310, reason="Pre-3.10 only.") + @pytest.mark.skipif(PY_3_10_PLUS, reason="Pre-3.10 only.") def test_match_args_pre_310(self): """ __match_args__ is not created on Python versions older than 3.10. @@ -2505,7 +2505,9 @@ class TestAutoDetect: assert None is getattr(C, "__match_args__", None) -@pytest.mark.skipif(not PY310, reason="Structural pattern matching is 3.10+") +@pytest.mark.skipif( + not PY_3_10_PLUS, reason="Structural pattern matching is 3.10+" +) class TestMatchArgs: """ Tests for match_args and __match_args__ generation.