Spaces:
Paused
Paused
| # 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 ( | |
| NOTHING, | |
| _frozen_setattrs, | |
| _ng_default_on_setattr, | |
| 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""" | |
| Define an *attrs* class. | |
| Differences to the classic `attr.s` that it uses underneath: | |
| - 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* | |
| .. caution:: | |
| 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. | |
| Please note that these are all defaults and you can change them as you | |
| wish. | |
| :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves | |
| exactly like `attr.s`. If left `None`, `attr.s` will try to guess: | |
| 1. If any attributes are annotated and no unannotated `attrs.fields`\ s | |
| are found, it assumes *auto_attribs=True*. | |
| 2. Otherwise it assumes *auto_attribs=False* and tries to collect | |
| `attrs.fields`\ s. | |
| For now, please refer to `attr.s` for the rest of the parameters. | |
| .. 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). | |
| """ | |
| 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 = _ng_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, | |
| ): | |
| """ | |
| Identical to `attr.ib`, except keyword-only and with some arguments | |
| removed. | |
| .. versionadded:: 23.1.0 | |
| The *type* parameter has been re-added; mostly for `attrs.make_class`. | |
| Please note that type checkers ignore this metadata. | |
| .. versionadded:: 20.1.0 | |
| """ | |
| 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 | |
| ) | |