49643
|
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 )
|