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