_next_gen.py 5.6 KB

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