Spaces:
Runtime error
Runtime error
# SPDX-License-Identifier: MIT | |
""" | |
These are keyword-only APIs that call `attr.s` and `attr.ib` with different | |
default values. | |
""" | |
from functools import partial | |
from . import setters | |
from ._funcs import asdict as _asdict | |
from ._funcs import astuple as _astuple | |
from ._make import ( | |
_DEFAULT_ON_SETATTR, | |
NOTHING, | |
_frozen_setattrs, | |
attrib, | |
attrs, | |
) | |
from .exceptions import UnannotatedAttributeError | |
def define( | |
maybe_cls=None, | |
*, | |
these=None, | |
repr=None, | |
unsafe_hash=None, | |
hash=None, | |
init=None, | |
slots=True, | |
frozen=False, | |
weakref_slot=True, | |
str=False, | |
auto_attribs=None, | |
kw_only=False, | |
cache_hash=False, | |
auto_exc=True, | |
eq=None, | |
order=False, | |
auto_detect=True, | |
getstate_setstate=None, | |
on_setattr=None, | |
field_transformer=None, | |
match_args=True, | |
): | |
r""" | |
A class decorator that adds :term:`dunder methods` according to | |
:term:`fields <field>` specified using :doc:`type annotations <types>`, | |
`field()` calls, or the *these* argument. | |
Since *attrs* patches or replaces an existing class, you cannot use | |
`object.__init_subclass__` with *attrs* classes, because it runs too early. | |
As a replacement, you can define ``__attrs_init_subclass__`` on your class. | |
It will be called by *attrs* classes that subclass it after they're | |
created. See also :ref:`init-subclass`. | |
Args: | |
slots (bool): | |
Create a :term:`slotted class <slotted classes>` that's more | |
memory-efficient. Slotted classes are generally superior to the | |
default dict classes, but have some gotchas you should know about, | |
so we encourage you to read the :term:`glossary entry <slotted | |
classes>`. | |
auto_detect (bool): | |
Instead of setting the *init*, *repr*, *eq*, 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 (meaning, it is *not* inherited from some base | |
class). | |
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 cases). | |
Passing True or False` to *init*, *repr*, *eq*, *cmp*, or *hash* | |
overrides whatever *auto_detect* would determine. | |
auto_exc (bool): | |
If the class subclasses `BaseException` (which implicitly includes | |
any subclass of any exception), the following happens to behave | |
like a well-behaved Python exception class: | |
- the values for *eq*, *order*, and *hash* are ignored and the | |
instances compare and hash by the instance's ids [#]_ , | |
- all attributes that are either passed into ``__init__`` or have a | |
default value are additionally available as a tuple in the | |
``args`` attribute, | |
- the value of *str* is ignored leaving ``__str__`` to base | |
classes. | |
.. [#] | |
Note that *attrs* will *not* remove existing implementations of | |
``__hash__`` or the equality methods. It just won't add own | |
ones. | |
on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): | |
A callable that is run whenever the user attempts to set an | |
attribute (either by assignment like ``i.x = 42`` or by using | |
`setattr` like ``setattr(i, "x", 42)``). It receives the same | |
arguments as validators: the instance, the attribute that is being | |
modified, and the new value. | |
If no exception is raised, the attribute is set to the return value | |
of the callable. | |
If a list of callables is passed, they're automatically wrapped in | |
an `attrs.setters.pipe`. | |
If left None, the default behavior is to run converters and | |
validators whenever an attribute is set. | |
init (bool): | |
Create a ``__init__`` method that initializes the *attrs* | |
attributes. Leading underscores are stripped for the argument name, | |
unless an alias is set on the attribute. | |
.. seealso:: | |
`init` shows advanced ways to customize the generated | |
``__init__`` method, including executing code before and after. | |
repr(bool): | |
Create a ``__repr__`` method with a human readable representation | |
of *attrs* attributes. | |
str (bool): | |
Create a ``__str__`` method that is identical to ``__repr__``. This | |
is usually not necessary except for `Exception`\ s. | |
eq (bool | None): | |
If True or None (default), add ``__eq__`` and ``__ne__`` methods | |
that check two instances for equality. | |
.. seealso:: | |
`comparison` describes how to customize the comparison behavior | |
going as far comparing NumPy arrays. | |
order (bool | None): | |
If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` | |
methods that behave like *eq* above and allow instances to be | |
ordered. | |
They compare the instances as if they were tuples of their *attrs* | |
attributes if and only if the types of both classes are | |
*identical*. | |
If `None` mirror value of *eq*. | |
.. seealso:: `comparison` | |
cmp (bool | None): | |
Setting *cmp* is equivalent to setting *eq* and *order* to the same | |
value. Must not be mixed with *eq* or *order*. | |
unsafe_hash (bool | None): | |
If None (default), the ``__hash__`` method is generated according | |
how *eq* and *frozen* are set. | |
1. If *both* are True, *attrs* will generate a ``__hash__`` for | |
you. | |
2. If *eq* is True and *frozen* is False, ``__hash__`` will be set | |
to None, marking it unhashable (which it is). | |
3. If *eq* is False, ``__hash__`` will be left untouched meaning | |
the ``__hash__`` method of the base class will be used. If the | |
base class is `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 (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 | |
<https://github.com/python-attrs/attrs/issues/136>`_ for more | |
details. | |
hash (bool | None): | |
Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. | |
cache_hash (bool): | |
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 hash code | |
is cached, avoid any reassignments of fields involved in hash code | |
computation or mutations of the objects those fields point to after | |
object creation. If such changes occur, the behavior of the | |
object's hash code is undefined. | |
frozen (bool): | |
Make instances immutable after initialization. If someone attempts | |
to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` | |
is raised. | |
.. note:: | |
1. This is achieved by installing a custom ``__setattr__`` | |
method on your class, so you can't implement your own. | |
2. True immutability is impossible in Python. | |
3. This *does* have a minor a runtime performance `impact | |
<how-frozen>` when initializing new instances. In other | |
words: ``__init__`` is slightly slower with ``frozen=True``. | |
4. If a class is frozen, you cannot modify ``self`` in | |
``__attrs_post_init__`` or a self-written ``__init__``. You | |
can circumvent that limitation by using | |
``object.__setattr__(self, "attribute_name", value)``. | |
5. Subclasses of a frozen class are frozen too. | |
kw_only (bool): | |
Make all attributes keyword-only in the generated ``__init__`` (if | |
*init* is False, this parameter is ignored). | |
weakref_slot (bool): | |
Make instances weak-referenceable. This has no effect unless | |
*slots* is True. | |
field_transformer (~typing.Callable | None): | |
A function that is called with the original class object and all | |
fields 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` | |
match_args (bool): | |
If True (default), set ``__match_args__`` on the class to support | |
: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. | |
collect_by_mro (bool): | |
If True, *attrs* collects attributes from base classes correctly | |
according to the `method resolution order | |
<https://docs.python.org/3/howto/mro.html>`_. If False, *attrs* | |
will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. | |
See also `issue #428 | |
<https://github.com/python-attrs/attrs/issues/428>`_. | |
getstate_setstate (bool | None): | |
.. note:: | |
This is usually only interesting for slotted classes and you | |
should probably just set *auto_detect* to True. | |
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. | |
If *auto_detect* is True, and *getstate_setstate* is left None, and | |
**either** ``__getstate__`` or ``__setstate__`` is detected | |
directly on the class (meaning: not inherited), it is set to False | |
(this is usually what you want). | |
auto_attribs (bool | None): | |
If True, look at type annotations to determine which attributes to | |
use, like `dataclasses`. If False, it will only look for explicit | |
:func:`field` class attributes, like classic *attrs*. | |
If left None, it will guess: | |
1. If any attributes are annotated and no unannotated | |
`attrs.field`\ s are found, it assumes *auto_attribs=True*. | |
2. Otherwise it assumes *auto_attribs=False* and tries to collect | |
`attrs.field`\ s. | |
If *attrs* decides to look at type annotations, **all** fields | |
**must** be annotated. If *attrs* encounters a field that is set to | |
a :func:`field` / `attr.ib` but lacks a type annotation, an | |
`attrs.exceptions.UnannotatedAttributeError` is raised. Use | |
``field_name: typing.Any = field(...)`` if you don't want to set a | |
type. | |
.. warning:: | |
For features that use the attribute name to create decorators | |
(for example, :ref:`validators <validators>`), you still *must* | |
assign :func:`field` / `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. | |
Attributes annotated as `typing.ClassVar`, and attributes that are | |
neither annotated nor set to an `field()` are **ignored**. | |
these (dict[str, object]): | |
A dictionary of name to the (private) return value of `field()` | |
mappings. This is useful to avoid the definition of your attributes | |
within the class body 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. | |
The order is deduced from the order of the attributes inside | |
*these*. | |
Arguably, this is a rather obscure feature. | |
.. versionadded:: 20.1.0 | |
.. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. | |
.. versionadded:: 22.2.0 | |
*unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). | |
.. versionchanged:: 24.1.0 | |
Instances are not compared as tuples of attributes anymore, but using a | |
big ``and`` condition. This is faster and has more correct behavior for | |
uncomparable values like `math.nan`. | |
.. versionadded:: 24.1.0 | |
If a class has an *inherited* classmethod called | |
``__attrs_init_subclass__``, it is executed after the class is created. | |
.. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. | |
.. note:: | |
The main differences to the classic `attr.s` are: | |
- Automatically detect whether or not *auto_attribs* should be `True` | |
(c.f. *auto_attribs* parameter). | |
- Converters and validators run when attributes are set by default -- | |
if *frozen* is `False`. | |
- *slots=True* | |
Usually, this has only upsides and few visible effects in everyday | |
programming. But it *can* lead to some surprising behaviors, so | |
please make sure to read :term:`slotted classes`. | |
- *auto_exc=True* | |
- *auto_detect=True* | |
- *order=False* | |
- Some options that were only relevant on Python 2 or were kept around | |
for backwards-compatibility have been removed. | |
""" | |
def do_it(cls, auto_attribs): | |
return attrs( | |
maybe_cls=cls, | |
these=these, | |
repr=repr, | |
hash=hash, | |
unsafe_hash=unsafe_hash, | |
init=init, | |
slots=slots, | |
frozen=frozen, | |
weakref_slot=weakref_slot, | |
str=str, | |
auto_attribs=auto_attribs, | |
kw_only=kw_only, | |
cache_hash=cache_hash, | |
auto_exc=auto_exc, | |
eq=eq, | |
order=order, | |
auto_detect=auto_detect, | |
collect_by_mro=True, | |
getstate_setstate=getstate_setstate, | |
on_setattr=on_setattr, | |
field_transformer=field_transformer, | |
match_args=match_args, | |
) | |
def wrap(cls): | |
""" | |
Making this a wrapper ensures this code runs during class creation. | |
We also ensure that frozen-ness of classes is inherited. | |
""" | |
nonlocal frozen, on_setattr | |
had_on_setattr = on_setattr not in (None, setters.NO_OP) | |
# By default, mutable classes convert & validate on setattr. | |
if frozen is False and on_setattr is None: | |
on_setattr = _DEFAULT_ON_SETATTR | |
# However, if we subclass a frozen class, we inherit the immutability | |
# and disable on_setattr. | |
for base_cls in cls.__bases__: | |
if base_cls.__setattr__ is _frozen_setattrs: | |
if had_on_setattr: | |
msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." | |
raise ValueError(msg) | |
on_setattr = setters.NO_OP | |
break | |
if auto_attribs is not None: | |
return do_it(cls, auto_attribs) | |
try: | |
return do_it(cls, True) | |
except UnannotatedAttributeError: | |
return do_it(cls, False) | |
# maybe_cls's type depends on the usage of the decorator. It's a class | |
# if it's used as `@attrs` but `None` if used as `@attrs()`. | |
if maybe_cls is None: | |
return wrap | |
return wrap(maybe_cls) | |
mutable = define | |
frozen = partial(define, frozen=True, on_setattr=None) | |
def field( | |
*, | |
default=NOTHING, | |
validator=None, | |
repr=True, | |
hash=None, | |
init=True, | |
metadata=None, | |
type=None, | |
converter=None, | |
factory=None, | |
kw_only=False, | |
eq=None, | |
order=None, | |
on_setattr=None, | |
alias=None, | |
): | |
""" | |
Create a new :term:`field` / :term:`attribute` on a class. | |
.. warning:: | |
Does **nothing** unless the class is also decorated with | |
`attrs.define` (or similar)! | |
Args: | |
default: | |
A value that is used if an *attrs*-generated ``__init__`` is used | |
and no value is passed while instantiating or the attribute is | |
excluded using ``init=False``. | |
If the value is an instance of `attrs.Factory`, its callable will | |
be used to construct a new value (useful for mutable data types | |
like lists or dicts). | |
If a default is not set (or set manually to `attrs.NOTHING`), a | |
value *must* be supplied when instantiating; otherwise a | |
`TypeError` will be raised. | |
.. seealso:: `defaults` | |
factory (~typing.Callable): | |
Syntactic sugar for ``default=attr.Factory(factory)``. | |
validator (~typing.Callable | list[~typing.Callable]): | |
Callable that is called by *attrs*-generated ``__init__`` methods | |
after the instance has been initialized. They receive the | |
initialized instance, the :func:`~attrs.Attribute`, and the passed | |
value. | |
The return value is *not* inspected so the validator has to throw | |
an exception itself. | |
If a `list` is passed, its items are treated as validators and must | |
all pass. | |
Validators can be globally disabled and re-enabled using | |
`attrs.validators.get_disabled` / `attrs.validators.set_disabled`. | |
The validator can also be set using decorator notation as shown | |
below. | |
.. seealso:: :ref:`validators` | |
repr (bool | ~typing.Callable): | |
Include this attribute in the generated ``__repr__`` method. 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, | |
which means it will be used directly *instead* of calling | |
``repr()`` (the default). | |
eq (bool | ~typing.Callable): | |
If True (default), include this attribute in the generated | |
``__eq__`` and ``__ne__`` methods that check two instances for | |
equality. To override how the attribute value is compared, pass a | |
callable that takes a single value and returns the value to be | |
compared. | |
.. seealso:: `comparison` | |
order (bool | ~typing.Callable): | |
If True (default), include this attributes in the generated | |
``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To | |
override how the attribute value is ordered, pass a callable that | |
takes a single value and returns the value to be ordered. | |
.. seealso:: `comparison` | |
cmp(bool | ~typing.Callable): | |
Setting *cmp* is equivalent to setting *eq* and *order* to the same | |
value. Must not be mixed with *eq* or *order*. | |
.. seealso:: `comparison` | |
hash (bool | None): | |
Include this attribute in the generated ``__hash__`` method. If | |
None (default), mirror *eq*'s value. This is the correct behavior | |
according the Python spec. Setting this value to anything else | |
than None is *discouraged*. | |
.. seealso:: `hashing` | |
init (bool): | |
Include this attribute in the generated ``__init__`` method. | |
It is possible to set this to False and set a default value. In | |
that case this attributed is unconditionally initialized with the | |
specified default value or factory. | |
.. seealso:: `init` | |
converter (typing.Callable | Converter): | |
A callable that is called by *attrs*-generated ``__init__`` methods | |
to convert attribute's value to the desired format. | |
If a vanilla callable is passed, it is given the passed-in value as | |
the only positional argument. It is possible to receive additional | |
arguments by wrapping the callable in a `Converter`. | |
Either way, the returned value will be used as the new value of the | |
attribute. The value is converted before being passed to the | |
validator, if any. | |
.. seealso:: :ref:`converters` | |
metadata (dict | None): | |
An arbitrary mapping, to be used by third-party code. | |
.. seealso:: `extending-metadata`. | |
type (type): | |
The type of the attribute. Nowadays, the preferred method to | |
specify the type is using a variable annotation (see :pep:`526`). | |
This argument is provided for backwards-compatibility and for usage | |
with `make_class`. Regardless of the approach used, the type will | |
be stored on ``Attribute.type``. | |
Please note that *attrs* doesn't do anything with this metadata by | |
itself. You can use it as part of your own code or for `static type | |
checking <types>`. | |
kw_only (bool): | |
Make this attribute keyword-only in the generated ``__init__`` (if | |
``init`` is False, this parameter is ignored). | |
on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): | |
Allows to overwrite the *on_setattr* setting from `attr.s`. If left | |
None, the *on_setattr* value from `attr.s` is used. Set to | |
`attrs.setters.NO_OP` to run **no** `setattr` hooks for this | |
attribute -- regardless of the setting in `define()`. | |
alias (str | None): | |
Override this attribute's parameter name in the generated | |
``__init__`` method. If left None, default to ``name`` stripped | |
of leading underscores. See `private-attributes`. | |
.. versionadded:: 20.1.0 | |
.. versionchanged:: 21.1.0 | |
*eq*, *order*, and *cmp* also accept a custom callable | |
.. versionadded:: 22.2.0 *alias* | |
.. versionadded:: 23.1.0 | |
The *type* parameter has been re-added; mostly for `attrs.make_class`. | |
Please note that type checkers ignore this metadata. | |
.. seealso:: | |
`attr.ib` | |
""" | |
return attrib( | |
default=default, | |
validator=validator, | |
repr=repr, | |
hash=hash, | |
init=init, | |
metadata=metadata, | |
type=type, | |
converter=converter, | |
factory=factory, | |
kw_only=kw_only, | |
eq=eq, | |
order=order, | |
on_setattr=on_setattr, | |
alias=alias, | |
) | |
def asdict(inst, *, recurse=True, filter=None, value_serializer=None): | |
""" | |
Same as `attr.asdict`, except that collections types are always retained | |
and dict is always used as *dict_factory*. | |
.. versionadded:: 21.3.0 | |
""" | |
return _asdict( | |
inst=inst, | |
recurse=recurse, | |
filter=filter, | |
value_serializer=value_serializer, | |
retain_collection_types=True, | |
) | |
def astuple(inst, *, recurse=True, filter=None): | |
""" | |
Same as `attr.astuple`, except that collections types are always retained | |
and `tuple` is always used as the *tuple_factory*. | |
.. versionadded:: 21.3.0 | |
""" | |
return _astuple( | |
inst=inst, recurse=recurse, filter=filter, retain_collection_types=True | |
) | |