1from __future__ import absolute_import, division, print_function 2 3import copy 4import hashlib 5import linecache 6import sys 7import threading 8import warnings 9 10from operator import itemgetter 11 12from . import _config 13from ._compat import ( 14 PY2, 15 isclass, 16 iteritems, 17 metadata_proxy, 18 ordered_dict, 19 set_closure_cell, 20) 21from .exceptions import ( 22 DefaultAlreadySetError, 23 FrozenInstanceError, 24 NotAnAttrsClassError, 25 PythonTooOldError, 26 UnannotatedAttributeError, 27) 28 29 30# This is used at least twice, so cache it here. 31_obj_setattr = object.__setattr__ 32_init_converter_pat = "__attr_converter_{}" 33_init_factory_pat = "__attr_factory_{}" 34_tuple_property_pat = ( 35 " {attr_name} = _attrs_property(_attrs_itemgetter({index}))" 36) 37_classvar_prefixes = ("typing.ClassVar", "t.ClassVar", "ClassVar") 38# we don't use a double-underscore prefix because that triggers 39# name mangling when trying to create a slot for the field 40# (when slots=True) 41_hash_cache_field = "_attrs_cached_hash" 42 43_empty_metadata_singleton = metadata_proxy({}) 44 45 46class _Nothing(object): 47 """ 48 Sentinel class to indicate the lack of a value when ``None`` is ambiguous. 49 50 ``_Nothing`` is a singleton. There is only ever one of it. 51 """ 52 53 _singleton = None 54 55 def __new__(cls): 56 if _Nothing._singleton is None: 57 _Nothing._singleton = super(_Nothing, cls).__new__(cls) 58 return _Nothing._singleton 59 60 def __repr__(self): 61 return "NOTHING" 62 63 64NOTHING = _Nothing() 65""" 66Sentinel to indicate the lack of a value when ``None`` is ambiguous. 67""" 68 69 70def attrib( 71 default=NOTHING, 72 validator=None, 73 repr=True, 74 cmp=True, 75 hash=None, 76 init=True, 77 convert=None, 78 metadata=None, 79 type=None, 80 converter=None, 81 factory=None, 82 kw_only=False, 83): 84 """ 85 Create a new attribute on a class. 86 87 .. warning:: 88 89 Does *not* do anything unless the class is also decorated with 90 :func:`attr.s`! 91 92 :param default: A value that is used if an ``attrs``-generated ``__init__`` 93 is used and no value is passed while instantiating or the attribute is 94 excluded using ``init=False``. 95 96 If the value is an instance of :class:`Factory`, its callable will be 97 used to construct a new value (useful for mutable data types like lists 98 or dicts). 99 100 If a default is not set (or set manually to ``attr.NOTHING``), a value 101 *must* be supplied when instantiating; otherwise a :exc:`TypeError` 102 will be raised. 103 104 The default can also be set using decorator notation as shown below. 105 106 :type default: Any value. 107 108 :param callable factory: Syntactic sugar for 109 ``default=attr.Factory(callable)``. 110 111 :param validator: :func:`callable` that is called by ``attrs``-generated 112 ``__init__`` methods after the instance has been initialized. They 113 receive the initialized instance, the :class:`Attribute`, and the 114 passed value. 115 116 The return value is *not* inspected so the validator has to throw an 117 exception itself. 118 119 If a ``list`` is passed, its items are treated as validators and must 120 all pass. 121 122 Validators can be globally disabled and re-enabled using 123 :func:`get_run_validators`. 124 125 The validator can also be set using decorator notation as shown below. 126 127 :type validator: ``callable`` or a ``list`` of ``callable``\\ s. 128 129 :param bool repr: Include this attribute in the generated ``__repr__`` 130 method. 131 :param bool cmp: Include this attribute in the generated comparison methods 132 (``__eq__`` et al). 133 :param hash: Include this attribute in the generated ``__hash__`` 134 method. If ``None`` (default), mirror *cmp*'s value. This is the 135 correct behavior according the Python spec. Setting this value to 136 anything else than ``None`` is *discouraged*. 137 :type hash: ``bool`` or ``None`` 138 :param bool init: Include this attribute in the generated ``__init__`` 139 method. It is possible to set this to ``False`` and set a default 140 value. In that case this attributed is unconditionally initialized 141 with the specified default value or factory. 142 :param callable converter: :func:`callable` that is called by 143 ``attrs``-generated ``__init__`` methods to converter attribute's value 144 to the desired format. It is given the passed-in value, and the 145 returned value will be used as the new value of the attribute. The 146 value is converted before being passed to the validator, if any. 147 :param metadata: An arbitrary mapping, to be used by third-party 148 components. See :ref:`extending_metadata`. 149 :param type: The type of the attribute. In Python 3.6 or greater, the 150 preferred method to specify the type is using a variable annotation 151 (see `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_). 152 This argument is provided for backward compatibility. 153 Regardless of the approach used, the type will be stored on 154 ``Attribute.type``. 155 156 Please note that ``attrs`` doesn't do anything with this metadata by 157 itself. You can use it as part of your own code or for 158 :doc:`static type checking <types>`. 159 :param kw_only: Make this attribute keyword-only (Python 3+) 160 in the generated ``__init__`` (if ``init`` is ``False``, this 161 parameter is ignored). 162 163 .. versionadded:: 15.2.0 *convert* 164 .. versionadded:: 16.3.0 *metadata* 165 .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. 166 .. versionchanged:: 17.1.0 167 *hash* is ``None`` and therefore mirrors *cmp* by default. 168 .. versionadded:: 17.3.0 *type* 169 .. deprecated:: 17.4.0 *convert* 170 .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated 171 *convert* to achieve consistency with other noun-based arguments. 172 .. versionadded:: 18.1.0 173 ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. 174 .. versionadded:: 18.2.0 *kw_only* 175 """ 176 if hash is not None and hash is not True and hash is not False: 177 raise TypeError( 178 "Invalid value for hash. Must be True, False, or None." 179 ) 180 181 if convert is not None: 182 if converter is not None: 183 raise RuntimeError( 184 "Can't pass both `convert` and `converter`. " 185 "Please use `converter` only." 186 ) 187 warnings.warn( 188 "The `convert` argument is deprecated in favor of `converter`. " 189 "It will be removed after 2019/01.", 190 DeprecationWarning, 191 stacklevel=2, 192 ) 193 converter = convert 194 195 if factory is not None: 196 if default is not NOTHING: 197 raise ValueError( 198 "The `default` and `factory` arguments are mutually " 199 "exclusive." 200 ) 201 if not callable(factory): 202 raise ValueError("The `factory` argument must be a callable.") 203 default = Factory(factory) 204 205 if metadata is None: 206 metadata = {} 207 208 return _CountingAttr( 209 default=default, 210 validator=validator, 211 repr=repr, 212 cmp=cmp, 213 hash=hash, 214 init=init, 215 converter=converter, 216 metadata=metadata, 217 type=type, 218 kw_only=kw_only, 219 ) 220 221 222def _make_attr_tuple_class(cls_name, attr_names): 223 """ 224 Create a tuple subclass to hold `Attribute`s for an `attrs` class. 225 226 The subclass is a bare tuple with properties for names. 227 228 class MyClassAttributes(tuple): 229 __slots__ = () 230 x = property(itemgetter(0)) 231 """ 232 attr_class_name = "{}Attributes".format(cls_name) 233 attr_class_template = [ 234 "class {}(tuple):".format(attr_class_name), 235 " __slots__ = ()", 236 ] 237 if attr_names: 238 for i, attr_name in enumerate(attr_names): 239 attr_class_template.append( 240 _tuple_property_pat.format(index=i, attr_name=attr_name) 241 ) 242 else: 243 attr_class_template.append(" pass") 244 globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} 245 eval(compile("\n".join(attr_class_template), "", "exec"), globs) 246 247 return globs[attr_class_name] 248 249 250# Tuple class for extracted attributes from a class definition. 251# `base_attrs` is a subset of `attrs`. 252_Attributes = _make_attr_tuple_class( 253 "_Attributes", 254 [ 255 # all attributes to build dunder methods for 256 "attrs", 257 # attributes that have been inherited 258 "base_attrs", 259 # map inherited attributes to their originating classes 260 "base_attrs_map", 261 ], 262) 263 264 265def _is_class_var(annot): 266 """ 267 Check whether *annot* is a typing.ClassVar. 268 269 The string comparison hack is used to avoid evaluating all string 270 annotations which would put attrs-based classes at a performance 271 disadvantage compared to plain old classes. 272 """ 273 return str(annot).startswith(_classvar_prefixes) 274 275 276def _get_annotations(cls): 277 """ 278 Get annotations for *cls*. 279 """ 280 anns = getattr(cls, "__annotations__", None) 281 if anns is None: 282 return {} 283 284 # Verify that the annotations aren't merely inherited. 285 for base_cls in cls.__mro__[1:]: 286 if anns is getattr(base_cls, "__annotations__", None): 287 return {} 288 289 return anns 290 291 292def _counter_getter(e): 293 """ 294 Key function for sorting to avoid re-creating a lambda for every class. 295 """ 296 return e[1].counter 297 298 299def _transform_attrs(cls, these, auto_attribs, kw_only): 300 """ 301 Transform all `_CountingAttr`s on a class into `Attribute`s. 302 303 If *these* is passed, use that and don't look for them on the class. 304 305 Return an `_Attributes`. 306 """ 307 cd = cls.__dict__ 308 anns = _get_annotations(cls) 309 310 if these is not None: 311 ca_list = [(name, ca) for name, ca in iteritems(these)] 312 313 if not isinstance(these, ordered_dict): 314 ca_list.sort(key=_counter_getter) 315 elif auto_attribs is True: 316 ca_names = { 317 name 318 for name, attr in cd.items() 319 if isinstance(attr, _CountingAttr) 320 } 321 ca_list = [] 322 annot_names = set() 323 for attr_name, type in anns.items(): 324 if _is_class_var(type): 325 continue 326 annot_names.add(attr_name) 327 a = cd.get(attr_name, NOTHING) 328 if not isinstance(a, _CountingAttr): 329 if a is NOTHING: 330 a = attrib() 331 else: 332 a = attrib(default=a) 333 ca_list.append((attr_name, a)) 334 335 unannotated = ca_names - annot_names 336 if len(unannotated) > 0: 337 raise UnannotatedAttributeError( 338 "The following `attr.ib`s lack a type annotation: " 339 + ", ".join( 340 sorted(unannotated, key=lambda n: cd.get(n).counter) 341 ) 342 + "." 343 ) 344 else: 345 ca_list = sorted( 346 ( 347 (name, attr) 348 for name, attr in cd.items() 349 if isinstance(attr, _CountingAttr) 350 ), 351 key=lambda e: e[1].counter, 352 ) 353 354 own_attrs = [ 355 Attribute.from_counting_attr( 356 name=attr_name, ca=ca, type=anns.get(attr_name) 357 ) 358 for attr_name, ca in ca_list 359 ] 360 361 base_attrs = [] 362 base_attr_map = {} # A dictionary of base attrs to their classes. 363 taken_attr_names = {a.name: a for a in own_attrs} 364 365 # Traverse the MRO and collect attributes. 366 for base_cls in cls.__mro__[1:-1]: 367 sub_attrs = getattr(base_cls, "__attrs_attrs__", None) 368 if sub_attrs is not None: 369 for a in sub_attrs: 370 prev_a = taken_attr_names.get(a.name) 371 # Only add an attribute if it hasn't been defined before. This 372 # allows for overwriting attribute definitions by subclassing. 373 if prev_a is None: 374 base_attrs.append(a) 375 taken_attr_names[a.name] = a 376 base_attr_map[a.name] = base_cls 377 378 attr_names = [a.name for a in base_attrs + own_attrs] 379 380 AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) 381 382 if kw_only: 383 own_attrs = [a._assoc(kw_only=True) for a in own_attrs] 384 base_attrs = [a._assoc(kw_only=True) for a in base_attrs] 385 386 attrs = AttrsClass(base_attrs + own_attrs) 387 388 had_default = False 389 was_kw_only = False 390 for a in attrs: 391 if ( 392 was_kw_only is False 393 and had_default is True 394 and a.default is NOTHING 395 and a.init is True 396 and a.kw_only is False 397 ): 398 raise ValueError( 399 "No mandatory attributes allowed after an attribute with a " 400 "default value or factory. Attribute in question: %r" % (a,) 401 ) 402 elif ( 403 had_default is False 404 and a.default is not NOTHING 405 and a.init is not False 406 and 407 # Keyword-only attributes without defaults can be specified 408 # after keyword-only attributes with defaults. 409 a.kw_only is False 410 ): 411 had_default = True 412 if was_kw_only is True and a.kw_only is False and a.init is True: 413 raise ValueError( 414 "Non keyword-only attributes are not allowed after a " 415 "keyword-only attribute (unless they are init=False). " 416 "Attribute in question: {a!r}".format(a=a) 417 ) 418 if was_kw_only is False and a.init is True and a.kw_only is True: 419 was_kw_only = True 420 421 return _Attributes((attrs, base_attrs, base_attr_map)) 422 423 424def _frozen_setattrs(self, name, value): 425 """ 426 Attached to frozen classes as __setattr__. 427 """ 428 raise FrozenInstanceError() 429 430 431def _frozen_delattrs(self, name): 432 """ 433 Attached to frozen classes as __delattr__. 434 """ 435 raise FrozenInstanceError() 436 437 438class _ClassBuilder(object): 439 """ 440 Iteratively build *one* class. 441 """ 442 443 __slots__ = ( 444 "_cls", 445 "_cls_dict", 446 "_attrs", 447 "_base_names", 448 "_attr_names", 449 "_slots", 450 "_frozen", 451 "_weakref_slot", 452 "_cache_hash", 453 "_has_post_init", 454 "_delete_attribs", 455 "_base_attr_map", 456 "_is_exc", 457 ) 458 459 def __init__( 460 self, 461 cls, 462 these, 463 slots, 464 frozen, 465 weakref_slot, 466 auto_attribs, 467 kw_only, 468 cache_hash, 469 is_exc, 470 ): 471 attrs, base_attrs, base_map = _transform_attrs( 472 cls, these, auto_attribs, kw_only 473 ) 474 475 self._cls = cls 476 self._cls_dict = dict(cls.__dict__) if slots else {} 477 self._attrs = attrs 478 self._base_names = set(a.name for a in base_attrs) 479 self._base_attr_map = base_map 480 self._attr_names = tuple(a.name for a in attrs) 481 self._slots = slots 482 self._frozen = frozen or _has_frozen_base_class(cls) 483 self._weakref_slot = weakref_slot 484 self._cache_hash = cache_hash 485 self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) 486 self._delete_attribs = not bool(these) 487 self._is_exc = is_exc 488 489 self._cls_dict["__attrs_attrs__"] = self._attrs 490 491 if frozen: 492 self._cls_dict["__setattr__"] = _frozen_setattrs 493 self._cls_dict["__delattr__"] = _frozen_delattrs 494 495 def __repr__(self): 496 return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) 497 498 def build_class(self): 499 """ 500 Finalize class based on the accumulated configuration. 501 502 Builder cannot be used after calling this method. 503 """ 504 if self._slots is True: 505 return self._create_slots_class() 506 else: 507 return self._patch_original_class() 508 509 def _patch_original_class(self): 510 """ 511 Apply accumulated methods and return the class. 512 """ 513 cls = self._cls 514 base_names = self._base_names 515 516 # Clean class of attribute definitions (`attr.ib()`s). 517 if self._delete_attribs: 518 for name in self._attr_names: 519 if ( 520 name not in base_names 521 and getattr(cls, name, None) is not None 522 ): 523 try: 524 delattr(cls, name) 525 except AttributeError: 526 # This can happen if a base class defines a class 527 # variable and we want to set an attribute with the 528 # same name by using only a type annotation. 529 pass 530 531 # Attach our dunder methods. 532 for name, value in self._cls_dict.items(): 533 setattr(cls, name, value) 534 535 # Attach __setstate__. This is necessary to clear the hash code 536 # cache on deserialization. See issue 537 # https://github.com/python-attrs/attrs/issues/482 . 538 # Note that this code only handles setstate for dict classes. 539 # For slotted classes, see similar code in _create_slots_class . 540 if self._cache_hash: 541 existing_set_state_method = getattr(cls, "__setstate__", None) 542 if existing_set_state_method: 543 raise NotImplementedError( 544 "Currently you cannot use hash caching if " 545 "you specify your own __setstate__ method." 546 "See https://github.com/python-attrs/attrs/issues/494 ." 547 ) 548 549 def cache_hash_set_state(chss_self, _): 550 # clear hash code cache 551 setattr(chss_self, _hash_cache_field, None) 552 553 setattr(cls, "__setstate__", cache_hash_set_state) 554 555 return cls 556 557 def _create_slots_class(self): 558 """ 559 Build and return a new class with a `__slots__` attribute. 560 """ 561 base_names = self._base_names 562 cd = { 563 k: v 564 for k, v in iteritems(self._cls_dict) 565 if k not in tuple(self._attr_names) + ("__dict__", "__weakref__") 566 } 567 568 weakref_inherited = False 569 570 # Traverse the MRO to check for an existing __weakref__. 571 for base_cls in self._cls.__mro__[1:-1]: 572 if "__weakref__" in getattr(base_cls, "__dict__", ()): 573 weakref_inherited = True 574 break 575 576 names = self._attr_names 577 if ( 578 self._weakref_slot 579 and "__weakref__" not in getattr(self._cls, "__slots__", ()) 580 and "__weakref__" not in names 581 and not weakref_inherited 582 ): 583 names += ("__weakref__",) 584 585 # We only add the names of attributes that aren't inherited. 586 # Settings __slots__ to inherited attributes wastes memory. 587 slot_names = [name for name in names if name not in base_names] 588 if self._cache_hash: 589 slot_names.append(_hash_cache_field) 590 cd["__slots__"] = tuple(slot_names) 591 592 qualname = getattr(self._cls, "__qualname__", None) 593 if qualname is not None: 594 cd["__qualname__"] = qualname 595 596 # __weakref__ is not writable. 597 state_attr_names = tuple( 598 an for an in self._attr_names if an != "__weakref__" 599 ) 600 601 def slots_getstate(self): 602 """ 603 Automatically created by attrs. 604 """ 605 return tuple(getattr(self, name) for name in state_attr_names) 606 607 hash_caching_enabled = self._cache_hash 608 609 def slots_setstate(self, state): 610 """ 611 Automatically created by attrs. 612 """ 613 __bound_setattr = _obj_setattr.__get__(self, Attribute) 614 for name, value in zip(state_attr_names, state): 615 __bound_setattr(name, value) 616 # Clearing the hash code cache on deserialization is needed 617 # because hash codes can change from run to run. See issue 618 # https://github.com/python-attrs/attrs/issues/482 . 619 # Note that this code only handles setstate for slotted classes. 620 # For dict classes, see similar code in _patch_original_class . 621 if hash_caching_enabled: 622 __bound_setattr(_hash_cache_field, None) 623 624 # slots and frozen require __getstate__/__setstate__ to work 625 cd["__getstate__"] = slots_getstate 626 cd["__setstate__"] = slots_setstate 627 628 # Create new class based on old class and our methods. 629 cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) 630 631 # The following is a fix for 632 # https://github.com/python-attrs/attrs/issues/102. On Python 3, 633 # if a method mentions `__class__` or uses the no-arg super(), the 634 # compiler will bake a reference to the class in the method itself 635 # as `method.__closure__`. Since we replace the class with a 636 # clone, we rewrite these references so it keeps working. 637 for item in cls.__dict__.values(): 638 if isinstance(item, (classmethod, staticmethod)): 639 # Class- and staticmethods hide their functions inside. 640 # These might need to be rewritten as well. 641 closure_cells = getattr(item.__func__, "__closure__", None) 642 else: 643 closure_cells = getattr(item, "__closure__", None) 644 645 if not closure_cells: # Catch None or the empty list. 646 continue 647 for cell in closure_cells: 648 if cell.cell_contents is self._cls: 649 set_closure_cell(cell, cls) 650 651 return cls 652 653 def add_repr(self, ns): 654 self._cls_dict["__repr__"] = self._add_method_dunders( 655 _make_repr(self._attrs, ns=ns) 656 ) 657 return self 658 659 def add_str(self): 660 repr = self._cls_dict.get("__repr__") 661 if repr is None: 662 raise ValueError( 663 "__str__ can only be generated if a __repr__ exists." 664 ) 665 666 def __str__(self): 667 return self.__repr__() 668 669 self._cls_dict["__str__"] = self._add_method_dunders(__str__) 670 return self 671 672 def make_unhashable(self): 673 self._cls_dict["__hash__"] = None 674 return self 675 676 def add_hash(self): 677 self._cls_dict["__hash__"] = self._add_method_dunders( 678 _make_hash( 679 self._attrs, frozen=self._frozen, cache_hash=self._cache_hash 680 ) 681 ) 682 683 return self 684 685 def add_init(self): 686 self._cls_dict["__init__"] = self._add_method_dunders( 687 _make_init( 688 self._attrs, 689 self._has_post_init, 690 self._frozen, 691 self._slots, 692 self._cache_hash, 693 self._base_attr_map, 694 self._is_exc, 695 ) 696 ) 697 698 return self 699 700 def add_cmp(self): 701 cd = self._cls_dict 702 703 cd["__eq__"], cd["__ne__"], cd["__lt__"], cd["__le__"], cd[ 704 "__gt__" 705 ], cd["__ge__"] = ( 706 self._add_method_dunders(meth) for meth in _make_cmp(self._attrs) 707 ) 708 709 return self 710 711 def _add_method_dunders(self, method): 712 """ 713 Add __module__ and __qualname__ to a *method* if possible. 714 """ 715 try: 716 method.__module__ = self._cls.__module__ 717 except AttributeError: 718 pass 719 720 try: 721 method.__qualname__ = ".".join( 722 (self._cls.__qualname__, method.__name__) 723 ) 724 except AttributeError: 725 pass 726 727 return method 728 729 730def attrs( 731 maybe_cls=None, 732 these=None, 733 repr_ns=None, 734 repr=True, 735 cmp=True, 736 hash=None, 737 init=True, 738 slots=False, 739 frozen=False, 740 weakref_slot=True, 741 str=False, 742 auto_attribs=False, 743 kw_only=False, 744 cache_hash=False, 745 auto_exc=False, 746): 747 r""" 748 A class decorator that adds `dunder 749 <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the 750 specified attributes using :func:`attr.ib` or the *these* argument. 751 752 :param these: A dictionary of name to :func:`attr.ib` mappings. This is 753 useful to avoid the definition of your attributes within the class body 754 because you can't (e.g. if you want to add ``__repr__`` methods to 755 Django models) or don't want to. 756 757 If *these* is not ``None``, ``attrs`` will *not* search the class body 758 for attributes and will *not* remove any attributes from it. 759 760 If *these* is an ordered dict (:class:`dict` on Python 3.6+, 761 :class:`collections.OrderedDict` otherwise), the order is deduced from 762 the order of the attributes inside *these*. Otherwise the order 763 of the definition of the attributes is used. 764 765 :type these: :class:`dict` of :class:`str` to :func:`attr.ib` 766 767 :param str repr_ns: When using nested classes, there's no way in Python 2 768 to automatically detect that. Therefore it's possible to set the 769 namespace explicitly for a more meaningful ``repr`` output. 770 :param bool repr: Create a ``__repr__`` method with a human readable 771 representation of ``attrs`` attributes.. 772 :param bool str: Create a ``__str__`` method that is identical to 773 ``__repr__``. This is usually not necessary except for 774 :class:`Exception`\ s. 775 :param bool cmp: Create ``__eq__``, ``__ne__``, ``__lt__``, ``__le__``, 776 ``__gt__``, and ``__ge__`` methods that compare the class as if it were 777 a tuple of its ``attrs`` attributes. But the attributes are *only* 778 compared, if the types of both classes are *identical*! 779 :param hash: If ``None`` (default), the ``__hash__`` method is generated 780 according how *cmp* and *frozen* are set. 781 782 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. 783 2. If *cmp* is True and *frozen* is False, ``__hash__`` will be set to 784 None, marking it unhashable (which it is). 785 3. If *cmp* is False, ``__hash__`` will be left untouched meaning the 786 ``__hash__`` method of the base class will be used (if base class is 787 ``object``, this means it will fall back to id-based hashing.). 788 789 Although not recommended, you can decide for yourself and force 790 ``attrs`` to create one (e.g. if the class is immutable even though you 791 didn't freeze it programmatically) by passing ``True`` or not. Both of 792 these cases are rather special and should be used carefully. 793 794 See the `Python documentation \ 795 <https://docs.python.org/3/reference/datamodel.html#object.__hash__>`_ 796 and the `GitHub issue that led to the default behavior \ 797 <https://github.com/python-attrs/attrs/issues/136>`_ for more details. 798 :type hash: ``bool`` or ``None`` 799 :param bool init: Create a ``__init__`` method that initializes the 800 ``attrs`` attributes. Leading underscores are stripped for the 801 argument name. If a ``__attrs_post_init__`` method exists on the 802 class, it will be called after the class is fully initialized. 803 :param bool slots: Create a slots_-style class that's more 804 memory-efficient. See :ref:`slots` for further ramifications. 805 :param bool frozen: Make instances immutable after initialization. If 806 someone attempts to modify a frozen instance, 807 :exc:`attr.exceptions.FrozenInstanceError` is raised. 808 809 Please note: 810 811 1. This is achieved by installing a custom ``__setattr__`` method 812 on your class so you can't implement an own one. 813 814 2. True immutability is impossible in Python. 815 816 3. This *does* have a minor a runtime performance :ref:`impact 817 <how-frozen>` when initializing new instances. In other words: 818 ``__init__`` is slightly slower with ``frozen=True``. 819 820 4. If a class is frozen, you cannot modify ``self`` in 821 ``__attrs_post_init__`` or a self-written ``__init__``. You can 822 circumvent that limitation by using 823 ``object.__setattr__(self, "attribute_name", value)``. 824 825 .. _slots: https://docs.python.org/3/reference/datamodel.html#slots 826 :param bool weakref_slot: Make instances weak-referenceable. This has no 827 effect unless ``slots`` is also enabled. 828 :param bool auto_attribs: If True, collect `PEP 526`_-annotated attributes 829 (Python 3.6 and later only) from the class body. 830 831 In this case, you **must** annotate every field. If ``attrs`` 832 encounters a field that is set to an :func:`attr.ib` but lacks a type 833 annotation, an :exc:`attr.exceptions.UnannotatedAttributeError` is 834 raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't 835 want to set a type. 836 837 If you assign a value to those attributes (e.g. ``x: int = 42``), that 838 value becomes the default value like if it were passed using 839 ``attr.ib(default=42)``. Passing an instance of :class:`Factory` also 840 works as expected. 841 842 Attributes annotated as :data:`typing.ClassVar` are **ignored**. 843 844 .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ 845 :param bool kw_only: Make all attributes keyword-only (Python 3+) 846 in the generated ``__init__`` (if ``init`` is ``False``, this 847 parameter is ignored). 848 :param bool cache_hash: Ensure that the object's hash code is computed 849 only once and stored on the object. If this is set to ``True``, 850 hashing must be either explicitly or implicitly enabled for this 851 class. If the hash code is cached, avoid any reassignments of 852 fields involved in hash code computation or mutations of the objects 853 those fields point to after object creation. If such changes occur, 854 the behavior of the object's hash code is undefined. 855 :param bool auto_exc: If the class subclasses :class:`BaseException` 856 (which implicitly includes any subclass of any exception), the 857 following happens to behave like a well-behaved Python exceptions 858 class: 859 860 - the values for *cmp* and *hash* are ignored and the instances compare 861 and hash by the instance's ids (N.B. ``attrs`` will *not* remove 862 existing implementations of ``__hash__`` or the equality methods. It 863 just won't add own ones.), 864 - all attributes that are either passed into ``__init__`` or have a 865 default value are additionally available as a tuple in the ``args`` 866 attribute, 867 - the value of *str* is ignored leaving ``__str__`` to base classes. 868 869 .. versionadded:: 16.0.0 *slots* 870 .. versionadded:: 16.1.0 *frozen* 871 .. versionadded:: 16.3.0 *str* 872 .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. 873 .. versionchanged:: 17.1.0 874 *hash* supports ``None`` as value which is also the default now. 875 .. versionadded:: 17.3.0 *auto_attribs* 876 .. versionchanged:: 18.1.0 877 If *these* is passed, no attributes are deleted from the class body. 878 .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. 879 .. versionadded:: 18.2.0 *weakref_slot* 880 .. deprecated:: 18.2.0 881 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a 882 :class:`DeprecationWarning` if the classes compared are subclasses of 883 each other. ``__eq`` and ``__ne__`` never tried to compared subclasses 884 to each other. 885 .. versionadded:: 18.2.0 *kw_only* 886 .. versionadded:: 18.2.0 *cache_hash* 887 .. versionadded:: 19.1.0 *auto_exc* 888 """ 889 890 def wrap(cls): 891 892 if getattr(cls, "__class__", None) is None: 893 raise TypeError("attrs only works with new-style classes.") 894 895 is_exc = auto_exc is True and issubclass(cls, BaseException) 896 897 builder = _ClassBuilder( 898 cls, 899 these, 900 slots, 901 frozen, 902 weakref_slot, 903 auto_attribs, 904 kw_only, 905 cache_hash, 906 is_exc, 907 ) 908 909 if repr is True: 910 builder.add_repr(repr_ns) 911 if str is True: 912 builder.add_str() 913 if cmp is True and not is_exc: 914 builder.add_cmp() 915 916 if hash is not True and hash is not False and hash is not None: 917 # Can't use `hash in` because 1 == True for example. 918 raise TypeError( 919 "Invalid value for hash. Must be True, False, or None." 920 ) 921 elif hash is False or (hash is None and cmp is False): 922 if cache_hash: 923 raise TypeError( 924 "Invalid value for cache_hash. To use hash caching," 925 " hashing must be either explicitly or implicitly " 926 "enabled." 927 ) 928 elif ( 929 hash is True 930 or (hash is None and cmp is True and frozen is True) 931 and is_exc is False 932 ): 933 builder.add_hash() 934 else: 935 if cache_hash: 936 raise TypeError( 937 "Invalid value for cache_hash. To use hash caching," 938 " hashing must be either explicitly or implicitly " 939 "enabled." 940 ) 941 builder.make_unhashable() 942 943 if init is True: 944 builder.add_init() 945 else: 946 if cache_hash: 947 raise TypeError( 948 "Invalid value for cache_hash. To use hash caching," 949 " init must be True." 950 ) 951 952 return builder.build_class() 953 954 # maybe_cls's type depends on the usage of the decorator. It's a class 955 # if it's used as `@attrs` but ``None`` if used as `@attrs()`. 956 if maybe_cls is None: 957 return wrap 958 else: 959 return wrap(maybe_cls) 960 961 962_attrs = attrs 963""" 964Internal alias so we can use it in functions that take an argument called 965*attrs*. 966""" 967 968 969if PY2: 970 971 def _has_frozen_base_class(cls): 972 """ 973 Check whether *cls* has a frozen ancestor by looking at its 974 __setattr__. 975 """ 976 return ( 977 getattr(cls.__setattr__, "__module__", None) 978 == _frozen_setattrs.__module__ 979 and cls.__setattr__.__name__ == _frozen_setattrs.__name__ 980 ) 981 982 983else: 984 985 def _has_frozen_base_class(cls): 986 """ 987 Check whether *cls* has a frozen ancestor by looking at its 988 __setattr__. 989 """ 990 return cls.__setattr__ == _frozen_setattrs 991 992 993def _attrs_to_tuple(obj, attrs): 994 """ 995 Create a tuple of all values of *obj*'s *attrs*. 996 """ 997 return tuple(getattr(obj, a.name) for a in attrs) 998 999 1000def _make_hash(attrs, frozen, cache_hash): 1001 attrs = tuple( 1002 a 1003 for a in attrs 1004 if a.hash is True or (a.hash is None and a.cmp is True) 1005 ) 1006 1007 tab = " " 1008 1009 # We cache the generated hash methods for the same kinds of attributes. 1010 sha1 = hashlib.sha1() 1011 sha1.update(repr(attrs).encode("utf-8")) 1012 unique_filename = "<attrs generated hash %s>" % (sha1.hexdigest(),) 1013 type_hash = hash(unique_filename) 1014 1015 method_lines = ["def __hash__(self):"] 1016 1017 def append_hash_computation_lines(prefix, indent): 1018 """ 1019 Generate the code for actually computing the hash code. 1020 Below this will either be returned directly or used to compute 1021 a value which is then cached, depending on the value of cache_hash 1022 """ 1023 method_lines.extend( 1024 [indent + prefix + "hash((", indent + " %d," % (type_hash,)] 1025 ) 1026 1027 for a in attrs: 1028 method_lines.append(indent + " self.%s," % a.name) 1029 1030 method_lines.append(indent + " ))") 1031 1032 if cache_hash: 1033 method_lines.append(tab + "if self.%s is None:" % _hash_cache_field) 1034 if frozen: 1035 append_hash_computation_lines( 1036 "object.__setattr__(self, '%s', " % _hash_cache_field, tab * 2 1037 ) 1038 method_lines.append(tab * 2 + ")") # close __setattr__ 1039 else: 1040 append_hash_computation_lines( 1041 "self.%s = " % _hash_cache_field, tab * 2 1042 ) 1043 method_lines.append(tab + "return self.%s" % _hash_cache_field) 1044 else: 1045 append_hash_computation_lines("return ", tab) 1046 1047 script = "\n".join(method_lines) 1048 globs = {} 1049 locs = {} 1050 bytecode = compile(script, unique_filename, "exec") 1051 eval(bytecode, globs, locs) 1052 1053 # In order of debuggers like PDB being able to step through the code, 1054 # we add a fake linecache entry. 1055 linecache.cache[unique_filename] = ( 1056 len(script), 1057 None, 1058 script.splitlines(True), 1059 unique_filename, 1060 ) 1061 1062 return locs["__hash__"] 1063 1064 1065def _add_hash(cls, attrs): 1066 """ 1067 Add a hash method to *cls*. 1068 """ 1069 cls.__hash__ = _make_hash(attrs, frozen=False, cache_hash=False) 1070 return cls 1071 1072 1073def __ne__(self, other): 1074 """ 1075 Check equality and either forward a NotImplemented or return the result 1076 negated. 1077 """ 1078 result = self.__eq__(other) 1079 if result is NotImplemented: 1080 return NotImplemented 1081 1082 return not result 1083 1084 1085WARNING_CMP_ISINSTANCE = ( 1086 "Comparision of subclasses using __%s__ is deprecated and will be removed " 1087 "in 2019." 1088) 1089 1090 1091def _make_cmp(attrs): 1092 attrs = [a for a in attrs if a.cmp] 1093 1094 # We cache the generated eq methods for the same kinds of attributes. 1095 sha1 = hashlib.sha1() 1096 sha1.update(repr(attrs).encode("utf-8")) 1097 unique_filename = "<attrs generated eq %s>" % (sha1.hexdigest(),) 1098 lines = [ 1099 "def __eq__(self, other):", 1100 " if other.__class__ is not self.__class__:", 1101 " return NotImplemented", 1102 ] 1103 # We can't just do a big self.x = other.x and... clause due to 1104 # irregularities like nan == nan is false but (nan,) == (nan,) is true. 1105 if attrs: 1106 lines.append(" return (") 1107 others = [" ) == ("] 1108 for a in attrs: 1109 lines.append(" self.%s," % (a.name,)) 1110 others.append(" other.%s," % (a.name,)) 1111 1112 lines += others + [" )"] 1113 else: 1114 lines.append(" return True") 1115 1116 script = "\n".join(lines) 1117 globs = {} 1118 locs = {} 1119 bytecode = compile(script, unique_filename, "exec") 1120 eval(bytecode, globs, locs) 1121 1122 # In order of debuggers like PDB being able to step through the code, 1123 # we add a fake linecache entry. 1124 linecache.cache[unique_filename] = ( 1125 len(script), 1126 None, 1127 script.splitlines(True), 1128 unique_filename, 1129 ) 1130 eq = locs["__eq__"] 1131 ne = __ne__ 1132 1133 def attrs_to_tuple(obj): 1134 """ 1135 Save us some typing. 1136 """ 1137 return _attrs_to_tuple(obj, attrs) 1138 1139 def __lt__(self, other): 1140 """ 1141 Automatically created by attrs. 1142 """ 1143 if isinstance(other, self.__class__): 1144 if other.__class__ is not self.__class__: 1145 warnings.warn( 1146 WARNING_CMP_ISINSTANCE % ("lt",), DeprecationWarning 1147 ) 1148 return attrs_to_tuple(self) < attrs_to_tuple(other) 1149 else: 1150 return NotImplemented 1151 1152 def __le__(self, other): 1153 """ 1154 Automatically created by attrs. 1155 """ 1156 if isinstance(other, self.__class__): 1157 if other.__class__ is not self.__class__: 1158 warnings.warn( 1159 WARNING_CMP_ISINSTANCE % ("le",), DeprecationWarning 1160 ) 1161 return attrs_to_tuple(self) <= attrs_to_tuple(other) 1162 else: 1163 return NotImplemented 1164 1165 def __gt__(self, other): 1166 """ 1167 Automatically created by attrs. 1168 """ 1169 if isinstance(other, self.__class__): 1170 if other.__class__ is not self.__class__: 1171 warnings.warn( 1172 WARNING_CMP_ISINSTANCE % ("gt",), DeprecationWarning 1173 ) 1174 return attrs_to_tuple(self) > attrs_to_tuple(other) 1175 else: 1176 return NotImplemented 1177 1178 def __ge__(self, other): 1179 """ 1180 Automatically created by attrs. 1181 """ 1182 if isinstance(other, self.__class__): 1183 if other.__class__ is not self.__class__: 1184 warnings.warn( 1185 WARNING_CMP_ISINSTANCE % ("ge",), DeprecationWarning 1186 ) 1187 return attrs_to_tuple(self) >= attrs_to_tuple(other) 1188 else: 1189 return NotImplemented 1190 1191 return eq, ne, __lt__, __le__, __gt__, __ge__ 1192 1193 1194def _add_cmp(cls, attrs=None): 1195 """ 1196 Add comparison methods to *cls*. 1197 """ 1198 if attrs is None: 1199 attrs = cls.__attrs_attrs__ 1200 1201 cls.__eq__, cls.__ne__, cls.__lt__, cls.__le__, cls.__gt__, cls.__ge__ = _make_cmp( # noqa 1202 attrs 1203 ) 1204 1205 return cls 1206 1207 1208_already_repring = threading.local() 1209 1210 1211def _make_repr(attrs, ns): 1212 """ 1213 Make a repr method for *attr_names* adding *ns* to the full name. 1214 """ 1215 attr_names = tuple(a.name for a in attrs if a.repr) 1216 1217 def __repr__(self): 1218 """ 1219 Automatically created by attrs. 1220 """ 1221 try: 1222 working_set = _already_repring.working_set 1223 except AttributeError: 1224 working_set = set() 1225 _already_repring.working_set = working_set 1226 1227 if id(self) in working_set: 1228 return "..." 1229 real_cls = self.__class__ 1230 if ns is None: 1231 qualname = getattr(real_cls, "__qualname__", None) 1232 if qualname is not None: 1233 class_name = qualname.rsplit(">.", 1)[-1] 1234 else: 1235 class_name = real_cls.__name__ 1236 else: 1237 class_name = ns + "." + real_cls.__name__ 1238 1239 # Since 'self' remains on the stack (i.e.: strongly referenced) for the 1240 # duration of this call, it's safe to depend on id(...) stability, and 1241 # not need to track the instance and therefore worry about properties 1242 # like weakref- or hash-ability. 1243 working_set.add(id(self)) 1244 try: 1245 result = [class_name, "("] 1246 first = True 1247 for name in attr_names: 1248 if first: 1249 first = False 1250 else: 1251 result.append(", ") 1252 result.extend((name, "=", repr(getattr(self, name, NOTHING)))) 1253 return "".join(result) + ")" 1254 finally: 1255 working_set.remove(id(self)) 1256 1257 return __repr__ 1258 1259 1260def _add_repr(cls, ns=None, attrs=None): 1261 """ 1262 Add a repr method to *cls*. 1263 """ 1264 if attrs is None: 1265 attrs = cls.__attrs_attrs__ 1266 1267 cls.__repr__ = _make_repr(attrs, ns) 1268 return cls 1269 1270 1271def _make_init( 1272 attrs, post_init, frozen, slots, cache_hash, base_attr_map, is_exc 1273): 1274 attrs = [a for a in attrs if a.init or a.default is not NOTHING] 1275 1276 # We cache the generated init methods for the same kinds of attributes. 1277 sha1 = hashlib.sha1() 1278 sha1.update(repr(attrs).encode("utf-8")) 1279 unique_filename = "<attrs generated init {0}>".format(sha1.hexdigest()) 1280 1281 script, globs, annotations = _attrs_to_init_script( 1282 attrs, frozen, slots, post_init, cache_hash, base_attr_map, is_exc 1283 ) 1284 locs = {} 1285 bytecode = compile(script, unique_filename, "exec") 1286 attr_dict = dict((a.name, a) for a in attrs) 1287 globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) 1288 1289 if frozen is True: 1290 # Save the lookup overhead in __init__ if we need to circumvent 1291 # immutability. 1292 globs["_cached_setattr"] = _obj_setattr 1293 1294 eval(bytecode, globs, locs) 1295 1296 # In order of debuggers like PDB being able to step through the code, 1297 # we add a fake linecache entry. 1298 linecache.cache[unique_filename] = ( 1299 len(script), 1300 None, 1301 script.splitlines(True), 1302 unique_filename, 1303 ) 1304 1305 __init__ = locs["__init__"] 1306 __init__.__annotations__ = annotations 1307 1308 return __init__ 1309 1310 1311def fields(cls): 1312 """ 1313 Return the tuple of ``attrs`` attributes for a class. 1314 1315 The tuple also allows accessing the fields by their names (see below for 1316 examples). 1317 1318 :param type cls: Class to introspect. 1319 1320 :raise TypeError: If *cls* is not a class. 1321 :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` 1322 class. 1323 1324 :rtype: tuple (with name accessors) of :class:`attr.Attribute` 1325 1326 .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields 1327 by name. 1328 """ 1329 if not isclass(cls): 1330 raise TypeError("Passed object must be a class.") 1331 attrs = getattr(cls, "__attrs_attrs__", None) 1332 if attrs is None: 1333 raise NotAnAttrsClassError( 1334 "{cls!r} is not an attrs-decorated class.".format(cls=cls) 1335 ) 1336 return attrs 1337 1338 1339def fields_dict(cls): 1340 """ 1341 Return an ordered dictionary of ``attrs`` attributes for a class, whose 1342 keys are the attribute names. 1343 1344 :param type cls: Class to introspect. 1345 1346 :raise TypeError: If *cls* is not a class. 1347 :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` 1348 class. 1349 1350 :rtype: an ordered dict where keys are attribute names and values are 1351 :class:`attr.Attribute`\\ s. This will be a :class:`dict` if it's 1352 naturally ordered like on Python 3.6+ or an 1353 :class:`~collections.OrderedDict` otherwise. 1354 1355 .. versionadded:: 18.1.0 1356 """ 1357 if not isclass(cls): 1358 raise TypeError("Passed object must be a class.") 1359 attrs = getattr(cls, "__attrs_attrs__", None) 1360 if attrs is None: 1361 raise NotAnAttrsClassError( 1362 "{cls!r} is not an attrs-decorated class.".format(cls=cls) 1363 ) 1364 return ordered_dict(((a.name, a) for a in attrs)) 1365 1366 1367def validate(inst): 1368 """ 1369 Validate all attributes on *inst* that have a validator. 1370 1371 Leaves all exceptions through. 1372 1373 :param inst: Instance of a class with ``attrs`` attributes. 1374 """ 1375 if _config._run_validators is False: 1376 return 1377 1378 for a in fields(inst.__class__): 1379 v = a.validator 1380 if v is not None: 1381 v(inst, a, getattr(inst, a.name)) 1382 1383 1384def _is_slot_cls(cls): 1385 return "__slots__" in cls.__dict__ 1386 1387 1388def _is_slot_attr(a_name, base_attr_map): 1389 """ 1390 Check if the attribute name comes from a slot class. 1391 """ 1392 return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) 1393 1394 1395def _attrs_to_init_script( 1396 attrs, frozen, slots, post_init, cache_hash, base_attr_map, is_exc 1397): 1398 """ 1399 Return a script of an initializer for *attrs* and a dict of globals. 1400 1401 The globals are expected by the generated script. 1402 1403 If *frozen* is True, we cannot set the attributes directly so we use 1404 a cached ``object.__setattr__``. 1405 """ 1406 lines = [] 1407 any_slot_ancestors = any( 1408 _is_slot_attr(a.name, base_attr_map) for a in attrs 1409 ) 1410 if frozen is True: 1411 if slots is True: 1412 lines.append( 1413 # Circumvent the __setattr__ descriptor to save one lookup per 1414 # assignment. 1415 # Note _setattr will be used again below if cache_hash is True 1416 "_setattr = _cached_setattr.__get__(self, self.__class__)" 1417 ) 1418 1419 def fmt_setter(attr_name, value_var): 1420 return "_setattr('%(attr_name)s', %(value_var)s)" % { 1421 "attr_name": attr_name, 1422 "value_var": value_var, 1423 } 1424 1425 def fmt_setter_with_converter(attr_name, value_var): 1426 conv_name = _init_converter_pat.format(attr_name) 1427 return "_setattr('%(attr_name)s', %(conv)s(%(value_var)s))" % { 1428 "attr_name": attr_name, 1429 "value_var": value_var, 1430 "conv": conv_name, 1431 } 1432 1433 else: 1434 # Dict frozen classes assign directly to __dict__. 1435 # But only if the attribute doesn't come from an ancestor slot 1436 # class. 1437 # Note _inst_dict will be used again below if cache_hash is True 1438 lines.append("_inst_dict = self.__dict__") 1439 if any_slot_ancestors: 1440 lines.append( 1441 # Circumvent the __setattr__ descriptor to save one lookup 1442 # per assignment. 1443 "_setattr = _cached_setattr.__get__(self, self.__class__)" 1444 ) 1445 1446 def fmt_setter(attr_name, value_var): 1447 if _is_slot_attr(attr_name, base_attr_map): 1448 res = "_setattr('%(attr_name)s', %(value_var)s)" % { 1449 "attr_name": attr_name, 1450 "value_var": value_var, 1451 } 1452 else: 1453 res = "_inst_dict['%(attr_name)s'] = %(value_var)s" % { 1454 "attr_name": attr_name, 1455 "value_var": value_var, 1456 } 1457 return res 1458 1459 def fmt_setter_with_converter(attr_name, value_var): 1460 conv_name = _init_converter_pat.format(attr_name) 1461 if _is_slot_attr(attr_name, base_attr_map): 1462 tmpl = "_setattr('%(attr_name)s', %(c)s(%(value_var)s))" 1463 else: 1464 tmpl = "_inst_dict['%(attr_name)s'] = %(c)s(%(value_var)s)" 1465 return tmpl % { 1466 "attr_name": attr_name, 1467 "value_var": value_var, 1468 "c": conv_name, 1469 } 1470 1471 else: 1472 # Not frozen. 1473 def fmt_setter(attr_name, value): 1474 return "self.%(attr_name)s = %(value)s" % { 1475 "attr_name": attr_name, 1476 "value": value, 1477 } 1478 1479 def fmt_setter_with_converter(attr_name, value_var): 1480 conv_name = _init_converter_pat.format(attr_name) 1481 return "self.%(attr_name)s = %(conv)s(%(value_var)s)" % { 1482 "attr_name": attr_name, 1483 "value_var": value_var, 1484 "conv": conv_name, 1485 } 1486 1487 args = [] 1488 kw_only_args = [] 1489 attrs_to_validate = [] 1490 1491 # This is a dictionary of names to validator and converter callables. 1492 # Injecting this into __init__ globals lets us avoid lookups. 1493 names_for_globals = {} 1494 annotations = {"return": None} 1495 1496 for a in attrs: 1497 if a.validator: 1498 attrs_to_validate.append(a) 1499 attr_name = a.name 1500 arg_name = a.name.lstrip("_") 1501 has_factory = isinstance(a.default, Factory) 1502 if has_factory and a.default.takes_self: 1503 maybe_self = "self" 1504 else: 1505 maybe_self = "" 1506 if a.init is False: 1507 if has_factory: 1508 init_factory_name = _init_factory_pat.format(a.name) 1509 if a.converter is not None: 1510 lines.append( 1511 fmt_setter_with_converter( 1512 attr_name, 1513 init_factory_name + "({0})".format(maybe_self), 1514 ) 1515 ) 1516 conv_name = _init_converter_pat.format(a.name) 1517 names_for_globals[conv_name] = a.converter 1518 else: 1519 lines.append( 1520 fmt_setter( 1521 attr_name, 1522 init_factory_name + "({0})".format(maybe_self), 1523 ) 1524 ) 1525 names_for_globals[init_factory_name] = a.default.factory 1526 else: 1527 if a.converter is not None: 1528 lines.append( 1529 fmt_setter_with_converter( 1530 attr_name, 1531 "attr_dict['{attr_name}'].default".format( 1532 attr_name=attr_name 1533 ), 1534 ) 1535 ) 1536 conv_name = _init_converter_pat.format(a.name) 1537 names_for_globals[conv_name] = a.converter 1538 else: 1539 lines.append( 1540 fmt_setter( 1541 attr_name, 1542 "attr_dict['{attr_name}'].default".format( 1543 attr_name=attr_name 1544 ), 1545 ) 1546 ) 1547 elif a.default is not NOTHING and not has_factory: 1548 arg = "{arg_name}=attr_dict['{attr_name}'].default".format( 1549 arg_name=arg_name, attr_name=attr_name 1550 ) 1551 if a.kw_only: 1552 kw_only_args.append(arg) 1553 else: 1554 args.append(arg) 1555 if a.converter is not None: 1556 lines.append(fmt_setter_with_converter(attr_name, arg_name)) 1557 names_for_globals[ 1558 _init_converter_pat.format(a.name) 1559 ] = a.converter 1560 else: 1561 lines.append(fmt_setter(attr_name, arg_name)) 1562 elif has_factory: 1563 arg = "{arg_name}=NOTHING".format(arg_name=arg_name) 1564 if a.kw_only: 1565 kw_only_args.append(arg) 1566 else: 1567 args.append(arg) 1568 lines.append( 1569 "if {arg_name} is not NOTHING:".format(arg_name=arg_name) 1570 ) 1571 init_factory_name = _init_factory_pat.format(a.name) 1572 if a.converter is not None: 1573 lines.append( 1574 " " + fmt_setter_with_converter(attr_name, arg_name) 1575 ) 1576 lines.append("else:") 1577 lines.append( 1578 " " 1579 + fmt_setter_with_converter( 1580 attr_name, 1581 init_factory_name + "({0})".format(maybe_self), 1582 ) 1583 ) 1584 names_for_globals[ 1585 _init_converter_pat.format(a.name) 1586 ] = a.converter 1587 else: 1588 lines.append(" " + fmt_setter(attr_name, arg_name)) 1589 lines.append("else:") 1590 lines.append( 1591 " " 1592 + fmt_setter( 1593 attr_name, 1594 init_factory_name + "({0})".format(maybe_self), 1595 ) 1596 ) 1597 names_for_globals[init_factory_name] = a.default.factory 1598 else: 1599 if a.kw_only: 1600 kw_only_args.append(arg_name) 1601 else: 1602 args.append(arg_name) 1603 if a.converter is not None: 1604 lines.append(fmt_setter_with_converter(attr_name, arg_name)) 1605 names_for_globals[ 1606 _init_converter_pat.format(a.name) 1607 ] = a.converter 1608 else: 1609 lines.append(fmt_setter(attr_name, arg_name)) 1610 1611 if a.init is True and a.converter is None and a.type is not None: 1612 annotations[arg_name] = a.type 1613 1614 if attrs_to_validate: # we can skip this if there are no validators. 1615 names_for_globals["_config"] = _config 1616 lines.append("if _config._run_validators is True:") 1617 for a in attrs_to_validate: 1618 val_name = "__attr_validator_{}".format(a.name) 1619 attr_name = "__attr_{}".format(a.name) 1620 lines.append( 1621 " {}(self, {}, self.{})".format(val_name, attr_name, a.name) 1622 ) 1623 names_for_globals[val_name] = a.validator 1624 names_for_globals[attr_name] = a 1625 if post_init: 1626 lines.append("self.__attrs_post_init__()") 1627 1628 # because this is set only after __attrs_post_init is called, a crash 1629 # will result if post-init tries to access the hash code. This seemed 1630 # preferable to setting this beforehand, in which case alteration to 1631 # field values during post-init combined with post-init accessing the 1632 # hash code would result in silent bugs. 1633 if cache_hash: 1634 if frozen: 1635 if slots: 1636 # if frozen and slots, then _setattr defined above 1637 init_hash_cache = "_setattr('%s', %s)" 1638 else: 1639 # if frozen and not slots, then _inst_dict defined above 1640 init_hash_cache = "_inst_dict['%s'] = %s" 1641 else: 1642 init_hash_cache = "self.%s = %s" 1643 lines.append(init_hash_cache % (_hash_cache_field, "None")) 1644 1645 # For exceptions we rely on BaseException.__init__ for proper 1646 # initialization. 1647 if is_exc: 1648 vals = ",".join("self." + a.name for a in attrs if a.init) 1649 1650 lines.append("BaseException.__init__(self, %s)" % (vals,)) 1651 1652 args = ", ".join(args) 1653 if kw_only_args: 1654 if PY2: 1655 raise PythonTooOldError( 1656 "Keyword-only arguments only work on Python 3 and later." 1657 ) 1658 1659 args += "{leading_comma}*, {kw_only_args}".format( 1660 leading_comma=", " if args else "", 1661 kw_only_args=", ".join(kw_only_args), 1662 ) 1663 return ( 1664 """\ 1665def __init__(self, {args}): 1666 {lines} 1667""".format( 1668 args=args, lines="\n ".join(lines) if lines else "pass" 1669 ), 1670 names_for_globals, 1671 annotations, 1672 ) 1673 1674 1675class Attribute(object): 1676 """ 1677 *Read-only* representation of an attribute. 1678 1679 :attribute name: The name of the attribute. 1680 1681 Plus *all* arguments of :func:`attr.ib`. 1682 1683 For the version history of the fields, see :func:`attr.ib`. 1684 """ 1685 1686 __slots__ = ( 1687 "name", 1688 "default", 1689 "validator", 1690 "repr", 1691 "cmp", 1692 "hash", 1693 "init", 1694 "metadata", 1695 "type", 1696 "converter", 1697 "kw_only", 1698 ) 1699 1700 def __init__( 1701 self, 1702 name, 1703 default, 1704 validator, 1705 repr, 1706 cmp, 1707 hash, 1708 init, 1709 convert=None, 1710 metadata=None, 1711 type=None, 1712 converter=None, 1713 kw_only=False, 1714 ): 1715 # Cache this descriptor here to speed things up later. 1716 bound_setattr = _obj_setattr.__get__(self, Attribute) 1717 1718 # Despite the big red warning, people *do* instantiate `Attribute` 1719 # themselves. 1720 if convert is not None: 1721 if converter is not None: 1722 raise RuntimeError( 1723 "Can't pass both `convert` and `converter`. " 1724 "Please use `converter` only." 1725 ) 1726 warnings.warn( 1727 "The `convert` argument is deprecated in favor of `converter`." 1728 " It will be removed after 2019/01.", 1729 DeprecationWarning, 1730 stacklevel=2, 1731 ) 1732 converter = convert 1733 1734 bound_setattr("name", name) 1735 bound_setattr("default", default) 1736 bound_setattr("validator", validator) 1737 bound_setattr("repr", repr) 1738 bound_setattr("cmp", cmp) 1739 bound_setattr("hash", hash) 1740 bound_setattr("init", init) 1741 bound_setattr("converter", converter) 1742 bound_setattr( 1743 "metadata", 1744 ( 1745 metadata_proxy(metadata) 1746 if metadata 1747 else _empty_metadata_singleton 1748 ), 1749 ) 1750 bound_setattr("type", type) 1751 bound_setattr("kw_only", kw_only) 1752 1753 def __setattr__(self, name, value): 1754 raise FrozenInstanceError() 1755 1756 @property 1757 def convert(self): 1758 warnings.warn( 1759 "The `convert` attribute is deprecated in favor of `converter`. " 1760 "It will be removed after 2019/01.", 1761 DeprecationWarning, 1762 stacklevel=2, 1763 ) 1764 return self.converter 1765 1766 @classmethod 1767 def from_counting_attr(cls, name, ca, type=None): 1768 # type holds the annotated value. deal with conflicts: 1769 if type is None: 1770 type = ca.type 1771 elif ca.type is not None: 1772 raise ValueError( 1773 "Type annotation and type argument cannot both be present" 1774 ) 1775 inst_dict = { 1776 k: getattr(ca, k) 1777 for k in Attribute.__slots__ 1778 if k 1779 not in ( 1780 "name", 1781 "validator", 1782 "default", 1783 "type", 1784 "convert", 1785 ) # exclude methods and deprecated alias 1786 } 1787 return cls( 1788 name=name, 1789 validator=ca._validator, 1790 default=ca._default, 1791 type=type, 1792 **inst_dict 1793 ) 1794 1795 # Don't use attr.assoc since fields(Attribute) doesn't work 1796 def _assoc(self, **changes): 1797 """ 1798 Copy *self* and apply *changes*. 1799 """ 1800 new = copy.copy(self) 1801 1802 new._setattrs(changes.items()) 1803 1804 return new 1805 1806 # Don't use _add_pickle since fields(Attribute) doesn't work 1807 def __getstate__(self): 1808 """ 1809 Play nice with pickle. 1810 """ 1811 return tuple( 1812 getattr(self, name) if name != "metadata" else dict(self.metadata) 1813 for name in self.__slots__ 1814 ) 1815 1816 def __setstate__(self, state): 1817 """ 1818 Play nice with pickle. 1819 """ 1820 self._setattrs(zip(self.__slots__, state)) 1821 1822 def _setattrs(self, name_values_pairs): 1823 bound_setattr = _obj_setattr.__get__(self, Attribute) 1824 for name, value in name_values_pairs: 1825 if name != "metadata": 1826 bound_setattr(name, value) 1827 else: 1828 bound_setattr( 1829 name, 1830 metadata_proxy(value) 1831 if value 1832 else _empty_metadata_singleton, 1833 ) 1834 1835 1836_a = [ 1837 Attribute( 1838 name=name, 1839 default=NOTHING, 1840 validator=None, 1841 repr=True, 1842 cmp=True, 1843 hash=(name != "metadata"), 1844 init=True, 1845 ) 1846 for name in Attribute.__slots__ 1847 if name != "convert" # XXX: remove once `convert` is gone 1848] 1849 1850Attribute = _add_hash( 1851 _add_cmp(_add_repr(Attribute, attrs=_a), attrs=_a), 1852 attrs=[a for a in _a if a.hash], 1853) 1854 1855 1856class _CountingAttr(object): 1857 """ 1858 Intermediate representation of attributes that uses a counter to preserve 1859 the order in which the attributes have been defined. 1860 1861 *Internal* data structure of the attrs library. Running into is most 1862 likely the result of a bug like a forgotten `@attr.s` decorator. 1863 """ 1864 1865 __slots__ = ( 1866 "counter", 1867 "_default", 1868 "repr", 1869 "cmp", 1870 "hash", 1871 "init", 1872 "metadata", 1873 "_validator", 1874 "converter", 1875 "type", 1876 "kw_only", 1877 ) 1878 __attrs_attrs__ = tuple( 1879 Attribute( 1880 name=name, 1881 default=NOTHING, 1882 validator=None, 1883 repr=True, 1884 cmp=True, 1885 hash=True, 1886 init=True, 1887 kw_only=False, 1888 ) 1889 for name in ("counter", "_default", "repr", "cmp", "hash", "init") 1890 ) + ( 1891 Attribute( 1892 name="metadata", 1893 default=None, 1894 validator=None, 1895 repr=True, 1896 cmp=True, 1897 hash=False, 1898 init=True, 1899 kw_only=False, 1900 ), 1901 ) 1902 cls_counter = 0 1903 1904 def __init__( 1905 self, 1906 default, 1907 validator, 1908 repr, 1909 cmp, 1910 hash, 1911 init, 1912 converter, 1913 metadata, 1914 type, 1915 kw_only, 1916 ): 1917 _CountingAttr.cls_counter += 1 1918 self.counter = _CountingAttr.cls_counter 1919 self._default = default 1920 # If validator is a list/tuple, wrap it using helper validator. 1921 if validator and isinstance(validator, (list, tuple)): 1922 self._validator = and_(*validator) 1923 else: 1924 self._validator = validator 1925 self.repr = repr 1926 self.cmp = cmp 1927 self.hash = hash 1928 self.init = init 1929 self.converter = converter 1930 self.metadata = metadata 1931 self.type = type 1932 self.kw_only = kw_only 1933 1934 def validator(self, meth): 1935 """ 1936 Decorator that adds *meth* to the list of validators. 1937 1938 Returns *meth* unchanged. 1939 1940 .. versionadded:: 17.1.0 1941 """ 1942 if self._validator is None: 1943 self._validator = meth 1944 else: 1945 self._validator = and_(self._validator, meth) 1946 return meth 1947 1948 def default(self, meth): 1949 """ 1950 Decorator that allows to set the default for an attribute. 1951 1952 Returns *meth* unchanged. 1953 1954 :raises DefaultAlreadySetError: If default has been set before. 1955 1956 .. versionadded:: 17.1.0 1957 """ 1958 if self._default is not NOTHING: 1959 raise DefaultAlreadySetError() 1960 1961 self._default = Factory(meth, takes_self=True) 1962 1963 return meth 1964 1965 1966_CountingAttr = _add_cmp(_add_repr(_CountingAttr)) 1967 1968 1969@attrs(slots=True, init=False, hash=True) 1970class Factory(object): 1971 """ 1972 Stores a factory callable. 1973 1974 If passed as the default value to :func:`attr.ib`, the factory is used to 1975 generate a new value. 1976 1977 :param callable factory: A callable that takes either none or exactly one 1978 mandatory positional argument depending on *takes_self*. 1979 :param bool takes_self: Pass the partially initialized instance that is 1980 being initialized as a positional argument. 1981 1982 .. versionadded:: 17.1.0 *takes_self* 1983 """ 1984 1985 factory = attrib() 1986 takes_self = attrib() 1987 1988 def __init__(self, factory, takes_self=False): 1989 """ 1990 `Factory` is part of the default machinery so if we want a default 1991 value here, we have to implement it ourselves. 1992 """ 1993 self.factory = factory 1994 self.takes_self = takes_self 1995 1996 1997def make_class(name, attrs, bases=(object,), **attributes_arguments): 1998 """ 1999 A quick way to create a new class called *name* with *attrs*. 2000 2001 :param name: The name for the new class. 2002 :type name: str 2003 2004 :param attrs: A list of names or a dictionary of mappings of names to 2005 attributes. 2006 2007 If *attrs* is a list or an ordered dict (:class:`dict` on Python 3.6+, 2008 :class:`collections.OrderedDict` otherwise), the order is deduced from 2009 the order of the names or attributes inside *attrs*. Otherwise the 2010 order of the definition of the attributes is used. 2011 :type attrs: :class:`list` or :class:`dict` 2012 2013 :param tuple bases: Classes that the new class will subclass. 2014 2015 :param attributes_arguments: Passed unmodified to :func:`attr.s`. 2016 2017 :return: A new class with *attrs*. 2018 :rtype: type 2019 2020 .. versionadded:: 17.1.0 *bases* 2021 .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. 2022 """ 2023 if isinstance(attrs, dict): 2024 cls_dict = attrs 2025 elif isinstance(attrs, (list, tuple)): 2026 cls_dict = dict((a, attrib()) for a in attrs) 2027 else: 2028 raise TypeError("attrs argument must be a dict or a list.") 2029 2030 post_init = cls_dict.pop("__attrs_post_init__", None) 2031 type_ = type( 2032 name, 2033 bases, 2034 {} if post_init is None else {"__attrs_post_init__": post_init}, 2035 ) 2036 # For pickling to work, the __module__ variable needs to be set to the 2037 # frame where the class is created. Bypass this step in environments where 2038 # sys._getframe is not defined (Jython for example) or sys._getframe is not 2039 # defined for arguments greater than 0 (IronPython). 2040 try: 2041 type_.__module__ = sys._getframe(1).f_globals.get( 2042 "__name__", "__main__" 2043 ) 2044 except (AttributeError, ValueError): 2045 pass 2046 2047 return _attrs(these=cls_dict, **attributes_arguments)(type_) 2048 2049 2050# These are required by within this module so we define them here and merely 2051# import into .validators. 2052 2053 2054@attrs(slots=True, hash=True) 2055class _AndValidator(object): 2056 """ 2057 Compose many validators to a single one. 2058 """ 2059 2060 _validators = attrib() 2061 2062 def __call__(self, inst, attr, value): 2063 for v in self._validators: 2064 v(inst, attr, value) 2065 2066 2067def and_(*validators): 2068 """ 2069 A validator that composes multiple validators into one. 2070 2071 When called on a value, it runs all wrapped validators. 2072 2073 :param validators: Arbitrary number of validators. 2074 :type validators: callables 2075 2076 .. versionadded:: 17.1.0 2077 """ 2078 vals = [] 2079 for validator in validators: 2080 vals.extend( 2081 validator._validators 2082 if isinstance(validator, _AndValidator) 2083 else [validator] 2084 ) 2085 2086 return _AndValidator(tuple(vals)) 2087