Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/attr/_make.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 from __future__ import absolute_import, division, print_function | |
2 | |
3 import copy | |
4 import linecache | |
5 import sys | |
6 import threading | |
7 import uuid | |
8 import warnings | |
9 | |
10 from operator import itemgetter | |
11 | |
12 from . import _config, setters | |
13 from ._compat import ( | |
14 PY2, | |
15 PYPY, | |
16 isclass, | |
17 iteritems, | |
18 metadata_proxy, | |
19 ordered_dict, | |
20 set_closure_cell, | |
21 ) | |
22 from .exceptions import ( | |
23 DefaultAlreadySetError, | |
24 FrozenInstanceError, | |
25 NotAnAttrsClassError, | |
26 PythonTooOldError, | |
27 UnannotatedAttributeError, | |
28 ) | |
29 | |
30 | |
31 # This is used at least twice, so cache it here. | |
32 _obj_setattr = object.__setattr__ | |
33 _init_converter_pat = "__attr_converter_%s" | |
34 _init_factory_pat = "__attr_factory_{}" | |
35 _tuple_property_pat = ( | |
36 " {attr_name} = _attrs_property(_attrs_itemgetter({index}))" | |
37 ) | |
38 _classvar_prefixes = ("typing.ClassVar", "t.ClassVar", "ClassVar") | |
39 # we don't use a double-underscore prefix because that triggers | |
40 # name mangling when trying to create a slot for the field | |
41 # (when slots=True) | |
42 _hash_cache_field = "_attrs_cached_hash" | |
43 | |
44 _empty_metadata_singleton = metadata_proxy({}) | |
45 | |
46 # Unique object for unequivocal getattr() defaults. | |
47 _sentinel = object() | |
48 | |
49 | |
50 class _Nothing(object): | |
51 """ | |
52 Sentinel class to indicate the lack of a value when ``None`` is ambiguous. | |
53 | |
54 ``_Nothing`` is a singleton. There is only ever one of it. | |
55 """ | |
56 | |
57 _singleton = None | |
58 | |
59 def __new__(cls): | |
60 if _Nothing._singleton is None: | |
61 _Nothing._singleton = super(_Nothing, cls).__new__(cls) | |
62 return _Nothing._singleton | |
63 | |
64 def __repr__(self): | |
65 return "NOTHING" | |
66 | |
67 | |
68 NOTHING = _Nothing() | |
69 """ | |
70 Sentinel to indicate the lack of a value when ``None`` is ambiguous. | |
71 """ | |
72 | |
73 | |
74 class _CacheHashWrapper(int): | |
75 """ | |
76 An integer subclass that pickles / copies as None | |
77 | |
78 This is used for non-slots classes with ``cache_hash=True``, to avoid | |
79 serializing a potentially (even likely) invalid hash value. Since ``None`` | |
80 is the default value for uncalculated hashes, whenever this is copied, | |
81 the copy's value for the hash should automatically reset. | |
82 | |
83 See GH #613 for more details. | |
84 """ | |
85 | |
86 if PY2: | |
87 # For some reason `type(None)` isn't callable in Python 2, but we don't | |
88 # actually need a constructor for None objects, we just need any | |
89 # available function that returns None. | |
90 def __reduce__(self, _none_constructor=getattr, _args=(0, "", None)): | |
91 return _none_constructor, _args | |
92 | |
93 else: | |
94 | |
95 def __reduce__(self, _none_constructor=type(None), _args=()): | |
96 return _none_constructor, _args | |
97 | |
98 | |
99 def attrib( | |
100 default=NOTHING, | |
101 validator=None, | |
102 repr=True, | |
103 cmp=None, | |
104 hash=None, | |
105 init=True, | |
106 metadata=None, | |
107 type=None, | |
108 converter=None, | |
109 factory=None, | |
110 kw_only=False, | |
111 eq=None, | |
112 order=None, | |
113 on_setattr=None, | |
114 ): | |
115 """ | |
116 Create a new attribute on a class. | |
117 | |
118 .. warning:: | |
119 | |
120 Does *not* do anything unless the class is also decorated with | |
121 `attr.s`! | |
122 | |
123 :param default: A value that is used if an ``attrs``-generated ``__init__`` | |
124 is used and no value is passed while instantiating or the attribute is | |
125 excluded using ``init=False``. | |
126 | |
127 If the value is an instance of `Factory`, its callable will be | |
128 used to construct a new value (useful for mutable data types like lists | |
129 or dicts). | |
130 | |
131 If a default is not set (or set manually to `attr.NOTHING`), a value | |
132 *must* be supplied when instantiating; otherwise a `TypeError` | |
133 will be raised. | |
134 | |
135 The default can also be set using decorator notation as shown below. | |
136 | |
137 :type default: Any value | |
138 | |
139 :param callable factory: Syntactic sugar for | |
140 ``default=attr.Factory(factory)``. | |
141 | |
142 :param validator: `callable` that is called by ``attrs``-generated | |
143 ``__init__`` methods after the instance has been initialized. They | |
144 receive the initialized instance, the `Attribute`, and the | |
145 passed value. | |
146 | |
147 The return value is *not* inspected so the validator has to throw an | |
148 exception itself. | |
149 | |
150 If a `list` is passed, its items are treated as validators and must | |
151 all pass. | |
152 | |
153 Validators can be globally disabled and re-enabled using | |
154 `get_run_validators`. | |
155 | |
156 The validator can also be set using decorator notation as shown below. | |
157 | |
158 :type validator: `callable` or a `list` of `callable`\\ s. | |
159 | |
160 :param repr: Include this attribute in the generated ``__repr__`` | |
161 method. If ``True``, include the attribute; if ``False``, omit it. By | |
162 default, the built-in ``repr()`` function is used. To override how the | |
163 attribute value is formatted, pass a ``callable`` that takes a single | |
164 value and returns a string. Note that the resulting string is used | |
165 as-is, i.e. it will be used directly *instead* of calling ``repr()`` | |
166 (the default). | |
167 :type repr: a `bool` or a `callable` to use a custom function. | |
168 :param bool eq: If ``True`` (default), include this attribute in the | |
169 generated ``__eq__`` and ``__ne__`` methods that check two instances | |
170 for equality. | |
171 :param bool order: If ``True`` (default), include this attributes in the | |
172 generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. | |
173 :param bool cmp: Setting to ``True`` is equivalent to setting ``eq=True, | |
174 order=True``. Deprecated in favor of *eq* and *order*. | |
175 :param Optional[bool] hash: Include this attribute in the generated | |
176 ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This | |
177 is the correct behavior according the Python spec. Setting this value | |
178 to anything else than ``None`` is *discouraged*. | |
179 :param bool init: Include this attribute in the generated ``__init__`` | |
180 method. It is possible to set this to ``False`` and set a default | |
181 value. In that case this attributed is unconditionally initialized | |
182 with the specified default value or factory. | |
183 :param callable converter: `callable` that is called by | |
184 ``attrs``-generated ``__init__`` methods to convert attribute's value | |
185 to the desired format. It is given the passed-in value, and the | |
186 returned value will be used as the new value of the attribute. The | |
187 value is converted before being passed to the validator, if any. | |
188 :param metadata: An arbitrary mapping, to be used by third-party | |
189 components. See `extending_metadata`. | |
190 :param type: The type of the attribute. In Python 3.6 or greater, the | |
191 preferred method to specify the type is using a variable annotation | |
192 (see `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_). | |
193 This argument is provided for backward compatibility. | |
194 Regardless of the approach used, the type will be stored on | |
195 ``Attribute.type``. | |
196 | |
197 Please note that ``attrs`` doesn't do anything with this metadata by | |
198 itself. You can use it as part of your own code or for | |
199 `static type checking <types>`. | |
200 :param kw_only: Make this attribute keyword-only (Python 3+) | |
201 in the generated ``__init__`` (if ``init`` is ``False``, this | |
202 parameter is ignored). | |
203 :param on_setattr: Allows to overwrite the *on_setattr* setting from | |
204 `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used. | |
205 Set to `attr.setters.NO_OP` to run **no** `setattr` hooks for this | |
206 attribute -- regardless of the setting in `attr.s`. | |
207 :type on_setattr: `callable`, or a list of callables, or `None`, or | |
208 `attr.setters.NO_OP` | |
209 | |
210 .. versionadded:: 15.2.0 *convert* | |
211 .. versionadded:: 16.3.0 *metadata* | |
212 .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. | |
213 .. versionchanged:: 17.1.0 | |
214 *hash* is ``None`` and therefore mirrors *eq* by default. | |
215 .. versionadded:: 17.3.0 *type* | |
216 .. deprecated:: 17.4.0 *convert* | |
217 .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated | |
218 *convert* to achieve consistency with other noun-based arguments. | |
219 .. versionadded:: 18.1.0 | |
220 ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. | |
221 .. versionadded:: 18.2.0 *kw_only* | |
222 .. versionchanged:: 19.2.0 *convert* keyword argument removed | |
223 .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. | |
224 .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. | |
225 .. versionadded:: 19.2.0 *eq* and *order* | |
226 .. versionadded:: 20.1.0 *on_setattr* | |
227 .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 | |
228 """ | |
229 eq, order = _determine_eq_order(cmp, eq, order, True) | |
230 | |
231 if hash is not None and hash is not True and hash is not False: | |
232 raise TypeError( | |
233 "Invalid value for hash. Must be True, False, or None." | |
234 ) | |
235 | |
236 if factory is not None: | |
237 if default is not NOTHING: | |
238 raise ValueError( | |
239 "The `default` and `factory` arguments are mutually " | |
240 "exclusive." | |
241 ) | |
242 if not callable(factory): | |
243 raise ValueError("The `factory` argument must be a callable.") | |
244 default = Factory(factory) | |
245 | |
246 if metadata is None: | |
247 metadata = {} | |
248 | |
249 # Apply syntactic sugar by auto-wrapping. | |
250 if isinstance(on_setattr, (list, tuple)): | |
251 on_setattr = setters.pipe(*on_setattr) | |
252 | |
253 if validator and isinstance(validator, (list, tuple)): | |
254 validator = and_(*validator) | |
255 | |
256 if converter and isinstance(converter, (list, tuple)): | |
257 converter = pipe(*converter) | |
258 | |
259 return _CountingAttr( | |
260 default=default, | |
261 validator=validator, | |
262 repr=repr, | |
263 cmp=None, | |
264 hash=hash, | |
265 init=init, | |
266 converter=converter, | |
267 metadata=metadata, | |
268 type=type, | |
269 kw_only=kw_only, | |
270 eq=eq, | |
271 order=order, | |
272 on_setattr=on_setattr, | |
273 ) | |
274 | |
275 | |
276 def _make_attr_tuple_class(cls_name, attr_names): | |
277 """ | |
278 Create a tuple subclass to hold `Attribute`s for an `attrs` class. | |
279 | |
280 The subclass is a bare tuple with properties for names. | |
281 | |
282 class MyClassAttributes(tuple): | |
283 __slots__ = () | |
284 x = property(itemgetter(0)) | |
285 """ | |
286 attr_class_name = "{}Attributes".format(cls_name) | |
287 attr_class_template = [ | |
288 "class {}(tuple):".format(attr_class_name), | |
289 " __slots__ = ()", | |
290 ] | |
291 if attr_names: | |
292 for i, attr_name in enumerate(attr_names): | |
293 attr_class_template.append( | |
294 _tuple_property_pat.format(index=i, attr_name=attr_name) | |
295 ) | |
296 else: | |
297 attr_class_template.append(" pass") | |
298 globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} | |
299 eval(compile("\n".join(attr_class_template), "", "exec"), globs) | |
300 | |
301 return globs[attr_class_name] | |
302 | |
303 | |
304 # Tuple class for extracted attributes from a class definition. | |
305 # `base_attrs` is a subset of `attrs`. | |
306 _Attributes = _make_attr_tuple_class( | |
307 "_Attributes", | |
308 [ | |
309 # all attributes to build dunder methods for | |
310 "attrs", | |
311 # attributes that have been inherited | |
312 "base_attrs", | |
313 # map inherited attributes to their originating classes | |
314 "base_attrs_map", | |
315 ], | |
316 ) | |
317 | |
318 | |
319 def _is_class_var(annot): | |
320 """ | |
321 Check whether *annot* is a typing.ClassVar. | |
322 | |
323 The string comparison hack is used to avoid evaluating all string | |
324 annotations which would put attrs-based classes at a performance | |
325 disadvantage compared to plain old classes. | |
326 """ | |
327 return str(annot).startswith(_classvar_prefixes) | |
328 | |
329 | |
330 def _has_own_attribute(cls, attrib_name): | |
331 """ | |
332 Check whether *cls* defines *attrib_name* (and doesn't just inherit it). | |
333 | |
334 Requires Python 3. | |
335 """ | |
336 attr = getattr(cls, attrib_name, _sentinel) | |
337 if attr is _sentinel: | |
338 return False | |
339 | |
340 for base_cls in cls.__mro__[1:]: | |
341 a = getattr(base_cls, attrib_name, None) | |
342 if attr is a: | |
343 return False | |
344 | |
345 return True | |
346 | |
347 | |
348 def _get_annotations(cls): | |
349 """ | |
350 Get annotations for *cls*. | |
351 """ | |
352 if _has_own_attribute(cls, "__annotations__"): | |
353 return cls.__annotations__ | |
354 | |
355 return {} | |
356 | |
357 | |
358 def _counter_getter(e): | |
359 """ | |
360 Key function for sorting to avoid re-creating a lambda for every class. | |
361 """ | |
362 return e[1].counter | |
363 | |
364 | |
365 def _collect_base_attrs(cls, taken_attr_names): | |
366 """ | |
367 Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. | |
368 """ | |
369 base_attrs = [] | |
370 base_attr_map = {} # A dictionary of base attrs to their classes. | |
371 | |
372 # Traverse the MRO and collect attributes. | |
373 for base_cls in reversed(cls.__mro__[1:-1]): | |
374 for a in getattr(base_cls, "__attrs_attrs__", []): | |
375 if a.inherited or a.name in taken_attr_names: | |
376 continue | |
377 | |
378 a = a.evolve(inherited=True) | |
379 base_attrs.append(a) | |
380 base_attr_map[a.name] = base_cls | |
381 | |
382 # For each name, only keep the freshest definition i.e. the furthest at the | |
383 # back. base_attr_map is fine because it gets overwritten with every new | |
384 # instance. | |
385 filtered = [] | |
386 seen = set() | |
387 for a in reversed(base_attrs): | |
388 if a.name in seen: | |
389 continue | |
390 filtered.insert(0, a) | |
391 seen.add(a.name) | |
392 | |
393 return filtered, base_attr_map | |
394 | |
395 | |
396 def _collect_base_attrs_broken(cls, taken_attr_names): | |
397 """ | |
398 Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. | |
399 | |
400 N.B. *taken_attr_names* will be mutated. | |
401 | |
402 Adhere to the old incorrect behavior. | |
403 | |
404 Notably it collects from the front and considers inherited attributes which | |
405 leads to the buggy behavior reported in #428. | |
406 """ | |
407 base_attrs = [] | |
408 base_attr_map = {} # A dictionary of base attrs to their classes. | |
409 | |
410 # Traverse the MRO and collect attributes. | |
411 for base_cls in cls.__mro__[1:-1]: | |
412 for a in getattr(base_cls, "__attrs_attrs__", []): | |
413 if a.name in taken_attr_names: | |
414 continue | |
415 | |
416 a = a.evolve(inherited=True) | |
417 taken_attr_names.add(a.name) | |
418 base_attrs.append(a) | |
419 base_attr_map[a.name] = base_cls | |
420 | |
421 return base_attrs, base_attr_map | |
422 | |
423 | |
424 def _transform_attrs( | |
425 cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer | |
426 ): | |
427 """ | |
428 Transform all `_CountingAttr`s on a class into `Attribute`s. | |
429 | |
430 If *these* is passed, use that and don't look for them on the class. | |
431 | |
432 *collect_by_mro* is True, collect them in the correct MRO order, otherwise | |
433 use the old -- incorrect -- order. See #428. | |
434 | |
435 Return an `_Attributes`. | |
436 """ | |
437 cd = cls.__dict__ | |
438 anns = _get_annotations(cls) | |
439 | |
440 if these is not None: | |
441 ca_list = [(name, ca) for name, ca in iteritems(these)] | |
442 | |
443 if not isinstance(these, ordered_dict): | |
444 ca_list.sort(key=_counter_getter) | |
445 elif auto_attribs is True: | |
446 ca_names = { | |
447 name | |
448 for name, attr in cd.items() | |
449 if isinstance(attr, _CountingAttr) | |
450 } | |
451 ca_list = [] | |
452 annot_names = set() | |
453 for attr_name, type in anns.items(): | |
454 if _is_class_var(type): | |
455 continue | |
456 annot_names.add(attr_name) | |
457 a = cd.get(attr_name, NOTHING) | |
458 | |
459 if not isinstance(a, _CountingAttr): | |
460 if a is NOTHING: | |
461 a = attrib() | |
462 else: | |
463 a = attrib(default=a) | |
464 ca_list.append((attr_name, a)) | |
465 | |
466 unannotated = ca_names - annot_names | |
467 if len(unannotated) > 0: | |
468 raise UnannotatedAttributeError( | |
469 "The following `attr.ib`s lack a type annotation: " | |
470 + ", ".join( | |
471 sorted(unannotated, key=lambda n: cd.get(n).counter) | |
472 ) | |
473 + "." | |
474 ) | |
475 else: | |
476 ca_list = sorted( | |
477 ( | |
478 (name, attr) | |
479 for name, attr in cd.items() | |
480 if isinstance(attr, _CountingAttr) | |
481 ), | |
482 key=lambda e: e[1].counter, | |
483 ) | |
484 | |
485 own_attrs = [ | |
486 Attribute.from_counting_attr( | |
487 name=attr_name, ca=ca, type=anns.get(attr_name) | |
488 ) | |
489 for attr_name, ca in ca_list | |
490 ] | |
491 | |
492 if collect_by_mro: | |
493 base_attrs, base_attr_map = _collect_base_attrs( | |
494 cls, {a.name for a in own_attrs} | |
495 ) | |
496 else: | |
497 base_attrs, base_attr_map = _collect_base_attrs_broken( | |
498 cls, {a.name for a in own_attrs} | |
499 ) | |
500 | |
501 attr_names = [a.name for a in base_attrs + own_attrs] | |
502 | |
503 AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) | |
504 | |
505 if kw_only: | |
506 own_attrs = [a.evolve(kw_only=True) for a in own_attrs] | |
507 base_attrs = [a.evolve(kw_only=True) for a in base_attrs] | |
508 | |
509 attrs = AttrsClass(base_attrs + own_attrs) | |
510 | |
511 # Mandatory vs non-mandatory attr order only matters when they are part of | |
512 # the __init__ signature and when they aren't kw_only (which are moved to | |
513 # the end and can be mandatory or non-mandatory in any order, as they will | |
514 # be specified as keyword args anyway). Check the order of those attrs: | |
515 had_default = False | |
516 for a in (a for a in attrs if a.init is not False and a.kw_only is False): | |
517 if had_default is True and a.default is NOTHING: | |
518 raise ValueError( | |
519 "No mandatory attributes allowed after an attribute with a " | |
520 "default value or factory. Attribute in question: %r" % (a,) | |
521 ) | |
522 | |
523 if had_default is False and a.default is not NOTHING: | |
524 had_default = True | |
525 | |
526 if field_transformer is not None: | |
527 attrs = field_transformer(cls, attrs) | |
528 return _Attributes((attrs, base_attrs, base_attr_map)) | |
529 | |
530 | |
531 if PYPY: | |
532 | |
533 def _frozen_setattrs(self, name, value): | |
534 """ | |
535 Attached to frozen classes as __setattr__. | |
536 """ | |
537 if isinstance(self, BaseException) and name in ( | |
538 "__cause__", | |
539 "__context__", | |
540 ): | |
541 BaseException.__setattr__(self, name, value) | |
542 return | |
543 | |
544 raise FrozenInstanceError() | |
545 | |
546 | |
547 else: | |
548 | |
549 def _frozen_setattrs(self, name, value): | |
550 """ | |
551 Attached to frozen classes as __setattr__. | |
552 """ | |
553 raise FrozenInstanceError() | |
554 | |
555 | |
556 def _frozen_delattrs(self, name): | |
557 """ | |
558 Attached to frozen classes as __delattr__. | |
559 """ | |
560 raise FrozenInstanceError() | |
561 | |
562 | |
563 class _ClassBuilder(object): | |
564 """ | |
565 Iteratively build *one* class. | |
566 """ | |
567 | |
568 __slots__ = ( | |
569 "_attr_names", | |
570 "_attrs", | |
571 "_base_attr_map", | |
572 "_base_names", | |
573 "_cache_hash", | |
574 "_cls", | |
575 "_cls_dict", | |
576 "_delete_attribs", | |
577 "_frozen", | |
578 "_has_post_init", | |
579 "_is_exc", | |
580 "_on_setattr", | |
581 "_slots", | |
582 "_weakref_slot", | |
583 "_has_own_setattr", | |
584 "_has_custom_setattr", | |
585 ) | |
586 | |
587 def __init__( | |
588 self, | |
589 cls, | |
590 these, | |
591 slots, | |
592 frozen, | |
593 weakref_slot, | |
594 getstate_setstate, | |
595 auto_attribs, | |
596 kw_only, | |
597 cache_hash, | |
598 is_exc, | |
599 collect_by_mro, | |
600 on_setattr, | |
601 has_custom_setattr, | |
602 field_transformer, | |
603 ): | |
604 attrs, base_attrs, base_map = _transform_attrs( | |
605 cls, | |
606 these, | |
607 auto_attribs, | |
608 kw_only, | |
609 collect_by_mro, | |
610 field_transformer, | |
611 ) | |
612 | |
613 self._cls = cls | |
614 self._cls_dict = dict(cls.__dict__) if slots else {} | |
615 self._attrs = attrs | |
616 self._base_names = set(a.name for a in base_attrs) | |
617 self._base_attr_map = base_map | |
618 self._attr_names = tuple(a.name for a in attrs) | |
619 self._slots = slots | |
620 self._frozen = frozen | |
621 self._weakref_slot = weakref_slot | |
622 self._cache_hash = cache_hash | |
623 self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) | |
624 self._delete_attribs = not bool(these) | |
625 self._is_exc = is_exc | |
626 self._on_setattr = on_setattr | |
627 | |
628 self._has_custom_setattr = has_custom_setattr | |
629 self._has_own_setattr = False | |
630 | |
631 self._cls_dict["__attrs_attrs__"] = self._attrs | |
632 | |
633 if frozen: | |
634 self._cls_dict["__setattr__"] = _frozen_setattrs | |
635 self._cls_dict["__delattr__"] = _frozen_delattrs | |
636 | |
637 self._has_own_setattr = True | |
638 | |
639 if getstate_setstate: | |
640 ( | |
641 self._cls_dict["__getstate__"], | |
642 self._cls_dict["__setstate__"], | |
643 ) = self._make_getstate_setstate() | |
644 | |
645 def __repr__(self): | |
646 return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) | |
647 | |
648 def build_class(self): | |
649 """ | |
650 Finalize class based on the accumulated configuration. | |
651 | |
652 Builder cannot be used after calling this method. | |
653 """ | |
654 if self._slots is True: | |
655 return self._create_slots_class() | |
656 else: | |
657 return self._patch_original_class() | |
658 | |
659 def _patch_original_class(self): | |
660 """ | |
661 Apply accumulated methods and return the class. | |
662 """ | |
663 cls = self._cls | |
664 base_names = self._base_names | |
665 | |
666 # Clean class of attribute definitions (`attr.ib()`s). | |
667 if self._delete_attribs: | |
668 for name in self._attr_names: | |
669 if ( | |
670 name not in base_names | |
671 and getattr(cls, name, _sentinel) is not _sentinel | |
672 ): | |
673 try: | |
674 delattr(cls, name) | |
675 except AttributeError: | |
676 # This can happen if a base class defines a class | |
677 # variable and we want to set an attribute with the | |
678 # same name by using only a type annotation. | |
679 pass | |
680 | |
681 # Attach our dunder methods. | |
682 for name, value in self._cls_dict.items(): | |
683 setattr(cls, name, value) | |
684 | |
685 # If we've inherited an attrs __setattr__ and don't write our own, | |
686 # reset it to object's. | |
687 if not self._has_own_setattr and getattr( | |
688 cls, "__attrs_own_setattr__", False | |
689 ): | |
690 cls.__attrs_own_setattr__ = False | |
691 | |
692 if not self._has_custom_setattr: | |
693 cls.__setattr__ = object.__setattr__ | |
694 | |
695 return cls | |
696 | |
697 def _create_slots_class(self): | |
698 """ | |
699 Build and return a new class with a `__slots__` attribute. | |
700 """ | |
701 base_names = self._base_names | |
702 cd = { | |
703 k: v | |
704 for k, v in iteritems(self._cls_dict) | |
705 if k not in tuple(self._attr_names) + ("__dict__", "__weakref__") | |
706 } | |
707 | |
708 # If our class doesn't have its own implementation of __setattr__ | |
709 # (either from the user or by us), check the bases, if one of them has | |
710 # an attrs-made __setattr__, that needs to be reset. We don't walk the | |
711 # MRO because we only care about our immediate base classes. | |
712 # XXX: This can be confused by subclassing a slotted attrs class with | |
713 # XXX: a non-attrs class and subclass the resulting class with an attrs | |
714 # XXX: class. See `test_slotted_confused` for details. For now that's | |
715 # XXX: OK with us. | |
716 if not self._has_own_setattr: | |
717 cd["__attrs_own_setattr__"] = False | |
718 | |
719 if not self._has_custom_setattr: | |
720 for base_cls in self._cls.__bases__: | |
721 if base_cls.__dict__.get("__attrs_own_setattr__", False): | |
722 cd["__setattr__"] = object.__setattr__ | |
723 break | |
724 | |
725 # Traverse the MRO to check for an existing __weakref__. | |
726 weakref_inherited = False | |
727 for base_cls in self._cls.__mro__[1:-1]: | |
728 if base_cls.__dict__.get("__weakref__", None) is not None: | |
729 weakref_inherited = True | |
730 break | |
731 | |
732 names = self._attr_names | |
733 if ( | |
734 self._weakref_slot | |
735 and "__weakref__" not in getattr(self._cls, "__slots__", ()) | |
736 and "__weakref__" not in names | |
737 and not weakref_inherited | |
738 ): | |
739 names += ("__weakref__",) | |
740 | |
741 # We only add the names of attributes that aren't inherited. | |
742 # Setting __slots__ to inherited attributes wastes memory. | |
743 slot_names = [name for name in names if name not in base_names] | |
744 if self._cache_hash: | |
745 slot_names.append(_hash_cache_field) | |
746 cd["__slots__"] = tuple(slot_names) | |
747 | |
748 qualname = getattr(self._cls, "__qualname__", None) | |
749 if qualname is not None: | |
750 cd["__qualname__"] = qualname | |
751 | |
752 # Create new class based on old class and our methods. | |
753 cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) | |
754 | |
755 # The following is a fix for | |
756 # https://github.com/python-attrs/attrs/issues/102. On Python 3, | |
757 # if a method mentions `__class__` or uses the no-arg super(), the | |
758 # compiler will bake a reference to the class in the method itself | |
759 # as `method.__closure__`. Since we replace the class with a | |
760 # clone, we rewrite these references so it keeps working. | |
761 for item in cls.__dict__.values(): | |
762 if isinstance(item, (classmethod, staticmethod)): | |
763 # Class- and staticmethods hide their functions inside. | |
764 # These might need to be rewritten as well. | |
765 closure_cells = getattr(item.__func__, "__closure__", None) | |
766 else: | |
767 closure_cells = getattr(item, "__closure__", None) | |
768 | |
769 if not closure_cells: # Catch None or the empty list. | |
770 continue | |
771 for cell in closure_cells: | |
772 try: | |
773 match = cell.cell_contents is self._cls | |
774 except ValueError: # ValueError: Cell is empty | |
775 pass | |
776 else: | |
777 if match: | |
778 set_closure_cell(cell, cls) | |
779 | |
780 return cls | |
781 | |
782 def add_repr(self, ns): | |
783 self._cls_dict["__repr__"] = self._add_method_dunders( | |
784 _make_repr(self._attrs, ns=ns) | |
785 ) | |
786 return self | |
787 | |
788 def add_str(self): | |
789 repr = self._cls_dict.get("__repr__") | |
790 if repr is None: | |
791 raise ValueError( | |
792 "__str__ can only be generated if a __repr__ exists." | |
793 ) | |
794 | |
795 def __str__(self): | |
796 return self.__repr__() | |
797 | |
798 self._cls_dict["__str__"] = self._add_method_dunders(__str__) | |
799 return self | |
800 | |
801 def _make_getstate_setstate(self): | |
802 """ | |
803 Create custom __setstate__ and __getstate__ methods. | |
804 """ | |
805 # __weakref__ is not writable. | |
806 state_attr_names = tuple( | |
807 an for an in self._attr_names if an != "__weakref__" | |
808 ) | |
809 | |
810 def slots_getstate(self): | |
811 """ | |
812 Automatically created by attrs. | |
813 """ | |
814 return tuple(getattr(self, name) for name in state_attr_names) | |
815 | |
816 hash_caching_enabled = self._cache_hash | |
817 | |
818 def slots_setstate(self, state): | |
819 """ | |
820 Automatically created by attrs. | |
821 """ | |
822 __bound_setattr = _obj_setattr.__get__(self, Attribute) | |
823 for name, value in zip(state_attr_names, state): | |
824 __bound_setattr(name, value) | |
825 | |
826 # The hash code cache is not included when the object is | |
827 # serialized, but it still needs to be initialized to None to | |
828 # indicate that the first call to __hash__ should be a cache | |
829 # miss. | |
830 if hash_caching_enabled: | |
831 __bound_setattr(_hash_cache_field, None) | |
832 | |
833 return slots_getstate, slots_setstate | |
834 | |
835 def make_unhashable(self): | |
836 self._cls_dict["__hash__"] = None | |
837 return self | |
838 | |
839 def add_hash(self): | |
840 self._cls_dict["__hash__"] = self._add_method_dunders( | |
841 _make_hash( | |
842 self._cls, | |
843 self._attrs, | |
844 frozen=self._frozen, | |
845 cache_hash=self._cache_hash, | |
846 ) | |
847 ) | |
848 | |
849 return self | |
850 | |
851 def add_init(self): | |
852 self._cls_dict["__init__"] = self._add_method_dunders( | |
853 _make_init( | |
854 self._cls, | |
855 self._attrs, | |
856 self._has_post_init, | |
857 self._frozen, | |
858 self._slots, | |
859 self._cache_hash, | |
860 self._base_attr_map, | |
861 self._is_exc, | |
862 self._on_setattr is not None | |
863 and self._on_setattr is not setters.NO_OP, | |
864 ) | |
865 ) | |
866 | |
867 return self | |
868 | |
869 def add_eq(self): | |
870 cd = self._cls_dict | |
871 | |
872 cd["__eq__"] = self._add_method_dunders( | |
873 _make_eq(self._cls, self._attrs) | |
874 ) | |
875 cd["__ne__"] = self._add_method_dunders(_make_ne()) | |
876 | |
877 return self | |
878 | |
879 def add_order(self): | |
880 cd = self._cls_dict | |
881 | |
882 cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( | |
883 self._add_method_dunders(meth) | |
884 for meth in _make_order(self._cls, self._attrs) | |
885 ) | |
886 | |
887 return self | |
888 | |
889 def add_setattr(self): | |
890 if self._frozen: | |
891 return self | |
892 | |
893 sa_attrs = {} | |
894 for a in self._attrs: | |
895 on_setattr = a.on_setattr or self._on_setattr | |
896 if on_setattr and on_setattr is not setters.NO_OP: | |
897 sa_attrs[a.name] = a, on_setattr | |
898 | |
899 if not sa_attrs: | |
900 return self | |
901 | |
902 if self._has_custom_setattr: | |
903 # We need to write a __setattr__ but there already is one! | |
904 raise ValueError( | |
905 "Can't combine custom __setattr__ with on_setattr hooks." | |
906 ) | |
907 | |
908 # docstring comes from _add_method_dunders | |
909 def __setattr__(self, name, val): | |
910 try: | |
911 a, hook = sa_attrs[name] | |
912 except KeyError: | |
913 nval = val | |
914 else: | |
915 nval = hook(self, a, val) | |
916 | |
917 _obj_setattr(self, name, nval) | |
918 | |
919 self._cls_dict["__attrs_own_setattr__"] = True | |
920 self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) | |
921 self._has_own_setattr = True | |
922 | |
923 return self | |
924 | |
925 def _add_method_dunders(self, method): | |
926 """ | |
927 Add __module__ and __qualname__ to a *method* if possible. | |
928 """ | |
929 try: | |
930 method.__module__ = self._cls.__module__ | |
931 except AttributeError: | |
932 pass | |
933 | |
934 try: | |
935 method.__qualname__ = ".".join( | |
936 (self._cls.__qualname__, method.__name__) | |
937 ) | |
938 except AttributeError: | |
939 pass | |
940 | |
941 try: | |
942 method.__doc__ = "Method generated by attrs for class %s." % ( | |
943 self._cls.__qualname__, | |
944 ) | |
945 except AttributeError: | |
946 pass | |
947 | |
948 return method | |
949 | |
950 | |
951 _CMP_DEPRECATION = ( | |
952 "The usage of `cmp` is deprecated and will be removed on or after " | |
953 "2021-06-01. Please use `eq` and `order` instead." | |
954 ) | |
955 | |
956 | |
957 def _determine_eq_order(cmp, eq, order, default_eq): | |
958 """ | |
959 Validate the combination of *cmp*, *eq*, and *order*. Derive the effective | |
960 values of eq and order. If *eq* is None, set it to *default_eq*. | |
961 """ | |
962 if cmp is not None and any((eq is not None, order is not None)): | |
963 raise ValueError("Don't mix `cmp` with `eq' and `order`.") | |
964 | |
965 # cmp takes precedence due to bw-compatibility. | |
966 if cmp is not None: | |
967 warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=3) | |
968 | |
969 return cmp, cmp | |
970 | |
971 # If left None, equality is set to the specified default and ordering | |
972 # mirrors equality. | |
973 if eq is None: | |
974 eq = default_eq | |
975 | |
976 if order is None: | |
977 order = eq | |
978 | |
979 if eq is False and order is True: | |
980 raise ValueError("`order` can only be True if `eq` is True too.") | |
981 | |
982 return eq, order | |
983 | |
984 | |
985 def _determine_whether_to_implement( | |
986 cls, flag, auto_detect, dunders, default=True | |
987 ): | |
988 """ | |
989 Check whether we should implement a set of methods for *cls*. | |
990 | |
991 *flag* is the argument passed into @attr.s like 'init', *auto_detect* the | |
992 same as passed into @attr.s and *dunders* is a tuple of attribute names | |
993 whose presence signal that the user has implemented it themselves. | |
994 | |
995 Return *default* if no reason for either for or against is found. | |
996 | |
997 auto_detect must be False on Python 2. | |
998 """ | |
999 if flag is True or flag is False: | |
1000 return flag | |
1001 | |
1002 if flag is None and auto_detect is False: | |
1003 return default | |
1004 | |
1005 # Logically, flag is None and auto_detect is True here. | |
1006 for dunder in dunders: | |
1007 if _has_own_attribute(cls, dunder): | |
1008 return False | |
1009 | |
1010 return default | |
1011 | |
1012 | |
1013 def attrs( | |
1014 maybe_cls=None, | |
1015 these=None, | |
1016 repr_ns=None, | |
1017 repr=None, | |
1018 cmp=None, | |
1019 hash=None, | |
1020 init=None, | |
1021 slots=False, | |
1022 frozen=False, | |
1023 weakref_slot=True, | |
1024 str=False, | |
1025 auto_attribs=False, | |
1026 kw_only=False, | |
1027 cache_hash=False, | |
1028 auto_exc=False, | |
1029 eq=None, | |
1030 order=None, | |
1031 auto_detect=False, | |
1032 collect_by_mro=False, | |
1033 getstate_setstate=None, | |
1034 on_setattr=None, | |
1035 field_transformer=None, | |
1036 ): | |
1037 r""" | |
1038 A class decorator that adds `dunder | |
1039 <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the | |
1040 specified attributes using `attr.ib` or the *these* argument. | |
1041 | |
1042 :param these: A dictionary of name to `attr.ib` mappings. This is | |
1043 useful to avoid the definition of your attributes within the class body | |
1044 because you can't (e.g. if you want to add ``__repr__`` methods to | |
1045 Django models) or don't want to. | |
1046 | |
1047 If *these* is not ``None``, ``attrs`` will *not* search the class body | |
1048 for attributes and will *not* remove any attributes from it. | |
1049 | |
1050 If *these* is an ordered dict (`dict` on Python 3.6+, | |
1051 `collections.OrderedDict` otherwise), the order is deduced from | |
1052 the order of the attributes inside *these*. Otherwise the order | |
1053 of the definition of the attributes is used. | |
1054 | |
1055 :type these: `dict` of `str` to `attr.ib` | |
1056 | |
1057 :param str repr_ns: When using nested classes, there's no way in Python 2 | |
1058 to automatically detect that. Therefore it's possible to set the | |
1059 namespace explicitly for a more meaningful ``repr`` output. | |
1060 :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, | |
1061 *order*, and *hash* arguments explicitly, assume they are set to | |
1062 ``True`` **unless any** of the involved methods for one of the | |
1063 arguments is implemented in the *current* class (i.e. it is *not* | |
1064 inherited from some base class). | |
1065 | |
1066 So for example by implementing ``__eq__`` on a class yourself, | |
1067 ``attrs`` will deduce ``eq=False`` and won't create *neither* | |
1068 ``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible | |
1069 ``__ne__`` by default, so it *should* be enough to only implement | |
1070 ``__eq__`` in most cases). | |
1071 | |
1072 .. warning:: | |
1073 | |
1074 If you prevent ``attrs`` from creating the ordering methods for you | |
1075 (``order=False``, e.g. by implementing ``__le__``), it becomes | |
1076 *your* responsibility to make sure its ordering is sound. The best | |
1077 way is to use the `functools.total_ordering` decorator. | |
1078 | |
1079 | |
1080 Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, | |
1081 *cmp*, or *hash* overrides whatever *auto_detect* would determine. | |
1082 | |
1083 *auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises | |
1084 a `PythonTooOldError`. | |
1085 | |
1086 :param bool repr: Create a ``__repr__`` method with a human readable | |
1087 representation of ``attrs`` attributes.. | |
1088 :param bool str: Create a ``__str__`` method that is identical to | |
1089 ``__repr__``. This is usually not necessary except for | |
1090 `Exception`\ s. | |
1091 :param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__`` | |
1092 and ``__ne__`` methods that check two instances for equality. | |
1093 | |
1094 They compare the instances as if they were tuples of their ``attrs`` | |
1095 attributes if and only if the types of both classes are *identical*! | |
1096 :param Optional[bool] order: If ``True``, add ``__lt__``, ``__le__``, | |
1097 ``__gt__``, and ``__ge__`` methods that behave like *eq* above and | |
1098 allow instances to be ordered. If ``None`` (default) mirror value of | |
1099 *eq*. | |
1100 :param Optional[bool] cmp: Setting to ``True`` is equivalent to setting | |
1101 ``eq=True, order=True``. Deprecated in favor of *eq* and *order*, has | |
1102 precedence over them for backward-compatibility though. Must not be | |
1103 mixed with *eq* or *order*. | |
1104 :param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method | |
1105 is generated according how *eq* and *frozen* are set. | |
1106 | |
1107 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. | |
1108 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to | |
1109 None, marking it unhashable (which it is). | |
1110 3. If *eq* is False, ``__hash__`` will be left untouched meaning the | |
1111 ``__hash__`` method of the base class will be used (if base class is | |
1112 ``object``, this means it will fall back to id-based hashing.). | |
1113 | |
1114 Although not recommended, you can decide for yourself and force | |
1115 ``attrs`` to create one (e.g. if the class is immutable even though you | |
1116 didn't freeze it programmatically) by passing ``True`` or not. Both of | |
1117 these cases are rather special and should be used carefully. | |
1118 | |
1119 See our documentation on `hashing`, Python's documentation on | |
1120 `object.__hash__`, and the `GitHub issue that led to the default \ | |
1121 behavior <https://github.com/python-attrs/attrs/issues/136>`_ for more | |
1122 details. | |
1123 :param bool init: Create a ``__init__`` method that initializes the | |
1124 ``attrs`` attributes. Leading underscores are stripped for the | |
1125 argument name. If a ``__attrs_post_init__`` method exists on the | |
1126 class, it will be called after the class is fully initialized. | |
1127 :param bool slots: Create a `slotted class <slotted classes>` that's more | |
1128 memory-efficient. Slotted classes are generally superior to the default | |
1129 dict classes, but have some gotchas you should know about, so we | |
1130 encourage you to read the `glossary entry <slotted classes>`. | |
1131 :param bool frozen: Make instances immutable after initialization. If | |
1132 someone attempts to modify a frozen instance, | |
1133 `attr.exceptions.FrozenInstanceError` is raised. | |
1134 | |
1135 .. note:: | |
1136 | |
1137 1. This is achieved by installing a custom ``__setattr__`` method | |
1138 on your class, so you can't implement your own. | |
1139 | |
1140 2. True immutability is impossible in Python. | |
1141 | |
1142 3. This *does* have a minor a runtime performance `impact | |
1143 <how-frozen>` when initializing new instances. In other words: | |
1144 ``__init__`` is slightly slower with ``frozen=True``. | |
1145 | |
1146 4. If a class is frozen, you cannot modify ``self`` in | |
1147 ``__attrs_post_init__`` or a self-written ``__init__``. You can | |
1148 circumvent that limitation by using | |
1149 ``object.__setattr__(self, "attribute_name", value)``. | |
1150 | |
1151 5. Subclasses of a frozen class are frozen too. | |
1152 | |
1153 :param bool weakref_slot: Make instances weak-referenceable. This has no | |
1154 effect unless ``slots`` is also enabled. | |
1155 :param bool auto_attribs: If ``True``, collect `PEP 526`_-annotated | |
1156 attributes (Python 3.6 and later only) from the class body. | |
1157 | |
1158 In this case, you **must** annotate every field. If ``attrs`` | |
1159 encounters a field that is set to an `attr.ib` but lacks a type | |
1160 annotation, an `attr.exceptions.UnannotatedAttributeError` is | |
1161 raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't | |
1162 want to set a type. | |
1163 | |
1164 If you assign a value to those attributes (e.g. ``x: int = 42``), that | |
1165 value becomes the default value like if it were passed using | |
1166 ``attr.ib(default=42)``. Passing an instance of `Factory` also | |
1167 works as expected. | |
1168 | |
1169 Attributes annotated as `typing.ClassVar`, and attributes that are | |
1170 neither annotated nor set to an `attr.ib` are **ignored**. | |
1171 | |
1172 .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ | |
1173 :param bool kw_only: Make all attributes keyword-only (Python 3+) | |
1174 in the generated ``__init__`` (if ``init`` is ``False``, this | |
1175 parameter is ignored). | |
1176 :param bool cache_hash: Ensure that the object's hash code is computed | |
1177 only once and stored on the object. If this is set to ``True``, | |
1178 hashing must be either explicitly or implicitly enabled for this | |
1179 class. If the hash code is cached, avoid any reassignments of | |
1180 fields involved in hash code computation or mutations of the objects | |
1181 those fields point to after object creation. If such changes occur, | |
1182 the behavior of the object's hash code is undefined. | |
1183 :param bool auto_exc: If the class subclasses `BaseException` | |
1184 (which implicitly includes any subclass of any exception), the | |
1185 following happens to behave like a well-behaved Python exceptions | |
1186 class: | |
1187 | |
1188 - the values for *eq*, *order*, and *hash* are ignored and the | |
1189 instances compare and hash by the instance's ids (N.B. ``attrs`` will | |
1190 *not* remove existing implementations of ``__hash__`` or the equality | |
1191 methods. It just won't add own ones.), | |
1192 - all attributes that are either passed into ``__init__`` or have a | |
1193 default value are additionally available as a tuple in the ``args`` | |
1194 attribute, | |
1195 - the value of *str* is ignored leaving ``__str__`` to base classes. | |
1196 :param bool collect_by_mro: Setting this to `True` fixes the way ``attrs`` | |
1197 collects attributes from base classes. The default behavior is | |
1198 incorrect in certain cases of multiple inheritance. It should be on by | |
1199 default but is kept off for backward-compatability. | |
1200 | |
1201 See issue `#428 <https://github.com/python-attrs/attrs/issues/428>`_ for | |
1202 more details. | |
1203 | |
1204 :param Optional[bool] getstate_setstate: | |
1205 .. note:: | |
1206 This is usually only interesting for slotted classes and you should | |
1207 probably just set *auto_detect* to `True`. | |
1208 | |
1209 If `True`, ``__getstate__`` and | |
1210 ``__setstate__`` are generated and attached to the class. This is | |
1211 necessary for slotted classes to be pickleable. If left `None`, it's | |
1212 `True` by default for slotted classes and ``False`` for dict classes. | |
1213 | |
1214 If *auto_detect* is `True`, and *getstate_setstate* is left `None`, | |
1215 and **either** ``__getstate__`` or ``__setstate__`` is detected directly | |
1216 on the class (i.e. not inherited), it is set to `False` (this is usually | |
1217 what you want). | |
1218 | |
1219 :param on_setattr: A callable that is run whenever the user attempts to set | |
1220 an attribute (either by assignment like ``i.x = 42`` or by using | |
1221 `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments | |
1222 as validators: the instance, the attribute that is being modified, and | |
1223 the new value. | |
1224 | |
1225 If no exception is raised, the attribute is set to the return value of | |
1226 the callable. | |
1227 | |
1228 If a list of callables is passed, they're automatically wrapped in an | |
1229 `attr.setters.pipe`. | |
1230 | |
1231 :param Optional[callable] field_transformer: | |
1232 A function that is called with the original class object and all | |
1233 fields right before ``attrs`` finalizes the class. You can use | |
1234 this, e.g., to automatically add converters or validators to | |
1235 fields based on their types. See `transform-fields` for more details. | |
1236 | |
1237 .. versionadded:: 16.0.0 *slots* | |
1238 .. versionadded:: 16.1.0 *frozen* | |
1239 .. versionadded:: 16.3.0 *str* | |
1240 .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. | |
1241 .. versionchanged:: 17.1.0 | |
1242 *hash* supports ``None`` as value which is also the default now. | |
1243 .. versionadded:: 17.3.0 *auto_attribs* | |
1244 .. versionchanged:: 18.1.0 | |
1245 If *these* is passed, no attributes are deleted from the class body. | |
1246 .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. | |
1247 .. versionadded:: 18.2.0 *weakref_slot* | |
1248 .. deprecated:: 18.2.0 | |
1249 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a | |
1250 `DeprecationWarning` if the classes compared are subclasses of | |
1251 each other. ``__eq`` and ``__ne__`` never tried to compared subclasses | |
1252 to each other. | |
1253 .. versionchanged:: 19.2.0 | |
1254 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider | |
1255 subclasses comparable anymore. | |
1256 .. versionadded:: 18.2.0 *kw_only* | |
1257 .. versionadded:: 18.2.0 *cache_hash* | |
1258 .. versionadded:: 19.1.0 *auto_exc* | |
1259 .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. | |
1260 .. versionadded:: 19.2.0 *eq* and *order* | |
1261 .. versionadded:: 20.1.0 *auto_detect* | |
1262 .. versionadded:: 20.1.0 *collect_by_mro* | |
1263 .. versionadded:: 20.1.0 *getstate_setstate* | |
1264 .. versionadded:: 20.1.0 *on_setattr* | |
1265 .. versionadded:: 20.3.0 *field_transformer* | |
1266 """ | |
1267 if auto_detect and PY2: | |
1268 raise PythonTooOldError( | |
1269 "auto_detect only works on Python 3 and later." | |
1270 ) | |
1271 | |
1272 eq_, order_ = _determine_eq_order(cmp, eq, order, None) | |
1273 hash_ = hash # work around the lack of nonlocal | |
1274 | |
1275 if isinstance(on_setattr, (list, tuple)): | |
1276 on_setattr = setters.pipe(*on_setattr) | |
1277 | |
1278 def wrap(cls): | |
1279 | |
1280 if getattr(cls, "__class__", None) is None: | |
1281 raise TypeError("attrs only works with new-style classes.") | |
1282 | |
1283 is_frozen = frozen or _has_frozen_base_class(cls) | |
1284 is_exc = auto_exc is True and issubclass(cls, BaseException) | |
1285 has_own_setattr = auto_detect and _has_own_attribute( | |
1286 cls, "__setattr__" | |
1287 ) | |
1288 | |
1289 if has_own_setattr and is_frozen: | |
1290 raise ValueError("Can't freeze a class with a custom __setattr__.") | |
1291 | |
1292 builder = _ClassBuilder( | |
1293 cls, | |
1294 these, | |
1295 slots, | |
1296 is_frozen, | |
1297 weakref_slot, | |
1298 _determine_whether_to_implement( | |
1299 cls, | |
1300 getstate_setstate, | |
1301 auto_detect, | |
1302 ("__getstate__", "__setstate__"), | |
1303 default=slots, | |
1304 ), | |
1305 auto_attribs, | |
1306 kw_only, | |
1307 cache_hash, | |
1308 is_exc, | |
1309 collect_by_mro, | |
1310 on_setattr, | |
1311 has_own_setattr, | |
1312 field_transformer, | |
1313 ) | |
1314 if _determine_whether_to_implement( | |
1315 cls, repr, auto_detect, ("__repr__",) | |
1316 ): | |
1317 builder.add_repr(repr_ns) | |
1318 if str is True: | |
1319 builder.add_str() | |
1320 | |
1321 eq = _determine_whether_to_implement( | |
1322 cls, eq_, auto_detect, ("__eq__", "__ne__") | |
1323 ) | |
1324 if not is_exc and eq is True: | |
1325 builder.add_eq() | |
1326 if not is_exc and _determine_whether_to_implement( | |
1327 cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") | |
1328 ): | |
1329 builder.add_order() | |
1330 | |
1331 builder.add_setattr() | |
1332 | |
1333 if ( | |
1334 hash_ is None | |
1335 and auto_detect is True | |
1336 and _has_own_attribute(cls, "__hash__") | |
1337 ): | |
1338 hash = False | |
1339 else: | |
1340 hash = hash_ | |
1341 if hash is not True and hash is not False and hash is not None: | |
1342 # Can't use `hash in` because 1 == True for example. | |
1343 raise TypeError( | |
1344 "Invalid value for hash. Must be True, False, or None." | |
1345 ) | |
1346 elif hash is False or (hash is None and eq is False) or is_exc: | |
1347 # Don't do anything. Should fall back to __object__'s __hash__ | |
1348 # which is by id. | |
1349 if cache_hash: | |
1350 raise TypeError( | |
1351 "Invalid value for cache_hash. To use hash caching," | |
1352 " hashing must be either explicitly or implicitly " | |
1353 "enabled." | |
1354 ) | |
1355 elif hash is True or ( | |
1356 hash is None and eq is True and is_frozen is True | |
1357 ): | |
1358 # Build a __hash__ if told so, or if it's safe. | |
1359 builder.add_hash() | |
1360 else: | |
1361 # Raise TypeError on attempts to hash. | |
1362 if cache_hash: | |
1363 raise TypeError( | |
1364 "Invalid value for cache_hash. To use hash caching," | |
1365 " hashing must be either explicitly or implicitly " | |
1366 "enabled." | |
1367 ) | |
1368 builder.make_unhashable() | |
1369 | |
1370 if _determine_whether_to_implement( | |
1371 cls, init, auto_detect, ("__init__",) | |
1372 ): | |
1373 builder.add_init() | |
1374 else: | |
1375 if cache_hash: | |
1376 raise TypeError( | |
1377 "Invalid value for cache_hash. To use hash caching," | |
1378 " init must be True." | |
1379 ) | |
1380 | |
1381 return builder.build_class() | |
1382 | |
1383 # maybe_cls's type depends on the usage of the decorator. It's a class | |
1384 # if it's used as `@attrs` but ``None`` if used as `@attrs()`. | |
1385 if maybe_cls is None: | |
1386 return wrap | |
1387 else: | |
1388 return wrap(maybe_cls) | |
1389 | |
1390 | |
1391 _attrs = attrs | |
1392 """ | |
1393 Internal alias so we can use it in functions that take an argument called | |
1394 *attrs*. | |
1395 """ | |
1396 | |
1397 | |
1398 if PY2: | |
1399 | |
1400 def _has_frozen_base_class(cls): | |
1401 """ | |
1402 Check whether *cls* has a frozen ancestor by looking at its | |
1403 __setattr__. | |
1404 """ | |
1405 return ( | |
1406 getattr(cls.__setattr__, "__module__", None) | |
1407 == _frozen_setattrs.__module__ | |
1408 and cls.__setattr__.__name__ == _frozen_setattrs.__name__ | |
1409 ) | |
1410 | |
1411 | |
1412 else: | |
1413 | |
1414 def _has_frozen_base_class(cls): | |
1415 """ | |
1416 Check whether *cls* has a frozen ancestor by looking at its | |
1417 __setattr__. | |
1418 """ | |
1419 return cls.__setattr__ == _frozen_setattrs | |
1420 | |
1421 | |
1422 def _attrs_to_tuple(obj, attrs): | |
1423 """ | |
1424 Create a tuple of all values of *obj*'s *attrs*. | |
1425 """ | |
1426 return tuple(getattr(obj, a.name) for a in attrs) | |
1427 | |
1428 | |
1429 def _generate_unique_filename(cls, func_name): | |
1430 """ | |
1431 Create a "filename" suitable for a function being generated. | |
1432 """ | |
1433 unique_id = uuid.uuid4() | |
1434 extra = "" | |
1435 count = 1 | |
1436 | |
1437 while True: | |
1438 unique_filename = "<attrs generated {0} {1}.{2}{3}>".format( | |
1439 func_name, | |
1440 cls.__module__, | |
1441 getattr(cls, "__qualname__", cls.__name__), | |
1442 extra, | |
1443 ) | |
1444 # To handle concurrency we essentially "reserve" our spot in | |
1445 # the linecache with a dummy line. The caller can then | |
1446 # set this value correctly. | |
1447 cache_line = (1, None, (str(unique_id),), unique_filename) | |
1448 if ( | |
1449 linecache.cache.setdefault(unique_filename, cache_line) | |
1450 == cache_line | |
1451 ): | |
1452 return unique_filename | |
1453 | |
1454 # Looks like this spot is taken. Try again. | |
1455 count += 1 | |
1456 extra = "-{0}".format(count) | |
1457 | |
1458 | |
1459 def _make_hash(cls, attrs, frozen, cache_hash): | |
1460 attrs = tuple( | |
1461 a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) | |
1462 ) | |
1463 | |
1464 tab = " " | |
1465 | |
1466 unique_filename = _generate_unique_filename(cls, "hash") | |
1467 type_hash = hash(unique_filename) | |
1468 | |
1469 hash_def = "def __hash__(self" | |
1470 hash_func = "hash((" | |
1471 closing_braces = "))" | |
1472 if not cache_hash: | |
1473 hash_def += "):" | |
1474 else: | |
1475 if not PY2: | |
1476 hash_def += ", *" | |
1477 | |
1478 hash_def += ( | |
1479 ", _cache_wrapper=" | |
1480 + "__import__('attr._make')._make._CacheHashWrapper):" | |
1481 ) | |
1482 hash_func = "_cache_wrapper(" + hash_func | |
1483 closing_braces += ")" | |
1484 | |
1485 method_lines = [hash_def] | |
1486 | |
1487 def append_hash_computation_lines(prefix, indent): | |
1488 """ | |
1489 Generate the code for actually computing the hash code. | |
1490 Below this will either be returned directly or used to compute | |
1491 a value which is then cached, depending on the value of cache_hash | |
1492 """ | |
1493 | |
1494 method_lines.extend( | |
1495 [ | |
1496 indent + prefix + hash_func, | |
1497 indent + " %d," % (type_hash,), | |
1498 ] | |
1499 ) | |
1500 | |
1501 for a in attrs: | |
1502 method_lines.append(indent + " self.%s," % a.name) | |
1503 | |
1504 method_lines.append(indent + " " + closing_braces) | |
1505 | |
1506 if cache_hash: | |
1507 method_lines.append(tab + "if self.%s is None:" % _hash_cache_field) | |
1508 if frozen: | |
1509 append_hash_computation_lines( | |
1510 "object.__setattr__(self, '%s', " % _hash_cache_field, tab * 2 | |
1511 ) | |
1512 method_lines.append(tab * 2 + ")") # close __setattr__ | |
1513 else: | |
1514 append_hash_computation_lines( | |
1515 "self.%s = " % _hash_cache_field, tab * 2 | |
1516 ) | |
1517 method_lines.append(tab + "return self.%s" % _hash_cache_field) | |
1518 else: | |
1519 append_hash_computation_lines("return ", tab) | |
1520 | |
1521 script = "\n".join(method_lines) | |
1522 globs = {} | |
1523 locs = {} | |
1524 bytecode = compile(script, unique_filename, "exec") | |
1525 eval(bytecode, globs, locs) | |
1526 | |
1527 # In order of debuggers like PDB being able to step through the code, | |
1528 # we add a fake linecache entry. | |
1529 linecache.cache[unique_filename] = ( | |
1530 len(script), | |
1531 None, | |
1532 script.splitlines(True), | |
1533 unique_filename, | |
1534 ) | |
1535 | |
1536 return locs["__hash__"] | |
1537 | |
1538 | |
1539 def _add_hash(cls, attrs): | |
1540 """ | |
1541 Add a hash method to *cls*. | |
1542 """ | |
1543 cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False) | |
1544 return cls | |
1545 | |
1546 | |
1547 def _make_ne(): | |
1548 """ | |
1549 Create __ne__ method. | |
1550 """ | |
1551 | |
1552 def __ne__(self, other): | |
1553 """ | |
1554 Check equality and either forward a NotImplemented or | |
1555 return the result negated. | |
1556 """ | |
1557 result = self.__eq__(other) | |
1558 if result is NotImplemented: | |
1559 return NotImplemented | |
1560 | |
1561 return not result | |
1562 | |
1563 return __ne__ | |
1564 | |
1565 | |
1566 def _make_eq(cls, attrs): | |
1567 """ | |
1568 Create __eq__ method for *cls* with *attrs*. | |
1569 """ | |
1570 attrs = [a for a in attrs if a.eq] | |
1571 | |
1572 unique_filename = _generate_unique_filename(cls, "eq") | |
1573 lines = [ | |
1574 "def __eq__(self, other):", | |
1575 " if other.__class__ is not self.__class__:", | |
1576 " return NotImplemented", | |
1577 ] | |
1578 # We can't just do a big self.x = other.x and... clause due to | |
1579 # irregularities like nan == nan is false but (nan,) == (nan,) is true. | |
1580 if attrs: | |
1581 lines.append(" return (") | |
1582 others = [" ) == ("] | |
1583 for a in attrs: | |
1584 lines.append(" self.%s," % (a.name,)) | |
1585 others.append(" other.%s," % (a.name,)) | |
1586 | |
1587 lines += others + [" )"] | |
1588 else: | |
1589 lines.append(" return True") | |
1590 | |
1591 script = "\n".join(lines) | |
1592 globs = {} | |
1593 locs = {} | |
1594 bytecode = compile(script, unique_filename, "exec") | |
1595 eval(bytecode, globs, locs) | |
1596 | |
1597 # In order of debuggers like PDB being able to step through the code, | |
1598 # we add a fake linecache entry. | |
1599 linecache.cache[unique_filename] = ( | |
1600 len(script), | |
1601 None, | |
1602 script.splitlines(True), | |
1603 unique_filename, | |
1604 ) | |
1605 return locs["__eq__"] | |
1606 | |
1607 | |
1608 def _make_order(cls, attrs): | |
1609 """ | |
1610 Create ordering methods for *cls* with *attrs*. | |
1611 """ | |
1612 attrs = [a for a in attrs if a.order] | |
1613 | |
1614 def attrs_to_tuple(obj): | |
1615 """ | |
1616 Save us some typing. | |
1617 """ | |
1618 return _attrs_to_tuple(obj, attrs) | |
1619 | |
1620 def __lt__(self, other): | |
1621 """ | |
1622 Automatically created by attrs. | |
1623 """ | |
1624 if other.__class__ is self.__class__: | |
1625 return attrs_to_tuple(self) < attrs_to_tuple(other) | |
1626 | |
1627 return NotImplemented | |
1628 | |
1629 def __le__(self, other): | |
1630 """ | |
1631 Automatically created by attrs. | |
1632 """ | |
1633 if other.__class__ is self.__class__: | |
1634 return attrs_to_tuple(self) <= attrs_to_tuple(other) | |
1635 | |
1636 return NotImplemented | |
1637 | |
1638 def __gt__(self, other): | |
1639 """ | |
1640 Automatically created by attrs. | |
1641 """ | |
1642 if other.__class__ is self.__class__: | |
1643 return attrs_to_tuple(self) > attrs_to_tuple(other) | |
1644 | |
1645 return NotImplemented | |
1646 | |
1647 def __ge__(self, other): | |
1648 """ | |
1649 Automatically created by attrs. | |
1650 """ | |
1651 if other.__class__ is self.__class__: | |
1652 return attrs_to_tuple(self) >= attrs_to_tuple(other) | |
1653 | |
1654 return NotImplemented | |
1655 | |
1656 return __lt__, __le__, __gt__, __ge__ | |
1657 | |
1658 | |
1659 def _add_eq(cls, attrs=None): | |
1660 """ | |
1661 Add equality methods to *cls* with *attrs*. | |
1662 """ | |
1663 if attrs is None: | |
1664 attrs = cls.__attrs_attrs__ | |
1665 | |
1666 cls.__eq__ = _make_eq(cls, attrs) | |
1667 cls.__ne__ = _make_ne() | |
1668 | |
1669 return cls | |
1670 | |
1671 | |
1672 _already_repring = threading.local() | |
1673 | |
1674 | |
1675 def _make_repr(attrs, ns): | |
1676 """ | |
1677 Make a repr method that includes relevant *attrs*, adding *ns* to the full | |
1678 name. | |
1679 """ | |
1680 | |
1681 # Figure out which attributes to include, and which function to use to | |
1682 # format them. The a.repr value can be either bool or a custom callable. | |
1683 attr_names_with_reprs = tuple( | |
1684 (a.name, repr if a.repr is True else a.repr) | |
1685 for a in attrs | |
1686 if a.repr is not False | |
1687 ) | |
1688 | |
1689 def __repr__(self): | |
1690 """ | |
1691 Automatically created by attrs. | |
1692 """ | |
1693 try: | |
1694 working_set = _already_repring.working_set | |
1695 except AttributeError: | |
1696 working_set = set() | |
1697 _already_repring.working_set = working_set | |
1698 | |
1699 if id(self) in working_set: | |
1700 return "..." | |
1701 real_cls = self.__class__ | |
1702 if ns is None: | |
1703 qualname = getattr(real_cls, "__qualname__", None) | |
1704 if qualname is not None: | |
1705 class_name = qualname.rsplit(">.", 1)[-1] | |
1706 else: | |
1707 class_name = real_cls.__name__ | |
1708 else: | |
1709 class_name = ns + "." + real_cls.__name__ | |
1710 | |
1711 # Since 'self' remains on the stack (i.e.: strongly referenced) for the | |
1712 # duration of this call, it's safe to depend on id(...) stability, and | |
1713 # not need to track the instance and therefore worry about properties | |
1714 # like weakref- or hash-ability. | |
1715 working_set.add(id(self)) | |
1716 try: | |
1717 result = [class_name, "("] | |
1718 first = True | |
1719 for name, attr_repr in attr_names_with_reprs: | |
1720 if first: | |
1721 first = False | |
1722 else: | |
1723 result.append(", ") | |
1724 result.extend( | |
1725 (name, "=", attr_repr(getattr(self, name, NOTHING))) | |
1726 ) | |
1727 return "".join(result) + ")" | |
1728 finally: | |
1729 working_set.remove(id(self)) | |
1730 | |
1731 return __repr__ | |
1732 | |
1733 | |
1734 def _add_repr(cls, ns=None, attrs=None): | |
1735 """ | |
1736 Add a repr method to *cls*. | |
1737 """ | |
1738 if attrs is None: | |
1739 attrs = cls.__attrs_attrs__ | |
1740 | |
1741 cls.__repr__ = _make_repr(attrs, ns) | |
1742 return cls | |
1743 | |
1744 | |
1745 def fields(cls): | |
1746 """ | |
1747 Return the tuple of ``attrs`` attributes for a class. | |
1748 | |
1749 The tuple also allows accessing the fields by their names (see below for | |
1750 examples). | |
1751 | |
1752 :param type cls: Class to introspect. | |
1753 | |
1754 :raise TypeError: If *cls* is not a class. | |
1755 :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` | |
1756 class. | |
1757 | |
1758 :rtype: tuple (with name accessors) of `attr.Attribute` | |
1759 | |
1760 .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields | |
1761 by name. | |
1762 """ | |
1763 if not isclass(cls): | |
1764 raise TypeError("Passed object must be a class.") | |
1765 attrs = getattr(cls, "__attrs_attrs__", None) | |
1766 if attrs is None: | |
1767 raise NotAnAttrsClassError( | |
1768 "{cls!r} is not an attrs-decorated class.".format(cls=cls) | |
1769 ) | |
1770 return attrs | |
1771 | |
1772 | |
1773 def fields_dict(cls): | |
1774 """ | |
1775 Return an ordered dictionary of ``attrs`` attributes for a class, whose | |
1776 keys are the attribute names. | |
1777 | |
1778 :param type cls: Class to introspect. | |
1779 | |
1780 :raise TypeError: If *cls* is not a class. | |
1781 :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` | |
1782 class. | |
1783 | |
1784 :rtype: an ordered dict where keys are attribute names and values are | |
1785 `attr.Attribute`\\ s. This will be a `dict` if it's | |
1786 naturally ordered like on Python 3.6+ or an | |
1787 :class:`~collections.OrderedDict` otherwise. | |
1788 | |
1789 .. versionadded:: 18.1.0 | |
1790 """ | |
1791 if not isclass(cls): | |
1792 raise TypeError("Passed object must be a class.") | |
1793 attrs = getattr(cls, "__attrs_attrs__", None) | |
1794 if attrs is None: | |
1795 raise NotAnAttrsClassError( | |
1796 "{cls!r} is not an attrs-decorated class.".format(cls=cls) | |
1797 ) | |
1798 return ordered_dict(((a.name, a) for a in attrs)) | |
1799 | |
1800 | |
1801 def validate(inst): | |
1802 """ | |
1803 Validate all attributes on *inst* that have a validator. | |
1804 | |
1805 Leaves all exceptions through. | |
1806 | |
1807 :param inst: Instance of a class with ``attrs`` attributes. | |
1808 """ | |
1809 if _config._run_validators is False: | |
1810 return | |
1811 | |
1812 for a in fields(inst.__class__): | |
1813 v = a.validator | |
1814 if v is not None: | |
1815 v(inst, a, getattr(inst, a.name)) | |
1816 | |
1817 | |
1818 def _is_slot_cls(cls): | |
1819 return "__slots__" in cls.__dict__ | |
1820 | |
1821 | |
1822 def _is_slot_attr(a_name, base_attr_map): | |
1823 """ | |
1824 Check if the attribute name comes from a slot class. | |
1825 """ | |
1826 return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) | |
1827 | |
1828 | |
1829 def _make_init( | |
1830 cls, | |
1831 attrs, | |
1832 post_init, | |
1833 frozen, | |
1834 slots, | |
1835 cache_hash, | |
1836 base_attr_map, | |
1837 is_exc, | |
1838 has_global_on_setattr, | |
1839 ): | |
1840 if frozen and has_global_on_setattr: | |
1841 raise ValueError("Frozen classes can't use on_setattr.") | |
1842 | |
1843 needs_cached_setattr = cache_hash or frozen | |
1844 filtered_attrs = [] | |
1845 attr_dict = {} | |
1846 for a in attrs: | |
1847 if not a.init and a.default is NOTHING: | |
1848 continue | |
1849 | |
1850 filtered_attrs.append(a) | |
1851 attr_dict[a.name] = a | |
1852 | |
1853 if a.on_setattr is not None: | |
1854 if frozen is True: | |
1855 raise ValueError("Frozen classes can't use on_setattr.") | |
1856 | |
1857 needs_cached_setattr = True | |
1858 elif ( | |
1859 has_global_on_setattr and a.on_setattr is not setters.NO_OP | |
1860 ) or _is_slot_attr(a.name, base_attr_map): | |
1861 needs_cached_setattr = True | |
1862 | |
1863 unique_filename = _generate_unique_filename(cls, "init") | |
1864 | |
1865 script, globs, annotations = _attrs_to_init_script( | |
1866 filtered_attrs, | |
1867 frozen, | |
1868 slots, | |
1869 post_init, | |
1870 cache_hash, | |
1871 base_attr_map, | |
1872 is_exc, | |
1873 needs_cached_setattr, | |
1874 has_global_on_setattr, | |
1875 ) | |
1876 locs = {} | |
1877 bytecode = compile(script, unique_filename, "exec") | |
1878 globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) | |
1879 | |
1880 if needs_cached_setattr: | |
1881 # Save the lookup overhead in __init__ if we need to circumvent | |
1882 # setattr hooks. | |
1883 globs["_cached_setattr"] = _obj_setattr | |
1884 | |
1885 eval(bytecode, globs, locs) | |
1886 | |
1887 # In order of debuggers like PDB being able to step through the code, | |
1888 # we add a fake linecache entry. | |
1889 linecache.cache[unique_filename] = ( | |
1890 len(script), | |
1891 None, | |
1892 script.splitlines(True), | |
1893 unique_filename, | |
1894 ) | |
1895 | |
1896 __init__ = locs["__init__"] | |
1897 __init__.__annotations__ = annotations | |
1898 | |
1899 return __init__ | |
1900 | |
1901 | |
1902 def _setattr(attr_name, value_var, has_on_setattr): | |
1903 """ | |
1904 Use the cached object.setattr to set *attr_name* to *value_var*. | |
1905 """ | |
1906 return "_setattr('%s', %s)" % (attr_name, value_var) | |
1907 | |
1908 | |
1909 def _setattr_with_converter(attr_name, value_var, has_on_setattr): | |
1910 """ | |
1911 Use the cached object.setattr to set *attr_name* to *value_var*, but run | |
1912 its converter first. | |
1913 """ | |
1914 return "_setattr('%s', %s(%s))" % ( | |
1915 attr_name, | |
1916 _init_converter_pat % (attr_name,), | |
1917 value_var, | |
1918 ) | |
1919 | |
1920 | |
1921 def _assign(attr_name, value, has_on_setattr): | |
1922 """ | |
1923 Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise | |
1924 relegate to _setattr. | |
1925 """ | |
1926 if has_on_setattr: | |
1927 return _setattr(attr_name, value, True) | |
1928 | |
1929 return "self.%s = %s" % (attr_name, value) | |
1930 | |
1931 | |
1932 def _assign_with_converter(attr_name, value_var, has_on_setattr): | |
1933 """ | |
1934 Unless *attr_name* has an on_setattr hook, use normal assignment after | |
1935 conversion. Otherwise relegate to _setattr_with_converter. | |
1936 """ | |
1937 if has_on_setattr: | |
1938 return _setattr_with_converter(attr_name, value_var, True) | |
1939 | |
1940 return "self.%s = %s(%s)" % ( | |
1941 attr_name, | |
1942 _init_converter_pat % (attr_name,), | |
1943 value_var, | |
1944 ) | |
1945 | |
1946 | |
1947 if PY2: | |
1948 | |
1949 def _unpack_kw_only_py2(attr_name, default=None): | |
1950 """ | |
1951 Unpack *attr_name* from _kw_only dict. | |
1952 """ | |
1953 if default is not None: | |
1954 arg_default = ", %s" % default | |
1955 else: | |
1956 arg_default = "" | |
1957 return "%s = _kw_only.pop('%s'%s)" % ( | |
1958 attr_name, | |
1959 attr_name, | |
1960 arg_default, | |
1961 ) | |
1962 | |
1963 def _unpack_kw_only_lines_py2(kw_only_args): | |
1964 """ | |
1965 Unpack all *kw_only_args* from _kw_only dict and handle errors. | |
1966 | |
1967 Given a list of strings "{attr_name}" and "{attr_name}={default}" | |
1968 generates list of lines of code that pop attrs from _kw_only dict and | |
1969 raise TypeError similar to builtin if required attr is missing or | |
1970 extra key is passed. | |
1971 | |
1972 >>> print("\n".join(_unpack_kw_only_lines_py2(["a", "b=42"]))) | |
1973 try: | |
1974 a = _kw_only.pop('a') | |
1975 b = _kw_only.pop('b', 42) | |
1976 except KeyError as _key_error: | |
1977 raise TypeError( | |
1978 ... | |
1979 if _kw_only: | |
1980 raise TypeError( | |
1981 ... | |
1982 """ | |
1983 lines = ["try:"] | |
1984 lines.extend( | |
1985 " " + _unpack_kw_only_py2(*arg.split("=")) | |
1986 for arg in kw_only_args | |
1987 ) | |
1988 lines += """\ | |
1989 except KeyError as _key_error: | |
1990 raise TypeError( | |
1991 '__init__() missing required keyword-only argument: %s' % _key_error | |
1992 ) | |
1993 if _kw_only: | |
1994 raise TypeError( | |
1995 '__init__() got an unexpected keyword argument %r' | |
1996 % next(iter(_kw_only)) | |
1997 ) | |
1998 """.split( | |
1999 "\n" | |
2000 ) | |
2001 return lines | |
2002 | |
2003 | |
2004 def _attrs_to_init_script( | |
2005 attrs, | |
2006 frozen, | |
2007 slots, | |
2008 post_init, | |
2009 cache_hash, | |
2010 base_attr_map, | |
2011 is_exc, | |
2012 needs_cached_setattr, | |
2013 has_global_on_setattr, | |
2014 ): | |
2015 """ | |
2016 Return a script of an initializer for *attrs* and a dict of globals. | |
2017 | |
2018 The globals are expected by the generated script. | |
2019 | |
2020 If *frozen* is True, we cannot set the attributes directly so we use | |
2021 a cached ``object.__setattr__``. | |
2022 """ | |
2023 lines = [] | |
2024 if needs_cached_setattr: | |
2025 lines.append( | |
2026 # Circumvent the __setattr__ descriptor to save one lookup per | |
2027 # assignment. | |
2028 # Note _setattr will be used again below if cache_hash is True | |
2029 "_setattr = _cached_setattr.__get__(self, self.__class__)" | |
2030 ) | |
2031 | |
2032 if frozen is True: | |
2033 if slots is True: | |
2034 fmt_setter = _setattr | |
2035 fmt_setter_with_converter = _setattr_with_converter | |
2036 else: | |
2037 # Dict frozen classes assign directly to __dict__. | |
2038 # But only if the attribute doesn't come from an ancestor slot | |
2039 # class. | |
2040 # Note _inst_dict will be used again below if cache_hash is True | |
2041 lines.append("_inst_dict = self.__dict__") | |
2042 | |
2043 def fmt_setter(attr_name, value_var, has_on_setattr): | |
2044 if _is_slot_attr(attr_name, base_attr_map): | |
2045 return _setattr(attr_name, value_var, has_on_setattr) | |
2046 | |
2047 return "_inst_dict['%s'] = %s" % (attr_name, value_var) | |
2048 | |
2049 def fmt_setter_with_converter( | |
2050 attr_name, value_var, has_on_setattr | |
2051 ): | |
2052 if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): | |
2053 return _setattr_with_converter( | |
2054 attr_name, value_var, has_on_setattr | |
2055 ) | |
2056 | |
2057 return "_inst_dict['%s'] = %s(%s)" % ( | |
2058 attr_name, | |
2059 _init_converter_pat % (attr_name,), | |
2060 value_var, | |
2061 ) | |
2062 | |
2063 else: | |
2064 # Not frozen. | |
2065 fmt_setter = _assign | |
2066 fmt_setter_with_converter = _assign_with_converter | |
2067 | |
2068 args = [] | |
2069 kw_only_args = [] | |
2070 attrs_to_validate = [] | |
2071 | |
2072 # This is a dictionary of names to validator and converter callables. | |
2073 # Injecting this into __init__ globals lets us avoid lookups. | |
2074 names_for_globals = {} | |
2075 annotations = {"return": None} | |
2076 | |
2077 for a in attrs: | |
2078 if a.validator: | |
2079 attrs_to_validate.append(a) | |
2080 | |
2081 attr_name = a.name | |
2082 has_on_setattr = a.on_setattr is not None or ( | |
2083 a.on_setattr is not setters.NO_OP and has_global_on_setattr | |
2084 ) | |
2085 arg_name = a.name.lstrip("_") | |
2086 | |
2087 has_factory = isinstance(a.default, Factory) | |
2088 if has_factory and a.default.takes_self: | |
2089 maybe_self = "self" | |
2090 else: | |
2091 maybe_self = "" | |
2092 | |
2093 if a.init is False: | |
2094 if has_factory: | |
2095 init_factory_name = _init_factory_pat.format(a.name) | |
2096 if a.converter is not None: | |
2097 lines.append( | |
2098 fmt_setter_with_converter( | |
2099 attr_name, | |
2100 init_factory_name + "(%s)" % (maybe_self,), | |
2101 has_on_setattr, | |
2102 ) | |
2103 ) | |
2104 conv_name = _init_converter_pat % (a.name,) | |
2105 names_for_globals[conv_name] = a.converter | |
2106 else: | |
2107 lines.append( | |
2108 fmt_setter( | |
2109 attr_name, | |
2110 init_factory_name + "(%s)" % (maybe_self,), | |
2111 has_on_setattr, | |
2112 ) | |
2113 ) | |
2114 names_for_globals[init_factory_name] = a.default.factory | |
2115 else: | |
2116 if a.converter is not None: | |
2117 lines.append( | |
2118 fmt_setter_with_converter( | |
2119 attr_name, | |
2120 "attr_dict['%s'].default" % (attr_name,), | |
2121 has_on_setattr, | |
2122 ) | |
2123 ) | |
2124 conv_name = _init_converter_pat % (a.name,) | |
2125 names_for_globals[conv_name] = a.converter | |
2126 else: | |
2127 lines.append( | |
2128 fmt_setter( | |
2129 attr_name, | |
2130 "attr_dict['%s'].default" % (attr_name,), | |
2131 has_on_setattr, | |
2132 ) | |
2133 ) | |
2134 elif a.default is not NOTHING and not has_factory: | |
2135 arg = "%s=attr_dict['%s'].default" % (arg_name, attr_name) | |
2136 if a.kw_only: | |
2137 kw_only_args.append(arg) | |
2138 else: | |
2139 args.append(arg) | |
2140 | |
2141 if a.converter is not None: | |
2142 lines.append( | |
2143 fmt_setter_with_converter( | |
2144 attr_name, arg_name, has_on_setattr | |
2145 ) | |
2146 ) | |
2147 names_for_globals[ | |
2148 _init_converter_pat % (a.name,) | |
2149 ] = a.converter | |
2150 else: | |
2151 lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) | |
2152 | |
2153 elif has_factory: | |
2154 arg = "%s=NOTHING" % (arg_name,) | |
2155 if a.kw_only: | |
2156 kw_only_args.append(arg) | |
2157 else: | |
2158 args.append(arg) | |
2159 lines.append("if %s is not NOTHING:" % (arg_name,)) | |
2160 | |
2161 init_factory_name = _init_factory_pat.format(a.name) | |
2162 if a.converter is not None: | |
2163 lines.append( | |
2164 " " | |
2165 + fmt_setter_with_converter( | |
2166 attr_name, arg_name, has_on_setattr | |
2167 ) | |
2168 ) | |
2169 lines.append("else:") | |
2170 lines.append( | |
2171 " " | |
2172 + fmt_setter_with_converter( | |
2173 attr_name, | |
2174 init_factory_name + "(" + maybe_self + ")", | |
2175 has_on_setattr, | |
2176 ) | |
2177 ) | |
2178 names_for_globals[ | |
2179 _init_converter_pat % (a.name,) | |
2180 ] = a.converter | |
2181 else: | |
2182 lines.append( | |
2183 " " + fmt_setter(attr_name, arg_name, has_on_setattr) | |
2184 ) | |
2185 lines.append("else:") | |
2186 lines.append( | |
2187 " " | |
2188 + fmt_setter( | |
2189 attr_name, | |
2190 init_factory_name + "(" + maybe_self + ")", | |
2191 has_on_setattr, | |
2192 ) | |
2193 ) | |
2194 names_for_globals[init_factory_name] = a.default.factory | |
2195 else: | |
2196 if a.kw_only: | |
2197 kw_only_args.append(arg_name) | |
2198 else: | |
2199 args.append(arg_name) | |
2200 | |
2201 if a.converter is not None: | |
2202 lines.append( | |
2203 fmt_setter_with_converter( | |
2204 attr_name, arg_name, has_on_setattr | |
2205 ) | |
2206 ) | |
2207 names_for_globals[ | |
2208 _init_converter_pat % (a.name,) | |
2209 ] = a.converter | |
2210 else: | |
2211 lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) | |
2212 | |
2213 if a.init is True and a.converter is None and a.type is not None: | |
2214 annotations[arg_name] = a.type | |
2215 | |
2216 if attrs_to_validate: # we can skip this if there are no validators. | |
2217 names_for_globals["_config"] = _config | |
2218 lines.append("if _config._run_validators is True:") | |
2219 for a in attrs_to_validate: | |
2220 val_name = "__attr_validator_" + a.name | |
2221 attr_name = "__attr_" + a.name | |
2222 lines.append( | |
2223 " %s(self, %s, self.%s)" % (val_name, attr_name, a.name) | |
2224 ) | |
2225 names_for_globals[val_name] = a.validator | |
2226 names_for_globals[attr_name] = a | |
2227 | |
2228 if post_init: | |
2229 lines.append("self.__attrs_post_init__()") | |
2230 | |
2231 # because this is set only after __attrs_post_init is called, a crash | |
2232 # will result if post-init tries to access the hash code. This seemed | |
2233 # preferable to setting this beforehand, in which case alteration to | |
2234 # field values during post-init combined with post-init accessing the | |
2235 # hash code would result in silent bugs. | |
2236 if cache_hash: | |
2237 if frozen: | |
2238 if slots: | |
2239 # if frozen and slots, then _setattr defined above | |
2240 init_hash_cache = "_setattr('%s', %s)" | |
2241 else: | |
2242 # if frozen and not slots, then _inst_dict defined above | |
2243 init_hash_cache = "_inst_dict['%s'] = %s" | |
2244 else: | |
2245 init_hash_cache = "self.%s = %s" | |
2246 lines.append(init_hash_cache % (_hash_cache_field, "None")) | |
2247 | |
2248 # For exceptions we rely on BaseException.__init__ for proper | |
2249 # initialization. | |
2250 if is_exc: | |
2251 vals = ",".join("self." + a.name for a in attrs if a.init) | |
2252 | |
2253 lines.append("BaseException.__init__(self, %s)" % (vals,)) | |
2254 | |
2255 args = ", ".join(args) | |
2256 if kw_only_args: | |
2257 if PY2: | |
2258 lines = _unpack_kw_only_lines_py2(kw_only_args) + lines | |
2259 | |
2260 args += "%s**_kw_only" % (", " if args else "",) # leading comma | |
2261 else: | |
2262 args += "%s*, %s" % ( | |
2263 ", " if args else "", # leading comma | |
2264 ", ".join(kw_only_args), # kw_only args | |
2265 ) | |
2266 return ( | |
2267 """\ | |
2268 def __init__(self, {args}): | |
2269 {lines} | |
2270 """.format( | |
2271 args=args, lines="\n ".join(lines) if lines else "pass" | |
2272 ), | |
2273 names_for_globals, | |
2274 annotations, | |
2275 ) | |
2276 | |
2277 | |
2278 class Attribute(object): | |
2279 """ | |
2280 *Read-only* representation of an attribute. | |
2281 | |
2282 Instances of this class are frequently used for introspection purposes | |
2283 like: | |
2284 | |
2285 - `fields` returns a tuple of them. | |
2286 - Validators get them passed as the first argument. | |
2287 - The *field transformer* hook receives a list of them. | |
2288 | |
2289 :attribute name: The name of the attribute. | |
2290 :attribute inherited: Whether or not that attribute has been inherited from | |
2291 a base class. | |
2292 | |
2293 Plus *all* arguments of `attr.ib` (except for ``factory`` | |
2294 which is only syntactic sugar for ``default=Factory(...)``. | |
2295 | |
2296 .. versionadded:: 20.1.0 *inherited* | |
2297 .. versionadded:: 20.1.0 *on_setattr* | |
2298 .. versionchanged:: 20.2.0 *inherited* is not taken into account for | |
2299 equality checks and hashing anymore. | |
2300 | |
2301 For the full version history of the fields, see `attr.ib`. | |
2302 """ | |
2303 | |
2304 __slots__ = ( | |
2305 "name", | |
2306 "default", | |
2307 "validator", | |
2308 "repr", | |
2309 "eq", | |
2310 "order", | |
2311 "hash", | |
2312 "init", | |
2313 "metadata", | |
2314 "type", | |
2315 "converter", | |
2316 "kw_only", | |
2317 "inherited", | |
2318 "on_setattr", | |
2319 ) | |
2320 | |
2321 def __init__( | |
2322 self, | |
2323 name, | |
2324 default, | |
2325 validator, | |
2326 repr, | |
2327 cmp, # XXX: unused, remove along with other cmp code. | |
2328 hash, | |
2329 init, | |
2330 inherited, | |
2331 metadata=None, | |
2332 type=None, | |
2333 converter=None, | |
2334 kw_only=False, | |
2335 eq=None, | |
2336 order=None, | |
2337 on_setattr=None, | |
2338 ): | |
2339 eq, order = _determine_eq_order(cmp, eq, order, True) | |
2340 | |
2341 # Cache this descriptor here to speed things up later. | |
2342 bound_setattr = _obj_setattr.__get__(self, Attribute) | |
2343 | |
2344 # Despite the big red warning, people *do* instantiate `Attribute` | |
2345 # themselves. | |
2346 bound_setattr("name", name) | |
2347 bound_setattr("default", default) | |
2348 bound_setattr("validator", validator) | |
2349 bound_setattr("repr", repr) | |
2350 bound_setattr("eq", eq) | |
2351 bound_setattr("order", order) | |
2352 bound_setattr("hash", hash) | |
2353 bound_setattr("init", init) | |
2354 bound_setattr("converter", converter) | |
2355 bound_setattr( | |
2356 "metadata", | |
2357 ( | |
2358 metadata_proxy(metadata) | |
2359 if metadata | |
2360 else _empty_metadata_singleton | |
2361 ), | |
2362 ) | |
2363 bound_setattr("type", type) | |
2364 bound_setattr("kw_only", kw_only) | |
2365 bound_setattr("inherited", inherited) | |
2366 bound_setattr("on_setattr", on_setattr) | |
2367 | |
2368 def __setattr__(self, name, value): | |
2369 raise FrozenInstanceError() | |
2370 | |
2371 @classmethod | |
2372 def from_counting_attr(cls, name, ca, type=None): | |
2373 # type holds the annotated value. deal with conflicts: | |
2374 if type is None: | |
2375 type = ca.type | |
2376 elif ca.type is not None: | |
2377 raise ValueError( | |
2378 "Type annotation and type argument cannot both be present" | |
2379 ) | |
2380 inst_dict = { | |
2381 k: getattr(ca, k) | |
2382 for k in Attribute.__slots__ | |
2383 if k | |
2384 not in ( | |
2385 "name", | |
2386 "validator", | |
2387 "default", | |
2388 "type", | |
2389 "inherited", | |
2390 ) # exclude methods and deprecated alias | |
2391 } | |
2392 return cls( | |
2393 name=name, | |
2394 validator=ca._validator, | |
2395 default=ca._default, | |
2396 type=type, | |
2397 cmp=None, | |
2398 inherited=False, | |
2399 **inst_dict | |
2400 ) | |
2401 | |
2402 @property | |
2403 def cmp(self): | |
2404 """ | |
2405 Simulate the presence of a cmp attribute and warn. | |
2406 """ | |
2407 warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=2) | |
2408 | |
2409 return self.eq and self.order | |
2410 | |
2411 # Don't use attr.evolve since fields(Attribute) doesn't work | |
2412 def evolve(self, **changes): | |
2413 """ | |
2414 Copy *self* and apply *changes*. | |
2415 | |
2416 This works similarly to `attr.evolve` but that function does not work | |
2417 with ``Attribute``. | |
2418 | |
2419 It is mainly meant to be used for `transform-fields`. | |
2420 | |
2421 .. versionadded:: 20.3.0 | |
2422 """ | |
2423 new = copy.copy(self) | |
2424 | |
2425 new._setattrs(changes.items()) | |
2426 | |
2427 return new | |
2428 | |
2429 # Don't use _add_pickle since fields(Attribute) doesn't work | |
2430 def __getstate__(self): | |
2431 """ | |
2432 Play nice with pickle. | |
2433 """ | |
2434 return tuple( | |
2435 getattr(self, name) if name != "metadata" else dict(self.metadata) | |
2436 for name in self.__slots__ | |
2437 ) | |
2438 | |
2439 def __setstate__(self, state): | |
2440 """ | |
2441 Play nice with pickle. | |
2442 """ | |
2443 self._setattrs(zip(self.__slots__, state)) | |
2444 | |
2445 def _setattrs(self, name_values_pairs): | |
2446 bound_setattr = _obj_setattr.__get__(self, Attribute) | |
2447 for name, value in name_values_pairs: | |
2448 if name != "metadata": | |
2449 bound_setattr(name, value) | |
2450 else: | |
2451 bound_setattr( | |
2452 name, | |
2453 metadata_proxy(value) | |
2454 if value | |
2455 else _empty_metadata_singleton, | |
2456 ) | |
2457 | |
2458 | |
2459 _a = [ | |
2460 Attribute( | |
2461 name=name, | |
2462 default=NOTHING, | |
2463 validator=None, | |
2464 repr=True, | |
2465 cmp=None, | |
2466 eq=True, | |
2467 order=False, | |
2468 hash=(name != "metadata"), | |
2469 init=True, | |
2470 inherited=False, | |
2471 ) | |
2472 for name in Attribute.__slots__ | |
2473 ] | |
2474 | |
2475 Attribute = _add_hash( | |
2476 _add_eq( | |
2477 _add_repr(Attribute, attrs=_a), | |
2478 attrs=[a for a in _a if a.name != "inherited"], | |
2479 ), | |
2480 attrs=[a for a in _a if a.hash and a.name != "inherited"], | |
2481 ) | |
2482 | |
2483 | |
2484 class _CountingAttr(object): | |
2485 """ | |
2486 Intermediate representation of attributes that uses a counter to preserve | |
2487 the order in which the attributes have been defined. | |
2488 | |
2489 *Internal* data structure of the attrs library. Running into is most | |
2490 likely the result of a bug like a forgotten `@attr.s` decorator. | |
2491 """ | |
2492 | |
2493 __slots__ = ( | |
2494 "counter", | |
2495 "_default", | |
2496 "repr", | |
2497 "eq", | |
2498 "order", | |
2499 "hash", | |
2500 "init", | |
2501 "metadata", | |
2502 "_validator", | |
2503 "converter", | |
2504 "type", | |
2505 "kw_only", | |
2506 "on_setattr", | |
2507 ) | |
2508 __attrs_attrs__ = tuple( | |
2509 Attribute( | |
2510 name=name, | |
2511 default=NOTHING, | |
2512 validator=None, | |
2513 repr=True, | |
2514 cmp=None, | |
2515 hash=True, | |
2516 init=True, | |
2517 kw_only=False, | |
2518 eq=True, | |
2519 order=False, | |
2520 inherited=False, | |
2521 on_setattr=None, | |
2522 ) | |
2523 for name in ( | |
2524 "counter", | |
2525 "_default", | |
2526 "repr", | |
2527 "eq", | |
2528 "order", | |
2529 "hash", | |
2530 "init", | |
2531 "on_setattr", | |
2532 ) | |
2533 ) + ( | |
2534 Attribute( | |
2535 name="metadata", | |
2536 default=None, | |
2537 validator=None, | |
2538 repr=True, | |
2539 cmp=None, | |
2540 hash=False, | |
2541 init=True, | |
2542 kw_only=False, | |
2543 eq=True, | |
2544 order=False, | |
2545 inherited=False, | |
2546 on_setattr=None, | |
2547 ), | |
2548 ) | |
2549 cls_counter = 0 | |
2550 | |
2551 def __init__( | |
2552 self, | |
2553 default, | |
2554 validator, | |
2555 repr, | |
2556 cmp, # XXX: unused, remove along with cmp | |
2557 hash, | |
2558 init, | |
2559 converter, | |
2560 metadata, | |
2561 type, | |
2562 kw_only, | |
2563 eq, | |
2564 order, | |
2565 on_setattr, | |
2566 ): | |
2567 _CountingAttr.cls_counter += 1 | |
2568 self.counter = _CountingAttr.cls_counter | |
2569 self._default = default | |
2570 self._validator = validator | |
2571 self.converter = converter | |
2572 self.repr = repr | |
2573 self.eq = eq | |
2574 self.order = order | |
2575 self.hash = hash | |
2576 self.init = init | |
2577 self.metadata = metadata | |
2578 self.type = type | |
2579 self.kw_only = kw_only | |
2580 self.on_setattr = on_setattr | |
2581 | |
2582 def validator(self, meth): | |
2583 """ | |
2584 Decorator that adds *meth* to the list of validators. | |
2585 | |
2586 Returns *meth* unchanged. | |
2587 | |
2588 .. versionadded:: 17.1.0 | |
2589 """ | |
2590 if self._validator is None: | |
2591 self._validator = meth | |
2592 else: | |
2593 self._validator = and_(self._validator, meth) | |
2594 return meth | |
2595 | |
2596 def default(self, meth): | |
2597 """ | |
2598 Decorator that allows to set the default for an attribute. | |
2599 | |
2600 Returns *meth* unchanged. | |
2601 | |
2602 :raises DefaultAlreadySetError: If default has been set before. | |
2603 | |
2604 .. versionadded:: 17.1.0 | |
2605 """ | |
2606 if self._default is not NOTHING: | |
2607 raise DefaultAlreadySetError() | |
2608 | |
2609 self._default = Factory(meth, takes_self=True) | |
2610 | |
2611 return meth | |
2612 | |
2613 | |
2614 _CountingAttr = _add_eq(_add_repr(_CountingAttr)) | |
2615 | |
2616 | |
2617 @attrs(slots=True, init=False, hash=True) | |
2618 class Factory(object): | |
2619 """ | |
2620 Stores a factory callable. | |
2621 | |
2622 If passed as the default value to `attr.ib`, the factory is used to | |
2623 generate a new value. | |
2624 | |
2625 :param callable factory: A callable that takes either none or exactly one | |
2626 mandatory positional argument depending on *takes_self*. | |
2627 :param bool takes_self: Pass the partially initialized instance that is | |
2628 being initialized as a positional argument. | |
2629 | |
2630 .. versionadded:: 17.1.0 *takes_self* | |
2631 """ | |
2632 | |
2633 factory = attrib() | |
2634 takes_self = attrib() | |
2635 | |
2636 def __init__(self, factory, takes_self=False): | |
2637 """ | |
2638 `Factory` is part of the default machinery so if we want a default | |
2639 value here, we have to implement it ourselves. | |
2640 """ | |
2641 self.factory = factory | |
2642 self.takes_self = takes_self | |
2643 | |
2644 | |
2645 def make_class(name, attrs, bases=(object,), **attributes_arguments): | |
2646 """ | |
2647 A quick way to create a new class called *name* with *attrs*. | |
2648 | |
2649 :param str name: The name for the new class. | |
2650 | |
2651 :param attrs: A list of names or a dictionary of mappings of names to | |
2652 attributes. | |
2653 | |
2654 If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, | |
2655 `collections.OrderedDict` otherwise), the order is deduced from | |
2656 the order of the names or attributes inside *attrs*. Otherwise the | |
2657 order of the definition of the attributes is used. | |
2658 :type attrs: `list` or `dict` | |
2659 | |
2660 :param tuple bases: Classes that the new class will subclass. | |
2661 | |
2662 :param attributes_arguments: Passed unmodified to `attr.s`. | |
2663 | |
2664 :return: A new class with *attrs*. | |
2665 :rtype: type | |
2666 | |
2667 .. versionadded:: 17.1.0 *bases* | |
2668 .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. | |
2669 """ | |
2670 if isinstance(attrs, dict): | |
2671 cls_dict = attrs | |
2672 elif isinstance(attrs, (list, tuple)): | |
2673 cls_dict = dict((a, attrib()) for a in attrs) | |
2674 else: | |
2675 raise TypeError("attrs argument must be a dict or a list.") | |
2676 | |
2677 post_init = cls_dict.pop("__attrs_post_init__", None) | |
2678 type_ = type( | |
2679 name, | |
2680 bases, | |
2681 {} if post_init is None else {"__attrs_post_init__": post_init}, | |
2682 ) | |
2683 # For pickling to work, the __module__ variable needs to be set to the | |
2684 # frame where the class is created. Bypass this step in environments where | |
2685 # sys._getframe is not defined (Jython for example) or sys._getframe is not | |
2686 # defined for arguments greater than 0 (IronPython). | |
2687 try: | |
2688 type_.__module__ = sys._getframe(1).f_globals.get( | |
2689 "__name__", "__main__" | |
2690 ) | |
2691 except (AttributeError, ValueError): | |
2692 pass | |
2693 | |
2694 # We do it here for proper warnings with meaningful stacklevel. | |
2695 cmp = attributes_arguments.pop("cmp", None) | |
2696 ( | |
2697 attributes_arguments["eq"], | |
2698 attributes_arguments["order"], | |
2699 ) = _determine_eq_order( | |
2700 cmp, | |
2701 attributes_arguments.get("eq"), | |
2702 attributes_arguments.get("order"), | |
2703 True, | |
2704 ) | |
2705 | |
2706 return _attrs(these=cls_dict, **attributes_arguments)(type_) | |
2707 | |
2708 | |
2709 # These are required by within this module so we define them here and merely | |
2710 # import into .validators / .converters. | |
2711 | |
2712 | |
2713 @attrs(slots=True, hash=True) | |
2714 class _AndValidator(object): | |
2715 """ | |
2716 Compose many validators to a single one. | |
2717 """ | |
2718 | |
2719 _validators = attrib() | |
2720 | |
2721 def __call__(self, inst, attr, value): | |
2722 for v in self._validators: | |
2723 v(inst, attr, value) | |
2724 | |
2725 | |
2726 def and_(*validators): | |
2727 """ | |
2728 A validator that composes multiple validators into one. | |
2729 | |
2730 When called on a value, it runs all wrapped validators. | |
2731 | |
2732 :param callables validators: Arbitrary number of validators. | |
2733 | |
2734 .. versionadded:: 17.1.0 | |
2735 """ | |
2736 vals = [] | |
2737 for validator in validators: | |
2738 vals.extend( | |
2739 validator._validators | |
2740 if isinstance(validator, _AndValidator) | |
2741 else [validator] | |
2742 ) | |
2743 | |
2744 return _AndValidator(tuple(vals)) | |
2745 | |
2746 | |
2747 def pipe(*converters): | |
2748 """ | |
2749 A converter that composes multiple converters into one. | |
2750 | |
2751 When called on a value, it runs all wrapped converters, returning the | |
2752 *last* value. | |
2753 | |
2754 :param callables converters: Arbitrary number of converters. | |
2755 | |
2756 .. versionadded:: 20.1.0 | |
2757 """ | |
2758 | |
2759 def pipe_converter(val): | |
2760 for converter in converters: | |
2761 val = converter(val) | |
2762 | |
2763 return val | |
2764 | |
2765 return pipe_converter |