| |
|
|
| """ |
| 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). |
| - If *frozen* is `False`, run converters and validators when setting an |
| attribute by default. |
| - *slots=True* |
| |
| .. caution:: |
| |
| Usually this has only upsides and few visible effects in everyday |
| programming. But it *can* lead to some suprising 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) |
|
|
| |
| if frozen is False and on_setattr is None: |
| on_setattr = _ng_default_on_setattr |
|
|
| |
| |
| for base_cls in cls.__bases__: |
| if base_cls.__setattr__ is _frozen_setattrs: |
| if had_on_setattr: |
| raise ValueError( |
| "Frozen classes can't use on_setattr " |
| "(frozen-ness was inherited)." |
| ) |
|
|
| 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) |
|
|
| |
| |
| if maybe_cls is None: |
| return wrap |
| else: |
| 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 |
| {func}`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 |
| ) |
|
|