diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/python/attrs | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/attrs')
-rw-r--r-- | contrib/python/attrs/attr/__init__.py | 102 | ||||
-rw-r--r-- | contrib/python/attrs/attr/_compat.py | 178 | ||||
-rw-r--r-- | contrib/python/attrs/attr/_config.py | 46 | ||||
-rw-r--r-- | contrib/python/attrs/attr/_funcs.py | 344 | ||||
-rw-r--r-- | contrib/python/attrs/attr/_make.py | 2076 | ||||
-rw-r--r-- | contrib/python/attrs/attr/converters.py | 46 | ||||
-rw-r--r-- | contrib/python/attrs/attr/exceptions.py | 88 | ||||
-rw-r--r-- | contrib/python/attrs/attr/filters.py | 94 | ||||
-rw-r--r-- | contrib/python/attrs/attr/validators.py | 254 | ||||
-rw-r--r-- | contrib/python/attrs/ya.make | 40 |
10 files changed, 1634 insertions, 1634 deletions
diff --git a/contrib/python/attrs/attr/__init__.py b/contrib/python/attrs/attr/__init__.py index 506199800f..b1ce7fe248 100644 --- a/contrib/python/attrs/attr/__init__.py +++ b/contrib/python/attrs/attr/__init__.py @@ -1,14 +1,14 @@ -from __future__ import absolute_import, division, print_function - +from __future__ import absolute_import, division, print_function + import sys -from functools import partial - +from functools import partial + from . import converters, exceptions, filters, setters, validators from ._cmp import cmp_using -from ._config import get_run_validators, set_run_validators +from ._config import get_run_validators, set_run_validators from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types -from ._make import ( +from ._make import ( NOTHING, Attribute, Factory, @@ -18,59 +18,59 @@ from ._make import ( fields_dict, make_class, validate, -) +) from ._version_info import VersionInfo - - + + __version__ = "21.2.0" __version_info__ = VersionInfo._from_version_string(__version__) - -__title__ = "attrs" -__description__ = "Classes Without Boilerplate" + +__title__ = "attrs" +__description__ = "Classes Without Boilerplate" __url__ = "https://www.attrs.org/" __uri__ = __url__ -__doc__ = __description__ + " <" + __uri__ + ">" - -__author__ = "Hynek Schlawack" -__email__ = "hs@ox.cx" - -__license__ = "MIT" -__copyright__ = "Copyright (c) 2015 Hynek Schlawack" - - -s = attributes = attrs -ib = attr = attrib -dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) - -__all__ = [ - "Attribute", - "Factory", - "NOTHING", - "asdict", - "assoc", - "astuple", - "attr", - "attrib", - "attributes", - "attrs", +__doc__ = __description__ + " <" + __uri__ + ">" + +__author__ = "Hynek Schlawack" +__email__ = "hs@ox.cx" + +__license__ = "MIT" +__copyright__ = "Copyright (c) 2015 Hynek Schlawack" + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + +__all__ = [ + "Attribute", + "Factory", + "NOTHING", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", "cmp_using", - "converters", - "evolve", - "exceptions", - "fields", - "fields_dict", - "filters", - "get_run_validators", - "has", - "ib", - "make_class", + "converters", + "evolve", + "exceptions", + "fields", + "fields_dict", + "filters", + "get_run_validators", + "has", + "ib", + "make_class", "resolve_types", - "s", - "set_run_validators", + "s", + "set_run_validators", "setters", - "validate", - "validators", -] + "validate", + "validators", +] if sys.version_info[:2] >= (3, 6): from ._next_gen import define, field, frozen, mutable diff --git a/contrib/python/attrs/attr/_compat.py b/contrib/python/attrs/attr/_compat.py index 9fefc975e1..6939f338da 100644 --- a/contrib/python/attrs/attr/_compat.py +++ b/contrib/python/attrs/attr/_compat.py @@ -1,33 +1,33 @@ -from __future__ import absolute_import, division, print_function - -import platform -import sys -import types -import warnings - - -PY2 = sys.version_info[0] == 2 -PYPY = platform.python_implementation() == "PyPy" - - -if PYPY or sys.version_info[:2] >= (3, 6): - ordered_dict = dict -else: - from collections import OrderedDict - - ordered_dict = OrderedDict - - -if PY2: +from __future__ import absolute_import, division, print_function + +import platform +import sys +import types +import warnings + + +PY2 = sys.version_info[0] == 2 +PYPY = platform.python_implementation() == "PyPy" + + +if PYPY or sys.version_info[:2] >= (3, 6): + ordered_dict = dict +else: + from collections import OrderedDict + + ordered_dict = OrderedDict + + +if PY2: from collections import Mapping, Sequence - + from UserDict import IterableUserDict - # We 'bundle' isclass instead of using inspect as importing inspect is - # fairly expensive (order of 10-15 ms for a modern machine in 2016) - def isclass(klass): - return isinstance(klass, (type, types.ClassType)) - + # We 'bundle' isclass instead of using inspect as importing inspect is + # fairly expensive (order of 10-15 ms for a modern machine in 2016) + def isclass(klass): + return isinstance(klass, (type, types.ClassType)) + def new_class(name, bases, kwds, exec_body): """ A minimal stub of types.new_class that we need for make_class. @@ -37,69 +37,69 @@ if PY2: return type(name, bases, ns) - # TYPE is used in exceptions, repr(int) is different on Python 2 and 3. - TYPE = "type" - - def iteritems(d): - return d.iteritems() - - # Python 2 is bereft of a read-only dict proxy, so we make one! - class ReadOnlyDict(IterableUserDict): - """ - Best-effort read-only dict wrapper. - """ - - def __setitem__(self, key, val): - # We gently pretend we're a Python 3 mappingproxy. + # TYPE is used in exceptions, repr(int) is different on Python 2 and 3. + TYPE = "type" + + def iteritems(d): + return d.iteritems() + + # Python 2 is bereft of a read-only dict proxy, so we make one! + class ReadOnlyDict(IterableUserDict): + """ + Best-effort read-only dict wrapper. + """ + + def __setitem__(self, key, val): + # We gently pretend we're a Python 3 mappingproxy. raise TypeError( "'mappingproxy' object does not support item assignment" ) - - def update(self, _): - # We gently pretend we're a Python 3 mappingproxy. + + def update(self, _): + # We gently pretend we're a Python 3 mappingproxy. raise AttributeError( "'mappingproxy' object has no attribute 'update'" ) - - def __delitem__(self, _): - # We gently pretend we're a Python 3 mappingproxy. + + def __delitem__(self, _): + # We gently pretend we're a Python 3 mappingproxy. raise TypeError( "'mappingproxy' object does not support item deletion" ) - - def clear(self): - # We gently pretend we're a Python 3 mappingproxy. + + def clear(self): + # We gently pretend we're a Python 3 mappingproxy. raise AttributeError( "'mappingproxy' object has no attribute 'clear'" ) - - def pop(self, key, default=None): - # We gently pretend we're a Python 3 mappingproxy. + + def pop(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. raise AttributeError( "'mappingproxy' object has no attribute 'pop'" ) - - def popitem(self): - # We gently pretend we're a Python 3 mappingproxy. + + def popitem(self): + # We gently pretend we're a Python 3 mappingproxy. raise AttributeError( "'mappingproxy' object has no attribute 'popitem'" ) - - def setdefault(self, key, default=None): - # We gently pretend we're a Python 3 mappingproxy. + + def setdefault(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. raise AttributeError( "'mappingproxy' object has no attribute 'setdefault'" ) - - def __repr__(self): - # Override to be identical to the Python 3 version. - return "mappingproxy(" + repr(self.data) + ")" - - def metadata_proxy(d): - res = ReadOnlyDict() - res.data.update(d) # We blocked update, so we have to do it like this. - return res - + + def __repr__(self): + # Override to be identical to the Python 3 version. + return "mappingproxy(" + repr(self.data) + ")" + + def metadata_proxy(d): + res = ReadOnlyDict() + res.data.update(d) # We blocked update, so we have to do it like this. + return res + def just_warn(*args, **kw): # pragma: no cover """ We only warn on Python 3 because we are not aware of any concrete @@ -123,30 +123,30 @@ else: # Python 3 and later. stacklevel=2, ) - def isclass(klass): - return isinstance(klass, type) - - TYPE = "class" - - def iteritems(d): - return d.items() - + def isclass(klass): + return isinstance(klass, type) + + TYPE = "class" + + def iteritems(d): + return d.items() + new_class = types.new_class - def metadata_proxy(d): - return types.MappingProxyType(dict(d)) - - -def make_set_closure_cell(): + def metadata_proxy(d): + return types.MappingProxyType(dict(d)) + + +def make_set_closure_cell(): """Return a function of two arguments (cell, value) which sets the value stored in the closure cell `cell` to `value`. - """ + """ # pypy makes this easy. (It also supports the logic below, but # why not do the easy/fast thing?) if PYPY: - def set_closure_cell(cell, value): - cell.__setstate__((value,)) + def set_closure_cell(cell, value): + cell.__setstate__((value,)) return set_closure_cell @@ -235,8 +235,8 @@ def make_set_closure_cell(): except Exception: return just_warn - else: + else: return set_closure_cell - - -set_closure_cell = make_set_closure_cell() + + +set_closure_cell = make_set_closure_cell() diff --git a/contrib/python/attrs/attr/_config.py b/contrib/python/attrs/attr/_config.py index 13923f3998..8ec920962d 100644 --- a/contrib/python/attrs/attr/_config.py +++ b/contrib/python/attrs/attr/_config.py @@ -1,23 +1,23 @@ -from __future__ import absolute_import, division, print_function - - -__all__ = ["set_run_validators", "get_run_validators"] - -_run_validators = True - - -def set_run_validators(run): - """ - Set whether or not validators are run. By default, they are run. - """ - if not isinstance(run, bool): - raise TypeError("'run' must be bool.") - global _run_validators - _run_validators = run - - -def get_run_validators(): - """ - Return whether or not validators are run. - """ - return _run_validators +from __future__ import absolute_import, division, print_function + + +__all__ = ["set_run_validators", "get_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + """ + if not isinstance(run, bool): + raise TypeError("'run' must be bool.") + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + """ + return _run_validators diff --git a/contrib/python/attrs/attr/_funcs.py b/contrib/python/attrs/attr/_funcs.py index 27487844af..fda508c5c4 100644 --- a/contrib/python/attrs/attr/_funcs.py +++ b/contrib/python/attrs/attr/_funcs.py @@ -1,12 +1,12 @@ -from __future__ import absolute_import, division, print_function - -import copy - -from ._compat import iteritems -from ._make import NOTHING, _obj_setattr, fields -from .exceptions import AttrsAttributeNotFoundError - - +from __future__ import absolute_import, division, print_function + +import copy + +from ._compat import iteritems +from ._make import NOTHING, _obj_setattr, fields +from .exceptions import AttrsAttributeNotFoundError + + def asdict( inst, recurse=True, @@ -15,50 +15,50 @@ def asdict( retain_collection_types=False, value_serializer=None, ): - """ - Return the ``attrs`` attribute values of *inst* as a dict. - - Optionally recurse into other ``attrs``-decorated classes. - - :param inst: Instance of an ``attrs``-decorated class. - :param bool recurse: Recurse into classes that are also - ``attrs``-decorated. - :param callable filter: A callable whose return code determines whether an - attribute or element is included (``True``) or dropped (``False``). Is + """ + Return the ``attrs`` attribute values of *inst* as a dict. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is called with the `attr.Attribute` as the first argument and the - value as the second argument. - :param callable dict_factory: A callable to produce dictionaries from. For - example, to produce ordered dictionaries instead of normal Python - dictionaries, pass in ``collections.OrderedDict``. - :param bool retain_collection_types: Do not convert to ``list`` when - encountering an attribute whose type is ``tuple`` or ``set``. Only - meaningful if ``recurse`` is ``True``. + value as the second argument. + :param callable dict_factory: A callable to produce dictionaries from. For + example, to produce ordered dictionaries instead of normal Python + dictionaries, pass in ``collections.OrderedDict``. + :param bool retain_collection_types: Do not convert to ``list`` when + encountering an attribute whose type is ``tuple`` or ``set``. Only + meaningful if ``recurse`` is ``True``. :param Optional[callable] value_serializer: A hook that is called for every attribute or dict key/value. It receives the current instance, field and value and must return the (updated) value. The hook is run *after* the optional *filter* has been applied. - - :rtype: return type of *dict_factory* - - :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` - class. - - .. versionadded:: 16.0.0 *dict_factory* - .. versionadded:: 16.1.0 *retain_collection_types* + + :rtype: return type of *dict_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* .. versionadded:: 20.3.0 *value_serializer* - """ - attrs = fields(inst.__class__) - rv = dict_factory() - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue if value_serializer is not None: v = value_serializer(inst, a, v) - if recurse is True: - if has(v.__class__): + if recurse is True: + if has(v.__class__): rv[a.name] = asdict( v, True, @@ -68,7 +68,7 @@ def asdict( value_serializer, ) elif isinstance(v, (tuple, list, set, frozenset)): - cf = v.__class__ if retain_collection_types is True else list + cf = v.__class__ if retain_collection_types is True else list rv[a.name] = cf( [ _asdict_anything( @@ -81,8 +81,8 @@ def asdict( for i in v ] ) - elif isinstance(v, dict): - df = dict_factory + elif isinstance(v, dict): + df = dict_factory rv[a.name] = df( ( _asdict_anything( @@ -102,13 +102,13 @@ def asdict( ) for kk, vv in iteritems(v) ) - else: - rv[a.name] = v - else: - rv[a.name] = v - return rv - - + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + def _asdict_anything( val, filter, @@ -116,7 +116,7 @@ def _asdict_anything( retain_collection_types, value_serializer, ): - """ + """ ``asdict`` only works on attrs instances, this works on anything. """ if getattr(val.__class__, "__attrs_attrs__", None) is not None: @@ -172,40 +172,40 @@ def astuple( retain_collection_types=False, ): """ - Return the ``attrs`` attribute values of *inst* as a tuple. - - Optionally recurse into other ``attrs``-decorated classes. - - :param inst: Instance of an ``attrs``-decorated class. - :param bool recurse: Recurse into classes that are also - ``attrs``-decorated. - :param callable filter: A callable whose return code determines whether an - attribute or element is included (``True``) or dropped (``False``). Is + Return the ``attrs`` attribute values of *inst* as a tuple. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is called with the `attr.Attribute` as the first argument and the - value as the second argument. - :param callable tuple_factory: A callable to produce tuples from. For - example, to produce lists instead of tuples. - :param bool retain_collection_types: Do not convert to ``list`` - or ``dict`` when encountering an attribute which type is - ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is - ``True``. - - :rtype: return type of *tuple_factory* - - :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` - class. - - .. versionadded:: 16.2.0 - """ - attrs = fields(inst.__class__) - rv = [] - retain = retain_collection_types # Very long. :/ - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - if recurse is True: - if has(v.__class__): + value as the second argument. + :param callable tuple_factory: A callable to produce tuples from. For + example, to produce lists instead of tuples. + :param bool retain_collection_types: Do not convert to ``list`` + or ``dict`` when encountering an attribute which type is + ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is + ``True``. + + :rtype: return type of *tuple_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): rv.append( astuple( v, @@ -216,7 +216,7 @@ def astuple( ) ) elif isinstance(v, (tuple, list, set, frozenset)): - cf = v.__class__ if retain is True else list + cf = v.__class__ if retain is True else list rv.append( cf( [ @@ -233,114 +233,114 @@ def astuple( ] ) ) - elif isinstance(v, dict): - df = v.__class__ if retain is True else dict + elif isinstance(v, dict): + df = v.__class__ if retain is True else dict rv.append( df( - ( - astuple( - kk, - tuple_factory=tuple_factory, + ( + astuple( + kk, + tuple_factory=tuple_factory, retain_collection_types=retain, ) if has(kk.__class__) else kk, - astuple( - vv, - tuple_factory=tuple_factory, + astuple( + vv, + tuple_factory=tuple_factory, retain_collection_types=retain, ) if has(vv.__class__) else vv, - ) + ) for kk, vv in iteritems(v) ) ) - else: - rv.append(v) - else: - rv.append(v) - - return rv if tuple_factory is list else tuple_factory(rv) - - -def has(cls): - """ - Check whether *cls* is a class with ``attrs`` attributes. - - :param type cls: Class to introspect. - :raise TypeError: If *cls* is not a class. - + else: + rv.append(v) + else: + rv.append(v) + + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with ``attrs`` attributes. + + :param type cls: Class to introspect. + :raise TypeError: If *cls* is not a class. + :rtype: bool - """ - return getattr(cls, "__attrs_attrs__", None) is not None - - -def assoc(inst, **changes): - """ - Copy *inst* and apply *changes*. - - :param inst: Instance of a class with ``attrs`` attributes. - :param changes: Keyword changes in the new copy. - - :return: A copy of inst with *changes* incorporated. - - :raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't - be found on *cls*. - :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` - class. - - .. deprecated:: 17.1.0 + """ + return getattr(cls, "__attrs_attrs__", None) is not None + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't + be found on *cls*. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. deprecated:: 17.1.0 Use `evolve` instead. - """ - import warnings + """ + import warnings warnings.warn( "assoc is deprecated and will be removed after 2018/01.", DeprecationWarning, stacklevel=2, ) - new = copy.copy(inst) - attrs = fields(inst.__class__) - for k, v in iteritems(changes): - a = getattr(attrs, k, NOTHING) - if a is NOTHING: - raise AttrsAttributeNotFoundError( + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in iteritems(changes): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + raise AttrsAttributeNotFoundError( "{k} is not an attrs attribute on {cl}.".format( k=k, cl=new.__class__ ) - ) - _obj_setattr(new, k, v) - return new - - -def evolve(inst, **changes): - """ - Create a new instance, based on *inst* with *changes* applied. - - :param inst: Instance of a class with ``attrs`` attributes. - :param changes: Keyword changes in the new copy. - - :return: A copy of inst with *changes* incorporated. - - :raise TypeError: If *attr_name* couldn't be found in the class - ``__init__``. - :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` - class. - - .. versionadded:: 17.1.0 - """ - cls = inst.__class__ - attrs = fields(cls) - for a in attrs: - if not a.init: - continue - attr_name = a.name # To deal with private attributes. - init_name = attr_name if attr_name[0] != "_" else attr_name[1:] - if init_name not in changes: - changes[init_name] = getattr(inst, attr_name) - - return cls(**changes) + ) + _obj_setattr(new, k, v) + return new + + +def evolve(inst, **changes): + """ + Create a new instance, based on *inst* with *changes* applied. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise TypeError: If *attr_name* couldn't be found in the class + ``__init__``. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 17.1.0 + """ + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = attr_name if attr_name[0] != "_" else attr_name[1:] + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + + return cls(**changes) def resolve_types(cls, globalns=None, localns=None, attribs=None): diff --git a/contrib/python/attrs/attr/_make.py b/contrib/python/attrs/attr/_make.py index e5d9352970..a1912b1233 100644 --- a/contrib/python/attrs/attr/_make.py +++ b/contrib/python/attrs/attr/_make.py @@ -1,17 +1,17 @@ -from __future__ import absolute_import, division, print_function - +from __future__ import absolute_import, division, print_function + import copy import inspect -import linecache -import sys -import threading +import linecache +import sys +import threading import uuid -import warnings - -from operator import itemgetter - +import warnings + +from operator import itemgetter + from . import _config, setters -from ._compat import ( +from ._compat import ( PY2, PYPY, isclass, @@ -20,24 +20,24 @@ from ._compat import ( new_class, ordered_dict, set_closure_cell, -) -from .exceptions import ( +) +from .exceptions import ( DefaultAlreadySetError, FrozenInstanceError, NotAnAttrsClassError, PythonTooOldError, UnannotatedAttributeError, -) - - +) + + if not PY2: import typing -# This is used at least twice, so cache it here. -_obj_setattr = object.__setattr__ +# This is used at least twice, so cache it here. +_obj_setattr = object.__setattr__ _init_converter_pat = "__attr_converter_%s" -_init_factory_pat = "__attr_factory_{}" +_init_factory_pat = "__attr_factory_{}" _tuple_property_pat = ( " {attr_name} = _attrs_property(_attrs_itemgetter({index}))" ) @@ -51,45 +51,45 @@ _classvar_prefixes = ( # name mangling when trying to create a slot for the field # (when slots=True) _hash_cache_field = "_attrs_cached_hash" - -_empty_metadata_singleton = metadata_proxy({}) - + +_empty_metadata_singleton = metadata_proxy({}) + # Unique object for unequivocal getattr() defaults. _sentinel = object() - -class _Nothing(object): - """ - Sentinel class to indicate the lack of a value when ``None`` is ambiguous. - + +class _Nothing(object): + """ + Sentinel class to indicate the lack of a value when ``None`` is ambiguous. + ``_Nothing`` is a singleton. There is only ever one of it. .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. - """ - + """ + _singleton = None - + def __new__(cls): if _Nothing._singleton is None: _Nothing._singleton = super(_Nothing, cls).__new__(cls) return _Nothing._singleton - - def __repr__(self): - return "NOTHING" - + + def __repr__(self): + return "NOTHING" + def __bool__(self): return False - + def __len__(self): return 0 # __bool__ for Python 2 -NOTHING = _Nothing() -""" -Sentinel to indicate the lack of a value when ``None`` is ambiguous. -""" - - +NOTHING = _Nothing() +""" +Sentinel to indicate the lack of a value when ``None`` is ambiguous. +""" + + class _CacheHashWrapper(int): """ An integer subclass that pickles / copies as None @@ -131,51 +131,51 @@ def attrib( order=None, on_setattr=None, ): - """ - Create a new attribute on a class. - - .. warning:: - - Does *not* do anything unless the class is also decorated with + """ + Create a new attribute on a class. + + .. warning:: + + Does *not* do anything unless the class is also decorated with `attr.s`! - - :param default: A value that is used if an ``attrs``-generated ``__init__`` - is used and no value is passed while instantiating or the attribute is - excluded using ``init=False``. - + + :param default: A value that is used if an ``attrs``-generated ``__init__`` + is used and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + If the value is an instance of `Factory`, its callable will be - used to construct a new value (useful for mutable data types like lists - or dicts). - + used to construct a new value (useful for mutable data types like lists + or dicts). + If a default is not set (or set manually to `attr.NOTHING`), a value *must* be supplied when instantiating; otherwise a `TypeError` - will be raised. - - The default can also be set using decorator notation as shown below. - + will be raised. + + The default can also be set using decorator notation as shown below. + :type default: Any value - - :param callable factory: Syntactic sugar for + + :param callable factory: Syntactic sugar for ``default=attr.Factory(factory)``. - + :param validator: `callable` that is called by ``attrs``-generated - ``__init__`` methods after the instance has been initialized. They + ``__init__`` methods after the instance has been initialized. They receive the initialized instance, the `Attribute`, and the - passed value. - - The return value is *not* inspected so the validator has to throw an - exception itself. - + passed value. + + The return value is *not* inspected so the validator has to throw an + exception itself. + If a `list` is passed, its items are treated as validators and must - all pass. - - Validators can be globally disabled and re-enabled using + all pass. + + Validators can be globally disabled and re-enabled using `get_run_validators`. - - The validator can also be set using decorator notation as shown below. - + + The validator can also be set using decorator notation as shown below. + :type validator: `callable` or a `list` of `callable`\\ s. - + :param repr: Include this attribute in the generated ``__repr__`` method. If ``True``, include the attribute; if ``False``, omit it. By default, the built-in ``repr()`` function is used. To override how the @@ -207,24 +207,24 @@ def attrib( ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This is the correct behavior according the Python spec. Setting this value to anything else than ``None`` is *discouraged*. - :param bool init: Include this attribute in the generated ``__init__`` - method. It is possible to set this to ``False`` and set a default - value. In that case this attributed is unconditionally initialized - with the specified default value or factory. + :param bool init: Include this attribute in the generated ``__init__`` + method. It is possible to set this to ``False`` and set a default + value. In that case this attributed is unconditionally initialized + with the specified default value or factory. :param callable converter: `callable` that is called by ``attrs``-generated ``__init__`` methods to convert attribute's value - to the desired format. It is given the passed-in value, and the - returned value will be used as the new value of the attribute. The - value is converted before being passed to the validator, if any. - :param metadata: An arbitrary mapping, to be used by third-party + to the desired format. It is given the passed-in value, and the + returned value will be used as the new value of the attribute. The + value is converted before being passed to the validator, if any. + :param metadata: An arbitrary mapping, to be used by third-party components. See `extending_metadata`. - :param type: The type of the attribute. In Python 3.6 or greater, the - preferred method to specify the type is using a variable annotation - (see `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_). - This argument is provided for backward compatibility. - Regardless of the approach used, the type will be stored on - ``Attribute.type``. - + :param type: The type of the attribute. In Python 3.6 or greater, the + preferred method to specify the type is using a variable annotation + (see `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_). + This argument is provided for backward compatibility. + Regardless of the approach used, the type will be stored on + ``Attribute.type``. + Please note that ``attrs`` doesn't do anything with this metadata by itself. You can use it as part of your own code or for `static type checking <types>`. @@ -238,17 +238,17 @@ def attrib( :type on_setattr: `callable`, or a list of callables, or `None`, or `attr.setters.NO_OP` - .. versionadded:: 15.2.0 *convert* - .. versionadded:: 16.3.0 *metadata* - .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. - .. versionchanged:: 17.1.0 + .. versionadded:: 15.2.0 *convert* + .. versionadded:: 16.3.0 *metadata* + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 *hash* is ``None`` and therefore mirrors *eq* by default. - .. versionadded:: 17.3.0 *type* - .. deprecated:: 17.4.0 *convert* - .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated - *convert* to achieve consistency with other noun-based arguments. - .. versionadded:: 18.1.0 - ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. + .. versionadded:: 17.3.0 *type* + .. deprecated:: 17.4.0 *convert* + .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated + *convert* to achieve consistency with other noun-based arguments. + .. versionadded:: 18.1.0 + ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. .. versionadded:: 18.2.0 *kw_only* .. versionchanged:: 19.2.0 *convert* keyword argument removed. .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. @@ -259,29 +259,29 @@ def attrib( .. versionchanged:: 21.1.0 *eq*, *order*, and *cmp* also accept a custom callable .. versionchanged:: 21.1.0 *cmp* undeprecated - """ + """ eq, eq_key, order, order_key = _determine_attrib_eq_order( cmp, eq, order, True ) - if hash is not None and hash is not True and hash is not False: - raise TypeError( - "Invalid value for hash. Must be True, False, or None." - ) - - if factory is not None: - if default is not NOTHING: - raise ValueError( - "The `default` and `factory` arguments are mutually " - "exclusive." - ) - if not callable(factory): + if hash is not None and hash is not True and hash is not False: + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + + if factory is not None: + if default is not NOTHING: + raise ValueError( + "The `default` and `factory` arguments are mutually " + "exclusive." + ) + if not callable(factory): raise ValueError("The `factory` argument must be a callable.") - default = Factory(factory) - - if metadata is None: - metadata = {} - + default = Factory(factory) + + if metadata is None: + metadata = {} + # Apply syntactic sugar by auto-wrapping. if isinstance(on_setattr, (list, tuple)): on_setattr = setters.pipe(*on_setattr) @@ -292,25 +292,25 @@ def attrib( if converter and isinstance(converter, (list, tuple)): converter = pipe(*converter) - return _CountingAttr( - default=default, - validator=validator, - repr=repr, + return _CountingAttr( + default=default, + validator=validator, + repr=repr, cmp=None, - hash=hash, - init=init, - converter=converter, - metadata=metadata, - type=type, + hash=hash, + init=init, + converter=converter, + metadata=metadata, + type=type, kw_only=kw_only, eq=eq, eq_key=eq_key, order=order, order_key=order_key, on_setattr=on_setattr, - ) - - + ) + + def _compile_and_eval(script, globs, locs=None, filename=""): """ "Exec" the script with the given global (globs) and local (locs) variables. @@ -341,34 +341,34 @@ def _make_method(name, script, filename, globs=None): return locs[name] -def _make_attr_tuple_class(cls_name, attr_names): - """ - Create a tuple subclass to hold `Attribute`s for an `attrs` class. - - The subclass is a bare tuple with properties for names. - - class MyClassAttributes(tuple): - __slots__ = () - x = property(itemgetter(0)) - """ - attr_class_name = "{}Attributes".format(cls_name) - attr_class_template = [ - "class {}(tuple):".format(attr_class_name), - " __slots__ = ()", - ] - if attr_names: - for i, attr_name in enumerate(attr_names): +def _make_attr_tuple_class(cls_name, attr_names): + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = "{}Attributes".format(cls_name) + attr_class_template = [ + "class {}(tuple):".format(attr_class_name), + " __slots__ = ()", + ] + if attr_names: + for i, attr_name in enumerate(attr_names): attr_class_template.append( _tuple_property_pat.format(index=i, attr_name=attr_name) ) - else: - attr_class_template.append(" pass") + else: + attr_class_template.append(" pass") globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} _compile_and_eval("\n".join(attr_class_template), globs) - return globs[attr_class_name] - - -# Tuple class for extracted attributes from a class definition. + return globs[attr_class_name] + + +# Tuple class for extracted attributes from a class definition. # `base_attrs` is a subset of `attrs`. _Attributes = _make_attr_tuple_class( "_Attributes", @@ -381,22 +381,22 @@ _Attributes = _make_attr_tuple_class( "base_attrs_map", ], ) - - -def _is_class_var(annot): - """ - Check whether *annot* is a typing.ClassVar. - - The string comparison hack is used to avoid evaluating all string - annotations which would put attrs-based classes at a performance - disadvantage compared to plain old classes. - """ + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The string comparison hack is used to avoid evaluating all string + annotations which would put attrs-based classes at a performance + disadvantage compared to plain old classes. + """ annot = str(annot) - + # Annotation can be quoted. if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): annot = annot[1:-1] - + return annot.startswith(_classvar_prefixes) @@ -418,25 +418,25 @@ def _has_own_attribute(cls, attrib_name): return True -def _get_annotations(cls): - """ - Get annotations for *cls*. - """ +def _get_annotations(cls): + """ + Get annotations for *cls*. + """ if _has_own_attribute(cls, "__annotations__"): return cls.__annotations__ - + return {} - - -def _counter_getter(e): - """ - Key function for sorting to avoid re-creating a lambda for every class. - """ - return e[1].counter - - + + +def _counter_getter(e): + """ + Key function for sorting to avoid re-creating a lambda for every class. + """ + return e[1].counter + + def _collect_base_attrs(cls, taken_attr_names): - """ + """ Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. """ base_attrs = [] @@ -498,54 +498,54 @@ def _transform_attrs( cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer ): """ - Transform all `_CountingAttr`s on a class into `Attribute`s. - - If *these* is passed, use that and don't look for them on the class. - + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + *collect_by_mro* is True, collect them in the correct MRO order, otherwise use the old -- incorrect -- order. See #428. - Return an `_Attributes`. - """ - cd = cls.__dict__ - anns = _get_annotations(cls) - - if these is not None: + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: ca_list = [(name, ca) for name, ca in iteritems(these)] - - if not isinstance(these, ordered_dict): - ca_list.sort(key=_counter_getter) - elif auto_attribs is True: - ca_names = { - name + + if not isinstance(these, ordered_dict): + ca_list.sort(key=_counter_getter) + elif auto_attribs is True: + ca_names = { + name for name, attr in cd.items() - if isinstance(attr, _CountingAttr) - } - ca_list = [] - annot_names = set() - for attr_name, type in anns.items(): - if _is_class_var(type): - continue - annot_names.add(attr_name) - a = cd.get(attr_name, NOTHING) - - if not isinstance(a, _CountingAttr): - if a is NOTHING: - a = attrib() - else: - a = attrib(default=a) - ca_list.append((attr_name, a)) - - unannotated = ca_names - annot_names - if len(unannotated) > 0: - raise UnannotatedAttributeError( + if isinstance(attr, _CountingAttr) + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + + if not isinstance(a, _CountingAttr): + if a is NOTHING: + a = attrib() + else: + a = attrib(default=a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if len(unannotated) > 0: + raise UnannotatedAttributeError( "The following `attr.ib`s lack a type annotation: " + ", ".join( sorted(unannotated, key=lambda n: cd.get(n).counter) ) + "." - ) - else: + ) + else: ca_list = sorted( ( (name, attr) @@ -554,14 +554,14 @@ def _transform_attrs( ), key=lambda e: e[1].counter, ) - - own_attrs = [ - Attribute.from_counting_attr( + + own_attrs = [ + Attribute.from_counting_attr( name=attr_name, ca=ca, type=anns.get(attr_name) - ) + ) for attr_name, ca in ca_list - ] - + ] + if collect_by_mro: base_attrs, base_attr_map = _collect_base_attrs( cls, {a.name for a in own_attrs} @@ -570,39 +570,39 @@ def _transform_attrs( base_attrs, base_attr_map = _collect_base_attrs_broken( cls, {a.name for a in own_attrs} ) - + attr_names = [a.name for a in base_attrs + own_attrs] - - AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) - + + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + if kw_only: own_attrs = [a.evolve(kw_only=True) for a in own_attrs] base_attrs = [a.evolve(kw_only=True) for a in base_attrs] - + attrs = AttrsClass(base_attrs + own_attrs) # Mandatory vs non-mandatory attr order only matters when they are part of # the __init__ signature and when they aren't kw_only (which are moved to # the end and can be mandatory or non-mandatory in any order, as they will # be specified as keyword args anyway). Check the order of those attrs: - had_default = False + had_default = False for a in (a for a in attrs if a.init is not False and a.kw_only is False): if had_default is True and a.default is NOTHING: - raise ValueError( - "No mandatory attributes allowed after an attribute with a " + raise ValueError( + "No mandatory attributes allowed after an attribute with a " "default value or factory. Attribute in question: %r" % (a,) - ) + ) if had_default is False and a.default is not NOTHING: - had_default = True - + had_default = True + if field_transformer is not None: attrs = field_transformer(cls, attrs) return _Attributes((attrs, base_attrs, base_attr_map)) - - + + if PYPY: - + def _frozen_setattrs(self, name, value): """ Attached to frozen classes as __setattr__. @@ -613,7 +613,7 @@ if PYPY: ): BaseException.__setattr__(self, name, value) return - + raise FrozenInstanceError() @@ -626,19 +626,19 @@ else: raise FrozenInstanceError() -def _frozen_delattrs(self, name): - """ - Attached to frozen classes as __delattr__. - """ - raise FrozenInstanceError() - - -class _ClassBuilder(object): - """ - Iteratively build *one* class. - """ +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + raise FrozenInstanceError() + - __slots__ = ( +class _ClassBuilder(object): + """ + Iteratively build *one* class. + """ + + __slots__ = ( "_attr_names", "_attrs", "_base_attr_map", @@ -656,8 +656,8 @@ class _ClassBuilder(object): "_weakref_slot", "_has_own_setattr", "_has_custom_setattr", - ) - + ) + def __init__( self, cls, @@ -682,33 +682,33 @@ class _ClassBuilder(object): kw_only, collect_by_mro, field_transformer, - ) - - self._cls = cls - self._cls_dict = dict(cls.__dict__) if slots else {} - self._attrs = attrs + ) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if slots else {} + self._attrs = attrs self._base_names = set(a.name for a in base_attrs) self._base_attr_map = base_map - self._attr_names = tuple(a.name for a in attrs) - self._slots = slots + self._attr_names = tuple(a.name for a in attrs) + self._slots = slots self._frozen = frozen self._weakref_slot = weakref_slot self._cache_hash = cache_hash self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) - self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) - self._delete_attribs = not bool(these) + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + self._delete_attribs = not bool(these) self._is_exc = is_exc self._on_setattr = on_setattr - + self._has_custom_setattr = has_custom_setattr self._has_own_setattr = False - self._cls_dict["__attrs_attrs__"] = self._attrs - - if frozen: - self._cls_dict["__setattr__"] = _frozen_setattrs - self._cls_dict["__delattr__"] = _frozen_delattrs - + self._cls_dict["__attrs_attrs__"] = self._attrs + + if frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + self._has_own_setattr = True if getstate_setstate: @@ -717,30 +717,30 @@ class _ClassBuilder(object): self._cls_dict["__setstate__"], ) = self._make_getstate_setstate() - def __repr__(self): - return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) - - def build_class(self): - """ - Finalize class based on the accumulated configuration. - + def __repr__(self): + return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + Builder cannot be used after calling this method. - """ - if self._slots is True: - return self._create_slots_class() - else: - return self._patch_original_class() - - def _patch_original_class(self): - """ - Apply accumulated methods and return the class. - """ - cls = self._cls + """ + if self._slots is True: + return self._create_slots_class() + else: + return self._patch_original_class() + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls base_names = self._base_names - - # Clean class of attribute definitions (`attr.ib()`s). - if self._delete_attribs: - for name in self._attr_names: + + # Clean class of attribute definitions (`attr.ib()`s). + if self._delete_attribs: + for name in self._attr_names: if ( name not in base_names and getattr(cls, name, _sentinel) is not _sentinel @@ -752,11 +752,11 @@ class _ClassBuilder(object): # variable and we want to set an attribute with the # same name by using only a type annotation. pass - - # Attach our dunder methods. - for name, value in self._cls_dict.items(): - setattr(cls, name, value) - + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + # If we've inherited an attrs __setattr__ and don't write our own, # reset it to object's. if not self._has_own_setattr and getattr( @@ -767,18 +767,18 @@ class _ClassBuilder(object): if not self._has_custom_setattr: cls.__setattr__ = object.__setattr__ - return cls - - def _create_slots_class(self): - """ - Build and return a new class with a `__slots__` attribute. - """ - cd = { - k: v - for k, v in iteritems(self._cls_dict) + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + cd = { + k: v + for k, v in iteritems(self._cls_dict) if k not in tuple(self._attr_names) + ("__dict__", "__weakref__") - } - + } + # If our class doesn't have its own implementation of __setattr__ # (either from the user or by us), check the bases, if one of them has # an attrs-made __setattr__, that needs to be reset. We don't walk the @@ -821,7 +821,7 @@ class _ClassBuilder(object): ): names += ("__weakref__",) - # We only add the names of attributes that aren't inherited. + # We only add the names of attributes that aren't inherited. # Setting __slots__ to inherited attributes wastes memory. slot_names = [name for name in names if name not in base_names] # There are slots for attributes from current class @@ -838,35 +838,35 @@ class _ClassBuilder(object): if self._cache_hash: slot_names.append(_hash_cache_field) cd["__slots__"] = tuple(slot_names) - - qualname = getattr(self._cls, "__qualname__", None) - if qualname is not None: - cd["__qualname__"] = qualname - - # Create new class based on old class and our methods. + + qualname = getattr(self._cls, "__qualname__", None) + if qualname is not None: + cd["__qualname__"] = qualname + + # Create new class based on old class and our methods. cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) - - # The following is a fix for - # https://github.com/python-attrs/attrs/issues/102. On Python 3, - # if a method mentions `__class__` or uses the no-arg super(), the - # compiler will bake a reference to the class in the method itself - # as `method.__closure__`. Since we replace the class with a - # clone, we rewrite these references so it keeps working. - for item in cls.__dict__.values(): - if isinstance(item, (classmethod, staticmethod)): - # Class- and staticmethods hide their functions inside. - # These might need to be rewritten as well. - closure_cells = getattr(item.__func__, "__closure__", None) + + # The following is a fix for + # https://github.com/python-attrs/attrs/issues/102. On Python 3, + # if a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in cls.__dict__.values(): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) elif isinstance(item, property): # Workaround for property `super()` shortcut (PY3-only). # There is no universal way for other descriptors. closure_cells = getattr(item.fget, "__closure__", None) - else: - closure_cells = getattr(item, "__closure__", None) - - if not closure_cells: # Catch None or the empty list. - continue - for cell in closure_cells: + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: try: match = cell.cell_contents is self._cls except ValueError: # ValueError: Cell is empty @@ -874,28 +874,28 @@ class _ClassBuilder(object): else: if match: set_closure_cell(cell, cls) - - return cls - - def add_repr(self, ns): - self._cls_dict["__repr__"] = self._add_method_dunders( - _make_repr(self._attrs, ns=ns) - ) - return self - - def add_str(self): - repr = self._cls_dict.get("__repr__") - if repr is None: - raise ValueError( - "__str__ can only be generated if a __repr__ exists." - ) - - def __str__(self): - return self.__repr__() - - self._cls_dict["__str__"] = self._add_method_dunders(__str__) - return self - + + return cls + + def add_repr(self, ns): + self._cls_dict["__repr__"] = self._add_method_dunders( + _make_repr(self._attrs, ns=ns) + ) + return self + + def add_str(self): + repr = self._cls_dict.get("__repr__") + if repr is None: + raise ValueError( + "__str__ can only be generated if a __repr__ exists." + ) + + def __str__(self): + return self.__repr__() + + self._cls_dict["__str__"] = self._add_method_dunders(__str__) + return self + def _make_getstate_setstate(self): """ Create custom __setstate__ and __getstate__ methods. @@ -930,42 +930,42 @@ class _ClassBuilder(object): return slots_getstate, slots_setstate - def make_unhashable(self): - self._cls_dict["__hash__"] = None - return self - - def add_hash(self): - self._cls_dict["__hash__"] = self._add_method_dunders( + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + self._cls_dict["__hash__"] = self._add_method_dunders( _make_hash( self._cls, self._attrs, frozen=self._frozen, cache_hash=self._cache_hash, ) - ) - - return self - - def add_init(self): - self._cls_dict["__init__"] = self._add_method_dunders( - _make_init( + ) + + return self + + def add_init(self): + self._cls_dict["__init__"] = self._add_method_dunders( + _make_init( self._cls, - self._attrs, + self._attrs, self._has_pre_init, - self._has_post_init, - self._frozen, - self._slots, + self._has_post_init, + self._frozen, + self._slots, self._cache_hash, self._base_attr_map, self._is_exc, self._on_setattr is not None and self._on_setattr is not setters.NO_OP, attrs_init=False, - ) - ) - - return self - + ) + ) + + return self + def add_attrs_init(self): self._cls_dict["__attrs_init__"] = self._add_method_dunders( _make_init( @@ -987,15 +987,15 @@ class _ClassBuilder(object): return self def add_eq(self): - cd = self._cls_dict - + cd = self._cls_dict + cd["__eq__"] = self._add_method_dunders( _make_eq(self._cls, self._attrs) ) cd["__ne__"] = self._add_method_dunders(_make_ne()) - - return self - + + return self + def add_order(self): cd = self._cls_dict @@ -1042,22 +1042,22 @@ class _ClassBuilder(object): return self - def _add_method_dunders(self, method): - """ - Add __module__ and __qualname__ to a *method* if possible. - """ - try: - method.__module__ = self._cls.__module__ - except AttributeError: - pass - - try: - method.__qualname__ = ".".join( + def _add_method_dunders(self, method): + """ + Add __module__ and __qualname__ to a *method* if possible. + """ + try: + method.__module__ = self._cls.__module__ + except AttributeError: + pass + + try: + method.__qualname__ = ".".join( (self._cls.__qualname__, method.__name__) - ) - except AttributeError: - pass - + ) + except AttributeError: + pass + try: method.__doc__ = "Method generated by attrs for class %s." % ( self._cls.__qualname__, @@ -1065,9 +1065,9 @@ class _ClassBuilder(object): except AttributeError: pass - return method - - + return method + + _CMP_DEPRECATION = ( "The usage of `cmp` is deprecated and will be removed on or after " "2021-06-01. Please use `eq` and `order` instead." @@ -1193,29 +1193,29 @@ def attrs( on_setattr=None, field_transformer=None, ): - r""" - A class decorator that adds `dunder - <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the + r""" + A class decorator that adds `dunder + <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the specified attributes using `attr.ib` or the *these* argument. - + :param these: A dictionary of name to `attr.ib` mappings. This is - useful to avoid the definition of your attributes within the class body - because you can't (e.g. if you want to add ``__repr__`` methods to - Django models) or don't want to. - - If *these* is not ``None``, ``attrs`` will *not* search the class body - for attributes and will *not* remove any attributes from it. - + useful to avoid the definition of your attributes within the class body + because you can't (e.g. if you want to add ``__repr__`` methods to + Django models) or don't want to. + + If *these* is not ``None``, ``attrs`` will *not* search the class body + for attributes and will *not* remove any attributes from it. + If *these* is an ordered dict (`dict` on Python 3.6+, `collections.OrderedDict` otherwise), the order is deduced from - the order of the attributes inside *these*. Otherwise the order - of the definition of the attributes is used. - + the order of the attributes inside *these*. Otherwise the order + of the definition of the attributes is used. + :type these: `dict` of `str` to `attr.ib` - - :param str repr_ns: When using nested classes, there's no way in Python 2 - to automatically detect that. Therefore it's possible to set the - namespace explicitly for a more meaningful ``repr`` output. + + :param str repr_ns: When using nested classes, there's no way in Python 2 + to automatically detect that. Therefore it's possible to set the + namespace explicitly for a more meaningful ``repr`` output. :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, *order*, and *hash* arguments explicitly, assume they are set to ``True`` **unless any** of the involved methods for one of the @@ -1242,10 +1242,10 @@ def attrs( *auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises a `PythonTooOldError`. - :param bool repr: Create a ``__repr__`` method with a human readable - representation of ``attrs`` attributes.. - :param bool str: Create a ``__str__`` method that is identical to - ``__repr__``. This is usually not necessary except for + :param bool repr: Create a ``__repr__`` method with a human readable + representation of ``attrs`` attributes.. + :param bool str: Create a ``__str__`` method that is identical to + ``__repr__``. This is usually not necessary except for `Exception`\ s. :param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__`` and ``__ne__`` methods that check two instances for equality. @@ -1260,24 +1260,24 @@ def attrs( and *order* to the same value. Must not be mixed with *eq* or *order*. :param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method is generated according how *eq* and *frozen* are set. - - 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. + + 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to - None, marking it unhashable (which it is). + None, marking it unhashable (which it is). 3. If *eq* is False, ``__hash__`` will be left untouched meaning the ``__hash__`` method of the base class will be used (if base class is - ``object``, this means it will fall back to id-based hashing.). - - Although not recommended, you can decide for yourself and force - ``attrs`` to create one (e.g. if the class is immutable even though you - didn't freeze it programmatically) by passing ``True`` or not. Both of - these cases are rather special and should be used carefully. - + ``object``, this means it will fall back to id-based hashing.). + + Although not recommended, you can decide for yourself and force + ``attrs`` to create one (e.g. if the class is immutable even though you + didn't freeze it programmatically) by passing ``True`` or not. Both of + these cases are rather special and should be used carefully. + See our documentation on `hashing`, Python's documentation on `object.__hash__`, and the `GitHub issue that led to the default \ behavior <https://github.com/python-attrs/attrs/issues/136>`_ for more details. - :param bool init: Create a ``__init__`` method that initializes the + :param bool init: Create a ``__init__`` method that initializes the ``attrs`` attributes. Leading underscores are stripped for the argument name. If a ``__attrs_pre_init__`` method exists on the class, it will be called before the class is initialized. If a ``__attrs_post_init__`` @@ -1292,47 +1292,47 @@ def attrs( memory-efficient. Slotted classes are generally superior to the default dict classes, but have some gotchas you should know about, so we encourage you to read the `glossary entry <slotted classes>`. - :param bool frozen: Make instances immutable after initialization. If - someone attempts to modify a frozen instance, + :param bool frozen: Make instances immutable after initialization. If + someone attempts to modify a frozen instance, `attr.exceptions.FrozenInstanceError` is raised. - + .. note:: - - 1. This is achieved by installing a custom ``__setattr__`` method + + 1. This is achieved by installing a custom ``__setattr__`` method on your class, so you can't implement your own. - - 2. True immutability is impossible in Python. - + + 2. True immutability is impossible in Python. + 3. This *does* have a minor a runtime performance `impact - <how-frozen>` when initializing new instances. In other words: - ``__init__`` is slightly slower with ``frozen=True``. - - 4. If a class is frozen, you cannot modify ``self`` in - ``__attrs_post_init__`` or a self-written ``__init__``. You can - circumvent that limitation by using - ``object.__setattr__(self, "attribute_name", value)``. - + <how-frozen>` when initializing new instances. In other words: + ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You can + circumvent that limitation by using + ``object.__setattr__(self, "attribute_name", value)``. + 5. Subclasses of a frozen class are frozen too. :param bool weakref_slot: Make instances weak-referenceable. This has no effect unless ``slots`` is also enabled. :param bool auto_attribs: If ``True``, collect `PEP 526`_-annotated attributes (Python 3.6 and later only) from the class body. - - In this case, you **must** annotate every field. If ``attrs`` + + In this case, you **must** annotate every field. If ``attrs`` encounters a field that is set to an `attr.ib` but lacks a type annotation, an `attr.exceptions.UnannotatedAttributeError` is - raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't - want to set a type. - - If you assign a value to those attributes (e.g. ``x: int = 42``), that - value becomes the default value like if it were passed using + raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't + want to set a type. + + If you assign a value to those attributes (e.g. ``x: int = 42``), that + value becomes the default value like if it were passed using ``attr.ib(default=42)``. Passing an instance of `Factory` also works as expected in most cases (see warning below). - + Attributes annotated as `typing.ClassVar`, and attributes that are neither annotated nor set to an `attr.ib` are **ignored**. - + .. warning:: For features that use the attribute name to create decorators (e.g. `validators <validators>`), you still *must* assign `attr.ib` to @@ -1342,7 +1342,7 @@ def attrs( These errors can be quite confusing and probably the most common bug report on our bug tracker. - .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ + .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ :param bool kw_only: Make all attributes keyword-only (Python 3+) in the generated ``__init__`` (if ``init`` is ``False``, this parameter is ignored). @@ -1357,7 +1357,7 @@ def attrs( (which implicitly includes any subclass of any exception), the following happens to behave like a well-behaved Python exceptions class: - + - the values for *eq*, *order*, and *hash* are ignored and the instances compare and hash by the instance's ids (N.B. ``attrs`` will *not* remove existing implementations of ``__hash__`` or the equality @@ -1407,16 +1407,16 @@ def attrs( this, e.g., to automatically add converters or validators to fields based on their types. See `transform-fields` for more details. - .. versionadded:: 16.0.0 *slots* - .. versionadded:: 16.1.0 *frozen* - .. versionadded:: 16.3.0 *str* - .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. - .. versionchanged:: 17.1.0 - *hash* supports ``None`` as value which is also the default now. - .. versionadded:: 17.3.0 *auto_attribs* - .. versionchanged:: 18.1.0 - If *these* is passed, no attributes are deleted from the class body. - .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str* + .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. + .. versionchanged:: 17.1.0 + *hash* supports ``None`` as value which is also the default now. + .. versionadded:: 17.3.0 *auto_attribs* + .. versionchanged:: 18.1.0 + If *these* is passed, no attributes are deleted from the class body. + .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. .. versionadded:: 18.2.0 *weakref_slot* .. deprecated:: 18.2.0 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a @@ -1440,7 +1440,7 @@ def attrs( ``init=False`` injects ``__attrs_init__`` .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` .. versionchanged:: 21.1.0 *cmp* undeprecated - """ + """ if auto_detect and PY2: raise PythonTooOldError( "auto_detect only works on Python 3 and later." @@ -1452,11 +1452,11 @@ def attrs( if isinstance(on_setattr, (list, tuple)): on_setattr = setters.pipe(*on_setattr) - def wrap(cls): + def wrap(cls): + + if getattr(cls, "__class__", None) is None: + raise TypeError("attrs only works with new-style classes.") - if getattr(cls, "__class__", None) is None: - raise TypeError("attrs only works with new-style classes.") - is_frozen = frozen or _has_frozen_base_class(cls) is_exc = auto_exc is True and issubclass(cls, BaseException) has_own_setattr = auto_detect and _has_own_attribute( @@ -1491,9 +1491,9 @@ def attrs( if _determine_whether_to_implement( cls, repr, auto_detect, ("__repr__",) ): - builder.add_repr(repr_ns) - if str is True: - builder.add_str() + builder.add_repr(repr_ns) + if str is True: + builder.add_str() eq = _determine_whether_to_implement( cls, eq_, auto_detect, ("__eq__", "__ne__") @@ -1504,7 +1504,7 @@ def attrs( cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") ): builder.add_order() - + builder.add_setattr() if ( @@ -1515,11 +1515,11 @@ def attrs( hash = False else: hash = hash_ - if hash is not True and hash is not False and hash is not None: - # Can't use `hash in` because 1 == True for example. - raise TypeError( - "Invalid value for hash. Must be True, False, or None." - ) + if hash is not True and hash is not False and hash is not None: + # Can't use `hash in` because 1 == True for example. + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) elif hash is False or (hash is None and eq is False) or is_exc: # Don't do anything. Should fall back to __object__'s __hash__ # which is by id. @@ -1533,8 +1533,8 @@ def attrs( hash is None and eq is True and is_frozen is True ): # Build a __hash__ if told so, or if it's safe. - builder.add_hash() - else: + builder.add_hash() + else: # Raise TypeError on attempts to hash. if cache_hash: raise TypeError( @@ -1542,12 +1542,12 @@ def attrs( " hashing must be either explicitly or implicitly " "enabled." ) - builder.make_unhashable() - + builder.make_unhashable() + if _determine_whether_to_implement( cls, init, auto_detect, ("__init__",) ): - builder.add_init() + builder.add_init() else: builder.add_attrs_init() if cache_hash: @@ -1555,48 +1555,48 @@ def attrs( "Invalid value for cache_hash. To use hash caching," " init must be True." ) - - return builder.build_class() - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but ``None`` if used as `@attrs()`. - if maybe_cls is None: - return wrap - else: - return wrap(maybe_cls) - - -_attrs = attrs -""" -Internal alias so we can use it in functions that take an argument called -*attrs*. -""" - - -if PY2: + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + else: + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +if PY2: def _has_frozen_base_class(cls): - """ - Check whether *cls* has a frozen ancestor by looking at its - __setattr__. - """ - return ( + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return ( getattr(cls.__setattr__, "__module__", None) == _frozen_setattrs.__module__ and cls.__setattr__.__name__ == _frozen_setattrs.__name__ - ) + ) -else: +else: def _has_frozen_base_class(cls): - """ - Check whether *cls* has a frozen ancestor by looking at its - __setattr__. - """ - return cls.__setattr__ == _frozen_setattrs - - + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ == _frozen_setattrs + + def _generate_unique_filename(cls, func_name): """ Create a "filename" suitable for a function being generated. @@ -1628,15 +1628,15 @@ def _generate_unique_filename(cls, func_name): def _make_hash(cls, attrs, frozen, cache_hash): - attrs = tuple( + attrs = tuple( a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) - ) - + ) + tab = " " unique_filename = _generate_unique_filename(cls, "hash") - type_hash = hash(unique_filename) - + type_hash = hash(unique_filename) + hash_def = "def __hash__(self" hash_func = "hash((" closing_braces = "))" @@ -1645,7 +1645,7 @@ def _make_hash(cls, attrs, frozen, cache_hash): else: if not PY2: hash_def += ", *" - + hash_def += ( ", _cache_wrapper=" + "__import__('attr._make')._make._CacheHashWrapper):" @@ -1691,21 +1691,21 @@ def _make_hash(cls, attrs, frozen, cache_hash): script = "\n".join(method_lines) return _make_method("__hash__", script, unique_filename) - - -def _add_hash(cls, attrs): - """ - Add a hash method to *cls*. - """ + + +def _add_hash(cls, attrs): + """ + Add a hash method to *cls*. + """ cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False) - return cls - - + return cls + + def _make_ne(): - """ + """ Create __ne__ method. - """ - + """ + def __ne__(self, other): """ Check equality and either forward a NotImplemented or @@ -1714,9 +1714,9 @@ def _make_ne(): result = self.__eq__(other) if result is NotImplemented: return NotImplemented - + return not result - + return __ne__ @@ -1727,19 +1727,19 @@ def _make_eq(cls, attrs): attrs = [a for a in attrs if a.eq] unique_filename = _generate_unique_filename(cls, "eq") - lines = [ - "def __eq__(self, other):", - " if other.__class__ is not self.__class__:", - " return NotImplemented", - ] - - # We can't just do a big self.x = other.x and... clause due to - # irregularities like nan == nan is false but (nan,) == (nan,) is true. + lines = [ + "def __eq__(self, other):", + " if other.__class__ is not self.__class__:", + " return NotImplemented", + ] + + # We can't just do a big self.x = other.x and... clause due to + # irregularities like nan == nan is false but (nan,) == (nan,) is true. globs = {} - if attrs: - lines.append(" return (") + if attrs: + lines.append(" return (") others = [" ) == ("] - for a in attrs: + for a in attrs: if a.eq_key: cmp_name = "_%s_key" % (a.name,) # Add the key function to the global namespace @@ -1762,15 +1762,15 @@ def _make_eq(cls, attrs): else: lines.append(" self.%s," % (a.name,)) others.append(" other.%s," % (a.name,)) - - lines += others + [" )"] - else: - lines.append(" return True") - - script = "\n".join(lines) - + + lines += others + [" )"] + else: + lines.append(" return True") + + script = "\n".join(lines) + return _make_method("__eq__", script, unique_filename, globs) - + def _make_order(cls, attrs): """ @@ -1778,78 +1778,78 @@ def _make_order(cls, attrs): """ attrs = [a for a in attrs if a.order] - def attrs_to_tuple(obj): - """ - Save us some typing. - """ + def attrs_to_tuple(obj): + """ + Save us some typing. + """ return tuple( key(value) if key else value for value, key in ( (getattr(obj, a.name), a.order_key) for a in attrs ) ) - - def __lt__(self, other): - """ - Automatically created by attrs. - """ + + def __lt__(self, other): + """ + Automatically created by attrs. + """ if other.__class__ is self.__class__: - return attrs_to_tuple(self) < attrs_to_tuple(other) - + return attrs_to_tuple(self) < attrs_to_tuple(other) + return NotImplemented - def __le__(self, other): - """ - Automatically created by attrs. - """ + def __le__(self, other): + """ + Automatically created by attrs. + """ if other.__class__ is self.__class__: - return attrs_to_tuple(self) <= attrs_to_tuple(other) - + return attrs_to_tuple(self) <= attrs_to_tuple(other) + return NotImplemented - def __gt__(self, other): - """ - Automatically created by attrs. - """ + def __gt__(self, other): + """ + Automatically created by attrs. + """ if other.__class__ is self.__class__: - return attrs_to_tuple(self) > attrs_to_tuple(other) - + return attrs_to_tuple(self) > attrs_to_tuple(other) + return NotImplemented - def __ge__(self, other): - """ - Automatically created by attrs. - """ + def __ge__(self, other): + """ + Automatically created by attrs. + """ if other.__class__ is self.__class__: - return attrs_to_tuple(self) >= attrs_to_tuple(other) - + return attrs_to_tuple(self) >= attrs_to_tuple(other) + return NotImplemented - + return __lt__, __le__, __gt__, __ge__ - + def _add_eq(cls, attrs=None): - """ + """ Add equality methods to *cls* with *attrs*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + cls.__eq__ = _make_eq(cls, attrs) cls.__ne__ = _make_ne() - - return cls - - -_already_repring = threading.local() - - -def _make_repr(attrs, ns): - """ + + return cls + + +_already_repring = threading.local() + + +def _make_repr(attrs, ns): + """ Make a repr method that includes relevant *attrs*, adding *ns* to the full name. - """ - + """ + # Figure out which attributes to include, and which function to use to # format them. The a.repr value can be either bool or a custom callable. attr_names_with_reprs = tuple( @@ -1858,146 +1858,146 @@ def _make_repr(attrs, ns): if a.repr is not False ) - def __repr__(self): - """ - Automatically created by attrs. - """ - try: - working_set = _already_repring.working_set - except AttributeError: - working_set = set() - _already_repring.working_set = working_set - - if id(self) in working_set: - return "..." - real_cls = self.__class__ - if ns is None: - qualname = getattr(real_cls, "__qualname__", None) - if qualname is not None: - class_name = qualname.rsplit(">.", 1)[-1] - else: - class_name = real_cls.__name__ - else: - class_name = ns + "." + real_cls.__name__ - - # Since 'self' remains on the stack (i.e.: strongly referenced) for the - # duration of this call, it's safe to depend on id(...) stability, and - # not need to track the instance and therefore worry about properties - # like weakref- or hash-ability. - working_set.add(id(self)) - try: - result = [class_name, "("] - first = True + def __repr__(self): + """ + Automatically created by attrs. + """ + try: + working_set = _already_repring.working_set + except AttributeError: + working_set = set() + _already_repring.working_set = working_set + + if id(self) in working_set: + return "..." + real_cls = self.__class__ + if ns is None: + qualname = getattr(real_cls, "__qualname__", None) + if qualname is not None: + class_name = qualname.rsplit(">.", 1)[-1] + else: + class_name = real_cls.__name__ + else: + class_name = ns + "." + real_cls.__name__ + + # Since 'self' remains on the stack (i.e.: strongly referenced) for the + # duration of this call, it's safe to depend on id(...) stability, and + # not need to track the instance and therefore worry about properties + # like weakref- or hash-ability. + working_set.add(id(self)) + try: + result = [class_name, "("] + first = True for name, attr_repr in attr_names_with_reprs: - if first: - first = False - else: - result.append(", ") + if first: + first = False + else: + result.append(", ") result.extend( (name, "=", attr_repr(getattr(self, name, NOTHING))) ) - return "".join(result) + ")" - finally: - working_set.remove(id(self)) - - return __repr__ - - -def _add_repr(cls, ns=None, attrs=None): - """ - Add a repr method to *cls*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - cls.__repr__ = _make_repr(attrs, ns) - return cls - - -def fields(cls): - """ - Return the tuple of ``attrs`` attributes for a class. - - The tuple also allows accessing the fields by their names (see below for - examples). - - :param type cls: Class to introspect. - - :raise TypeError: If *cls* is not a class. - :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` - class. - + return "".join(result) + ")" + finally: + working_set.remove(id(self)) + + return __repr__ + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__repr__ = _make_repr(attrs, ns) + return cls + + +def fields(cls): + """ + Return the tuple of ``attrs`` attributes for a class. + + The tuple also allows accessing the fields by their names (see below for + examples). + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + :rtype: tuple (with name accessors) of `attr.Attribute` - - .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields - by name. - """ - if not isclass(cls): - raise TypeError("Passed object must be a class.") - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is None: - raise NotAnAttrsClassError( - "{cls!r} is not an attrs-decorated class.".format(cls=cls) - ) - return attrs - - -def fields_dict(cls): - """ - Return an ordered dictionary of ``attrs`` attributes for a class, whose - keys are the attribute names. - - :param type cls: Class to introspect. - - :raise TypeError: If *cls* is not a class. - :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` - class. - - :rtype: an ordered dict where keys are attribute names and values are + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return attrs + + +def fields_dict(cls): + """ + Return an ordered dictionary of ``attrs`` attributes for a class, whose + keys are the attribute names. + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + :rtype: an ordered dict where keys are attribute names and values are `attr.Attribute`\\ s. This will be a `dict` if it's - naturally ordered like on Python 3.6+ or an - :class:`~collections.OrderedDict` otherwise. - - .. versionadded:: 18.1.0 - """ - if not isclass(cls): - raise TypeError("Passed object must be a class.") - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is None: - raise NotAnAttrsClassError( - "{cls!r} is not an attrs-decorated class.".format(cls=cls) - ) - return ordered_dict(((a.name, a) for a in attrs)) - - -def validate(inst): - """ - Validate all attributes on *inst* that have a validator. - - Leaves all exceptions through. - - :param inst: Instance of a class with ``attrs`` attributes. - """ - if _config._run_validators is False: - return - - for a in fields(inst.__class__): - v = a.validator - if v is not None: - v(inst, a, getattr(inst, a.name)) - - -def _is_slot_cls(cls): - return "__slots__" in cls.__dict__ - - + naturally ordered like on Python 3.6+ or an + :class:`~collections.OrderedDict` otherwise. + + .. versionadded:: 18.1.0 + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return ordered_dict(((a.name, a) for a in attrs)) + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + :param inst: Instance of a class with ``attrs`` attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _is_slot_cls(cls): + return "__slots__" in cls.__dict__ + + def _is_slot_attr(a_name, base_attr_map): - """ - Check if the attribute name comes from a slot class. - """ + """ + Check if the attribute name comes from a slot class. + """ return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) - - + + def _make_init( cls, attrs, @@ -2186,15 +2186,15 @@ def _attrs_to_init_script( has_global_on_setattr, attrs_init, ): - """ - Return a script of an initializer for *attrs* and a dict of globals. - - The globals are expected by the generated script. - - If *frozen* is True, we cannot set the attributes directly so we use - a cached ``object.__setattr__``. - """ - lines = [] + """ + Return a script of an initializer for *attrs* and a dict of globals. + + The globals are expected by the generated script. + + If *frozen* is True, we cannot set the attributes directly so we use + a cached ``object.__setattr__``. + """ + lines = [] if pre_init: lines.append("self.__attrs_pre_init__()") @@ -2206,21 +2206,21 @@ def _attrs_to_init_script( "_setattr = _cached_setattr.__get__(self, self.__class__)" ) - if frozen is True: - if slots is True: + if frozen is True: + if slots is True: fmt_setter = _setattr fmt_setter_with_converter = _setattr_with_converter - else: - # Dict frozen classes assign directly to __dict__. - # But only if the attribute doesn't come from an ancestor slot - # class. + else: + # Dict frozen classes assign directly to __dict__. + # But only if the attribute doesn't come from an ancestor slot + # class. # Note _inst_dict will be used again below if cache_hash is True lines.append("_inst_dict = self.__dict__") - + def fmt_setter(attr_name, value_var, has_on_setattr): if _is_slot_attr(attr_name, base_attr_map): return _setattr(attr_name, value_var, has_on_setattr) - + return "_inst_dict['%s'] = %s" % (attr_name, value_var) def fmt_setter_with_converter( @@ -2237,40 +2237,40 @@ def _attrs_to_init_script( value_var, ) - else: - # Not frozen. + else: + # Not frozen. fmt_setter = _assign fmt_setter_with_converter = _assign_with_converter - - args = [] + + args = [] kw_only_args = [] - attrs_to_validate = [] - - # This is a dictionary of names to validator and converter callables. - # Injecting this into __init__ globals lets us avoid lookups. - names_for_globals = {} + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} annotations = {"return": None} - - for a in attrs: - if a.validator: - attrs_to_validate.append(a) - attr_name = a.name + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + + attr_name = a.name has_on_setattr = a.on_setattr is not None or ( a.on_setattr is not setters.NO_OP and has_global_on_setattr ) - arg_name = a.name.lstrip("_") - - has_factory = isinstance(a.default, Factory) - if has_factory and a.default.takes_self: - maybe_self = "self" - else: - maybe_self = "" - - if a.init is False: - if has_factory: - init_factory_name = _init_factory_pat.format(a.name) - if a.converter is not None: + arg_name = a.name.lstrip("_") + + has_factory = isinstance(a.default, Factory) + if has_factory and a.default.takes_self: + maybe_self = "self" + else: + maybe_self = "" + + if a.init is False: + if has_factory: + init_factory_name = _init_factory_pat.format(a.name) + if a.converter is not None: lines.append( fmt_setter_with_converter( attr_name, @@ -2279,8 +2279,8 @@ def _attrs_to_init_script( ) ) conv_name = _init_converter_pat % (a.name,) - names_for_globals[conv_name] = a.converter - else: + names_for_globals[conv_name] = a.converter + else: lines.append( fmt_setter( attr_name, @@ -2288,9 +2288,9 @@ def _attrs_to_init_script( has_on_setattr, ) ) - names_for_globals[init_factory_name] = a.default.factory - else: - if a.converter is not None: + names_for_globals[init_factory_name] = a.default.factory + else: + if a.converter is not None: lines.append( fmt_setter_with_converter( attr_name, @@ -2299,8 +2299,8 @@ def _attrs_to_init_script( ) ) conv_name = _init_converter_pat % (a.name,) - names_for_globals[conv_name] = a.converter - else: + names_for_globals[conv_name] = a.converter + else: lines.append( fmt_setter( attr_name, @@ -2308,14 +2308,14 @@ def _attrs_to_init_script( has_on_setattr, ) ) - elif a.default is not NOTHING and not has_factory: + elif a.default is not NOTHING and not has_factory: arg = "%s=attr_dict['%s'].default" % (arg_name, attr_name) if a.kw_only: kw_only_args.append(arg) else: args.append(arg) - if a.converter is not None: + if a.converter is not None: lines.append( fmt_setter_with_converter( attr_name, arg_name, has_on_setattr @@ -2324,10 +2324,10 @@ def _attrs_to_init_script( names_for_globals[ _init_converter_pat % (a.name,) ] = a.converter - else: + else: lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - elif has_factory: + elif has_factory: arg = "%s=NOTHING" % (arg_name,) if a.kw_only: kw_only_args.append(arg) @@ -2335,15 +2335,15 @@ def _attrs_to_init_script( args.append(arg) lines.append("if %s is not NOTHING:" % (arg_name,)) - init_factory_name = _init_factory_pat.format(a.name) - if a.converter is not None: + init_factory_name = _init_factory_pat.format(a.name) + if a.converter is not None: lines.append( " " + fmt_setter_with_converter( attr_name, arg_name, has_on_setattr ) ) - lines.append("else:") + lines.append("else:") lines.append( " " + fmt_setter_with_converter( @@ -2351,15 +2351,15 @@ def _attrs_to_init_script( init_factory_name + "(" + maybe_self + ")", has_on_setattr, ) - ) + ) names_for_globals[ _init_converter_pat % (a.name,) ] = a.converter - else: + else: lines.append( " " + fmt_setter(attr_name, arg_name, has_on_setattr) ) - lines.append("else:") + lines.append("else:") lines.append( " " + fmt_setter( @@ -2368,14 +2368,14 @@ def _attrs_to_init_script( has_on_setattr, ) ) - names_for_globals[init_factory_name] = a.default.factory - else: + names_for_globals[init_factory_name] = a.default.factory + else: if a.kw_only: kw_only_args.append(arg_name) else: args.append(arg_name) - if a.converter is not None: + if a.converter is not None: lines.append( fmt_setter_with_converter( attr_name, arg_name, has_on_setattr @@ -2384,9 +2384,9 @@ def _attrs_to_init_script( names_for_globals[ _init_converter_pat % (a.name,) ] = a.converter - else: + else: lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - + if a.init is True: if a.type is not None and a.converter is None: annotations[arg_name] = a.type @@ -2405,22 +2405,22 @@ def _attrs_to_init_script( is not inspect.Parameter.empty ): annotations[arg_name] = sig_params[0].annotation - - if attrs_to_validate: # we can skip this if there are no validators. - names_for_globals["_config"] = _config - lines.append("if _config._run_validators is True:") - for a in attrs_to_validate: + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: val_name = "__attr_validator_" + a.name attr_name = "__attr_" + a.name lines.append( " %s(self, %s, self.%s)" % (val_name, attr_name, a.name) ) - names_for_globals[val_name] = a.validator - names_for_globals[attr_name] = a + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + + if post_init: + lines.append("self.__attrs_post_init__()") - if post_init: - lines.append("self.__attrs_post_init__()") - # because this is set only after __attrs_post_init is called, a crash # will result if post-init tries to access the hash code. This seemed # preferable to setting this beforehand, in which case alteration to @@ -2459,8 +2459,8 @@ def _attrs_to_init_script( return ( """\ def {init_name}(self, {args}): - {lines} -""".format( + {lines} +""".format( init_name=("__attrs_init__" if attrs_init else "__init__"), args=args, lines="\n ".join(lines) if lines else "pass", @@ -2468,12 +2468,12 @@ def {init_name}(self, {args}): names_for_globals, annotations, ) - - -class Attribute(object): - """ - *Read-only* representation of an attribute. - + + +class Attribute(object): + """ + *Read-only* representation of an attribute. + Instances of this class are frequently used for introspection purposes like: @@ -2481,13 +2481,13 @@ class Attribute(object): - Validators get them passed as the first argument. - The *field transformer* hook receives a list of them. - :attribute name: The name of the attribute. + :attribute name: The name of the attribute. :attribute inherited: Whether or not that attribute has been inherited from a base class. - + Plus *all* arguments of `attr.ib` (except for ``factory`` which is only syntactic sugar for ``default=Factory(...)``. - + .. versionadded:: 20.1.0 *inherited* .. versionadded:: 20.1.0 *on_setattr* .. versionchanged:: 20.2.0 *inherited* is not taken into account for @@ -2495,9 +2495,9 @@ class Attribute(object): .. versionadded:: 21.1.0 *eq_key* and *order_key* For the full version history of the fields, see `attr.ib`. - """ + """ - __slots__ = ( + __slots__ = ( "name", "default", "validator", @@ -2514,8 +2514,8 @@ class Attribute(object): "kw_only", "inherited", "on_setattr", - ) - + ) + def __init__( self, name, @@ -2540,22 +2540,22 @@ class Attribute(object): cmp, eq_key or eq, order_key or order, True ) - # Cache this descriptor here to speed things up later. - bound_setattr = _obj_setattr.__get__(self, Attribute) - - # Despite the big red warning, people *do* instantiate `Attribute` - # themselves. - bound_setattr("name", name) - bound_setattr("default", default) - bound_setattr("validator", validator) - bound_setattr("repr", repr) + # Cache this descriptor here to speed things up later. + bound_setattr = _obj_setattr.__get__(self, Attribute) + + # Despite the big red warning, people *do* instantiate `Attribute` + # themselves. + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) bound_setattr("eq", eq) bound_setattr("eq_key", eq_key) bound_setattr("order", order) bound_setattr("order_key", order_key) - bound_setattr("hash", hash) - bound_setattr("init", init) - bound_setattr("converter", converter) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("converter", converter) bound_setattr( "metadata", ( @@ -2564,25 +2564,25 @@ class Attribute(object): else _empty_metadata_singleton ), ) - bound_setattr("type", type) + bound_setattr("type", type) bound_setattr("kw_only", kw_only) bound_setattr("inherited", inherited) bound_setattr("on_setattr", on_setattr) - - def __setattr__(self, name, value): - raise FrozenInstanceError() - - @classmethod - def from_counting_attr(cls, name, ca, type=None): - # type holds the annotated value. deal with conflicts: - if type is None: - type = ca.type - elif ca.type is not None: - raise ValueError( - "Type annotation and type argument cannot both be present" - ) - inst_dict = { - k: getattr(ca, k) + + def __setattr__(self, name, value): + raise FrozenInstanceError() + + @classmethod + def from_counting_attr(cls, name, ca, type=None): + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + raise ValueError( + "Type annotation and type argument cannot both be present" + ) + inst_dict = { + k: getattr(ca, k) for k in Attribute.__slots__ if k not in ( @@ -2591,18 +2591,18 @@ class Attribute(object): "default", "type", "inherited", - ) # exclude methods and deprecated alias - } - return cls( + ) # exclude methods and deprecated alias + } + return cls( name=name, validator=ca._validator, default=ca._default, type=type, cmp=None, inherited=False, - **inst_dict - ) - + **inst_dict + ) + @property def cmp(self): """ @@ -2630,37 +2630,37 @@ class Attribute(object): return new - # Don't use _add_pickle since fields(Attribute) doesn't work - def __getstate__(self): - """ - Play nice with pickle. - """ + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ return tuple( getattr(self, name) if name != "metadata" else dict(self.metadata) for name in self.__slots__ ) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ + + def __setstate__(self, state): + """ + Play nice with pickle. + """ self._setattrs(zip(self.__slots__, state)) def _setattrs(self, name_values_pairs): - bound_setattr = _obj_setattr.__get__(self, Attribute) + bound_setattr = _obj_setattr.__get__(self, Attribute) for name, value in name_values_pairs: - if name != "metadata": - bound_setattr(name, value) - else: + if name != "metadata": + bound_setattr(name, value) + else: bound_setattr( name, metadata_proxy(value) if value else _empty_metadata_singleton, ) - - -_a = [ + + +_a = [ Attribute( name=name, default=NOTHING, @@ -2673,26 +2673,26 @@ _a = [ init=True, inherited=False, ) - for name in Attribute.__slots__ -] - -Attribute = _add_hash( + for name in Attribute.__slots__ +] + +Attribute = _add_hash( _add_eq( _add_repr(Attribute, attrs=_a), attrs=[a for a in _a if a.name != "inherited"], ), attrs=[a for a in _a if a.hash and a.name != "inherited"], -) - - -class _CountingAttr(object): - """ - Intermediate representation of attributes that uses a counter to preserve - the order in which the attributes have been defined. - - *Internal* data structure of the attrs library. Running into is most - likely the result of a bug like a forgotten `@attr.s` decorator. - """ +) + + +class _CountingAttr(object): + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ __slots__ = ( "counter", @@ -2711,7 +2711,7 @@ class _CountingAttr(object): "kw_only", "on_setattr", ) - __attrs_attrs__ = tuple( + __attrs_attrs__ = tuple( Attribute( name=name, default=NOTHING, @@ -2738,7 +2738,7 @@ class _CountingAttr(object): "init", "on_setattr", ) - ) + ( + ) + ( Attribute( name="metadata", default=None, @@ -2755,9 +2755,9 @@ class _CountingAttr(object): inherited=False, on_setattr=None, ), - ) - cls_counter = 0 - + ) + cls_counter = 0 + def __init__( self, default, @@ -2776,89 +2776,89 @@ class _CountingAttr(object): order_key, on_setattr, ): - _CountingAttr.cls_counter += 1 - self.counter = _CountingAttr.cls_counter - self._default = default + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default self._validator = validator self.converter = converter - self.repr = repr + self.repr = repr self.eq = eq self.eq_key = eq_key self.order = order self.order_key = order_key - self.hash = hash - self.init = init - self.metadata = metadata - self.type = type + self.hash = hash + self.init = init + self.metadata = metadata + self.type = type self.kw_only = kw_only self.on_setattr = on_setattr - - def validator(self, meth): - """ - Decorator that adds *meth* to the list of validators. - - Returns *meth* unchanged. - - .. versionadded:: 17.1.0 - """ - if self._validator is None: - self._validator = meth - else: - self._validator = and_(self._validator, meth) - return meth - - def default(self, meth): - """ - Decorator that allows to set the default for an attribute. - - Returns *meth* unchanged. - - :raises DefaultAlreadySetError: If default has been set before. - - .. versionadded:: 17.1.0 - """ - if self._default is not NOTHING: - raise DefaultAlreadySetError() - - self._default = Factory(meth, takes_self=True) - - return meth - - + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + :raises DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError() + + self._default = Factory(meth, takes_self=True) + + return meth + + _CountingAttr = _add_eq(_add_repr(_CountingAttr)) - - -class Factory(object): - """ - Stores a factory callable. - + + +class Factory(object): + """ + Stores a factory callable. + If passed as the default value to `attr.ib`, the factory is used to - generate a new value. - - :param callable factory: A callable that takes either none or exactly one - mandatory positional argument depending on *takes_self*. - :param bool takes_self: Pass the partially initialized instance that is - being initialized as a positional argument. - - .. versionadded:: 17.1.0 *takes_self* - """ + generate a new value. + + :param callable factory: A callable that takes either none or exactly one + mandatory positional argument depending on *takes_self*. + :param bool takes_self: Pass the partially initialized instance that is + being initialized as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ __slots__ = ("factory", "takes_self") - - def __init__(self, factory, takes_self=False): - """ - `Factory` is part of the default machinery so if we want a default - value here, we have to implement it ourselves. - """ - self.factory = factory - self.takes_self = takes_self - + + def __init__(self, factory, takes_self=False): + """ + `Factory` is part of the default machinery so if we want a default + value here, we have to implement it ourselves. + """ + self.factory = factory + self.takes_self = takes_self + def __getstate__(self): """ Play nice with pickle. """ return tuple(getattr(self, name) for name in self.__slots__) - + def __setstate__(self, state): """ Play nice with pickle. @@ -2886,40 +2886,40 @@ _f = [ Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) -def make_class(name, attrs, bases=(object,), **attributes_arguments): - """ - A quick way to create a new class called *name* with *attrs*. - +def make_class(name, attrs, bases=(object,), **attributes_arguments): + """ + A quick way to create a new class called *name* with *attrs*. + :param str name: The name for the new class. - - :param attrs: A list of names or a dictionary of mappings of names to - attributes. - + + :param attrs: A list of names or a dictionary of mappings of names to + attributes. + If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, `collections.OrderedDict` otherwise), the order is deduced from - the order of the names or attributes inside *attrs*. Otherwise the - order of the definition of the attributes is used. + the order of the names or attributes inside *attrs*. Otherwise the + order of the definition of the attributes is used. :type attrs: `list` or `dict` - - :param tuple bases: Classes that the new class will subclass. - + + :param tuple bases: Classes that the new class will subclass. + :param attributes_arguments: Passed unmodified to `attr.s`. - - :return: A new class with *attrs*. - :rtype: type - - .. versionadded:: 17.1.0 *bases* - .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. - """ - if isinstance(attrs, dict): - cls_dict = attrs - elif isinstance(attrs, (list, tuple)): - cls_dict = dict((a, attrib()) for a in attrs) - else: - raise TypeError("attrs argument must be a dict or a list.") - + + :return: A new class with *attrs*. + :rtype: type + + .. versionadded:: 17.1.0 *bases* + .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. + """ + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = dict((a, attrib()) for a in attrs) + else: + raise TypeError("attrs argument must be a dict or a list.") + pre_init = cls_dict.pop("__attrs_pre_init__", None) - post_init = cls_dict.pop("__attrs_post_init__", None) + post_init = cls_dict.pop("__attrs_post_init__", None) user_init = cls_dict.pop("__init__", None) body = {} @@ -2932,17 +2932,17 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments): type_ = new_class(name, bases, {}, lambda ns: ns.update(body)) - # For pickling to work, the __module__ variable needs to be set to the - # frame where the class is created. Bypass this step in environments where - # sys._getframe is not defined (Jython for example) or sys._getframe is not - # defined for arguments greater than 0 (IronPython). - try: - type_.__module__ = sys._getframe(1).f_globals.get( + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + try: + type_.__module__ = sys._getframe(1).f_globals.get( "__name__", "__main__" - ) - except (AttributeError, ValueError): - pass - + ) + except (AttributeError, ValueError): + pass + # We do it here for proper warnings with meaningful stacklevel. cmp = attributes_arguments.pop("cmp", None) ( @@ -2955,45 +2955,45 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments): True, ) - return _attrs(these=cls_dict, **attributes_arguments)(type_) - - -# These are required by within this module so we define them here and merely + return _attrs(these=cls_dict, **attributes_arguments)(type_) + + +# These are required by within this module so we define them here and merely # import into .validators / .converters. - - -@attrs(slots=True, hash=True) -class _AndValidator(object): - """ - Compose many validators to a single one. - """ - - _validators = attrib() - - def __call__(self, inst, attr, value): - for v in self._validators: - v(inst, attr, value) - - -def and_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators. - + + +@attrs(slots=True, hash=True) +class _AndValidator(object): + """ + Compose many validators to a single one. + """ + + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + :param callables validators: Arbitrary number of validators. - - .. versionadded:: 17.1.0 - """ - vals = [] - for validator in validators: - vals.extend( + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( validator._validators if isinstance(validator, _AndValidator) - else [validator] - ) - - return _AndValidator(tuple(vals)) + else [validator] + ) + + return _AndValidator(tuple(vals)) def pipe(*converters): diff --git a/contrib/python/attrs/attr/converters.py b/contrib/python/attrs/attr/converters.py index d36652e31c..2777db6d0a 100644 --- a/contrib/python/attrs/attr/converters.py +++ b/contrib/python/attrs/attr/converters.py @@ -1,12 +1,12 @@ -""" -Commonly useful converters. -""" - -from __future__ import absolute_import, division, print_function - +""" +Commonly useful converters. +""" + +from __future__ import absolute_import, division, print_function + from ._compat import PY2 from ._make import NOTHING, Factory, pipe - + if not PY2: import inspect @@ -20,25 +20,25 @@ __all__ = [ ] -def optional(converter): - """ - A converter that allows an attribute to be optional. An optional attribute - is one which can be set to ``None``. - +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to ``None``. + Type annotations will be inferred from the wrapped converter's, if it has any. - :param callable converter: the converter that is used for non-``None`` - values. - + :param callable converter: the converter that is used for non-``None`` + values. + .. versionadded:: 17.1.0 - """ - - def optional_converter(val): - if val is None: - return None - return converter(val) - + """ + + def optional_converter(val): + if val is None: + return None + return converter(val) + if not PY2: sig = None try: @@ -56,7 +56,7 @@ def optional(converter): sig.return_annotation ] - return optional_converter + return optional_converter def default_if_none(default=NOTHING, factory=None): diff --git a/contrib/python/attrs/attr/exceptions.py b/contrib/python/attrs/attr/exceptions.py index 3669abab3a..f6f9861bea 100644 --- a/contrib/python/attrs/attr/exceptions.py +++ b/contrib/python/attrs/attr/exceptions.py @@ -1,21 +1,21 @@ -from __future__ import absolute_import, division, print_function - - +from __future__ import absolute_import, division, print_function + + class FrozenError(AttributeError): - """ + """ A frozen/immutable instance or attribute have been attempted to be modified. - - It mirrors the behavior of ``namedtuples`` by using the same error message + + It mirrors the behavior of ``namedtuples`` by using the same error message and subclassing `AttributeError`. - + .. versionadded:: 20.1.0 - """ + """ + + msg = "can't set attribute" + args = [msg] + - msg = "can't set attribute" - args = [msg] - - class FrozenInstanceError(FrozenError): """ A frozen instance has been attempted to be modified. @@ -32,38 +32,38 @@ class FrozenAttributeError(FrozenError): """ -class AttrsAttributeNotFoundError(ValueError): - """ - An ``attrs`` function couldn't find an attribute that the user asked for. - - .. versionadded:: 16.2.0 - """ - - -class NotAnAttrsClassError(ValueError): - """ - A non-``attrs`` class has been passed into an ``attrs`` function. - - .. versionadded:: 16.2.0 - """ - - -class DefaultAlreadySetError(RuntimeError): - """ - A default has been set using ``attr.ib()`` and is attempted to be reset - using the decorator. - - .. versionadded:: 17.1.0 - """ - - -class UnannotatedAttributeError(RuntimeError): - """ - A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type - annotation. - - .. versionadded:: 17.3.0 - """ +class AttrsAttributeNotFoundError(ValueError): + """ + An ``attrs`` function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-``attrs`` class has been passed into an ``attrs`` function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set using ``attr.ib()`` and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type + annotation. + + .. versionadded:: 17.3.0 + """ class PythonTooOldError(RuntimeError): diff --git a/contrib/python/attrs/attr/filters.py b/contrib/python/attrs/attr/filters.py index ba8f0482f9..dc47e8fa38 100644 --- a/contrib/python/attrs/attr/filters.py +++ b/contrib/python/attrs/attr/filters.py @@ -1,52 +1,52 @@ -""" +""" Commonly useful filters for `attr.asdict`. -""" - -from __future__ import absolute_import, division, print_function - -from ._compat import isclass -from ._make import Attribute - - -def _split_what(what): - """ - Returns a tuple of `frozenset`s of classes and attributes. - """ - return ( - frozenset(cls for cls in what if isclass(cls)), - frozenset(cls for cls in what if isinstance(cls, Attribute)), - ) - - -def include(*what): - """ - Whitelist *what*. - - :param what: What to whitelist. +""" + +from __future__ import absolute_import, division, print_function + +from ._compat import isclass +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isclass(cls)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Whitelist *what*. + + :param what: What to whitelist. :type what: `list` of `type` or `attr.Attribute`\\ s - + :rtype: `callable` - """ - cls, attrs = _split_what(what) - - def include_(attribute, value): - return value.__class__ in cls or attribute in attrs - - return include_ - - -def exclude(*what): - """ - Blacklist *what*. - - :param what: What to blacklist. + """ + cls, attrs = _split_what(what) + + def include_(attribute, value): + return value.__class__ in cls or attribute in attrs + + return include_ + + +def exclude(*what): + """ + Blacklist *what*. + + :param what: What to blacklist. :type what: `list` of classes or `attr.Attribute`\\ s. - + :rtype: `callable` - """ - cls, attrs = _split_what(what) - - def exclude_(attribute, value): - return value.__class__ not in cls and attribute not in attrs - - return exclude_ + """ + cls, attrs = _split_what(what) + + def exclude_(attribute, value): + return value.__class__ not in cls and attribute not in attrs + + return exclude_ diff --git a/contrib/python/attrs/attr/validators.py b/contrib/python/attrs/attr/validators.py index 6932bac87a..b9a73054e9 100644 --- a/contrib/python/attrs/attr/validators.py +++ b/contrib/python/attrs/attr/validators.py @@ -1,15 +1,15 @@ -""" -Commonly useful validators. -""" - -from __future__ import absolute_import, division, print_function - +""" +Commonly useful validators. +""" + +from __future__ import absolute_import, division, print_function + import re -from ._make import _AndValidator, and_, attrib, attrs +from ._make import _AndValidator, and_, attrib, attrs from .exceptions import NotCallableError - - + + __all__ = [ "and_", "deep_iterable", @@ -21,19 +21,19 @@ __all__ = [ "optional", "provides", ] - - -@attrs(repr=False, slots=True, hash=True) -class _InstanceOfValidator(object): - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not isinstance(value, self.type): - raise TypeError( - "'{name}' must be {type!r} (got {value!r} that is a " + + +@attrs(repr=False, slots=True, hash=True) +class _InstanceOfValidator(object): + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + raise TypeError( + "'{name}' must be {type!r} (got {value!r} that is a " "{actual!r}).".format( name=attr.name, type=self.type, @@ -43,30 +43,30 @@ class _InstanceOfValidator(object): attr, self.type, value, - ) - - def __repr__(self): + ) + + def __repr__(self): return "<instance_of validator for type {type!r}>".format( type=self.type - ) - - -def instance_of(type): - """ + ) + + +def instance_of(type): + """ A validator that raises a `TypeError` if the initializer is called - with a wrong type for this particular attribute (checks are performed using + with a wrong type for this particular attribute (checks are performed using `isinstance` therefore it's also valid to pass a tuple of types). - - :param type: The type to check for. - :type type: type or tuple of types - - :raises TypeError: With a human readable error message, the attribute + + :param type: The type to check for. + :type type: type or tuple of types + + :raises TypeError: With a human readable error message, the attribute (of type `attr.Attribute`), the expected type, and the value it - got. - """ - return _InstanceOfValidator(type) - - + got. + """ + return _InstanceOfValidator(type) + + @attrs(repr=False, frozen=True, slots=True) class _MatchesReValidator(object): regex = attrib() @@ -139,121 +139,121 @@ def matches_re(regex, flags=0, func=None): return _MatchesReValidator(pattern, flags, match_func) -@attrs(repr=False, slots=True, hash=True) -class _ProvidesValidator(object): - interface = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.interface.providedBy(value): - raise TypeError( - "'{name}' must provide {interface!r} which {value!r} " +@attrs(repr=False, slots=True, hash=True) +class _ProvidesValidator(object): + interface = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.interface.providedBy(value): + raise TypeError( + "'{name}' must provide {interface!r} which {value!r} " "doesn't.".format( name=attr.name, interface=self.interface, value=value ), attr, self.interface, value, - ) - - def __repr__(self): + ) + + def __repr__(self): return "<provides validator for interface {interface!r}>".format( interface=self.interface - ) - - -def provides(interface): - """ + ) + + +def provides(interface): + """ A validator that raises a `TypeError` if the initializer is called - with an object that does not provide the requested *interface* (checks are - performed using ``interface.providedBy(value)`` (see `zope.interface - <https://zopeinterface.readthedocs.io/en/latest/>`_). - + with an object that does not provide the requested *interface* (checks are + performed using ``interface.providedBy(value)`` (see `zope.interface + <https://zopeinterface.readthedocs.io/en/latest/>`_). + :param interface: The interface to check for. :type interface: ``zope.interface.Interface`` - - :raises TypeError: With a human readable error message, the attribute + + :raises TypeError: With a human readable error message, the attribute (of type `attr.Attribute`), the expected interface, and the - value it got. - """ - return _ProvidesValidator(interface) - - -@attrs(repr=False, slots=True, hash=True) -class _OptionalValidator(object): - validator = attrib() - - def __call__(self, inst, attr, value): - if value is None: - return - - self.validator(inst, attr, value) - - def __repr__(self): + value it got. + """ + return _ProvidesValidator(interface) + + +@attrs(repr=False, slots=True, hash=True) +class _OptionalValidator(object): + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): return "<optional validator for {what} or None>".format( what=repr(self.validator) - ) - - -def optional(validator): - """ - A validator that makes an attribute optional. An optional attribute is one - which can be set to ``None`` in addition to satisfying the requirements of - the sub-validator. - - :param validator: A validator (or a list of validators) that is used for - non-``None`` values. + ) + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to ``None`` in addition to satisfying the requirements of + the sub-validator. + + :param validator: A validator (or a list of validators) that is used for + non-``None`` values. :type validator: callable or `list` of callables. - - .. versionadded:: 15.1.0 - .. versionchanged:: 17.1.0 *validator* can be a list of validators. - """ - if isinstance(validator, list): - return _OptionalValidator(_AndValidator(validator)) - return _OptionalValidator(validator) - - -@attrs(repr=False, slots=True, hash=True) -class _InValidator(object): - options = attrib() - - def __call__(self, inst, attr, value): + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + """ + if isinstance(validator, list): + return _OptionalValidator(_AndValidator(validator)) + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, hash=True) +class _InValidator(object): + options = attrib() + + def __call__(self, inst, attr, value): try: in_options = value in self.options except TypeError: # e.g. `1 in "abc"` in_options = False if not in_options: - raise ValueError( + raise ValueError( "'{name}' must be in {options!r} (got {value!r})".format( name=attr.name, options=self.options, value=value ) - ) - - def __repr__(self): + ) + + def __repr__(self): return "<in_ validator with options {options!r}>".format( options=self.options - ) - - -def in_(options): - """ + ) + + +def in_(options): + """ A validator that raises a `ValueError` if the initializer is called - with a value that does not belong in the options provided. The check is - performed using ``value in options``. - - :param options: Allowed options. + with a value that does not belong in the options provided. The check is + performed using ``value in options``. + + :param options: Allowed options. :type options: list, tuple, `enum.Enum`, ... - - :raises ValueError: With a human readable error message, the attribute (of + + :raises ValueError: With a human readable error message, the attribute (of type `attr.Attribute`), the expected options, and the value it - got. - - .. versionadded:: 17.1.0 - """ - return _InValidator(options) + got. + + .. versionadded:: 17.1.0 + """ + return _InValidator(options) @attrs(repr=False, slots=False, hash=True) diff --git a/contrib/python/attrs/ya.make b/contrib/python/attrs/ya.make index 397cb2e55e..15fb4c423b 100644 --- a/contrib/python/attrs/ya.make +++ b/contrib/python/attrs/ya.make @@ -1,37 +1,37 @@ PY23_LIBRARY() - + LICENSE(MIT) -OWNER(g:python-contrib) - +OWNER(g:python-contrib) + VERSION(21.2.0) - -NO_LINT() - -PY_SRCS( - TOP_LEVEL - attr/__init__.py + +NO_LINT() + +PY_SRCS( + TOP_LEVEL + attr/__init__.py attr/__init__.pyi attr/_cmp.py attr/_cmp.pyi - attr/_compat.py - attr/_config.py - attr/_funcs.py - attr/_make.py + attr/_compat.py + attr/_config.py + attr/_funcs.py + attr/_make.py attr/_version_info.py attr/_version_info.pyi - attr/converters.py + attr/converters.py attr/converters.pyi - attr/exceptions.py + attr/exceptions.py attr/exceptions.pyi - attr/filters.py + attr/filters.py attr/filters.pyi attr/setters.py attr/setters.pyi - attr/validators.py + attr/validators.py attr/validators.pyi -) - +) + IF (PYTHON3) PY_SRCS( TOP_LEVEL @@ -46,4 +46,4 @@ RESOURCE_FILES( attr/py.typed ) -END() +END() |