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 |
