Spaces:
Running
Running
# 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 | |
) | |