mercurial/thirdparty/attr/_next_gen.py
changeset 49643 e1c586b9a43c
equal deleted inserted replaced
49642:7e6f3c69c0fb 49643:e1c586b9a43c
       
     1 # SPDX-License-Identifier: MIT
       
     2 
       
     3 """
       
     4 These are Python 3.6+-only and keyword-only APIs that call `attr.s` and
       
     5 `attr.ib` with different default values.
       
     6 """
       
     7 
       
     8 
       
     9 from functools import partial
       
    10 
       
    11 from . import setters
       
    12 from ._funcs import asdict as _asdict
       
    13 from ._funcs import astuple as _astuple
       
    14 from ._make import (
       
    15     NOTHING,
       
    16     _frozen_setattrs,
       
    17     _ng_default_on_setattr,
       
    18     attrib,
       
    19     attrs,
       
    20 )
       
    21 from .exceptions import UnannotatedAttributeError
       
    22 
       
    23 
       
    24 def define(
       
    25     maybe_cls=None,
       
    26     *,
       
    27     these=None,
       
    28     repr=None,
       
    29     hash=None,
       
    30     init=None,
       
    31     slots=True,
       
    32     frozen=False,
       
    33     weakref_slot=True,
       
    34     str=False,
       
    35     auto_attribs=None,
       
    36     kw_only=False,
       
    37     cache_hash=False,
       
    38     auto_exc=True,
       
    39     eq=None,
       
    40     order=False,
       
    41     auto_detect=True,
       
    42     getstate_setstate=None,
       
    43     on_setattr=None,
       
    44     field_transformer=None,
       
    45     match_args=True,
       
    46 ):
       
    47     r"""
       
    48     Define an ``attrs`` class.
       
    49 
       
    50     Differences to the classic `attr.s` that it uses underneath:
       
    51 
       
    52     - Automatically detect whether or not *auto_attribs* should be `True` (c.f.
       
    53       *auto_attribs* parameter).
       
    54     - If *frozen* is `False`, run converters and validators when setting an
       
    55       attribute by default.
       
    56     - *slots=True*
       
    57 
       
    58       .. caution::
       
    59 
       
    60          Usually this has only upsides and few visible effects in everyday
       
    61          programming. But it *can* lead to some suprising behaviors, so please
       
    62          make sure to read :term:`slotted classes`.
       
    63     - *auto_exc=True*
       
    64     - *auto_detect=True*
       
    65     - *order=False*
       
    66     - Some options that were only relevant on Python 2 or were kept around for
       
    67       backwards-compatibility have been removed.
       
    68 
       
    69     Please note that these are all defaults and you can change them as you
       
    70     wish.
       
    71 
       
    72     :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves
       
    73        exactly like `attr.s`. If left `None`, `attr.s` will try to guess:
       
    74 
       
    75        1. If any attributes are annotated and no unannotated `attrs.fields`\ s
       
    76           are found, it assumes *auto_attribs=True*.
       
    77        2. Otherwise it assumes *auto_attribs=False* and tries to collect
       
    78           `attrs.fields`\ s.
       
    79 
       
    80     For now, please refer to `attr.s` for the rest of the parameters.
       
    81 
       
    82     .. versionadded:: 20.1.0
       
    83     .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``.
       
    84     """
       
    85 
       
    86     def do_it(cls, auto_attribs):
       
    87         return attrs(
       
    88             maybe_cls=cls,
       
    89             these=these,
       
    90             repr=repr,
       
    91             hash=hash,
       
    92             init=init,
       
    93             slots=slots,
       
    94             frozen=frozen,
       
    95             weakref_slot=weakref_slot,
       
    96             str=str,
       
    97             auto_attribs=auto_attribs,
       
    98             kw_only=kw_only,
       
    99             cache_hash=cache_hash,
       
   100             auto_exc=auto_exc,
       
   101             eq=eq,
       
   102             order=order,
       
   103             auto_detect=auto_detect,
       
   104             collect_by_mro=True,
       
   105             getstate_setstate=getstate_setstate,
       
   106             on_setattr=on_setattr,
       
   107             field_transformer=field_transformer,
       
   108             match_args=match_args,
       
   109         )
       
   110 
       
   111     def wrap(cls):
       
   112         """
       
   113         Making this a wrapper ensures this code runs during class creation.
       
   114 
       
   115         We also ensure that frozen-ness of classes is inherited.
       
   116         """
       
   117         nonlocal frozen, on_setattr
       
   118 
       
   119         had_on_setattr = on_setattr not in (None, setters.NO_OP)
       
   120 
       
   121         # By default, mutable classes convert & validate on setattr.
       
   122         if frozen is False and on_setattr is None:
       
   123             on_setattr = _ng_default_on_setattr
       
   124 
       
   125         # However, if we subclass a frozen class, we inherit the immutability
       
   126         # and disable on_setattr.
       
   127         for base_cls in cls.__bases__:
       
   128             if base_cls.__setattr__ is _frozen_setattrs:
       
   129                 if had_on_setattr:
       
   130                     raise ValueError(
       
   131                         "Frozen classes can't use on_setattr "
       
   132                         "(frozen-ness was inherited)."
       
   133                     )
       
   134 
       
   135                 on_setattr = setters.NO_OP
       
   136                 break
       
   137 
       
   138         if auto_attribs is not None:
       
   139             return do_it(cls, auto_attribs)
       
   140 
       
   141         try:
       
   142             return do_it(cls, True)
       
   143         except UnannotatedAttributeError:
       
   144             return do_it(cls, False)
       
   145 
       
   146     # maybe_cls's type depends on the usage of the decorator.  It's a class
       
   147     # if it's used as `@attrs` but ``None`` if used as `@attrs()`.
       
   148     if maybe_cls is None:
       
   149         return wrap
       
   150     else:
       
   151         return wrap(maybe_cls)
       
   152 
       
   153 
       
   154 mutable = define
       
   155 frozen = partial(define, frozen=True, on_setattr=None)
       
   156 
       
   157 
       
   158 def field(
       
   159     *,
       
   160     default=NOTHING,
       
   161     validator=None,
       
   162     repr=True,
       
   163     hash=None,
       
   164     init=True,
       
   165     metadata=None,
       
   166     converter=None,
       
   167     factory=None,
       
   168     kw_only=False,
       
   169     eq=None,
       
   170     order=None,
       
   171     on_setattr=None,
       
   172 ):
       
   173     """
       
   174     Identical to `attr.ib`, except keyword-only and with some arguments
       
   175     removed.
       
   176 
       
   177     .. versionadded:: 20.1.0
       
   178     """
       
   179     return attrib(
       
   180         default=default,
       
   181         validator=validator,
       
   182         repr=repr,
       
   183         hash=hash,
       
   184         init=init,
       
   185         metadata=metadata,
       
   186         converter=converter,
       
   187         factory=factory,
       
   188         kw_only=kw_only,
       
   189         eq=eq,
       
   190         order=order,
       
   191         on_setattr=on_setattr,
       
   192     )
       
   193 
       
   194 
       
   195 def asdict(inst, *, recurse=True, filter=None, value_serializer=None):
       
   196     """
       
   197     Same as `attr.asdict`, except that collections types are always retained
       
   198     and dict is always used as *dict_factory*.
       
   199 
       
   200     .. versionadded:: 21.3.0
       
   201     """
       
   202     return _asdict(
       
   203         inst=inst,
       
   204         recurse=recurse,
       
   205         filter=filter,
       
   206         value_serializer=value_serializer,
       
   207         retain_collection_types=True,
       
   208     )
       
   209 
       
   210 
       
   211 def astuple(inst, *, recurse=True, filter=None):
       
   212     """
       
   213     Same as `attr.astuple`, except that collections types are always retained
       
   214     and `tuple` is always used as the *tuple_factory*.
       
   215 
       
   216     .. versionadded:: 21.3.0
       
   217     """
       
   218     return _astuple(
       
   219         inst=inst, recurse=recurse, filter=filter, retain_collection_types=True
       
   220     )