_next_gen.py 6.1 KB

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