Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/attr/_make.py
7759 views
# SPDX-License-Identifier: MIT12from __future__ import absolute_import, division, print_function34import copy5import inspect6import linecache7import sys8import warnings910from operator import itemgetter1112# We need to import _compat itself in addition to the _compat members to avoid13# having the thread-local in the globals here.14from . import _compat, _config, setters15from ._compat import (16HAS_F_STRINGS,17PY2,18PY310,19PYPY,20isclass,21iteritems,22metadata_proxy,23new_class,24ordered_dict,25set_closure_cell,26)27from .exceptions import (28DefaultAlreadySetError,29FrozenInstanceError,30NotAnAttrsClassError,31PythonTooOldError,32UnannotatedAttributeError,33)343536if not PY2:37import typing383940# This is used at least twice, so cache it here.41_obj_setattr = object.__setattr__42_init_converter_pat = "__attr_converter_%s"43_init_factory_pat = "__attr_factory_{}"44_tuple_property_pat = (45" {attr_name} = _attrs_property(_attrs_itemgetter({index}))"46)47_classvar_prefixes = (48"typing.ClassVar",49"t.ClassVar",50"ClassVar",51"typing_extensions.ClassVar",52)53# we don't use a double-underscore prefix because that triggers54# name mangling when trying to create a slot for the field55# (when slots=True)56_hash_cache_field = "_attrs_cached_hash"5758_empty_metadata_singleton = metadata_proxy({})5960# Unique object for unequivocal getattr() defaults.61_sentinel = object()6263_ng_default_on_setattr = setters.pipe(setters.convert, setters.validate)646566class _Nothing(object):67"""68Sentinel class to indicate the lack of a value when ``None`` is ambiguous.6970``_Nothing`` is a singleton. There is only ever one of it.7172.. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False.73"""7475_singleton = None7677def __new__(cls):78if _Nothing._singleton is None:79_Nothing._singleton = super(_Nothing, cls).__new__(cls)80return _Nothing._singleton8182def __repr__(self):83return "NOTHING"8485def __bool__(self):86return False8788def __len__(self):89return 0 # __bool__ for Python 2909192NOTHING = _Nothing()93"""94Sentinel to indicate the lack of a value when ``None`` is ambiguous.95"""969798class _CacheHashWrapper(int):99"""100An integer subclass that pickles / copies as None101102This is used for non-slots classes with ``cache_hash=True``, to avoid103serializing a potentially (even likely) invalid hash value. Since ``None``104is the default value for uncalculated hashes, whenever this is copied,105the copy's value for the hash should automatically reset.106107See GH #613 for more details.108"""109110if PY2:111# For some reason `type(None)` isn't callable in Python 2, but we don't112# actually need a constructor for None objects, we just need any113# available function that returns None.114def __reduce__(self, _none_constructor=getattr, _args=(0, "", None)):115return _none_constructor, _args116117else:118119def __reduce__(self, _none_constructor=type(None), _args=()):120return _none_constructor, _args121122123def attrib(124default=NOTHING,125validator=None,126repr=True,127cmp=None,128hash=None,129init=True,130metadata=None,131type=None,132converter=None,133factory=None,134kw_only=False,135eq=None,136order=None,137on_setattr=None,138):139"""140Create a new attribute on a class.141142.. warning::143144Does *not* do anything unless the class is also decorated with145`attr.s`!146147:param default: A value that is used if an ``attrs``-generated ``__init__``148is used and no value is passed while instantiating or the attribute is149excluded using ``init=False``.150151If the value is an instance of `attrs.Factory`, its callable will be152used to construct a new value (useful for mutable data types like lists153or dicts).154155If a default is not set (or set manually to `attrs.NOTHING`), a value156*must* be supplied when instantiating; otherwise a `TypeError`157will be raised.158159The default can also be set using decorator notation as shown below.160161:type default: Any value162163:param callable factory: Syntactic sugar for164``default=attr.Factory(factory)``.165166:param validator: `callable` that is called by ``attrs``-generated167``__init__`` methods after the instance has been initialized. They168receive the initialized instance, the :func:`~attrs.Attribute`, and the169passed value.170171The return value is *not* inspected so the validator has to throw an172exception itself.173174If a `list` is passed, its items are treated as validators and must175all pass.176177Validators can be globally disabled and re-enabled using178`get_run_validators`.179180The validator can also be set using decorator notation as shown below.181182:type validator: `callable` or a `list` of `callable`\\ s.183184:param repr: Include this attribute in the generated ``__repr__``185method. If ``True``, include the attribute; if ``False``, omit it. By186default, the built-in ``repr()`` function is used. To override how the187attribute value is formatted, pass a ``callable`` that takes a single188value and returns a string. Note that the resulting string is used189as-is, i.e. it will be used directly *instead* of calling ``repr()``190(the default).191:type repr: a `bool` or a `callable` to use a custom function.192193:param eq: If ``True`` (default), include this attribute in the194generated ``__eq__`` and ``__ne__`` methods that check two instances195for equality. To override how the attribute value is compared,196pass a ``callable`` that takes a single value and returns the value197to be compared.198:type eq: a `bool` or a `callable`.199200:param order: If ``True`` (default), include this attributes in the201generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods.202To override how the attribute value is ordered,203pass a ``callable`` that takes a single value and returns the value204to be ordered.205:type order: a `bool` or a `callable`.206207:param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the208same value. Must not be mixed with *eq* or *order*.209:type cmp: a `bool` or a `callable`.210211:param Optional[bool] hash: Include this attribute in the generated212``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This213is the correct behavior according the Python spec. Setting this value214to anything else than ``None`` is *discouraged*.215:param bool init: Include this attribute in the generated ``__init__``216method. It is possible to set this to ``False`` and set a default217value. In that case this attributed is unconditionally initialized218with the specified default value or factory.219:param callable converter: `callable` that is called by220``attrs``-generated ``__init__`` methods to convert attribute's value221to the desired format. It is given the passed-in value, and the222returned value will be used as the new value of the attribute. The223value is converted before being passed to the validator, if any.224:param metadata: An arbitrary mapping, to be used by third-party225components. See `extending_metadata`.226:param type: The type of the attribute. In Python 3.6 or greater, the227preferred method to specify the type is using a variable annotation228(see `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_).229This argument is provided for backward compatibility.230Regardless of the approach used, the type will be stored on231``Attribute.type``.232233Please note that ``attrs`` doesn't do anything with this metadata by234itself. You can use it as part of your own code or for235`static type checking <types>`.236:param kw_only: Make this attribute keyword-only (Python 3+)237in the generated ``__init__`` (if ``init`` is ``False``, this238parameter is ignored).239:param on_setattr: Allows to overwrite the *on_setattr* setting from240`attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used.241Set to `attrs.setters.NO_OP` to run **no** `setattr` hooks for this242attribute -- regardless of the setting in `attr.s`.243:type on_setattr: `callable`, or a list of callables, or `None`, or244`attrs.setters.NO_OP`245246.. versionadded:: 15.2.0 *convert*247.. versionadded:: 16.3.0 *metadata*248.. versionchanged:: 17.1.0 *validator* can be a ``list`` now.249.. versionchanged:: 17.1.0250*hash* is ``None`` and therefore mirrors *eq* by default.251.. versionadded:: 17.3.0 *type*252.. deprecated:: 17.4.0 *convert*253.. versionadded:: 17.4.0 *converter* as a replacement for the deprecated254*convert* to achieve consistency with other noun-based arguments.255.. versionadded:: 18.1.0256``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.257.. versionadded:: 18.2.0 *kw_only*258.. versionchanged:: 19.2.0 *convert* keyword argument removed.259.. versionchanged:: 19.2.0 *repr* also accepts a custom callable.260.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.261.. versionadded:: 19.2.0 *eq* and *order*262.. versionadded:: 20.1.0 *on_setattr*263.. versionchanged:: 20.3.0 *kw_only* backported to Python 2264.. versionchanged:: 21.1.0265*eq*, *order*, and *cmp* also accept a custom callable266.. versionchanged:: 21.1.0 *cmp* undeprecated267"""268eq, eq_key, order, order_key = _determine_attrib_eq_order(269cmp, eq, order, True270)271272if hash is not None and hash is not True and hash is not False:273raise TypeError(274"Invalid value for hash. Must be True, False, or None."275)276277if factory is not None:278if default is not NOTHING:279raise ValueError(280"The `default` and `factory` arguments are mutually "281"exclusive."282)283if not callable(factory):284raise ValueError("The `factory` argument must be a callable.")285default = Factory(factory)286287if metadata is None:288metadata = {}289290# Apply syntactic sugar by auto-wrapping.291if isinstance(on_setattr, (list, tuple)):292on_setattr = setters.pipe(*on_setattr)293294if validator and isinstance(validator, (list, tuple)):295validator = and_(*validator)296297if converter and isinstance(converter, (list, tuple)):298converter = pipe(*converter)299300return _CountingAttr(301default=default,302validator=validator,303repr=repr,304cmp=None,305hash=hash,306init=init,307converter=converter,308metadata=metadata,309type=type,310kw_only=kw_only,311eq=eq,312eq_key=eq_key,313order=order,314order_key=order_key,315on_setattr=on_setattr,316)317318319def _compile_and_eval(script, globs, locs=None, filename=""):320"""321"Exec" the script with the given global (globs) and local (locs) variables.322"""323bytecode = compile(script, filename, "exec")324eval(bytecode, globs, locs)325326327def _make_method(name, script, filename, globs=None):328"""329Create the method with the script given and return the method object.330"""331locs = {}332if globs is None:333globs = {}334335# In order of debuggers like PDB being able to step through the code,336# we add a fake linecache entry.337count = 1338base_filename = filename339while True:340linecache_tuple = (341len(script),342None,343script.splitlines(True),344filename,345)346old_val = linecache.cache.setdefault(filename, linecache_tuple)347if old_val == linecache_tuple:348break349else:350filename = "{}-{}>".format(base_filename[:-1], count)351count += 1352353_compile_and_eval(script, globs, locs, filename)354355return locs[name]356357358def _make_attr_tuple_class(cls_name, attr_names):359"""360Create a tuple subclass to hold `Attribute`s for an `attrs` class.361362The subclass is a bare tuple with properties for names.363364class MyClassAttributes(tuple):365__slots__ = ()366x = property(itemgetter(0))367"""368attr_class_name = "{}Attributes".format(cls_name)369attr_class_template = [370"class {}(tuple):".format(attr_class_name),371" __slots__ = ()",372]373if attr_names:374for i, attr_name in enumerate(attr_names):375attr_class_template.append(376_tuple_property_pat.format(index=i, attr_name=attr_name)377)378else:379attr_class_template.append(" pass")380globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}381_compile_and_eval("\n".join(attr_class_template), globs)382return globs[attr_class_name]383384385# Tuple class for extracted attributes from a class definition.386# `base_attrs` is a subset of `attrs`.387_Attributes = _make_attr_tuple_class(388"_Attributes",389[390# all attributes to build dunder methods for391"attrs",392# attributes that have been inherited393"base_attrs",394# map inherited attributes to their originating classes395"base_attrs_map",396],397)398399400def _is_class_var(annot):401"""402Check whether *annot* is a typing.ClassVar.403404The string comparison hack is used to avoid evaluating all string405annotations which would put attrs-based classes at a performance406disadvantage compared to plain old classes.407"""408annot = str(annot)409410# Annotation can be quoted.411if annot.startswith(("'", '"')) and annot.endswith(("'", '"')):412annot = annot[1:-1]413414return annot.startswith(_classvar_prefixes)415416417def _has_own_attribute(cls, attrib_name):418"""419Check whether *cls* defines *attrib_name* (and doesn't just inherit it).420421Requires Python 3.422"""423attr = getattr(cls, attrib_name, _sentinel)424if attr is _sentinel:425return False426427for base_cls in cls.__mro__[1:]:428a = getattr(base_cls, attrib_name, None)429if attr is a:430return False431432return True433434435def _get_annotations(cls):436"""437Get annotations for *cls*.438"""439if _has_own_attribute(cls, "__annotations__"):440return cls.__annotations__441442return {}443444445def _counter_getter(e):446"""447Key function for sorting to avoid re-creating a lambda for every class.448"""449return e[1].counter450451452def _collect_base_attrs(cls, taken_attr_names):453"""454Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.455"""456base_attrs = []457base_attr_map = {} # A dictionary of base attrs to their classes.458459# Traverse the MRO and collect attributes.460for base_cls in reversed(cls.__mro__[1:-1]):461for a in getattr(base_cls, "__attrs_attrs__", []):462if a.inherited or a.name in taken_attr_names:463continue464465a = a.evolve(inherited=True)466base_attrs.append(a)467base_attr_map[a.name] = base_cls468469# For each name, only keep the freshest definition i.e. the furthest at the470# back. base_attr_map is fine because it gets overwritten with every new471# instance.472filtered = []473seen = set()474for a in reversed(base_attrs):475if a.name in seen:476continue477filtered.insert(0, a)478seen.add(a.name)479480return filtered, base_attr_map481482483def _collect_base_attrs_broken(cls, taken_attr_names):484"""485Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.486487N.B. *taken_attr_names* will be mutated.488489Adhere to the old incorrect behavior.490491Notably it collects from the front and considers inherited attributes which492leads to the buggy behavior reported in #428.493"""494base_attrs = []495base_attr_map = {} # A dictionary of base attrs to their classes.496497# Traverse the MRO and collect attributes.498for base_cls in cls.__mro__[1:-1]:499for a in getattr(base_cls, "__attrs_attrs__", []):500if a.name in taken_attr_names:501continue502503a = a.evolve(inherited=True)504taken_attr_names.add(a.name)505base_attrs.append(a)506base_attr_map[a.name] = base_cls507508return base_attrs, base_attr_map509510511def _transform_attrs(512cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer513):514"""515Transform all `_CountingAttr`s on a class into `Attribute`s.516517If *these* is passed, use that and don't look for them on the class.518519*collect_by_mro* is True, collect them in the correct MRO order, otherwise520use the old -- incorrect -- order. See #428.521522Return an `_Attributes`.523"""524cd = cls.__dict__525anns = _get_annotations(cls)526527if these is not None:528ca_list = [(name, ca) for name, ca in iteritems(these)]529530if not isinstance(these, ordered_dict):531ca_list.sort(key=_counter_getter)532elif auto_attribs is True:533ca_names = {534name535for name, attr in cd.items()536if isinstance(attr, _CountingAttr)537}538ca_list = []539annot_names = set()540for attr_name, type in anns.items():541if _is_class_var(type):542continue543annot_names.add(attr_name)544a = cd.get(attr_name, NOTHING)545546if not isinstance(a, _CountingAttr):547if a is NOTHING:548a = attrib()549else:550a = attrib(default=a)551ca_list.append((attr_name, a))552553unannotated = ca_names - annot_names554if len(unannotated) > 0:555raise UnannotatedAttributeError(556"The following `attr.ib`s lack a type annotation: "557+ ", ".join(558sorted(unannotated, key=lambda n: cd.get(n).counter)559)560+ "."561)562else:563ca_list = sorted(564(565(name, attr)566for name, attr in cd.items()567if isinstance(attr, _CountingAttr)568),569key=lambda e: e[1].counter,570)571572own_attrs = [573Attribute.from_counting_attr(574name=attr_name, ca=ca, type=anns.get(attr_name)575)576for attr_name, ca in ca_list577]578579if collect_by_mro:580base_attrs, base_attr_map = _collect_base_attrs(581cls, {a.name for a in own_attrs}582)583else:584base_attrs, base_attr_map = _collect_base_attrs_broken(585cls, {a.name for a in own_attrs}586)587588if kw_only:589own_attrs = [a.evolve(kw_only=True) for a in own_attrs]590base_attrs = [a.evolve(kw_only=True) for a in base_attrs]591592attrs = base_attrs + own_attrs593594# Mandatory vs non-mandatory attr order only matters when they are part of595# the __init__ signature and when they aren't kw_only (which are moved to596# the end and can be mandatory or non-mandatory in any order, as they will597# be specified as keyword args anyway). Check the order of those attrs:598had_default = False599for a in (a for a in attrs if a.init is not False and a.kw_only is False):600if had_default is True and a.default is NOTHING:601raise ValueError(602"No mandatory attributes allowed after an attribute with a "603"default value or factory. Attribute in question: %r" % (a,)604)605606if had_default is False and a.default is not NOTHING:607had_default = True608609if field_transformer is not None:610attrs = field_transformer(cls, attrs)611612# Create AttrsClass *after* applying the field_transformer since it may613# add or remove attributes!614attr_names = [a.name for a in attrs]615AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)616617return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map))618619620if PYPY:621622def _frozen_setattrs(self, name, value):623"""624Attached to frozen classes as __setattr__.625"""626if isinstance(self, BaseException) and name in (627"__cause__",628"__context__",629):630BaseException.__setattr__(self, name, value)631return632633raise FrozenInstanceError()634635else:636637def _frozen_setattrs(self, name, value):638"""639Attached to frozen classes as __setattr__.640"""641raise FrozenInstanceError()642643644def _frozen_delattrs(self, name):645"""646Attached to frozen classes as __delattr__.647"""648raise FrozenInstanceError()649650651class _ClassBuilder(object):652"""653Iteratively build *one* class.654"""655656__slots__ = (657"_attr_names",658"_attrs",659"_base_attr_map",660"_base_names",661"_cache_hash",662"_cls",663"_cls_dict",664"_delete_attribs",665"_frozen",666"_has_pre_init",667"_has_post_init",668"_is_exc",669"_on_setattr",670"_slots",671"_weakref_slot",672"_wrote_own_setattr",673"_has_custom_setattr",674)675676def __init__(677self,678cls,679these,680slots,681frozen,682weakref_slot,683getstate_setstate,684auto_attribs,685kw_only,686cache_hash,687is_exc,688collect_by_mro,689on_setattr,690has_custom_setattr,691field_transformer,692):693attrs, base_attrs, base_map = _transform_attrs(694cls,695these,696auto_attribs,697kw_only,698collect_by_mro,699field_transformer,700)701702self._cls = cls703self._cls_dict = dict(cls.__dict__) if slots else {}704self._attrs = attrs705self._base_names = set(a.name for a in base_attrs)706self._base_attr_map = base_map707self._attr_names = tuple(a.name for a in attrs)708self._slots = slots709self._frozen = frozen710self._weakref_slot = weakref_slot711self._cache_hash = cache_hash712self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))713self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))714self._delete_attribs = not bool(these)715self._is_exc = is_exc716self._on_setattr = on_setattr717718self._has_custom_setattr = has_custom_setattr719self._wrote_own_setattr = False720721self._cls_dict["__attrs_attrs__"] = self._attrs722723if frozen:724self._cls_dict["__setattr__"] = _frozen_setattrs725self._cls_dict["__delattr__"] = _frozen_delattrs726727self._wrote_own_setattr = True728elif on_setattr in (729_ng_default_on_setattr,730setters.validate,731setters.convert,732):733has_validator = has_converter = False734for a in attrs:735if a.validator is not None:736has_validator = True737if a.converter is not None:738has_converter = True739740if has_validator and has_converter:741break742if (743(744on_setattr == _ng_default_on_setattr745and not (has_validator or has_converter)746)747or (on_setattr == setters.validate and not has_validator)748or (on_setattr == setters.convert and not has_converter)749):750# If class-level on_setattr is set to convert + validate, but751# there's no field to convert or validate, pretend like there's752# no on_setattr.753self._on_setattr = None754755if getstate_setstate:756(757self._cls_dict["__getstate__"],758self._cls_dict["__setstate__"],759) = self._make_getstate_setstate()760761def __repr__(self):762return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__)763764def build_class(self):765"""766Finalize class based on the accumulated configuration.767768Builder cannot be used after calling this method.769"""770if self._slots is True:771return self._create_slots_class()772else:773return self._patch_original_class()774775def _patch_original_class(self):776"""777Apply accumulated methods and return the class.778"""779cls = self._cls780base_names = self._base_names781782# Clean class of attribute definitions (`attr.ib()`s).783if self._delete_attribs:784for name in self._attr_names:785if (786name not in base_names787and getattr(cls, name, _sentinel) is not _sentinel788):789try:790delattr(cls, name)791except AttributeError:792# This can happen if a base class defines a class793# variable and we want to set an attribute with the794# same name by using only a type annotation.795pass796797# Attach our dunder methods.798for name, value in self._cls_dict.items():799setattr(cls, name, value)800801# If we've inherited an attrs __setattr__ and don't write our own,802# reset it to object's.803if not self._wrote_own_setattr and getattr(804cls, "__attrs_own_setattr__", False805):806cls.__attrs_own_setattr__ = False807808if not self._has_custom_setattr:809cls.__setattr__ = object.__setattr__810811return cls812813def _create_slots_class(self):814"""815Build and return a new class with a `__slots__` attribute.816"""817cd = {818k: v819for k, v in iteritems(self._cls_dict)820if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")821}822823# If our class doesn't have its own implementation of __setattr__824# (either from the user or by us), check the bases, if one of them has825# an attrs-made __setattr__, that needs to be reset. We don't walk the826# MRO because we only care about our immediate base classes.827# XXX: This can be confused by subclassing a slotted attrs class with828# XXX: a non-attrs class and subclass the resulting class with an attrs829# XXX: class. See `test_slotted_confused` for details. For now that's830# XXX: OK with us.831if not self._wrote_own_setattr:832cd["__attrs_own_setattr__"] = False833834if not self._has_custom_setattr:835for base_cls in self._cls.__bases__:836if base_cls.__dict__.get("__attrs_own_setattr__", False):837cd["__setattr__"] = object.__setattr__838break839840# Traverse the MRO to collect existing slots841# and check for an existing __weakref__.842existing_slots = dict()843weakref_inherited = False844for base_cls in self._cls.__mro__[1:-1]:845if base_cls.__dict__.get("__weakref__", None) is not None:846weakref_inherited = True847existing_slots.update(848{849name: getattr(base_cls, name)850for name in getattr(base_cls, "__slots__", [])851}852)853854base_names = set(self._base_names)855856names = self._attr_names857if (858self._weakref_slot859and "__weakref__" not in getattr(self._cls, "__slots__", ())860and "__weakref__" not in names861and not weakref_inherited862):863names += ("__weakref__",)864865# We only add the names of attributes that aren't inherited.866# Setting __slots__ to inherited attributes wastes memory.867slot_names = [name for name in names if name not in base_names]868# There are slots for attributes from current class869# that are defined in parent classes.870# As their descriptors may be overriden by a child class,871# we collect them here and update the class dict872reused_slots = {873slot: slot_descriptor874for slot, slot_descriptor in iteritems(existing_slots)875if slot in slot_names876}877slot_names = [name for name in slot_names if name not in reused_slots]878cd.update(reused_slots)879if self._cache_hash:880slot_names.append(_hash_cache_field)881cd["__slots__"] = tuple(slot_names)882883qualname = getattr(self._cls, "__qualname__", None)884if qualname is not None:885cd["__qualname__"] = qualname886887# Create new class based on old class and our methods.888cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd)889890# The following is a fix for891# <https://github.com/python-attrs/attrs/issues/102>. On Python 3,892# if a method mentions `__class__` or uses the no-arg super(), the893# compiler will bake a reference to the class in the method itself894# as `method.__closure__`. Since we replace the class with a895# clone, we rewrite these references so it keeps working.896for item in cls.__dict__.values():897if isinstance(item, (classmethod, staticmethod)):898# Class- and staticmethods hide their functions inside.899# These might need to be rewritten as well.900closure_cells = getattr(item.__func__, "__closure__", None)901elif isinstance(item, property):902# Workaround for property `super()` shortcut (PY3-only).903# There is no universal way for other descriptors.904closure_cells = getattr(item.fget, "__closure__", None)905else:906closure_cells = getattr(item, "__closure__", None)907908if not closure_cells: # Catch None or the empty list.909continue910for cell in closure_cells:911try:912match = cell.cell_contents is self._cls913except ValueError: # ValueError: Cell is empty914pass915else:916if match:917set_closure_cell(cell, cls)918919return cls920921def add_repr(self, ns):922self._cls_dict["__repr__"] = self._add_method_dunders(923_make_repr(self._attrs, ns, self._cls)924)925return self926927def add_str(self):928repr = self._cls_dict.get("__repr__")929if repr is None:930raise ValueError(931"__str__ can only be generated if a __repr__ exists."932)933934def __str__(self):935return self.__repr__()936937self._cls_dict["__str__"] = self._add_method_dunders(__str__)938return self939940def _make_getstate_setstate(self):941"""942Create custom __setstate__ and __getstate__ methods.943"""944# __weakref__ is not writable.945state_attr_names = tuple(946an for an in self._attr_names if an != "__weakref__"947)948949def slots_getstate(self):950"""951Automatically created by attrs.952"""953return tuple(getattr(self, name) for name in state_attr_names)954955hash_caching_enabled = self._cache_hash956957def slots_setstate(self, state):958"""959Automatically created by attrs.960"""961__bound_setattr = _obj_setattr.__get__(self, Attribute)962for name, value in zip(state_attr_names, state):963__bound_setattr(name, value)964965# The hash code cache is not included when the object is966# serialized, but it still needs to be initialized to None to967# indicate that the first call to __hash__ should be a cache968# miss.969if hash_caching_enabled:970__bound_setattr(_hash_cache_field, None)971972return slots_getstate, slots_setstate973974def make_unhashable(self):975self._cls_dict["__hash__"] = None976return self977978def add_hash(self):979self._cls_dict["__hash__"] = self._add_method_dunders(980_make_hash(981self._cls,982self._attrs,983frozen=self._frozen,984cache_hash=self._cache_hash,985)986)987988return self989990def add_init(self):991self._cls_dict["__init__"] = self._add_method_dunders(992_make_init(993self._cls,994self._attrs,995self._has_pre_init,996self._has_post_init,997self._frozen,998self._slots,999self._cache_hash,1000self._base_attr_map,1001self._is_exc,1002self._on_setattr,1003attrs_init=False,1004)1005)10061007return self10081009def add_match_args(self):1010self._cls_dict["__match_args__"] = tuple(1011field.name1012for field in self._attrs1013if field.init and not field.kw_only1014)10151016def add_attrs_init(self):1017self._cls_dict["__attrs_init__"] = self._add_method_dunders(1018_make_init(1019self._cls,1020self._attrs,1021self._has_pre_init,1022self._has_post_init,1023self._frozen,1024self._slots,1025self._cache_hash,1026self._base_attr_map,1027self._is_exc,1028self._on_setattr,1029attrs_init=True,1030)1031)10321033return self10341035def add_eq(self):1036cd = self._cls_dict10371038cd["__eq__"] = self._add_method_dunders(1039_make_eq(self._cls, self._attrs)1040)1041cd["__ne__"] = self._add_method_dunders(_make_ne())10421043return self10441045def add_order(self):1046cd = self._cls_dict10471048cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = (1049self._add_method_dunders(meth)1050for meth in _make_order(self._cls, self._attrs)1051)10521053return self10541055def add_setattr(self):1056if self._frozen:1057return self10581059sa_attrs = {}1060for a in self._attrs:1061on_setattr = a.on_setattr or self._on_setattr1062if on_setattr and on_setattr is not setters.NO_OP:1063sa_attrs[a.name] = a, on_setattr10641065if not sa_attrs:1066return self10671068if self._has_custom_setattr:1069# We need to write a __setattr__ but there already is one!1070raise ValueError(1071"Can't combine custom __setattr__ with on_setattr hooks."1072)10731074# docstring comes from _add_method_dunders1075def __setattr__(self, name, val):1076try:1077a, hook = sa_attrs[name]1078except KeyError:1079nval = val1080else:1081nval = hook(self, a, val)10821083_obj_setattr(self, name, nval)10841085self._cls_dict["__attrs_own_setattr__"] = True1086self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__)1087self._wrote_own_setattr = True10881089return self10901091def _add_method_dunders(self, method):1092"""1093Add __module__ and __qualname__ to a *method* if possible.1094"""1095try:1096method.__module__ = self._cls.__module__1097except AttributeError:1098pass10991100try:1101method.__qualname__ = ".".join(1102(self._cls.__qualname__, method.__name__)1103)1104except AttributeError:1105pass11061107try:1108method.__doc__ = "Method generated by attrs for class %s." % (1109self._cls.__qualname__,1110)1111except AttributeError:1112pass11131114return method111511161117_CMP_DEPRECATION = (1118"The usage of `cmp` is deprecated and will be removed on or after "1119"2021-06-01. Please use `eq` and `order` instead."1120)112111221123def _determine_attrs_eq_order(cmp, eq, order, default_eq):1124"""1125Validate the combination of *cmp*, *eq*, and *order*. Derive the effective1126values of eq and order. If *eq* is None, set it to *default_eq*.1127"""1128if cmp is not None and any((eq is not None, order is not None)):1129raise ValueError("Don't mix `cmp` with `eq' and `order`.")11301131# cmp takes precedence due to bw-compatibility.1132if cmp is not None:1133return cmp, cmp11341135# If left None, equality is set to the specified default and ordering1136# mirrors equality.1137if eq is None:1138eq = default_eq11391140if order is None:1141order = eq11421143if eq is False and order is True:1144raise ValueError("`order` can only be True if `eq` is True too.")11451146return eq, order114711481149def _determine_attrib_eq_order(cmp, eq, order, default_eq):1150"""1151Validate the combination of *cmp*, *eq*, and *order*. Derive the effective1152values of eq and order. If *eq* is None, set it to *default_eq*.1153"""1154if cmp is not None and any((eq is not None, order is not None)):1155raise ValueError("Don't mix `cmp` with `eq' and `order`.")11561157def decide_callable_or_boolean(value):1158"""1159Decide whether a key function is used.1160"""1161if callable(value):1162value, key = True, value1163else:1164key = None1165return value, key11661167# cmp takes precedence due to bw-compatibility.1168if cmp is not None:1169cmp, cmp_key = decide_callable_or_boolean(cmp)1170return cmp, cmp_key, cmp, cmp_key11711172# If left None, equality is set to the specified default and ordering1173# mirrors equality.1174if eq is None:1175eq, eq_key = default_eq, None1176else:1177eq, eq_key = decide_callable_or_boolean(eq)11781179if order is None:1180order, order_key = eq, eq_key1181else:1182order, order_key = decide_callable_or_boolean(order)11831184if eq is False and order is True:1185raise ValueError("`order` can only be True if `eq` is True too.")11861187return eq, eq_key, order, order_key118811891190def _determine_whether_to_implement(1191cls, flag, auto_detect, dunders, default=True1192):1193"""1194Check whether we should implement a set of methods for *cls*.11951196*flag* is the argument passed into @attr.s like 'init', *auto_detect* the1197same as passed into @attr.s and *dunders* is a tuple of attribute names1198whose presence signal that the user has implemented it themselves.11991200Return *default* if no reason for either for or against is found.12011202auto_detect must be False on Python 2.1203"""1204if flag is True or flag is False:1205return flag12061207if flag is None and auto_detect is False:1208return default12091210# Logically, flag is None and auto_detect is True here.1211for dunder in dunders:1212if _has_own_attribute(cls, dunder):1213return False12141215return default121612171218def attrs(1219maybe_cls=None,1220these=None,1221repr_ns=None,1222repr=None,1223cmp=None,1224hash=None,1225init=None,1226slots=False,1227frozen=False,1228weakref_slot=True,1229str=False,1230auto_attribs=False,1231kw_only=False,1232cache_hash=False,1233auto_exc=False,1234eq=None,1235order=None,1236auto_detect=False,1237collect_by_mro=False,1238getstate_setstate=None,1239on_setattr=None,1240field_transformer=None,1241match_args=True,1242):1243r"""1244A class decorator that adds `dunder1245<https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the1246specified attributes using `attr.ib` or the *these* argument.12471248:param these: A dictionary of name to `attr.ib` mappings. This is1249useful to avoid the definition of your attributes within the class body1250because you can't (e.g. if you want to add ``__repr__`` methods to1251Django models) or don't want to.12521253If *these* is not ``None``, ``attrs`` will *not* search the class body1254for attributes and will *not* remove any attributes from it.12551256If *these* is an ordered dict (`dict` on Python 3.6+,1257`collections.OrderedDict` otherwise), the order is deduced from1258the order of the attributes inside *these*. Otherwise the order1259of the definition of the attributes is used.12601261:type these: `dict` of `str` to `attr.ib`12621263:param str repr_ns: When using nested classes, there's no way in Python 21264to automatically detect that. Therefore it's possible to set the1265namespace explicitly for a more meaningful ``repr`` output.1266:param bool auto_detect: Instead of setting the *init*, *repr*, *eq*,1267*order*, and *hash* arguments explicitly, assume they are set to1268``True`` **unless any** of the involved methods for one of the1269arguments is implemented in the *current* class (i.e. it is *not*1270inherited from some base class).12711272So for example by implementing ``__eq__`` on a class yourself,1273``attrs`` will deduce ``eq=False`` and will create *neither*1274``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible1275``__ne__`` by default, so it *should* be enough to only implement1276``__eq__`` in most cases).12771278.. warning::12791280If you prevent ``attrs`` from creating the ordering methods for you1281(``order=False``, e.g. by implementing ``__le__``), it becomes1282*your* responsibility to make sure its ordering is sound. The best1283way is to use the `functools.total_ordering` decorator.128412851286Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*,1287*cmp*, or *hash* overrides whatever *auto_detect* would determine.12881289*auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises1290an `attrs.exceptions.PythonTooOldError`.12911292:param bool repr: Create a ``__repr__`` method with a human readable1293representation of ``attrs`` attributes..1294:param bool str: Create a ``__str__`` method that is identical to1295``__repr__``. This is usually not necessary except for1296`Exception`\ s.1297:param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__``1298and ``__ne__`` methods that check two instances for equality.12991300They compare the instances as if they were tuples of their ``attrs``1301attributes if and only if the types of both classes are *identical*!1302:param Optional[bool] order: If ``True``, add ``__lt__``, ``__le__``,1303``__gt__``, and ``__ge__`` methods that behave like *eq* above and1304allow instances to be ordered. If ``None`` (default) mirror value of1305*eq*.1306:param Optional[bool] cmp: Setting *cmp* is equivalent to setting *eq*1307and *order* to the same value. Must not be mixed with *eq* or *order*.1308:param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method1309is generated according how *eq* and *frozen* are set.131013111. If *both* are True, ``attrs`` will generate a ``__hash__`` for you.13122. If *eq* is True and *frozen* is False, ``__hash__`` will be set to1313None, marking it unhashable (which it is).13143. If *eq* is False, ``__hash__`` will be left untouched meaning the1315``__hash__`` method of the base class will be used (if base class is1316``object``, this means it will fall back to id-based hashing.).13171318Although not recommended, you can decide for yourself and force1319``attrs`` to create one (e.g. if the class is immutable even though you1320didn't freeze it programmatically) by passing ``True`` or not. Both of1321these cases are rather special and should be used carefully.13221323See our documentation on `hashing`, Python's documentation on1324`object.__hash__`, and the `GitHub issue that led to the default \1325behavior <https://github.com/python-attrs/attrs/issues/136>`_ for more1326details.1327:param bool init: Create a ``__init__`` method that initializes the1328``attrs`` attributes. Leading underscores are stripped for the argument1329name. If a ``__attrs_pre_init__`` method exists on the class, it will1330be called before the class is initialized. If a ``__attrs_post_init__``1331method exists on the class, it will be called after the class is fully1332initialized.13331334If ``init`` is ``False``, an ``__attrs_init__`` method will be1335injected instead. This allows you to define a custom ``__init__``1336method that can do pre-init work such as ``super().__init__()``,1337and then call ``__attrs_init__()`` and ``__attrs_post_init__()``.1338:param bool slots: Create a `slotted class <slotted classes>` that's more1339memory-efficient. Slotted classes are generally superior to the default1340dict classes, but have some gotchas you should know about, so we1341encourage you to read the `glossary entry <slotted classes>`.1342:param bool frozen: Make instances immutable after initialization. If1343someone attempts to modify a frozen instance,1344`attr.exceptions.FrozenInstanceError` is raised.13451346.. note::134713481. This is achieved by installing a custom ``__setattr__`` method1349on your class, so you can't implement your own.135013512. True immutability is impossible in Python.135213533. This *does* have a minor a runtime performance `impact1354<how-frozen>` when initializing new instances. In other words:1355``__init__`` is slightly slower with ``frozen=True``.135613574. If a class is frozen, you cannot modify ``self`` in1358``__attrs_post_init__`` or a self-written ``__init__``. You can1359circumvent that limitation by using1360``object.__setattr__(self, "attribute_name", value)``.136113625. Subclasses of a frozen class are frozen too.13631364:param bool weakref_slot: Make instances weak-referenceable. This has no1365effect unless ``slots`` is also enabled.1366:param bool auto_attribs: If ``True``, collect `PEP 526`_-annotated1367attributes (Python 3.6 and later only) from the class body.13681369In this case, you **must** annotate every field. If ``attrs``1370encounters a field that is set to an `attr.ib` but lacks a type1371annotation, an `attr.exceptions.UnannotatedAttributeError` is1372raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't1373want to set a type.13741375If you assign a value to those attributes (e.g. ``x: int = 42``), that1376value becomes the default value like if it were passed using1377``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also1378works as expected in most cases (see warning below).13791380Attributes annotated as `typing.ClassVar`, and attributes that are1381neither annotated nor set to an `attr.ib` are **ignored**.13821383.. warning::1384For features that use the attribute name to create decorators (e.g.1385`validators <validators>`), you still *must* assign `attr.ib` to1386them. Otherwise Python will either not find the name or try to use1387the default value to call e.g. ``validator`` on it.13881389These errors can be quite confusing and probably the most common bug1390report on our bug tracker.13911392.. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/1393:param bool kw_only: Make all attributes keyword-only (Python 3+)1394in the generated ``__init__`` (if ``init`` is ``False``, this1395parameter is ignored).1396:param bool cache_hash: Ensure that the object's hash code is computed1397only once and stored on the object. If this is set to ``True``,1398hashing must be either explicitly or implicitly enabled for this1399class. If the hash code is cached, avoid any reassignments of1400fields involved in hash code computation or mutations of the objects1401those fields point to after object creation. If such changes occur,1402the behavior of the object's hash code is undefined.1403:param bool auto_exc: If the class subclasses `BaseException`1404(which implicitly includes any subclass of any exception), the1405following happens to behave like a well-behaved Python exceptions1406class:14071408- the values for *eq*, *order*, and *hash* are ignored and the1409instances compare and hash by the instance's ids (N.B. ``attrs`` will1410*not* remove existing implementations of ``__hash__`` or the equality1411methods. It just won't add own ones.),1412- all attributes that are either passed into ``__init__`` or have a1413default value are additionally available as a tuple in the ``args``1414attribute,1415- the value of *str* is ignored leaving ``__str__`` to base classes.1416:param bool collect_by_mro: Setting this to `True` fixes the way ``attrs``1417collects attributes from base classes. The default behavior is1418incorrect in certain cases of multiple inheritance. It should be on by1419default but is kept off for backward-compatibility.14201421See issue `#428 <https://github.com/python-attrs/attrs/issues/428>`_ for1422more details.14231424:param Optional[bool] getstate_setstate:1425.. note::1426This is usually only interesting for slotted classes and you should1427probably just set *auto_detect* to `True`.14281429If `True`, ``__getstate__`` and1430``__setstate__`` are generated and attached to the class. This is1431necessary for slotted classes to be pickleable. If left `None`, it's1432`True` by default for slotted classes and ``False`` for dict classes.14331434If *auto_detect* is `True`, and *getstate_setstate* is left `None`,1435and **either** ``__getstate__`` or ``__setstate__`` is detected directly1436on the class (i.e. not inherited), it is set to `False` (this is usually1437what you want).14381439:param on_setattr: A callable that is run whenever the user attempts to set1440an attribute (either by assignment like ``i.x = 42`` or by using1441`setattr` like ``setattr(i, "x", 42)``). It receives the same arguments1442as validators: the instance, the attribute that is being modified, and1443the new value.14441445If no exception is raised, the attribute is set to the return value of1446the callable.14471448If a list of callables is passed, they're automatically wrapped in an1449`attrs.setters.pipe`.14501451:param Optional[callable] field_transformer:1452A function that is called with the original class object and all1453fields right before ``attrs`` finalizes the class. You can use1454this, e.g., to automatically add converters or validators to1455fields based on their types. See `transform-fields` for more details.14561457:param bool match_args:1458If `True` (default), set ``__match_args__`` on the class to support1459`PEP 634 <https://www.python.org/dev/peps/pep-0634/>`_ (Structural1460Pattern Matching). It is a tuple of all positional-only ``__init__``1461parameter names on Python 3.10 and later. Ignored on older Python1462versions.14631464.. versionadded:: 16.0.0 *slots*1465.. versionadded:: 16.1.0 *frozen*1466.. versionadded:: 16.3.0 *str*1467.. versionadded:: 16.3.0 Support for ``__attrs_post_init__``.1468.. versionchanged:: 17.1.01469*hash* supports ``None`` as value which is also the default now.1470.. versionadded:: 17.3.0 *auto_attribs*1471.. versionchanged:: 18.1.01472If *these* is passed, no attributes are deleted from the class body.1473.. versionchanged:: 18.1.0 If *these* is ordered, the order is retained.1474.. versionadded:: 18.2.0 *weakref_slot*1475.. deprecated:: 18.2.01476``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a1477`DeprecationWarning` if the classes compared are subclasses of1478each other. ``__eq`` and ``__ne__`` never tried to compared subclasses1479to each other.1480.. versionchanged:: 19.2.01481``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider1482subclasses comparable anymore.1483.. versionadded:: 18.2.0 *kw_only*1484.. versionadded:: 18.2.0 *cache_hash*1485.. versionadded:: 19.1.0 *auto_exc*1486.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.1487.. versionadded:: 19.2.0 *eq* and *order*1488.. versionadded:: 20.1.0 *auto_detect*1489.. versionadded:: 20.1.0 *collect_by_mro*1490.. versionadded:: 20.1.0 *getstate_setstate*1491.. versionadded:: 20.1.0 *on_setattr*1492.. versionadded:: 20.3.0 *field_transformer*1493.. versionchanged:: 21.1.01494``init=False`` injects ``__attrs_init__``1495.. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__``1496.. versionchanged:: 21.1.0 *cmp* undeprecated1497.. versionadded:: 21.3.0 *match_args*1498"""1499if auto_detect and PY2:1500raise PythonTooOldError(1501"auto_detect only works on Python 3 and later."1502)15031504eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None)1505hash_ = hash # work around the lack of nonlocal15061507if isinstance(on_setattr, (list, tuple)):1508on_setattr = setters.pipe(*on_setattr)15091510def wrap(cls):15111512if getattr(cls, "__class__", None) is None:1513raise TypeError("attrs only works with new-style classes.")15141515is_frozen = frozen or _has_frozen_base_class(cls)1516is_exc = auto_exc is True and issubclass(cls, BaseException)1517has_own_setattr = auto_detect and _has_own_attribute(1518cls, "__setattr__"1519)15201521if has_own_setattr and is_frozen:1522raise ValueError("Can't freeze a class with a custom __setattr__.")15231524builder = _ClassBuilder(1525cls,1526these,1527slots,1528is_frozen,1529weakref_slot,1530_determine_whether_to_implement(1531cls,1532getstate_setstate,1533auto_detect,1534("__getstate__", "__setstate__"),1535default=slots,1536),1537auto_attribs,1538kw_only,1539cache_hash,1540is_exc,1541collect_by_mro,1542on_setattr,1543has_own_setattr,1544field_transformer,1545)1546if _determine_whether_to_implement(1547cls, repr, auto_detect, ("__repr__",)1548):1549builder.add_repr(repr_ns)1550if str is True:1551builder.add_str()15521553eq = _determine_whether_to_implement(1554cls, eq_, auto_detect, ("__eq__", "__ne__")1555)1556if not is_exc and eq is True:1557builder.add_eq()1558if not is_exc and _determine_whether_to_implement(1559cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__")1560):1561builder.add_order()15621563builder.add_setattr()15641565if (1566hash_ is None1567and auto_detect is True1568and _has_own_attribute(cls, "__hash__")1569):1570hash = False1571else:1572hash = hash_1573if hash is not True and hash is not False and hash is not None:1574# Can't use `hash in` because 1 == True for example.1575raise TypeError(1576"Invalid value for hash. Must be True, False, or None."1577)1578elif hash is False or (hash is None and eq is False) or is_exc:1579# Don't do anything. Should fall back to __object__'s __hash__1580# which is by id.1581if cache_hash:1582raise TypeError(1583"Invalid value for cache_hash. To use hash caching,"1584" hashing must be either explicitly or implicitly "1585"enabled."1586)1587elif hash is True or (1588hash is None and eq is True and is_frozen is True1589):1590# Build a __hash__ if told so, or if it's safe.1591builder.add_hash()1592else:1593# Raise TypeError on attempts to hash.1594if cache_hash:1595raise TypeError(1596"Invalid value for cache_hash. To use hash caching,"1597" hashing must be either explicitly or implicitly "1598"enabled."1599)1600builder.make_unhashable()16011602if _determine_whether_to_implement(1603cls, init, auto_detect, ("__init__",)1604):1605builder.add_init()1606else:1607builder.add_attrs_init()1608if cache_hash:1609raise TypeError(1610"Invalid value for cache_hash. To use hash caching,"1611" init must be True."1612)16131614if (1615PY3101616and match_args1617and not _has_own_attribute(cls, "__match_args__")1618):1619builder.add_match_args()16201621return builder.build_class()16221623# maybe_cls's type depends on the usage of the decorator. It's a class1624# if it's used as `@attrs` but ``None`` if used as `@attrs()`.1625if maybe_cls is None:1626return wrap1627else:1628return wrap(maybe_cls)162916301631_attrs = attrs1632"""1633Internal alias so we can use it in functions that take an argument called1634*attrs*.1635"""163616371638if PY2:16391640def _has_frozen_base_class(cls):1641"""1642Check whether *cls* has a frozen ancestor by looking at its1643__setattr__.1644"""1645return (1646getattr(cls.__setattr__, "__module__", None)1647== _frozen_setattrs.__module__1648and cls.__setattr__.__name__ == _frozen_setattrs.__name__1649)16501651else:16521653def _has_frozen_base_class(cls):1654"""1655Check whether *cls* has a frozen ancestor by looking at its1656__setattr__.1657"""1658return cls.__setattr__ == _frozen_setattrs165916601661def _generate_unique_filename(cls, func_name):1662"""1663Create a "filename" suitable for a function being generated.1664"""1665unique_filename = "<attrs generated {0} {1}.{2}>".format(1666func_name,1667cls.__module__,1668getattr(cls, "__qualname__", cls.__name__),1669)1670return unique_filename167116721673def _make_hash(cls, attrs, frozen, cache_hash):1674attrs = tuple(1675a for a in attrs if a.hash is True or (a.hash is None and a.eq is True)1676)16771678tab = " "16791680unique_filename = _generate_unique_filename(cls, "hash")1681type_hash = hash(unique_filename)16821683hash_def = "def __hash__(self"1684hash_func = "hash(("1685closing_braces = "))"1686if not cache_hash:1687hash_def += "):"1688else:1689if not PY2:1690hash_def += ", *"16911692hash_def += (1693", _cache_wrapper="1694+ "__import__('attr._make')._make._CacheHashWrapper):"1695)1696hash_func = "_cache_wrapper(" + hash_func1697closing_braces += ")"16981699method_lines = [hash_def]17001701def append_hash_computation_lines(prefix, indent):1702"""1703Generate the code for actually computing the hash code.1704Below this will either be returned directly or used to compute1705a value which is then cached, depending on the value of cache_hash1706"""17071708method_lines.extend(1709[1710indent + prefix + hash_func,1711indent + " %d," % (type_hash,),1712]1713)17141715for a in attrs:1716method_lines.append(indent + " self.%s," % a.name)17171718method_lines.append(indent + " " + closing_braces)17191720if cache_hash:1721method_lines.append(tab + "if self.%s is None:" % _hash_cache_field)1722if frozen:1723append_hash_computation_lines(1724"object.__setattr__(self, '%s', " % _hash_cache_field, tab * 21725)1726method_lines.append(tab * 2 + ")") # close __setattr__1727else:1728append_hash_computation_lines(1729"self.%s = " % _hash_cache_field, tab * 21730)1731method_lines.append(tab + "return self.%s" % _hash_cache_field)1732else:1733append_hash_computation_lines("return ", tab)17341735script = "\n".join(method_lines)1736return _make_method("__hash__", script, unique_filename)173717381739def _add_hash(cls, attrs):1740"""1741Add a hash method to *cls*.1742"""1743cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False)1744return cls174517461747def _make_ne():1748"""1749Create __ne__ method.1750"""17511752def __ne__(self, other):1753"""1754Check equality and either forward a NotImplemented or1755return the result negated.1756"""1757result = self.__eq__(other)1758if result is NotImplemented:1759return NotImplemented17601761return not result17621763return __ne__176417651766def _make_eq(cls, attrs):1767"""1768Create __eq__ method for *cls* with *attrs*.1769"""1770attrs = [a for a in attrs if a.eq]17711772unique_filename = _generate_unique_filename(cls, "eq")1773lines = [1774"def __eq__(self, other):",1775" if other.__class__ is not self.__class__:",1776" return NotImplemented",1777]17781779# We can't just do a big self.x = other.x and... clause due to1780# irregularities like nan == nan is false but (nan,) == (nan,) is true.1781globs = {}1782if attrs:1783lines.append(" return (")1784others = [" ) == ("]1785for a in attrs:1786if a.eq_key:1787cmp_name = "_%s_key" % (a.name,)1788# Add the key function to the global namespace1789# of the evaluated function.1790globs[cmp_name] = a.eq_key1791lines.append(1792" %s(self.%s),"1793% (1794cmp_name,1795a.name,1796)1797)1798others.append(1799" %s(other.%s),"1800% (1801cmp_name,1802a.name,1803)1804)1805else:1806lines.append(" self.%s," % (a.name,))1807others.append(" other.%s," % (a.name,))18081809lines += others + [" )"]1810else:1811lines.append(" return True")18121813script = "\n".join(lines)18141815return _make_method("__eq__", script, unique_filename, globs)181618171818def _make_order(cls, attrs):1819"""1820Create ordering methods for *cls* with *attrs*.1821"""1822attrs = [a for a in attrs if a.order]18231824def attrs_to_tuple(obj):1825"""1826Save us some typing.1827"""1828return tuple(1829key(value) if key else value1830for value, key in (1831(getattr(obj, a.name), a.order_key) for a in attrs1832)1833)18341835def __lt__(self, other):1836"""1837Automatically created by attrs.1838"""1839if other.__class__ is self.__class__:1840return attrs_to_tuple(self) < attrs_to_tuple(other)18411842return NotImplemented18431844def __le__(self, other):1845"""1846Automatically created by attrs.1847"""1848if other.__class__ is self.__class__:1849return attrs_to_tuple(self) <= attrs_to_tuple(other)18501851return NotImplemented18521853def __gt__(self, other):1854"""1855Automatically created by attrs.1856"""1857if other.__class__ is self.__class__:1858return attrs_to_tuple(self) > attrs_to_tuple(other)18591860return NotImplemented18611862def __ge__(self, other):1863"""1864Automatically created by attrs.1865"""1866if other.__class__ is self.__class__:1867return attrs_to_tuple(self) >= attrs_to_tuple(other)18681869return NotImplemented18701871return __lt__, __le__, __gt__, __ge__187218731874def _add_eq(cls, attrs=None):1875"""1876Add equality methods to *cls* with *attrs*.1877"""1878if attrs is None:1879attrs = cls.__attrs_attrs__18801881cls.__eq__ = _make_eq(cls, attrs)1882cls.__ne__ = _make_ne()18831884return cls188518861887if HAS_F_STRINGS:18881889def _make_repr(attrs, ns, cls):1890unique_filename = _generate_unique_filename(cls, "repr")1891# Figure out which attributes to include, and which function to use to1892# format them. The a.repr value can be either bool or a custom1893# callable.1894attr_names_with_reprs = tuple(1895(a.name, (repr if a.repr is True else a.repr), a.init)1896for a in attrs1897if a.repr is not False1898)1899globs = {1900name + "_repr": r1901for name, r, _ in attr_names_with_reprs1902if r != repr1903}1904globs["_compat"] = _compat1905globs["AttributeError"] = AttributeError1906globs["NOTHING"] = NOTHING1907attribute_fragments = []1908for name, r, i in attr_names_with_reprs:1909accessor = (1910"self." + name1911if i1912else 'getattr(self, "' + name + '", NOTHING)'1913)1914fragment = (1915"%s={%s!r}" % (name, accessor)1916if r == repr1917else "%s={%s_repr(%s)}" % (name, name, accessor)1918)1919attribute_fragments.append(fragment)1920repr_fragment = ", ".join(attribute_fragments)19211922if ns is None:1923cls_name_fragment = (1924'{self.__class__.__qualname__.rsplit(">.", 1)[-1]}'1925)1926else:1927cls_name_fragment = ns + ".{self.__class__.__name__}"19281929lines = [1930"def __repr__(self):",1931" try:",1932" already_repring = _compat.repr_context.already_repring",1933" except AttributeError:",1934" already_repring = {id(self),}",1935" _compat.repr_context.already_repring = already_repring",1936" else:",1937" if id(self) in already_repring:",1938" return '...'",1939" else:",1940" already_repring.add(id(self))",1941" try:",1942" return f'%s(%s)'" % (cls_name_fragment, repr_fragment),1943" finally:",1944" already_repring.remove(id(self))",1945]19461947return _make_method(1948"__repr__", "\n".join(lines), unique_filename, globs=globs1949)19501951else:19521953def _make_repr(attrs, ns, _):1954"""1955Make a repr method that includes relevant *attrs*, adding *ns* to the1956full name.1957"""19581959# Figure out which attributes to include, and which function to use to1960# format them. The a.repr value can be either bool or a custom1961# callable.1962attr_names_with_reprs = tuple(1963(a.name, repr if a.repr is True else a.repr)1964for a in attrs1965if a.repr is not False1966)19671968def __repr__(self):1969"""1970Automatically created by attrs.1971"""1972try:1973already_repring = _compat.repr_context.already_repring1974except AttributeError:1975already_repring = set()1976_compat.repr_context.already_repring = already_repring19771978if id(self) in already_repring:1979return "..."1980real_cls = self.__class__1981if ns is None:1982qualname = getattr(real_cls, "__qualname__", None)1983if qualname is not None: # pragma: no cover1984# This case only happens on Python 3.5 and 3.6. We exclude1985# it from coverage, because we don't want to slow down our1986# test suite by running them under coverage too for this1987# one line.1988class_name = qualname.rsplit(">.", 1)[-1]1989else:1990class_name = real_cls.__name__1991else:1992class_name = ns + "." + real_cls.__name__19931994# Since 'self' remains on the stack (i.e.: strongly referenced)1995# for the duration of this call, it's safe to depend on id(...)1996# stability, and not need to track the instance and therefore1997# worry about properties like weakref- or hash-ability.1998already_repring.add(id(self))1999try:2000result = [class_name, "("]2001first = True2002for name, attr_repr in attr_names_with_reprs:2003if first:2004first = False2005else:2006result.append(", ")2007result.extend(2008(name, "=", attr_repr(getattr(self, name, NOTHING)))2009)2010return "".join(result) + ")"2011finally:2012already_repring.remove(id(self))20132014return __repr__201520162017def _add_repr(cls, ns=None, attrs=None):2018"""2019Add a repr method to *cls*.2020"""2021if attrs is None:2022attrs = cls.__attrs_attrs__20232024cls.__repr__ = _make_repr(attrs, ns, cls)2025return cls202620272028def fields(cls):2029"""2030Return the tuple of ``attrs`` attributes for a class.20312032The tuple also allows accessing the fields by their names (see below for2033examples).20342035:param type cls: Class to introspect.20362037:raise TypeError: If *cls* is not a class.2038:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``2039class.20402041:rtype: tuple (with name accessors) of `attrs.Attribute`20422043.. versionchanged:: 16.2.0 Returned tuple allows accessing the fields2044by name.2045"""2046if not isclass(cls):2047raise TypeError("Passed object must be a class.")2048attrs = getattr(cls, "__attrs_attrs__", None)2049if attrs is None:2050raise NotAnAttrsClassError(2051"{cls!r} is not an attrs-decorated class.".format(cls=cls)2052)2053return attrs205420552056def fields_dict(cls):2057"""2058Return an ordered dictionary of ``attrs`` attributes for a class, whose2059keys are the attribute names.20602061:param type cls: Class to introspect.20622063:raise TypeError: If *cls* is not a class.2064:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``2065class.20662067:rtype: an ordered dict where keys are attribute names and values are2068`attrs.Attribute`\\ s. This will be a `dict` if it's2069naturally ordered like on Python 3.6+ or an2070:class:`~collections.OrderedDict` otherwise.20712072.. versionadded:: 18.1.02073"""2074if not isclass(cls):2075raise TypeError("Passed object must be a class.")2076attrs = getattr(cls, "__attrs_attrs__", None)2077if attrs is None:2078raise NotAnAttrsClassError(2079"{cls!r} is not an attrs-decorated class.".format(cls=cls)2080)2081return ordered_dict(((a.name, a) for a in attrs))208220832084def validate(inst):2085"""2086Validate all attributes on *inst* that have a validator.20872088Leaves all exceptions through.20892090:param inst: Instance of a class with ``attrs`` attributes.2091"""2092if _config._run_validators is False:2093return20942095for a in fields(inst.__class__):2096v = a.validator2097if v is not None:2098v(inst, a, getattr(inst, a.name))209921002101def _is_slot_cls(cls):2102return "__slots__" in cls.__dict__210321042105def _is_slot_attr(a_name, base_attr_map):2106"""2107Check if the attribute name comes from a slot class.2108"""2109return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name])211021112112def _make_init(2113cls,2114attrs,2115pre_init,2116post_init,2117frozen,2118slots,2119cache_hash,2120base_attr_map,2121is_exc,2122cls_on_setattr,2123attrs_init,2124):2125has_cls_on_setattr = (2126cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP2127)21282129if frozen and has_cls_on_setattr:2130raise ValueError("Frozen classes can't use on_setattr.")21312132needs_cached_setattr = cache_hash or frozen2133filtered_attrs = []2134attr_dict = {}2135for a in attrs:2136if not a.init and a.default is NOTHING:2137continue21382139filtered_attrs.append(a)2140attr_dict[a.name] = a21412142if a.on_setattr is not None:2143if frozen is True:2144raise ValueError("Frozen classes can't use on_setattr.")21452146needs_cached_setattr = True2147elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP:2148needs_cached_setattr = True21492150unique_filename = _generate_unique_filename(cls, "init")21512152script, globs, annotations = _attrs_to_init_script(2153filtered_attrs,2154frozen,2155slots,2156pre_init,2157post_init,2158cache_hash,2159base_attr_map,2160is_exc,2161needs_cached_setattr,2162has_cls_on_setattr,2163attrs_init,2164)2165if cls.__module__ in sys.modules:2166# This makes typing.get_type_hints(CLS.__init__) resolve string types.2167globs.update(sys.modules[cls.__module__].__dict__)21682169globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})21702171if needs_cached_setattr:2172# Save the lookup overhead in __init__ if we need to circumvent2173# setattr hooks.2174globs["_cached_setattr"] = _obj_setattr21752176init = _make_method(2177"__attrs_init__" if attrs_init else "__init__",2178script,2179unique_filename,2180globs,2181)2182init.__annotations__ = annotations21832184return init218521862187def _setattr(attr_name, value_var, has_on_setattr):2188"""2189Use the cached object.setattr to set *attr_name* to *value_var*.2190"""2191return "_setattr('%s', %s)" % (attr_name, value_var)219221932194def _setattr_with_converter(attr_name, value_var, has_on_setattr):2195"""2196Use the cached object.setattr to set *attr_name* to *value_var*, but run2197its converter first.2198"""2199return "_setattr('%s', %s(%s))" % (2200attr_name,2201_init_converter_pat % (attr_name,),2202value_var,2203)220422052206def _assign(attr_name, value, has_on_setattr):2207"""2208Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise2209relegate to _setattr.2210"""2211if has_on_setattr:2212return _setattr(attr_name, value, True)22132214return "self.%s = %s" % (attr_name, value)221522162217def _assign_with_converter(attr_name, value_var, has_on_setattr):2218"""2219Unless *attr_name* has an on_setattr hook, use normal assignment after2220conversion. Otherwise relegate to _setattr_with_converter.2221"""2222if has_on_setattr:2223return _setattr_with_converter(attr_name, value_var, True)22242225return "self.%s = %s(%s)" % (2226attr_name,2227_init_converter_pat % (attr_name,),2228value_var,2229)223022312232if PY2:22332234def _unpack_kw_only_py2(attr_name, default=None):2235"""2236Unpack *attr_name* from _kw_only dict.2237"""2238if default is not None:2239arg_default = ", %s" % default2240else:2241arg_default = ""2242return "%s = _kw_only.pop('%s'%s)" % (2243attr_name,2244attr_name,2245arg_default,2246)22472248def _unpack_kw_only_lines_py2(kw_only_args):2249"""2250Unpack all *kw_only_args* from _kw_only dict and handle errors.22512252Given a list of strings "{attr_name}" and "{attr_name}={default}"2253generates list of lines of code that pop attrs from _kw_only dict and2254raise TypeError similar to builtin if required attr is missing or2255extra key is passed.22562257>>> print("\n".join(_unpack_kw_only_lines_py2(["a", "b=42"])))2258try:2259a = _kw_only.pop('a')2260b = _kw_only.pop('b', 42)2261except KeyError as _key_error:2262raise TypeError(2263...2264if _kw_only:2265raise TypeError(2266...2267"""2268lines = ["try:"]2269lines.extend(2270" " + _unpack_kw_only_py2(*arg.split("="))2271for arg in kw_only_args2272)2273lines += """\2274except KeyError as _key_error:2275raise TypeError(2276'__init__() missing required keyword-only argument: %s' % _key_error2277)2278if _kw_only:2279raise TypeError(2280'__init__() got an unexpected keyword argument %r'2281% next(iter(_kw_only))2282)2283""".split(2284"\n"2285)2286return lines228722882289def _attrs_to_init_script(2290attrs,2291frozen,2292slots,2293pre_init,2294post_init,2295cache_hash,2296base_attr_map,2297is_exc,2298needs_cached_setattr,2299has_cls_on_setattr,2300attrs_init,2301):2302"""2303Return a script of an initializer for *attrs* and a dict of globals.23042305The globals are expected by the generated script.23062307If *frozen* is True, we cannot set the attributes directly so we use2308a cached ``object.__setattr__``.2309"""2310lines = []2311if pre_init:2312lines.append("self.__attrs_pre_init__()")23132314if needs_cached_setattr:2315lines.append(2316# Circumvent the __setattr__ descriptor to save one lookup per2317# assignment.2318# Note _setattr will be used again below if cache_hash is True2319"_setattr = _cached_setattr.__get__(self, self.__class__)"2320)23212322if frozen is True:2323if slots is True:2324fmt_setter = _setattr2325fmt_setter_with_converter = _setattr_with_converter2326else:2327# Dict frozen classes assign directly to __dict__.2328# But only if the attribute doesn't come from an ancestor slot2329# class.2330# Note _inst_dict will be used again below if cache_hash is True2331lines.append("_inst_dict = self.__dict__")23322333def fmt_setter(attr_name, value_var, has_on_setattr):2334if _is_slot_attr(attr_name, base_attr_map):2335return _setattr(attr_name, value_var, has_on_setattr)23362337return "_inst_dict['%s'] = %s" % (attr_name, value_var)23382339def fmt_setter_with_converter(2340attr_name, value_var, has_on_setattr2341):2342if has_on_setattr or _is_slot_attr(attr_name, base_attr_map):2343return _setattr_with_converter(2344attr_name, value_var, has_on_setattr2345)23462347return "_inst_dict['%s'] = %s(%s)" % (2348attr_name,2349_init_converter_pat % (attr_name,),2350value_var,2351)23522353else:2354# Not frozen.2355fmt_setter = _assign2356fmt_setter_with_converter = _assign_with_converter23572358args = []2359kw_only_args = []2360attrs_to_validate = []23612362# This is a dictionary of names to validator and converter callables.2363# Injecting this into __init__ globals lets us avoid lookups.2364names_for_globals = {}2365annotations = {"return": None}23662367for a in attrs:2368if a.validator:2369attrs_to_validate.append(a)23702371attr_name = a.name2372has_on_setattr = a.on_setattr is not None or (2373a.on_setattr is not setters.NO_OP and has_cls_on_setattr2374)2375arg_name = a.name.lstrip("_")23762377has_factory = isinstance(a.default, Factory)2378if has_factory and a.default.takes_self:2379maybe_self = "self"2380else:2381maybe_self = ""23822383if a.init is False:2384if has_factory:2385init_factory_name = _init_factory_pat.format(a.name)2386if a.converter is not None:2387lines.append(2388fmt_setter_with_converter(2389attr_name,2390init_factory_name + "(%s)" % (maybe_self,),2391has_on_setattr,2392)2393)2394conv_name = _init_converter_pat % (a.name,)2395names_for_globals[conv_name] = a.converter2396else:2397lines.append(2398fmt_setter(2399attr_name,2400init_factory_name + "(%s)" % (maybe_self,),2401has_on_setattr,2402)2403)2404names_for_globals[init_factory_name] = a.default.factory2405else:2406if a.converter is not None:2407lines.append(2408fmt_setter_with_converter(2409attr_name,2410"attr_dict['%s'].default" % (attr_name,),2411has_on_setattr,2412)2413)2414conv_name = _init_converter_pat % (a.name,)2415names_for_globals[conv_name] = a.converter2416else:2417lines.append(2418fmt_setter(2419attr_name,2420"attr_dict['%s'].default" % (attr_name,),2421has_on_setattr,2422)2423)2424elif a.default is not NOTHING and not has_factory:2425arg = "%s=attr_dict['%s'].default" % (arg_name, attr_name)2426if a.kw_only:2427kw_only_args.append(arg)2428else:2429args.append(arg)24302431if a.converter is not None:2432lines.append(2433fmt_setter_with_converter(2434attr_name, arg_name, has_on_setattr2435)2436)2437names_for_globals[2438_init_converter_pat % (a.name,)2439] = a.converter2440else:2441lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))24422443elif has_factory:2444arg = "%s=NOTHING" % (arg_name,)2445if a.kw_only:2446kw_only_args.append(arg)2447else:2448args.append(arg)2449lines.append("if %s is not NOTHING:" % (arg_name,))24502451init_factory_name = _init_factory_pat.format(a.name)2452if a.converter is not None:2453lines.append(2454" "2455+ fmt_setter_with_converter(2456attr_name, arg_name, has_on_setattr2457)2458)2459lines.append("else:")2460lines.append(2461" "2462+ fmt_setter_with_converter(2463attr_name,2464init_factory_name + "(" + maybe_self + ")",2465has_on_setattr,2466)2467)2468names_for_globals[2469_init_converter_pat % (a.name,)2470] = a.converter2471else:2472lines.append(2473" " + fmt_setter(attr_name, arg_name, has_on_setattr)2474)2475lines.append("else:")2476lines.append(2477" "2478+ fmt_setter(2479attr_name,2480init_factory_name + "(" + maybe_self + ")",2481has_on_setattr,2482)2483)2484names_for_globals[init_factory_name] = a.default.factory2485else:2486if a.kw_only:2487kw_only_args.append(arg_name)2488else:2489args.append(arg_name)24902491if a.converter is not None:2492lines.append(2493fmt_setter_with_converter(2494attr_name, arg_name, has_on_setattr2495)2496)2497names_for_globals[2498_init_converter_pat % (a.name,)2499] = a.converter2500else:2501lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))25022503if a.init is True:2504if a.type is not None and a.converter is None:2505annotations[arg_name] = a.type2506elif a.converter is not None and not PY2:2507# Try to get the type from the converter.2508sig = None2509try:2510sig = inspect.signature(a.converter)2511except (ValueError, TypeError): # inspect failed2512pass2513if sig:2514sig_params = list(sig.parameters.values())2515if (2516sig_params2517and sig_params[0].annotation2518is not inspect.Parameter.empty2519):2520annotations[arg_name] = sig_params[0].annotation25212522if attrs_to_validate: # we can skip this if there are no validators.2523names_for_globals["_config"] = _config2524lines.append("if _config._run_validators is True:")2525for a in attrs_to_validate:2526val_name = "__attr_validator_" + a.name2527attr_name = "__attr_" + a.name2528lines.append(2529" %s(self, %s, self.%s)" % (val_name, attr_name, a.name)2530)2531names_for_globals[val_name] = a.validator2532names_for_globals[attr_name] = a25332534if post_init:2535lines.append("self.__attrs_post_init__()")25362537# because this is set only after __attrs_post_init is called, a crash2538# will result if post-init tries to access the hash code. This seemed2539# preferable to setting this beforehand, in which case alteration to2540# field values during post-init combined with post-init accessing the2541# hash code would result in silent bugs.2542if cache_hash:2543if frozen:2544if slots:2545# if frozen and slots, then _setattr defined above2546init_hash_cache = "_setattr('%s', %s)"2547else:2548# if frozen and not slots, then _inst_dict defined above2549init_hash_cache = "_inst_dict['%s'] = %s"2550else:2551init_hash_cache = "self.%s = %s"2552lines.append(init_hash_cache % (_hash_cache_field, "None"))25532554# For exceptions we rely on BaseException.__init__ for proper2555# initialization.2556if is_exc:2557vals = ",".join("self." + a.name for a in attrs if a.init)25582559lines.append("BaseException.__init__(self, %s)" % (vals,))25602561args = ", ".join(args)2562if kw_only_args:2563if PY2:2564lines = _unpack_kw_only_lines_py2(kw_only_args) + lines25652566args += "%s**_kw_only" % (", " if args else "",) # leading comma2567else:2568args += "%s*, %s" % (2569", " if args else "", # leading comma2570", ".join(kw_only_args), # kw_only args2571)2572return (2573"""\2574def {init_name}(self, {args}):2575{lines}2576""".format(2577init_name=("__attrs_init__" if attrs_init else "__init__"),2578args=args,2579lines="\n ".join(lines) if lines else "pass",2580),2581names_for_globals,2582annotations,2583)258425852586class Attribute(object):2587"""2588*Read-only* representation of an attribute.25892590The class has *all* arguments of `attr.ib` (except for ``factory``2591which is only syntactic sugar for ``default=Factory(...)`` plus the2592following:25932594- ``name`` (`str`): The name of the attribute.2595- ``inherited`` (`bool`): Whether or not that attribute has been inherited2596from a base class.2597- ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The callables2598that are used for comparing and ordering objects by this attribute,2599respectively. These are set by passing a callable to `attr.ib`'s ``eq``,2600``order``, or ``cmp`` arguments. See also :ref:`comparison customization2601<custom-comparison>`.26022603Instances of this class are frequently used for introspection purposes2604like:26052606- `fields` returns a tuple of them.2607- Validators get them passed as the first argument.2608- The :ref:`field transformer <transform-fields>` hook receives a list of2609them.26102611.. versionadded:: 20.1.0 *inherited*2612.. versionadded:: 20.1.0 *on_setattr*2613.. versionchanged:: 20.2.0 *inherited* is not taken into account for2614equality checks and hashing anymore.2615.. versionadded:: 21.1.0 *eq_key* and *order_key*26162617For the full version history of the fields, see `attr.ib`.2618"""26192620__slots__ = (2621"name",2622"default",2623"validator",2624"repr",2625"eq",2626"eq_key",2627"order",2628"order_key",2629"hash",2630"init",2631"metadata",2632"type",2633"converter",2634"kw_only",2635"inherited",2636"on_setattr",2637)26382639def __init__(2640self,2641name,2642default,2643validator,2644repr,2645cmp, # XXX: unused, remove along with other cmp code.2646hash,2647init,2648inherited,2649metadata=None,2650type=None,2651converter=None,2652kw_only=False,2653eq=None,2654eq_key=None,2655order=None,2656order_key=None,2657on_setattr=None,2658):2659eq, eq_key, order, order_key = _determine_attrib_eq_order(2660cmp, eq_key or eq, order_key or order, True2661)26622663# Cache this descriptor here to speed things up later.2664bound_setattr = _obj_setattr.__get__(self, Attribute)26652666# Despite the big red warning, people *do* instantiate `Attribute`2667# themselves.2668bound_setattr("name", name)2669bound_setattr("default", default)2670bound_setattr("validator", validator)2671bound_setattr("repr", repr)2672bound_setattr("eq", eq)2673bound_setattr("eq_key", eq_key)2674bound_setattr("order", order)2675bound_setattr("order_key", order_key)2676bound_setattr("hash", hash)2677bound_setattr("init", init)2678bound_setattr("converter", converter)2679bound_setattr(2680"metadata",2681(2682metadata_proxy(metadata)2683if metadata2684else _empty_metadata_singleton2685),2686)2687bound_setattr("type", type)2688bound_setattr("kw_only", kw_only)2689bound_setattr("inherited", inherited)2690bound_setattr("on_setattr", on_setattr)26912692def __setattr__(self, name, value):2693raise FrozenInstanceError()26942695@classmethod2696def from_counting_attr(cls, name, ca, type=None):2697# type holds the annotated value. deal with conflicts:2698if type is None:2699type = ca.type2700elif ca.type is not None:2701raise ValueError(2702"Type annotation and type argument cannot both be present"2703)2704inst_dict = {2705k: getattr(ca, k)2706for k in Attribute.__slots__2707if k2708not in (2709"name",2710"validator",2711"default",2712"type",2713"inherited",2714) # exclude methods and deprecated alias2715}2716return cls(2717name=name,2718validator=ca._validator,2719default=ca._default,2720type=type,2721cmp=None,2722inherited=False,2723**inst_dict2724)27252726@property2727def cmp(self):2728"""2729Simulate the presence of a cmp attribute and warn.2730"""2731warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=2)27322733return self.eq and self.order27342735# Don't use attr.evolve since fields(Attribute) doesn't work2736def evolve(self, **changes):2737"""2738Copy *self* and apply *changes*.27392740This works similarly to `attr.evolve` but that function does not work2741with ``Attribute``.27422743It is mainly meant to be used for `transform-fields`.27442745.. versionadded:: 20.3.02746"""2747new = copy.copy(self)27482749new._setattrs(changes.items())27502751return new27522753# Don't use _add_pickle since fields(Attribute) doesn't work2754def __getstate__(self):2755"""2756Play nice with pickle.2757"""2758return tuple(2759getattr(self, name) if name != "metadata" else dict(self.metadata)2760for name in self.__slots__2761)27622763def __setstate__(self, state):2764"""2765Play nice with pickle.2766"""2767self._setattrs(zip(self.__slots__, state))27682769def _setattrs(self, name_values_pairs):2770bound_setattr = _obj_setattr.__get__(self, Attribute)2771for name, value in name_values_pairs:2772if name != "metadata":2773bound_setattr(name, value)2774else:2775bound_setattr(2776name,2777metadata_proxy(value)2778if value2779else _empty_metadata_singleton,2780)278127822783_a = [2784Attribute(2785name=name,2786default=NOTHING,2787validator=None,2788repr=True,2789cmp=None,2790eq=True,2791order=False,2792hash=(name != "metadata"),2793init=True,2794inherited=False,2795)2796for name in Attribute.__slots__2797]27982799Attribute = _add_hash(2800_add_eq(2801_add_repr(Attribute, attrs=_a),2802attrs=[a for a in _a if a.name != "inherited"],2803),2804attrs=[a for a in _a if a.hash and a.name != "inherited"],2805)280628072808class _CountingAttr(object):2809"""2810Intermediate representation of attributes that uses a counter to preserve2811the order in which the attributes have been defined.28122813*Internal* data structure of the attrs library. Running into is most2814likely the result of a bug like a forgotten `@attr.s` decorator.2815"""28162817__slots__ = (2818"counter",2819"_default",2820"repr",2821"eq",2822"eq_key",2823"order",2824"order_key",2825"hash",2826"init",2827"metadata",2828"_validator",2829"converter",2830"type",2831"kw_only",2832"on_setattr",2833)2834__attrs_attrs__ = tuple(2835Attribute(2836name=name,2837default=NOTHING,2838validator=None,2839repr=True,2840cmp=None,2841hash=True,2842init=True,2843kw_only=False,2844eq=True,2845eq_key=None,2846order=False,2847order_key=None,2848inherited=False,2849on_setattr=None,2850)2851for name in (2852"counter",2853"_default",2854"repr",2855"eq",2856"order",2857"hash",2858"init",2859"on_setattr",2860)2861) + (2862Attribute(2863name="metadata",2864default=None,2865validator=None,2866repr=True,2867cmp=None,2868hash=False,2869init=True,2870kw_only=False,2871eq=True,2872eq_key=None,2873order=False,2874order_key=None,2875inherited=False,2876on_setattr=None,2877),2878)2879cls_counter = 028802881def __init__(2882self,2883default,2884validator,2885repr,2886cmp,2887hash,2888init,2889converter,2890metadata,2891type,2892kw_only,2893eq,2894eq_key,2895order,2896order_key,2897on_setattr,2898):2899_CountingAttr.cls_counter += 12900self.counter = _CountingAttr.cls_counter2901self._default = default2902self._validator = validator2903self.converter = converter2904self.repr = repr2905self.eq = eq2906self.eq_key = eq_key2907self.order = order2908self.order_key = order_key2909self.hash = hash2910self.init = init2911self.metadata = metadata2912self.type = type2913self.kw_only = kw_only2914self.on_setattr = on_setattr29152916def validator(self, meth):2917"""2918Decorator that adds *meth* to the list of validators.29192920Returns *meth* unchanged.29212922.. versionadded:: 17.1.02923"""2924if self._validator is None:2925self._validator = meth2926else:2927self._validator = and_(self._validator, meth)2928return meth29292930def default(self, meth):2931"""2932Decorator that allows to set the default for an attribute.29332934Returns *meth* unchanged.29352936:raises DefaultAlreadySetError: If default has been set before.29372938.. versionadded:: 17.1.02939"""2940if self._default is not NOTHING:2941raise DefaultAlreadySetError()29422943self._default = Factory(meth, takes_self=True)29442945return meth294629472948_CountingAttr = _add_eq(_add_repr(_CountingAttr))294929502951class Factory(object):2952"""2953Stores a factory callable.29542955If passed as the default value to `attrs.field`, the factory is used to2956generate a new value.29572958:param callable factory: A callable that takes either none or exactly one2959mandatory positional argument depending on *takes_self*.2960:param bool takes_self: Pass the partially initialized instance that is2961being initialized as a positional argument.29622963.. versionadded:: 17.1.0 *takes_self*2964"""29652966__slots__ = ("factory", "takes_self")29672968def __init__(self, factory, takes_self=False):2969"""2970`Factory` is part of the default machinery so if we want a default2971value here, we have to implement it ourselves.2972"""2973self.factory = factory2974self.takes_self = takes_self29752976def __getstate__(self):2977"""2978Play nice with pickle.2979"""2980return tuple(getattr(self, name) for name in self.__slots__)29812982def __setstate__(self, state):2983"""2984Play nice with pickle.2985"""2986for name, value in zip(self.__slots__, state):2987setattr(self, name, value)298829892990_f = [2991Attribute(2992name=name,2993default=NOTHING,2994validator=None,2995repr=True,2996cmp=None,2997eq=True,2998order=False,2999hash=True,3000init=True,3001inherited=False,3002)3003for name in Factory.__slots__3004]30053006Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)300730083009def make_class(name, attrs, bases=(object,), **attributes_arguments):3010"""3011A quick way to create a new class called *name* with *attrs*.30123013:param str name: The name for the new class.30143015:param attrs: A list of names or a dictionary of mappings of names to3016attributes.30173018If *attrs* is a list or an ordered dict (`dict` on Python 3.6+,3019`collections.OrderedDict` otherwise), the order is deduced from3020the order of the names or attributes inside *attrs*. Otherwise the3021order of the definition of the attributes is used.3022:type attrs: `list` or `dict`30233024:param tuple bases: Classes that the new class will subclass.30253026:param attributes_arguments: Passed unmodified to `attr.s`.30273028:return: A new class with *attrs*.3029:rtype: type30303031.. versionadded:: 17.1.0 *bases*3032.. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained.3033"""3034if isinstance(attrs, dict):3035cls_dict = attrs3036elif isinstance(attrs, (list, tuple)):3037cls_dict = dict((a, attrib()) for a in attrs)3038else:3039raise TypeError("attrs argument must be a dict or a list.")30403041pre_init = cls_dict.pop("__attrs_pre_init__", None)3042post_init = cls_dict.pop("__attrs_post_init__", None)3043user_init = cls_dict.pop("__init__", None)30443045body = {}3046if pre_init is not None:3047body["__attrs_pre_init__"] = pre_init3048if post_init is not None:3049body["__attrs_post_init__"] = post_init3050if user_init is not None:3051body["__init__"] = user_init30523053type_ = new_class(name, bases, {}, lambda ns: ns.update(body))30543055# For pickling to work, the __module__ variable needs to be set to the3056# frame where the class is created. Bypass this step in environments where3057# sys._getframe is not defined (Jython for example) or sys._getframe is not3058# defined for arguments greater than 0 (IronPython).3059try:3060type_.__module__ = sys._getframe(1).f_globals.get(3061"__name__", "__main__"3062)3063except (AttributeError, ValueError):3064pass30653066# We do it here for proper warnings with meaningful stacklevel.3067cmp = attributes_arguments.pop("cmp", None)3068(3069attributes_arguments["eq"],3070attributes_arguments["order"],3071) = _determine_attrs_eq_order(3072cmp,3073attributes_arguments.get("eq"),3074attributes_arguments.get("order"),3075True,3076)30773078return _attrs(these=cls_dict, **attributes_arguments)(type_)307930803081# These are required by within this module so we define them here and merely3082# import into .validators / .converters.308330843085@attrs(slots=True, hash=True)3086class _AndValidator(object):3087"""3088Compose many validators to a single one.3089"""30903091_validators = attrib()30923093def __call__(self, inst, attr, value):3094for v in self._validators:3095v(inst, attr, value)309630973098def and_(*validators):3099"""3100A validator that composes multiple validators into one.31013102When called on a value, it runs all wrapped validators.31033104:param callables validators: Arbitrary number of validators.31053106.. versionadded:: 17.1.03107"""3108vals = []3109for validator in validators:3110vals.extend(3111validator._validators3112if isinstance(validator, _AndValidator)3113else [validator]3114)31153116return _AndValidator(tuple(vals))311731183119def pipe(*converters):3120"""3121A converter that composes multiple converters into one.31223123When called on a value, it runs all wrapped converters, returning the3124*last* value.31253126Type annotations will be inferred from the wrapped converters', if3127they have any.31283129:param callables converters: Arbitrary number of converters.31303131.. versionadded:: 20.1.03132"""31333134def pipe_converter(val):3135for converter in converters:3136val = converter(val)31373138return val31393140if not PY2:3141if not converters:3142# If the converter list is empty, pipe_converter is the identity.3143A = typing.TypeVar("A")3144pipe_converter.__annotations__ = {"val": A, "return": A}3145else:3146# Get parameter type.3147sig = None3148try:3149sig = inspect.signature(converters[0])3150except (ValueError, TypeError): # inspect failed3151pass3152if sig:3153params = list(sig.parameters.values())3154if (3155params3156and params[0].annotation is not inspect.Parameter.empty3157):3158pipe_converter.__annotations__["val"] = params[315903160].annotation3161# Get return type.3162sig = None3163try:3164sig = inspect.signature(converters[-1])3165except (ValueError, TypeError): # inspect failed3166pass3167if sig and sig.return_annotation is not inspect.Signature().empty:3168pipe_converter.__annotations__[3169"return"3170] = sig.return_annotation31713172return pipe_converter317331743175